silicium 0.0.20 → 0.0.21
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 +4 -4
- data/.codeclimate.yml +3 -3
- data/.gitignore +13 -13
- data/.rakeTasks +8 -0
- data/.travis.yml +28 -25
- data/CODE_OF_CONDUCT.md +74 -74
- data/Gemfile +8 -8
- data/LICENSE.txt +21 -21
- data/Makefile +269 -269
- data/README.md +588 -46
- data/Rakefile +16 -16
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/docs/Object.html +117 -117
- data/docs/README_md.html +142 -142
- data/docs/Silicium/Combinatorics.html +270 -270
- data/docs/Silicium/Dice/Polyhedron.html +315 -315
- data/docs/Silicium/Dice/PolyhedronSet.html +321 -321
- data/docs/Silicium/Dice.html +99 -99
- data/docs/Silicium/Error.html +106 -106
- data/docs/Silicium/Geometry/Line2dCanon.html +243 -243
- data/docs/Silicium/Geometry/VariablesOrderException.html +106 -106
- data/docs/Silicium/Geometry.html +940 -940
- data/docs/Silicium/GraphVisualizer.html +226 -0
- data/docs/Silicium/Graphs/GraphError.html +106 -106
- data/docs/Silicium/Graphs/OrientedGraph.html +901 -775
- data/docs/Silicium/Graphs/UnorientedGraph.html +237 -284
- data/docs/Silicium/Graphs.html +374 -164
- data/docs/Silicium/IntegralDoesntExistError.html +106 -106
- data/docs/Silicium/NumericalIntegration.html +521 -521
- data/docs/Silicium/Optimization.html +629 -639
- data/docs/Silicium/Plotter/Image.html +297 -297
- data/docs/Silicium/Plotter.html +186 -186
- data/docs/Silicium.html +101 -101
- data/docs/created.rid +9 -9
- data/docs/css/fonts.css +167 -167
- data/docs/css/rdoc.css +619 -619
- data/docs/index.html +134 -132
- data/docs/js/darkfish.js +84 -84
- data/docs/js/navigation.js +105 -105
- data/docs/js/search.js +110 -110
- data/docs/js/search_index.js +1 -1
- data/docs/js/search_index.js.gz +0 -0
- data/docs/js/searcher.js +229 -229
- data/docs/table_of_contents.html +697 -608
- data/lib/algebra.rb +452 -0
- data/lib/algebra_diff.rb +258 -0
- data/lib/geometry/figure.rb +62 -0
- data/lib/geometry.rb +290 -236
- data/lib/geometry3d.rb +270 -0
- data/lib/graph/dfs.rb +42 -0
- data/lib/graph/kruskal.rb +36 -0
- data/lib/graph/scc.rb +97 -0
- data/lib/graph.rb +350 -164
- data/lib/graph_visualizer.rb +287 -0
- data/lib/ml_algorithms.rb +181 -0
- data/lib/numerical_integration.rb +184 -147
- data/lib/optimization.rb +209 -144
- data/lib/plotter.rb +256 -96
- data/lib/polynomial_division.rb +132 -0
- data/lib/polynomial_interpolation.rb +94 -0
- data/lib/regression.rb +120 -0
- data/lib/silicium/adding.rb +37 -0
- data/lib/silicium/conversions.rb +23 -0
- data/lib/silicium/multi.rb +82 -0
- data/lib/silicium/sparse.rb +76 -0
- data/lib/silicium/sugar.rb +37 -0
- data/lib/silicium/trans.rb +26 -0
- data/lib/silicium/version.rb +3 -3
- data/lib/silicium.rb +5 -5
- data/lib/theory_of_probability.rb +240 -226
- data/lib/topological_sort.rb +50 -0
- data/oriented_graph.png +0 -0
- data/plot.png +0 -0
- data/silicium.gemspec +38 -39
- metadata +38 -16
data/lib/geometry3d.rb
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'geometry/figure'
|
4
|
+
|
5
|
+
module Silicium
|
6
|
+
|
7
|
+
module Geometry3d
|
8
|
+
##
|
9
|
+
# Represents a point as three coordinates
|
10
|
+
# in three-dimensional space
|
11
|
+
Point3d = Struct.new(:x, :y, :z)
|
12
|
+
|
13
|
+
##
|
14
|
+
# Calculates the distance from given points in three-dimensional space
|
15
|
+
def distance_point_to_point3d(a, b)
|
16
|
+
Math.sqrt((b.x - a.x)**2 + (b.y - a.y)**2 + (b.z - a.z)**2)
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Class represents a plane as equation Ax + By + Cz+D = 0
|
21
|
+
# in two-dimensional space
|
22
|
+
class Plane3d
|
23
|
+
attr_reader :x_coefficient
|
24
|
+
attr_reader :y_coefficient
|
25
|
+
attr_reader :z_coefficient
|
26
|
+
attr_reader :free_coefficient
|
27
|
+
|
28
|
+
# Initializes with three objects of type Point
|
29
|
+
def initialize(point1, point2, point3)
|
30
|
+
vector1 = Vector3d.new(point1)
|
31
|
+
norm = vector1.norm_vector(point2, point3)
|
32
|
+
@x_coefficient = norm.x
|
33
|
+
@y_coefficient = norm.y
|
34
|
+
@z_coefficient = norm.z
|
35
|
+
@free_coefficient = -point1.x * norm.x + (-point1.y * norm.y) + (-point1.z * norm.z)
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Initializes with coefficients
|
40
|
+
def initialize_with_coefficients(a, b, c, d)
|
41
|
+
raise ArgumentError, 'All coefficients cannot be 0 ' if a.equal?(0) && b.equal?(0) && c.equal?(0) && (d.equal?(0) || !d.equal?(0))
|
42
|
+
|
43
|
+
@x_coefficient = a
|
44
|
+
@y_coefficient = b
|
45
|
+
@z_coefficient = c
|
46
|
+
@free_coefficient = d
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# check if the points isn't on the same line
|
51
|
+
def point_is_on_line?(point1, point2, point3)
|
52
|
+
check_p1 = @x_coefficient * point1.x + @y_coefficient * point1.y + @z_coefficient * point1.z + @free_coefficient
|
53
|
+
check_p2 = @x_coefficient * point2.x + @y_coefficient * point2.y + @z_coefficient * point2.z + @free_coefficient
|
54
|
+
check_p3 = @x_coefficient * point3.x + @y_coefficient * point3.y + @z_coefficient * point3.z + @free_coefficient
|
55
|
+
check_p1.equal?(0) && check_p2.equal?(0) && check_p3.equal?(0)
|
56
|
+
end
|
57
|
+
|
58
|
+
# check if the point isn't on the plane
|
59
|
+
def point_is_on_plane?(point)
|
60
|
+
(@x_coefficient * point.x + @y_coefficient * point.y + @z_coefficient * point.z + @free_coefficient).equal?(0)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Checks if two planes are parallel in 3-dimensional space
|
64
|
+
def parallel?(other_plane)
|
65
|
+
v1 = Vector3d.new(Point3d.new(@x_coefficient, @y_coefficient, @z_coefficient))
|
66
|
+
v2 = Vector3d.new(Point3d.new(other_plane.x_coefficient, other_plane.y_coefficient, other_plane.z_coefficient))
|
67
|
+
v1.collinear?(v2)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Checks if two planes are intersecting in 3-dimensional space
|
72
|
+
def intersecting?(other_plane)
|
73
|
+
check_x = @x_coefficient != other_plane.x_coefficient
|
74
|
+
check_y = @y_coefficient != other_plane.y_coefficient
|
75
|
+
check_z = @z_coefficient != other_plane.z_coefficient
|
76
|
+
check_x || check_y || check_z
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Checks if two planes are perpendicular
|
81
|
+
def perpendicular?(other_plane)
|
82
|
+
check_x = @x_coefficient * other_plane.x_coefficient
|
83
|
+
check_y = @y_coefficient * other_plane.y_coefficient
|
84
|
+
check_z = @z_coefficient * other_plane.z_coefficient
|
85
|
+
(check_x + check_y + check_z).equal?(0)
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# The distance between parallel planes
|
90
|
+
def distance_between_parallel_planes(other_plane)
|
91
|
+
raise 'Planes are not parallel' if !parallel?(other_plane)
|
92
|
+
|
93
|
+
free = (other_plane.free_coefficient - @free_coefficient).abs
|
94
|
+
free / sqrt(@x_coefficient**2 + @y_coefficient**2 + @z_coefficient**2)
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# The distance from a point to a plane
|
99
|
+
#
|
100
|
+
def distance_point_to_plane(point)
|
101
|
+
norm = 1 / Math.sqrt(@x_coefficient**2 + @y_coefficient**2 + @z_coefficient**2)
|
102
|
+
(@x_coefficient * norm * point.x + @y_coefficient * norm * point.y +
|
103
|
+
@z_coefficient * norm * point.z + @free_coefficient * norm).abs
|
104
|
+
end
|
105
|
+
end
|
106
|
+
##
|
107
|
+
# Class represents vector
|
108
|
+
# in three-dimensional space
|
109
|
+
class Vector3d
|
110
|
+
attr_reader :x
|
111
|
+
attr_reader :y
|
112
|
+
attr_reader :z
|
113
|
+
|
114
|
+
##
|
115
|
+
# Initializes with one objects of type Point3d
|
116
|
+
# 2nd point is (0,0,0)
|
117
|
+
def initialize(point)
|
118
|
+
@x = point.x
|
119
|
+
@y = point.y
|
120
|
+
@z = point.z
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Checks if vector is zero vector
|
125
|
+
def zero_vector?
|
126
|
+
(@x.eql?(0) && @y.eql?(0) && @z.eql?(0)).eql?(true) ? true : false
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Returns length of the vector
|
131
|
+
def length
|
132
|
+
Math.sqrt(@x**2 + @y**2 + @z**2)
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Add one vector to another
|
137
|
+
def addition!(other_vector)
|
138
|
+
@x += other_vector.x
|
139
|
+
@y += other_vector.y
|
140
|
+
@z += other_vector.z
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Sub one vector from another
|
145
|
+
def subtraction!(other_vector)
|
146
|
+
@x -= other_vector.x
|
147
|
+
@y -= other_vector.y
|
148
|
+
@z -= other_vector.z
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# Mult vector by number
|
153
|
+
def multiplication_by_number!(r)
|
154
|
+
@x *= r
|
155
|
+
@y *= r
|
156
|
+
@z *= r
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# Returns scalar multiplication of 2 vectors
|
161
|
+
def scalar_multiplication(other_vector)
|
162
|
+
x * other_vector.x + y * other_vector.y + z * other_vector.z
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Returns cos between two vectors
|
167
|
+
def cos_between_vectors(other_vector)
|
168
|
+
scalar_multiplication(other_vector) / (length * other_vector.length).to_f
|
169
|
+
end
|
170
|
+
|
171
|
+
##
|
172
|
+
# Returns vector multiplication of 2 vectors
|
173
|
+
def vector_multiplication(other_vector)
|
174
|
+
x = @y * other_vector.z - @z * other_vector.y
|
175
|
+
y = @z * other_vector.x - @x * other_vector.z
|
176
|
+
z = @x * other_vector.y - @y * other_vector.x
|
177
|
+
Vector3d.new(Point3d.new(x, y, z))
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Find normal vector
|
182
|
+
##
|
183
|
+
# vector mult
|
184
|
+
def norm_vector(point2, point3)
|
185
|
+
point1 = Point3d.new(@x, @y, @z)
|
186
|
+
# checking if the points isn't on the same line
|
187
|
+
# finding vector between points 1 and 2 ;1 and 3
|
188
|
+
vector12 = Vector3d.new(Point3d.new(point2.x - point1.x, point2.y - point1.y, point2.z - point1.z))
|
189
|
+
vector13 = Vector3d.new(Point3d.new(point3.x - point1.x, point3.y - point1.y, point3.z - point1.z))
|
190
|
+
# vector13=vector1.scalar_multiplication(vector3)
|
191
|
+
x = vector12.y * vector13.z - vector12.z * vector13.y
|
192
|
+
y = -(vector12.x * vector13.z - vector12.z * vector13.x)
|
193
|
+
z = vector12.x * vector13.y - vector12.y * vector13.x
|
194
|
+
Vector3d.new(Point3d.new(x, y, z))
|
195
|
+
end
|
196
|
+
|
197
|
+
##
|
198
|
+
# Function for checking sign of number
|
199
|
+
def sign(integer)
|
200
|
+
integer >= 0 ? 1 : -1
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# help function for collinear function
|
205
|
+
def help_check(vector2, x, y, z)
|
206
|
+
check1 = x * sign(vector2.x) * sign(@x) == y * sign(vector2.y) * sign(@y)
|
207
|
+
check2 = x * sign(vector2.x) * sign(@x) == z * sign(vector2.z) * sign(@z)
|
208
|
+
check3 = z * sign(vector2.z) * sign(@z) == y * sign(vector2.y) * sign(@y)
|
209
|
+
check1 && check2 && check3
|
210
|
+
end
|
211
|
+
##
|
212
|
+
# helps to divide correctly
|
213
|
+
def helper(value1, value2)
|
214
|
+
result = 0
|
215
|
+
if value1 > value2
|
216
|
+
result = value1 / value2
|
217
|
+
else
|
218
|
+
result = value2 / value1
|
219
|
+
end
|
220
|
+
result
|
221
|
+
end
|
222
|
+
|
223
|
+
# Check if two vectors are collinear
|
224
|
+
def collinear?(vector2)
|
225
|
+
x1 = (vector2.x).abs
|
226
|
+
y1 = (vector2.y).abs
|
227
|
+
z1 = (vector2.z).abs
|
228
|
+
x = helper(x1,@x.abs)
|
229
|
+
y = helper(y1,@y.abs)
|
230
|
+
z = helper(z1,@z.abs)
|
231
|
+
help_check(vector2, x, y, z)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
##
|
236
|
+
# Creates an array- directing vector in three-dimensional space .
|
237
|
+
# The equation is specified in the canonical form.
|
238
|
+
# Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
|
239
|
+
#
|
240
|
+
# Important: mandatory order of variables: x, y, z
|
241
|
+
def directing_vector3d(line_equation)
|
242
|
+
process_line_by_coordinates(line_equation, :process_cf)
|
243
|
+
end
|
244
|
+
|
245
|
+
##
|
246
|
+
# Creates an array of coordinates of the point ([x, y, z] on the line
|
247
|
+
# given by the equation in the canonical form.
|
248
|
+
# Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
|
249
|
+
#
|
250
|
+
# Important: mandatory order of variables: x, y, z
|
251
|
+
def height_point_3d(line_equation)
|
252
|
+
process_line_by_coordinates(line_equation, :process_free_member)
|
253
|
+
end
|
254
|
+
|
255
|
+
##
|
256
|
+
# Calculates the distance from a point given by a Point3d structure
|
257
|
+
# to a straight line given by a canonical equation.
|
258
|
+
# Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
|
259
|
+
#
|
260
|
+
# Important: mandatory order of variables: x, y, z
|
261
|
+
def point_to_line_distance_3d(point, line_eq)
|
262
|
+
dir_vector = directing_vector3d(line_eq)
|
263
|
+
line_point = height_point_3d(line_eq)
|
264
|
+
height_vector = [line_point[0] - point.x, line_point[1] - point.y, line_point[2] - point.z]
|
265
|
+
|
266
|
+
height_on_dir = vectors_product(height_vector, dir_vector)
|
267
|
+
vector_length(height_on_dir) / vector_length(dir_vector)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
data/lib/graph/dfs.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'silicium'
|
2
|
+
module Silicium
|
3
|
+
module Graphs
|
4
|
+
|
5
|
+
def depth_first_search?(graph, start, goal)
|
6
|
+
visited = Hash.new(false)
|
7
|
+
stack = [start]
|
8
|
+
until stack.empty?
|
9
|
+
node = stack.pop
|
10
|
+
return true if goal_node?(graph, node, goal)
|
11
|
+
add_to_stack(graph, node, stack, visited)
|
12
|
+
end
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def goal_node?(graph, node, goal)
|
17
|
+
raise ArgumentError if graph.vertices[node].nil?
|
18
|
+
|
19
|
+
node == goal
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_to_stack(graph, node, stack, visited)
|
23
|
+
return if visited[node]
|
24
|
+
|
25
|
+
visited[node] = true
|
26
|
+
graph.vertices[node].each { |child| stack.push(child) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def dfs_traverse(graph, start)
|
30
|
+
visited = Hash.new(false)
|
31
|
+
traversed = []
|
32
|
+
dfs_traverse_recursive(graph, start, visited, traversed)
|
33
|
+
traversed
|
34
|
+
end
|
35
|
+
|
36
|
+
def dfs_traverse_recursive(graph, node, visited, traversed)
|
37
|
+
visited[node] = true
|
38
|
+
traversed.push(node)
|
39
|
+
graph.vertices[node].each { |child| dfs_traverse_recursive(graph, child, visited, traversed) unless visited[child] }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Silicium
|
2
|
+
module Graphs
|
3
|
+
|
4
|
+
class UnionFind
|
5
|
+
def initialize(graph)
|
6
|
+
@parents = []
|
7
|
+
graph.vertices.keys.each do |vertex|
|
8
|
+
@parents[vertex] = vertex
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def connected?(vertex1, vertex2)
|
13
|
+
@parents[vertex1] == @parents[vertex2]
|
14
|
+
end
|
15
|
+
|
16
|
+
def union(vertex1, vertex2)
|
17
|
+
parent1, parent2 = @parents[vertex1], @parents[vertex2]
|
18
|
+
@parents.map! { |i| i == parent1 ? parent2 : i }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Implements algorithm of Kruskal
|
23
|
+
def kruskal_mst(graph)
|
24
|
+
mst = UnorientedGraph.new
|
25
|
+
uf = UnionFind.new(graph)
|
26
|
+
graph_to_sets(graph).each do |edge, label|
|
27
|
+
unless uf.connected?(edge[0], edge[1])
|
28
|
+
add_edge!(mst, edge, label)
|
29
|
+
uf.union(edge[0], edge[1])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
mst
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/lib/graph/scc.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
module Silicium
|
2
|
+
|
3
|
+
module Graphs
|
4
|
+
class OrientedGraph
|
5
|
+
include Graphs
|
6
|
+
|
7
|
+
##
|
8
|
+
# Finds Strongly Connected Components (SCC) in graph. SCC is a subgraph where every vertex is reachable from every other vertex.
|
9
|
+
# @return Array of SCC. Each component is represented as Array of vertices in decreasing order of their DFS timestamps.
|
10
|
+
# @author vaimon
|
11
|
+
def find_strongly_connected_components
|
12
|
+
# Vertices we have already visited.
|
13
|
+
visited = Hash.new(false)
|
14
|
+
# Timestamps got during depth-first search.
|
15
|
+
order = []
|
16
|
+
# Resulting array of SCC.
|
17
|
+
res = []
|
18
|
+
|
19
|
+
# Step 1: Launch DFS to get order marks
|
20
|
+
@vertices.keys.each do |key|
|
21
|
+
visited, order = scc_dfs_first key, visited, order unless visited[key]
|
22
|
+
end
|
23
|
+
order.uniq!
|
24
|
+
|
25
|
+
# Step 2: Transpose adjacency list
|
26
|
+
transposed = transpose_adjacency_list
|
27
|
+
|
28
|
+
# Step 3: Launch second DFS in reverse order of timestamps from Step 1 to build components.
|
29
|
+
# HACK: In original algorithm, we use *visited* again, but here the code is a bit
|
30
|
+
# optimized using *order* instead of *visited*
|
31
|
+
until order.empty?
|
32
|
+
component = []
|
33
|
+
order, component = scc_dfs_second order.last, component, order, transposed
|
34
|
+
res << component
|
35
|
+
end
|
36
|
+
res
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
##
|
43
|
+
# Processes the first pass of <b>depth-first search</b> as a step of SCC search algorithm.
|
44
|
+
#
|
45
|
+
# Parameters:
|
46
|
+
# +v+: current vertex;
|
47
|
+
# +visited+: array of booleans representing which vertices have been processed;
|
48
|
+
# +order+: array of vertex exit timestamps.
|
49
|
+
#
|
50
|
+
# @return Tuple <code>[visited, order]</code> of params changed during current step of DFS.
|
51
|
+
def scc_dfs_first(v, visited, order)
|
52
|
+
visited[v] = true
|
53
|
+
@vertices[v].each do |adj|
|
54
|
+
visited, order = scc_dfs_first adj, visited, order unless visited[adj]
|
55
|
+
end
|
56
|
+
order << v
|
57
|
+
[visited, order]
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Transposes adjacency list as a step of SCC search algorithm.
|
62
|
+
#
|
63
|
+
# g.vertices #=> {1 => [2,3], 2 => [3], 3 => []}
|
64
|
+
# g.transpose_adjacency_list #=> {2=>[1], 3=>[1, 2]}
|
65
|
+
def transpose_adjacency_list
|
66
|
+
# HACK
|
67
|
+
res = Hash.new { |h, k| h[k] = [] }
|
68
|
+
@vertices.each do |vert, adj|
|
69
|
+
adj.each { |x| res[x] << vert }
|
70
|
+
end
|
71
|
+
res
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Processes the second pass of <b>depth-first search</b> collecting vertices to a component as a step of SCC search algorithm.
|
76
|
+
#
|
77
|
+
# Parameters:
|
78
|
+
# +v+: current vertex;
|
79
|
+
# +component+: component we are building;
|
80
|
+
# +order+: order of timestamps got after first DFS;
|
81
|
+
# +transposed+: transposed adjacency list.
|
82
|
+
#
|
83
|
+
# @return Tuple <code>[order, component]</code> of params changed during current step of DFS.
|
84
|
+
def scc_dfs_second(v, component, order, transposed)
|
85
|
+
order.delete v
|
86
|
+
component << v
|
87
|
+
transposed[v].each do |adj|
|
88
|
+
if order.include? adj
|
89
|
+
order, component = scc_dfs_second adj, component, order, transposed
|
90
|
+
end
|
91
|
+
end
|
92
|
+
[order, component]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|