silicium 0.0.20 → 0.0.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +3 -3
  3. data/.gitignore +13 -13
  4. data/.rakeTasks +8 -0
  5. data/.travis.yml +28 -25
  6. data/CODE_OF_CONDUCT.md +74 -74
  7. data/Gemfile +8 -8
  8. data/LICENSE.txt +21 -21
  9. data/Makefile +269 -269
  10. data/README.md +588 -46
  11. data/Rakefile +16 -16
  12. data/bin/console +14 -14
  13. data/bin/setup +8 -8
  14. data/docs/Object.html +117 -117
  15. data/docs/README_md.html +142 -142
  16. data/docs/Silicium/Combinatorics.html +270 -270
  17. data/docs/Silicium/Dice/Polyhedron.html +315 -315
  18. data/docs/Silicium/Dice/PolyhedronSet.html +321 -321
  19. data/docs/Silicium/Dice.html +99 -99
  20. data/docs/Silicium/Error.html +106 -106
  21. data/docs/Silicium/Geometry/Line2dCanon.html +243 -243
  22. data/docs/Silicium/Geometry/VariablesOrderException.html +106 -106
  23. data/docs/Silicium/Geometry.html +940 -940
  24. data/docs/Silicium/GraphVisualizer.html +226 -0
  25. data/docs/Silicium/Graphs/GraphError.html +106 -106
  26. data/docs/Silicium/Graphs/OrientedGraph.html +901 -775
  27. data/docs/Silicium/Graphs/UnorientedGraph.html +237 -284
  28. data/docs/Silicium/Graphs.html +374 -164
  29. data/docs/Silicium/IntegralDoesntExistError.html +106 -106
  30. data/docs/Silicium/NumericalIntegration.html +521 -521
  31. data/docs/Silicium/Optimization.html +629 -639
  32. data/docs/Silicium/Plotter/Image.html +297 -297
  33. data/docs/Silicium/Plotter.html +186 -186
  34. data/docs/Silicium.html +101 -101
  35. data/docs/created.rid +9 -9
  36. data/docs/css/fonts.css +167 -167
  37. data/docs/css/rdoc.css +619 -619
  38. data/docs/index.html +134 -132
  39. data/docs/js/darkfish.js +84 -84
  40. data/docs/js/navigation.js +105 -105
  41. data/docs/js/search.js +110 -110
  42. data/docs/js/search_index.js +1 -1
  43. data/docs/js/search_index.js.gz +0 -0
  44. data/docs/js/searcher.js +229 -229
  45. data/docs/table_of_contents.html +697 -608
  46. data/lib/algebra.rb +452 -0
  47. data/lib/algebra_diff.rb +258 -0
  48. data/lib/geometry/figure.rb +62 -0
  49. data/lib/geometry.rb +290 -236
  50. data/lib/geometry3d.rb +270 -0
  51. data/lib/graph/dfs.rb +42 -0
  52. data/lib/graph/kruskal.rb +36 -0
  53. data/lib/graph/scc.rb +97 -0
  54. data/lib/graph.rb +350 -164
  55. data/lib/graph_visualizer.rb +287 -0
  56. data/lib/ml_algorithms.rb +181 -0
  57. data/lib/numerical_integration.rb +184 -147
  58. data/lib/optimization.rb +209 -144
  59. data/lib/plotter.rb +256 -96
  60. data/lib/polynomial_division.rb +132 -0
  61. data/lib/polynomial_interpolation.rb +94 -0
  62. data/lib/regression.rb +120 -0
  63. data/lib/silicium/adding.rb +37 -0
  64. data/lib/silicium/conversions.rb +23 -0
  65. data/lib/silicium/multi.rb +82 -0
  66. data/lib/silicium/sparse.rb +76 -0
  67. data/lib/silicium/sugar.rb +37 -0
  68. data/lib/silicium/trans.rb +26 -0
  69. data/lib/silicium/version.rb +3 -3
  70. data/lib/silicium.rb +5 -5
  71. data/lib/theory_of_probability.rb +240 -226
  72. data/lib/topological_sort.rb +50 -0
  73. data/oriented_graph.png +0 -0
  74. data/plot.png +0 -0
  75. data/silicium.gemspec +38 -39
  76. 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