graphunk 0.1.0
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 +7 -0
- data/lib/graph.rb +191 -0
- data/lib/graphunk.rb +1 -0
- metadata +46 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: db25940291ff0dba0ccab4d46a61f1caf520bbd4
|
4
|
+
data.tar.gz: 9fa3edb089b77c4075805f84dd9e135486d656e1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c1f02220f4bd9b6f650ae202d5e2f80e7cb74bb0b6ccadb13c0874dfb2e7288b1c87c79de6ae1c82a3f16f32df0a3471f0afb5725a65c248900b21616058df85
|
7
|
+
data.tar.gz: 8c2e00a649ad8e78a7fd6ed71cff5c74b104de15124e75db4af78ff1280b18fb570ff6c5f14713a93677732238f095d107114853b9a97efd17713dc4c37e4b4c
|
data/lib/graph.rb
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
# Undirected graph
|
4
|
+
# Vertices represented by strings
|
5
|
+
class Graph < Hash
|
6
|
+
def vertices
|
7
|
+
keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def edges
|
11
|
+
[].tap do |edge_constructor|
|
12
|
+
vertices.each do |vertex|
|
13
|
+
self[vertex].each do |neighbor|
|
14
|
+
edge_constructor << [vertex, neighbor]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_vertex(name)
|
21
|
+
unless vertex_exists?(name)
|
22
|
+
self[name] = []
|
23
|
+
else
|
24
|
+
raise ArgumentError, "Vertex already exists"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_edge(first_vertex, second_vertex)
|
29
|
+
if edge_exists?(first_vertex, second_vertex)
|
30
|
+
raise ArgumentError, "This edge already exists"
|
31
|
+
elsif vertex_exists?(first_vertex) && vertex_exists?(second_vertex)
|
32
|
+
ordered_vertices = order_vertices(first_vertex, second_vertex)
|
33
|
+
self[ordered_vertices.first] << ordered_vertices.last
|
34
|
+
else
|
35
|
+
raise ArgumentError, "One of the vertices referenced does not exist in the graph"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove_vertex(name)
|
40
|
+
if vertex_exists?(name)
|
41
|
+
self.each_pair do |key, value|
|
42
|
+
self[key].delete(name) if value.include?(name)
|
43
|
+
end
|
44
|
+
self.delete(name)
|
45
|
+
else
|
46
|
+
raise ArgumentError, "That vertex does not exist in the graph"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def remove_edge(first_vertex, second_vertex)
|
51
|
+
if edge_exists?(first_vertex, second_vertex)
|
52
|
+
ordered_vertices = order_vertices(first_vertex, second_vertex)
|
53
|
+
self[ordered_vertices.first].delete(ordered_vertices.last)
|
54
|
+
else
|
55
|
+
raise ArgumentError, "That edge does not exist in the graph"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def edges_on_vertex(name)
|
60
|
+
if vertex_exists?(name)
|
61
|
+
edges.select { |edge| edge.include?(name) }
|
62
|
+
else
|
63
|
+
raise ArgumentError, "That vertex does not exist in the graph"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def neighbors_of_vertex(name)
|
68
|
+
if vertex_exists?(name)
|
69
|
+
edges.select { |edge| edge.include? name }.map do |edge|
|
70
|
+
if edge.first == name
|
71
|
+
edge.last
|
72
|
+
else
|
73
|
+
edge.first
|
74
|
+
end
|
75
|
+
end
|
76
|
+
else
|
77
|
+
raise ArgumentError, "That vertex does not exist in the graph"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def edge_exists?(first_vertex, second_vertex)
|
82
|
+
edges.include?(order_vertices(first_vertex, second_vertex))
|
83
|
+
end
|
84
|
+
|
85
|
+
def vertex_exists?(name)
|
86
|
+
vertices.include?(name)
|
87
|
+
end
|
88
|
+
|
89
|
+
def lexicographic_bfs
|
90
|
+
sets = [vertices]
|
91
|
+
output_vertices = []
|
92
|
+
|
93
|
+
until sets.empty?
|
94
|
+
v = sets.first.delete_at(0)
|
95
|
+
sets.delete_at(0) if sets.first.empty?
|
96
|
+
output_vertices << v
|
97
|
+
replaced = []
|
98
|
+
neighbors_of_vertex(v).each do |neighbor|
|
99
|
+
s = sets.select{ |set| set.include?(neighbor) }.first
|
100
|
+
if s
|
101
|
+
if replaced.include?(s)
|
102
|
+
t = sets[sets.find_index(s)-1]
|
103
|
+
else
|
104
|
+
t = []
|
105
|
+
sets.insert(sets.find_index(s), t)
|
106
|
+
replaced << s
|
107
|
+
end
|
108
|
+
s.delete(neighbor)
|
109
|
+
t << neighbor
|
110
|
+
sets.delete(s) if s.empty?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
output_vertices
|
116
|
+
end
|
117
|
+
|
118
|
+
def clique?(vertex_list)
|
119
|
+
clique = true
|
120
|
+
vertex_list.each do |vertex|
|
121
|
+
unless (neighbors_of_vertex(vertex) & vertex_list).to_set == (vertex_list - [vertex]).to_set
|
122
|
+
clique = false
|
123
|
+
break
|
124
|
+
end
|
125
|
+
end
|
126
|
+
clique
|
127
|
+
end
|
128
|
+
|
129
|
+
def chordal?
|
130
|
+
chordal = true
|
131
|
+
(lexicographic_ordering = lexicographic_bfs.reverse).each_with_index do |v, i|
|
132
|
+
successors_of_v = lexicographic_ordering[i, lexicographic_ordering.size]
|
133
|
+
unless clique?([v] | (neighbors_of_vertex(v) & successors_of_v))
|
134
|
+
chordal = false
|
135
|
+
break
|
136
|
+
end
|
137
|
+
end
|
138
|
+
chordal
|
139
|
+
end
|
140
|
+
alias_method :triangulated?, :chordal?
|
141
|
+
|
142
|
+
def complete?
|
143
|
+
n = vertices.count
|
144
|
+
edges.count == (n * (n-1) / 2)
|
145
|
+
end
|
146
|
+
|
147
|
+
def bipartite?
|
148
|
+
colors = Hash.new
|
149
|
+
d = Hash.new
|
150
|
+
partition = Hash.new
|
151
|
+
vertices.each do |vertex|
|
152
|
+
colors[vertex] = "white"
|
153
|
+
d[vertex] = Float::INFINITY
|
154
|
+
partition[vertex] = 0
|
155
|
+
end
|
156
|
+
|
157
|
+
start = vertices.first
|
158
|
+
colors[start] = "gray"
|
159
|
+
partition[start] = 1
|
160
|
+
d[start] = 0
|
161
|
+
|
162
|
+
stack = []
|
163
|
+
stack.push(start)
|
164
|
+
|
165
|
+
until stack.empty?
|
166
|
+
vertex = stack.pop
|
167
|
+
neighbors_of_vertex(vertex).each do |neighbor|
|
168
|
+
if partition[neighbor] == partition[vertex]
|
169
|
+
return false
|
170
|
+
else
|
171
|
+
if colors[neighbor] == "white"
|
172
|
+
colors[neighbor] == "gray"
|
173
|
+
d[neighbor] = d[vertex] + 1
|
174
|
+
partition[neighbor] = 3 - partition[vertex]
|
175
|
+
stack.push(neighbor)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
stack.pop
|
180
|
+
colors[vertex] = "black"
|
181
|
+
end
|
182
|
+
|
183
|
+
true
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
def order_vertices(first_vertex, second_vertex)
|
189
|
+
[first_vertex, second_vertex].sort
|
190
|
+
end
|
191
|
+
end
|
data/lib/graphunk.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'graph'
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: graphunk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Evan Hemsley
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2010-04-28 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: This gem defines a Graph class which you can is useful in various mathematical
|
14
|
+
applications.
|
15
|
+
email: evan.hemsley@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/graph.rb
|
21
|
+
- lib/graphunk.rb
|
22
|
+
homepage: http://rubygems.org/gems/graphunk
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 2.2.2
|
43
|
+
signing_key:
|
44
|
+
specification_version: 4
|
45
|
+
summary: A funky Ruby library for working with graphs (as related to graph theory).
|
46
|
+
test_files: []
|