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.
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