tangle 0.8.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +37 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +15 -4
- data/CHANGELOG.md +45 -0
- data/Gemfile +4 -10
- data/README.md +8 -3
- data/Rakefile +3 -1
- data/bin/console +5 -4
- data/bin/setup +0 -1
- data/lib/tangle.rb +7 -4
- data/lib/tangle/base_graph.rb +154 -0
- data/lib/tangle/{graph_vertices.rb → base_graph_private.rb} +12 -35
- data/lib/tangle/base_graph_protected.rb +50 -0
- data/lib/tangle/currify.rb +58 -0
- data/lib/tangle/directed/acyclic/graph.rb +3 -0
- data/lib/tangle/directed/acyclic/partial_order.rb +3 -0
- data/lib/tangle/directed/edge.rb +4 -2
- data/lib/tangle/directed/graph.rb +28 -6
- data/lib/tangle/edge.rb +5 -14
- data/lib/tangle/errors.rb +2 -0
- data/lib/tangle/mixin.rb +2 -1
- data/lib/tangle/mixin/directory.rb +48 -13
- data/lib/tangle/undirected/edge.rb +30 -0
- data/lib/tangle/undirected/graph.rb +73 -0
- data/lib/tangle/undirected/simple/graph.rb +22 -0
- data/lib/tangle/version.rb +8 -4
- data/ruby-tangle.sublime-project +8 -0
- data/tangle.gemspec +19 -7
- metadata +103 -27
- data/.travis.yml +0 -5
- data/lib/tangle/graph.rb +0 -81
- data/lib/tangle/graph_edges.rb +0 -49
- data/lib/tangle/mixin/connectedness.rb +0 -68
- data/lib/tangle/simple/graph.rb +0 -17
data/.travis.yml
DELETED
data/lib/tangle/graph.rb
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
require 'tangle/mixin'
|
2
|
-
require 'tangle/mixin/connectedness'
|
3
|
-
require 'tangle/edge'
|
4
|
-
require 'tangle/graph_vertices'
|
5
|
-
require 'tangle/graph_edges'
|
6
|
-
|
7
|
-
module Tangle
|
8
|
-
#
|
9
|
-
# Base class for all kinds of graphs
|
10
|
-
#
|
11
|
-
class Graph
|
12
|
-
include Tangle::GraphVertices
|
13
|
-
include Tangle::GraphEdges
|
14
|
-
include Tangle::Mixin::Initialize
|
15
|
-
Edge = Tangle::Edge
|
16
|
-
DEFAULT_MIXINS = Tangle::Mixin::Connectedness::MIXINS
|
17
|
-
|
18
|
-
# Initialize a new graph, preloading it with vertices and edges
|
19
|
-
#
|
20
|
-
# Graph[+vertices+] => Graph
|
21
|
-
# Graph[+vertices+, +edges+) => Graph
|
22
|
-
#
|
23
|
-
# When +vertices+ is a hash, it contains initialization kwargs as
|
24
|
-
# values and vertex names as keys. When +vertices+ is an array of
|
25
|
-
# initialization kwargs, the vertices will be be anonymous.
|
26
|
-
#
|
27
|
-
# +edges+ can contain an array of exactly two, either names of vertices
|
28
|
-
# or vertices.
|
29
|
-
#
|
30
|
-
# Any kwarg supported by Graph.new is also allowed.
|
31
|
-
#
|
32
|
-
def self.[](vertices, edges = {}, **kwargs)
|
33
|
-
graph = new(**kwargs)
|
34
|
-
vertices.each { |vertex| graph.add_vertex(vertex) }
|
35
|
-
edges.each { |from, to| graph.add_edge(from, to) }
|
36
|
-
graph
|
37
|
-
end
|
38
|
-
|
39
|
-
# Initialize a new graph, optionally preloading it with vertices and edges
|
40
|
-
#
|
41
|
-
# Graph.new() => Graph
|
42
|
-
# Graph.new(mixins: [MixinModule, ...], ...) => Graph
|
43
|
-
#
|
44
|
-
# +mixins+ is an array of modules that can be mixed into the various
|
45
|
-
# classes that makes up a graph. Initialization of a Graph, Vertex or Edge
|
46
|
-
# looks for submodules in each mixin, with the same name and extends
|
47
|
-
# any created object. Defaults to [Tangle::Mixin::Connectedness].
|
48
|
-
#
|
49
|
-
# Any subclass of Graph should also subclass Edge to manage its unique
|
50
|
-
# constraints.
|
51
|
-
#
|
52
|
-
def initialize(mixins: self.class::DEFAULT_MIXINS, **kwargs)
|
53
|
-
initialize_vertices
|
54
|
-
initialize_edges
|
55
|
-
initialize_mixins(mixins: mixins, **kwargs)
|
56
|
-
end
|
57
|
-
|
58
|
-
# Return a subgraph, optionally filtered by a vertex selector block
|
59
|
-
#
|
60
|
-
# subgraph => Graph
|
61
|
-
# subgraph { |vertex| ... } => Graph
|
62
|
-
#
|
63
|
-
# Unless a selector is provided, the subgraph contains the entire graph.
|
64
|
-
#
|
65
|
-
def subgraph(included = nil)
|
66
|
-
included ||= vertices
|
67
|
-
result = clone
|
68
|
-
vertices.each do |vertex|
|
69
|
-
result.remove_vertex(vertex) unless included.include?(vertex)
|
70
|
-
next unless block_given?
|
71
|
-
result.remove_vertex(vertex) unless yield(vertex)
|
72
|
-
end
|
73
|
-
result
|
74
|
-
end
|
75
|
-
|
76
|
-
def to_s
|
77
|
-
"#<#{self.class}: #{vertices.count} vertices, #{edges.count} edges>"
|
78
|
-
end
|
79
|
-
alias inspect to_s
|
80
|
-
end
|
81
|
-
end
|
data/lib/tangle/graph_edges.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module Tangle
|
4
|
-
# Edge related methods in a graph
|
5
|
-
module GraphEdges
|
6
|
-
# Get all edges.
|
7
|
-
#
|
8
|
-
# edges => Array
|
9
|
-
#
|
10
|
-
def edges(vertex = nil)
|
11
|
-
return @edges if vertex.nil?
|
12
|
-
@vertices.fetch(vertex)
|
13
|
-
end
|
14
|
-
|
15
|
-
# Add a new edge to the graph
|
16
|
-
#
|
17
|
-
# add_edge(vtx1, vtx2, ...) => Edge
|
18
|
-
#
|
19
|
-
def add_edge(*vertices, **kvargs)
|
20
|
-
insert_edge(self.class::Edge.new(*vertices, mixins: @mixins, **kvargs))
|
21
|
-
end
|
22
|
-
|
23
|
-
# Remove an edge from the graph
|
24
|
-
def remove_edge(edge)
|
25
|
-
edge.each_vertex do |vertex|
|
26
|
-
@vertices.fetch(vertex).delete(edge)
|
27
|
-
end
|
28
|
-
@edges.delete(edge)
|
29
|
-
end
|
30
|
-
|
31
|
-
protected
|
32
|
-
|
33
|
-
# Insert a prepared edge into the graph
|
34
|
-
#
|
35
|
-
def insert_edge(edge)
|
36
|
-
@edges << edge
|
37
|
-
edge.each_vertex do |vertex|
|
38
|
-
@vertices.fetch(vertex) << edge
|
39
|
-
end
|
40
|
-
edge
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def initialize_edges
|
46
|
-
@edges = Set[]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
module Tangle
|
2
|
-
module Mixin
|
3
|
-
#
|
4
|
-
# Mixins for adding connectedness features
|
5
|
-
#
|
6
|
-
module Connectedness
|
7
|
-
MIXINS = [Tangle::Mixin::Connectedness].freeze
|
8
|
-
#
|
9
|
-
# Mixin for adding connectedness to a graph
|
10
|
-
#
|
11
|
-
module Graph
|
12
|
-
# Two vertices are adjacent if there is an edge between them
|
13
|
-
def adjacent?(vertex, other)
|
14
|
-
edges(vertex).any? { |edge| edge[vertex] == other }
|
15
|
-
end
|
16
|
-
|
17
|
-
# Return the set of adjacent vertices
|
18
|
-
def adjacent(vertex)
|
19
|
-
Set.new(edges(vertex).map { |edge| edge.walk(vertex) })
|
20
|
-
end
|
21
|
-
|
22
|
-
# Get the largest connected subgraph for a vertex.
|
23
|
-
# Also aliased as :component and :connected_component
|
24
|
-
#
|
25
|
-
# connected_subgraph(vertex) => Graph
|
26
|
-
#
|
27
|
-
def connected_subgraph(vertex)
|
28
|
-
subgraph { |other| connected_vertices?(vertex, other) }
|
29
|
-
end
|
30
|
-
alias component connected_subgraph
|
31
|
-
alias connected_component connected_subgraph
|
32
|
-
|
33
|
-
# Get the largest subgraph that is not connected to a vertex, or what's
|
34
|
-
# left after removing the connected subgraph.
|
35
|
-
#
|
36
|
-
def disconnected_subgraph(vertex)
|
37
|
-
subgraph { |other| !connected_vertices?(vertex, other) }
|
38
|
-
end
|
39
|
-
|
40
|
-
# A graph is connected if all vertices are connected to all vertices
|
41
|
-
# An empty graph is disconnected.
|
42
|
-
#
|
43
|
-
def connected?(*tested_vertices)
|
44
|
-
tested_vertices = vertices if tested_vertices.empty?
|
45
|
-
return false if tested_vertices.empty?
|
46
|
-
|
47
|
-
tested_vertices.combination(2).all? do |pair|
|
48
|
-
this, that = pair.to_a
|
49
|
-
reachable(this).any? { |other| other == that }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# A graph is disconnected if any vertex is not connected to all other.
|
54
|
-
# An empty graph is disconnected.
|
55
|
-
#
|
56
|
-
def disconnected?(*tested_vertices)
|
57
|
-
!connected?(*tested_vertices)
|
58
|
-
end
|
59
|
-
|
60
|
-
# Return a breadth-first Enumerator for all reachable vertices,
|
61
|
-
# by transitive adjacency.
|
62
|
-
def reachable(start_vertex)
|
63
|
-
vertex_enumerator(start_vertex, :adjacent)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
data/lib/tangle/simple/graph.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'tangle/graph'
|
2
|
-
|
3
|
-
module Tangle
|
4
|
-
module Simple
|
5
|
-
#
|
6
|
-
# A simple graph, without loops and multiple edges
|
7
|
-
class Graph < Tangle::Graph
|
8
|
-
protected
|
9
|
-
|
10
|
-
def insert_edge(edge)
|
11
|
-
raise LoopError if edge.loop?
|
12
|
-
raise MultiEdgeError if adjacent?(*edge.each_vertex)
|
13
|
-
super
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|