rbgraph 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 565742a594907115555240ba8d9112b22b4254e2
4
+ data.tar.gz: 1d4f367ef3bd8ece33ec00bbd4258a2feb4d444e
5
+ SHA512:
6
+ metadata.gz: 494dc5cd4a37f4744e311fefabfa43c68c8bc15dabee0da1dc0ebb7c4191096cc546933a2c75b269d1375765206453406e92ed723750a3074c1d782e19fcb958
7
+ data.tar.gz: d02edd56db4b14e52266ebb2d72137dd300a5b5624174ca69f74860b865cd11922d6f6ff5236ec7cff817a3793758d1b4a98eaee6eea8228a743c72900fa6133
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # Rbgraph
2
+ A simple and lightweight ruby implementation of graphs and traversal algorithms
3
+
4
+ ## General Requirements
5
+
6
+ Install via rubygems
7
+
8
+ ```gem install rbgraph```
9
+
10
+ or add it to your Gemfile
11
+
12
+ ```gem 'rbgraph'```
13
+
14
+ ## Example
15
+
16
+ ```ruby
17
+ graph = Rbgraph::UndirectedGraph.new()
18
+ graph.add_edge!({id: 1}, {id: 2})
19
+ graph.add_edge!({id: 2}, {id: 3})
20
+ graph.add_edge!({id: 1}, {id: 4})
21
+ graph.add_edge!({id: 4}, {id: 5})
22
+ graph.add_edge!({id: 3}, {id: 6})
23
+ graph.add_edge!({id: 7}, {id: 8})
24
+ graph.add_edge!({id: 7}, {id: 8})
25
+ graph.add_edge!({id: 7}, {id: 9})
26
+ graph.add_edge!({id: 10}, {id: 11})
27
+ graph.add_edge!({id: 12}, {id: 1})
28
+
29
+ t = Rbgraph::Traverser::BfsTraverser.new(graph)
30
+ t.connected_components.sort { |a, b| b.size <=> a.size }.each do |subgraph|
31
+ puts subgraph.nodes.values.map(&:id).inspect
32
+ end
33
+ ```
34
+
35
+ will output
36
+
37
+ ```ruby
38
+ [1, 2, 4, 12, 3, 5, 6]
39
+ [7, 8, 9]
40
+ [10, 11]
41
+ ```
42
+
43
+
44
+ ### Disclaimer
45
+ This project is written on a need to use basis for inclusion to other projects I'm working on for now, so completion is not an immediate goal.
@@ -0,0 +1,33 @@
1
+ module Rbgraph
2
+
3
+ class Edge
4
+
5
+ attr_accessor :id
6
+ attr_accessor :node1
7
+ attr_accessor :node2
8
+ attr_accessor :attributes
9
+
10
+ def initialize(node1, node2, attributes = {})
11
+ self.node1 = node1
12
+ self.node2 = node2
13
+ self.attributes = attributes
14
+ self.id = attributes[:id] || "#{node1.id}=#{self.class}=#{node2.id}"
15
+ end
16
+
17
+ def ==(node)
18
+ self.id == node.id
19
+ end
20
+ alias_method :==, :eql?
21
+
22
+ def hash
23
+ id
24
+ end
25
+
26
+ def merge(edge)
27
+ attributes.merge!(edge.attributes.reject { |k, v| k == :id })
28
+ self
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,46 @@
1
+ module Rbgraph
2
+
3
+ class Graph
4
+
5
+ attr_accessor :nodes
6
+ attr_accessor :edges
7
+
8
+ def initialize(nodes = {}, edges = {})
9
+ self.nodes = nodes
10
+ self.edges = edges
11
+ end
12
+
13
+ def size
14
+ nodes.values.length
15
+ end
16
+
17
+ def add_node!(node)
18
+ node = node.is_a?(Node) ? node : Node.new(node)
19
+ if nodes[node.id].nil?
20
+ nodes[node.id] = node
21
+ else
22
+ nodes[node.id].merge(node)
23
+ end
24
+ nodes[node.id]
25
+ end
26
+
27
+ def add_edge!(node1, node2, edge_attributes = {})
28
+ node1 = add_node!(node1)
29
+ node2 = add_node!(node2)
30
+ edge = Edge.new(node1, node2, edge_attributes)
31
+ edge = if edges[edge.id].nil?
32
+ edges[edge.id] = edge
33
+ else
34
+ edges[edge.id].merge(edge)
35
+ end
36
+ connect_nodes(node1, node2, edge)
37
+ edge
38
+ end
39
+
40
+ def connect_nodes(node1, node2, edge)
41
+ raise NotImplementedError("Cannot connect nodes on a general graph! Use either Directed or Undirected subclasses")
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,11 @@
1
+ module Rbgraph
2
+
3
+ class DirectedGraph < Graph
4
+
5
+ def connect_nodes(node1, node2, edge)
6
+ node1.connect_to(node2, edge)
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,12 @@
1
+ module Rbgraph
2
+
3
+ class UndirectedGraph < Graph
4
+
5
+ def connect_nodes(node1, node2, edge)
6
+ node1.connect_to(node2, edge)
7
+ node2.connect_to(node1, edge)
8
+ end
9
+
10
+ end
11
+
12
+ end
@@ -0,0 +1,40 @@
1
+ module Rbgraph
2
+
3
+ class Node
4
+
5
+ attr_accessor :id
6
+ attr_accessor :attributes
7
+ attr_accessor :neighbors
8
+ attr_accessor :edges
9
+
10
+ def initialize(attributes = {})
11
+ self.attributes = attributes
12
+ raise "Node should have an id attribute!" if attributes[:id].nil?
13
+ self.id = attributes[:id]
14
+ self.neighbors = {}
15
+ self.edges = {}
16
+ end
17
+
18
+ def ==(node)
19
+ self.id == node.id
20
+ end
21
+ alias_method :==, :eql?
22
+
23
+ def hash
24
+ id
25
+ end
26
+
27
+ def merge(node)
28
+ attributes.merge!(node.attributes.reject { |k, v| k == :id })
29
+ self
30
+ end
31
+
32
+ def connect_to(node, edge)
33
+ neighbors[node.id] = node
34
+ edges[edge.id] = edge
35
+ self
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,52 @@
1
+ module Rbgraph
2
+ module Traverser
3
+
4
+ class BfsTraverser
5
+
6
+ attr_accessor :graph
7
+ attr_accessor :connected_subgraphs
8
+ attr_accessor :visited_nodes
9
+ attr_accessor :unvisited_nodes
10
+ attr_accessor :queue
11
+
12
+ def initialize(graph)
13
+ self.graph = graph
14
+ self.connected_subgraphs = []
15
+ self.unvisited_nodes = Set.new [*graph.nodes.values]
16
+ end
17
+
18
+ def connected_components
19
+ self.visited_nodes = Set.new
20
+ self.queue = Queue.new
21
+
22
+ while !unvisited_nodes.empty? do
23
+ root = unvisited_nodes.to_a.first
24
+ unvisited_nodes.delete(unvisited_nodes.to_a.first)
25
+ self.connected_subgraphs << bfs_from_root(root)
26
+ end
27
+ connected_subgraphs
28
+ end
29
+
30
+ def bfs_from_root(root)
31
+ subgraph = graph.class.new
32
+ visited_nodes.add(root)
33
+ queue.enq(root)
34
+ while !queue.empty? do
35
+ t = queue.deq
36
+ unvisited_nodes.delete(t)
37
+ yield(t) if block_given? # do sth on current node
38
+ t.neighbors.each do |nid, neighbor|
39
+ subgraph.add_edge!(t, neighbor)
40
+ if !visited_nodes.include?(neighbor)
41
+ visited_nodes.add(neighbor)
42
+ queue.enq(neighbor)
43
+ end
44
+ end
45
+ end
46
+ subgraph
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,7 @@
1
+ module Rbgraph
2
+ module Traverser
3
+
4
+ autoload :BfsTraverser, 'rbgraph/traverser/bfs_traverser'
5
+
6
+ end
7
+ end
data/lib/rbgraph.rb ADDED
@@ -0,0 +1,12 @@
1
+ module Rbgraph
2
+
3
+ autoload :Graph, 'rbgraph/graph'
4
+ autoload :DirectedGraph, 'rbgraph/graphs/directed'
5
+ autoload :UndirectedGraph, 'rbgraph/graphs/undirected'
6
+
7
+ autoload :Node, 'rbgraph/node'
8
+ autoload :Edge, 'rbgraph/edge'
9
+
10
+ autoload :Traverser, 'rbgraph/traverser'
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rbgraph
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - George Lamprianidis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Generic Ruby graphs and operations on them!
28
+ email: giorgos.lamprianidis@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - Gemfile
34
+ - README.md
35
+ - lib/rbgraph.rb
36
+ - lib/rbgraph/edge.rb
37
+ - lib/rbgraph/graph.rb
38
+ - lib/rbgraph/graphs/directed.rb
39
+ - lib/rbgraph/graphs/undirected.rb
40
+ - lib/rbgraph/node.rb
41
+ - lib/rbgraph/traverser.rb
42
+ - lib/rbgraph/traverser/bfs_traverser.rb
43
+ homepage: http://rubygems.org/gems/rbgraph
44
+ licenses:
45
+ - MIT
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 2.2.2
64
+ signing_key:
65
+ specification_version: 4
66
+ summary: Generic Ruby graphs and operations on them!
67
+ test_files: []