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
@@ -0,0 +1,62 @@
1
+ module Silicium
2
+
3
+ module Geometry
4
+ class Figure
5
+ include Geometry
6
+ end
7
+
8
+ class Triangle < Figure
9
+
10
+ def initialize(p1, p2, p3)
11
+ s_p1p2 = distance_point_to_point2d(p1, p2)
12
+ s_p1p3 = distance_point_to_point2d(p1, p3)
13
+ s_p2p3 = distance_point_to_point2d(p2, p3)
14
+ if s_p1p2 + s_p2p3 <= s_p1p3 || s_p1p2 + s_p1p3 <= s_p2p3 || s_p2p3 + s_p1p3 <= s_p1p2
15
+ raise ArgumentError, 'Triangle does not exist'
16
+ else
17
+ @side_p1p2 = s_p1p2
18
+ @side_p1p3 = s_p1p3
19
+ @side_p2p3 = s_p2p3
20
+ end
21
+ end
22
+
23
+ def perimeter
24
+ @side_p1p2 + @side_p1p3 + @side_p2p3
25
+ end
26
+
27
+ def area
28
+ half_perimeter = perimeter / 2.0
29
+ Math.sqrt(half_perimeter * (half_perimeter - @side_p1p2) * (half_perimeter - @side_p2p3) * (half_perimeter - @side_p1p3))
30
+ end
31
+ end
32
+
33
+
34
+ ##
35
+ # TODO: Add a description
36
+ class Rectangle < Figure
37
+
38
+ def initialize(p1, p2, p3, p4)
39
+ raise ArgumentError, 'This is not a rectangle.' unless valid?(p1, p2, p3, p4)
40
+
41
+ @side1 = distance_point_to_point2d(p1, p2)
42
+ @side2 = distance_point_to_point2d(p2, p3)
43
+ @side3 = distance_point_to_point2d(p3, p4)
44
+ @side4 = distance_point_to_point2d(p4, p1)
45
+ end
46
+
47
+ ##
48
+ # Checks if input points form rectangle
49
+ def valid?(p1, p2, p3, p4)
50
+ distance_point_to_point2d(p1, p3) == distance_point_to_point2d(p2, p4)
51
+ end
52
+
53
+ def perimeter
54
+ @side1 + @side2 + @side3 + @side4
55
+ end
56
+
57
+ def area
58
+ @side1 * @side2
59
+ end
60
+ end
61
+ end
62
+ end
data/lib/geometry.rb CHANGED
@@ -1,236 +1,290 @@
1
- # frozen_string_literal: true
2
-
3
- module Silicium
4
-
5
- module Geometry
6
-
7
- ##
8
- # Represents a point as two coordinates
9
- # in two-dimensional space
10
- Point = Struct.new(:x, :y)
11
-
12
- ##
13
- # Represents a point as three coordinates
14
- # in three-dimensional space
15
- Point3d = Struct.new(:x, :y, :z)
16
-
17
- ##
18
- #Calculates the distance from given points in two-dimensional space
19
- def distance_point_to_point2d(a, b)
20
- Math.sqrt((b.x - a.x)**2 + (b.y - a.y)**2)
21
- end
22
-
23
- # Class represents a line as equation y = k*x +b
24
- # k - slope
25
- # b - free_term
26
- # in two-dimensional space
27
- class Line2dCanon
28
- attr_reader :slope
29
- attr_reader :free_term
30
-
31
- def initialize(p1, p2)
32
- if (p1.x == p2.x) && (p1.y == p2.y)
33
- raise ArgumentError, "You need 2 diffrent points"
34
- end
35
- if (p1.x == p2.x)
36
- raise ArgumentError, "The straight line equation cannot be written in canonical form"
37
- end
38
- @slope = (p2.y - p1.y) / (p2.x - p1.x).to_f
39
- @free_term = (p2.x * p1.y - p2.y * p1.x) / (p2.x - p1.x).to_f
40
- end
41
-
42
- ##
43
- # Checks the point lies on the line or not
44
- def point_is_on_line?(p1)
45
- p1.y == @slope * p1.x + @free_term
46
- end
47
- end
48
-
49
-
50
- ##
51
- # Calculates the distance from given points in three-dimensional space
52
- def distance_point_to_point3d(a, b)
53
- Math.sqrt((b.x - a.x)**2 + (b.y - a.y)**2 + (b.z - a.z)**2)
54
- end
55
-
56
- ##
57
- # The distance from a point to a line on a plane
58
- # The line is defined by two points
59
- # https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
60
- def distance_point_line2d(p1, p2, a)
61
- line_segment_length = distance_point_to_point2d(p1, p2)
62
- ((p2.y - p1.y) * a.x - (p2.x - p1.x) * a.y + p2.x * p1.y - p2.y * p1.x).abs / (line_segment_length * 1.0)
63
- end
64
-
65
- ##
66
- # The distance from a point to a line on a plane
67
- # Line defined by an equation
68
- # return 0 if the equation does not define a line.
69
- def distance_point_line_equation2d(a, b, c, p)
70
- if a == 0 and b == 0
71
- return 0
72
- end
73
- (a * p.x + b * p.y + c).abs / Math.sqrt(a**2 + b**2)
74
- end
75
-
76
- def oriented_area(a, b, c)
77
- a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)
78
- end
79
-
80
- ##
81
- # Determines if a clockwise crawl is performed
82
- # for defined order of points
83
- def clockwise(a, b, c)
84
- oriented_area(a, b, c).negative?
85
- end
86
-
87
- ##
88
- # Determines if a counter-clockwise crawl is
89
- # performed for defined order of points
90
- def counter_clockwise(a, b, c)
91
- oriented_area(a, b, c).positive?
92
- end
93
-
94
- def not_polygon?(points)
95
- points.empty? || points.size == 1 || points.size == 2
96
- end
97
-
98
- def put_point_in_part(part, point, direction)
99
- direction = method(direction)
100
- while part.size >= 2 && !direction.call(part[part.size - 2], part[part.size - 1], point)
101
- part.pop
102
- end
103
- part.push(point)
104
- end
105
-
106
- ##
107
- # Returns an array containing points that are included
108
- # in the minimal convex hull for a given array of points
109
- # https://e-maxx.ru/algo/convex_hull_graham
110
- def minimal_convex_hull_2d(points)
111
- return points if not_polygon?(points)
112
-
113
- points.sort_by! { |p| [p.x, p.y] }
114
- first = points[0]
115
- last = points.last
116
- up = [first]
117
- down = [first]
118
-
119
- (1...points.size).each do |i|
120
- point = points[i]
121
- is_last = i == points.size - 1
122
- if is_last || clockwise(first, point, last)
123
- put_point_in_part(up, point, :clockwise)
124
- end
125
- if is_last || counter_clockwise(first, point, last)
126
- put_point_in_part(down, point, :counter_clockwise)
127
- end
128
- end
129
-
130
- hull = up
131
- (1..(down.size - 2)).reverse_each do |j|
132
- hull.push(down[j])
133
- end
134
- hull
135
- end
136
-
137
- def process_cf(line_equation, variable)
138
- if line_equation.include?(variable)
139
- before = line_equation.index('/') + 1
140
- after = line_equation.index('=')
141
- line_equation.slice(before..after).gsub('=', '').sub('*', '').gsub('(', '').gsub(')', '').to_f
142
- else
143
- 0.0
144
- end
145
- end
146
-
147
- def cut_by_eq(line_equation)
148
- line_equation.slice(line_equation.index('='), line_equation.length).sub('=', '')
149
- end
150
-
151
- def process_line_by_coordinates(line_equation, func)
152
- copy_line = insert_eq(line_equation)
153
- func = method(func)
154
- res = []
155
- res[0] = func.call(copy_line, 'x')
156
- copy_line = cut_by_eq(copy_line)
157
- res[1] = func.call(copy_line, 'y')
158
- copy_line = cut_by_eq(copy_line)
159
- res[2] = func.call(copy_line, 'z')
160
- res
161
- end
162
-
163
- ##
164
- # Creates an array- directing vector in three-dimensional space .
165
- # The equation is specified in the canonical form.
166
- # Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
167
- #
168
- # Important: mandatory order of variables: x, y, z
169
- def directing_vector3d(line_equation)
170
- process_line_by_coordinates(line_equation, :process_cf)
171
- end
172
-
173
- class VariablesOrderException < Exception
174
- end
175
-
176
- def needed_variables_order?(before, after)
177
- before < after
178
- end
179
-
180
- def process_free_member(line_equation, variable)
181
- if line_equation.include?(variable)
182
- before = line_equation.index(variable) + 1
183
- after = line_equation.index('/')
184
-
185
- unless needed_variables_order?(before, after)
186
- throw VariablesOrderException
187
- end
188
-
189
- line_equation.slice(before..after).gsub('/', '').to_f * (-1)
190
- else
191
- 0.0
192
- end
193
- end
194
-
195
- ##
196
- # Creates an array of coordinates of the point ([x, y, z] on the line
197
- # given by the equation in the canonical form.
198
- # Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
199
- #
200
- # Important: mandatory order of variables: x, y, z
201
- def height_point_3d(line_equation)
202
- process_line_by_coordinates(line_equation, :process_free_member)
203
- end
204
-
205
- def vectors_product(v1, v2)
206
- res = Array.new(3)
207
- (0..2).each do |i|
208
- res[i] = v1[(i + 1) % 3] * v2[(i + 2) % 3] - v1[(i + 2) % 3] * v2[(i + 1) % 3]
209
- end
210
- res
211
- end
212
-
213
- def vector_length(vector)
214
- Math.sqrt(vector[0]**2 + vector[1]**2 + vector[2]**2)
215
- end
216
-
217
- ##
218
- # Calculates the distance from a point given by a Point3d structure
219
- # to a straight line given by a canonical equation.
220
- # Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
221
- #
222
- # Important: mandatory order of variables: x, y, z
223
- def point_to_line_distance_3d(point, line_eq)
224
- dir_vector = directing_vector3d(line_eq)
225
- line_point = height_point_3d(line_eq)
226
- height_vector = [line_point[0] - point.x, line_point[1] - point.y, line_point[2] - point.z]
227
-
228
- height_on_dir = vectors_product(height_vector, dir_vector)
229
- vector_length(height_on_dir) / vector_length(dir_vector)
230
- end
231
-
232
- def insert_eq(line_equation)
233
- line_equation.gsub(' ', '').insert(line_equation.length, '=')
234
- end
235
- end
236
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'geometry/figure'
4
+
5
+ module Silicium
6
+
7
+ module Geometry
8
+ ##
9
+ # Represents a point as two coordinates
10
+ # in two-dimensional space
11
+ Point = Struct.new(:x, :y)
12
+
13
+ ##
14
+ # Calculates the distance from given points in two-dimensional space
15
+ def distance_point_to_point2d(a, b)
16
+ Math.sqrt((b.x - a.x)**2 + (b.y - a.y)**2)
17
+ end
18
+
19
+ ##
20
+ # Class represents a line as equation Ax + By + C = 0
21
+ # in two-dimensional space
22
+ class Line2dCanon
23
+ attr_reader :x_coefficient
24
+ attr_reader :y_coefficient
25
+ attr_reader :free_coefficient
26
+
27
+ ##
28
+ # Initializes with two objects of type Point
29
+ def initialize(point1, point2)
30
+ raise ArgumentError, 'You need 2 different points' if point1.x.equal?(point2.x) && point1.y.equal?(point2.y)
31
+ if point1.x.equal?(point2.x)
32
+ @x_coefficient = 1
33
+ @y_coefficient = 0
34
+ @free_coefficient = - point1.x
35
+ else
36
+ slope_point = (point2.y - point1.y) / (point2.x - point1.x)
37
+ @x_coefficient = -slope_point
38
+ @y_coefficient = 1
39
+ @free_coefficient = - point1.y + slope_point * point1.x
40
+ end
41
+ end
42
+
43
+ # Initializes with coefficients
44
+ def initialize_with_coefficients(a, b, c)
45
+ raise ArgumentError, 'All coefficients cannot be 0 ' if a.equal?(0) && b.equal?(0) && (c.equal?(0) || !c.equal?(0))
46
+
47
+ @x_coefficient = a
48
+ @y_coefficient = b
49
+ @free_coefficient = c
50
+ end
51
+
52
+ ##
53
+ # Checks the point lies on the line or not
54
+ def point_is_on_line?(point)
55
+ ((@x_coefficient * point.x + @y_coefficient * point.y + @free_coefficient) - 0.0).abs < 0.0001
56
+ end
57
+
58
+ # Checks if two lines are parallel
59
+ def parallel?(other_line)
60
+ @x_coefficient.equal?(other_line.x_coefficient) && @y_coefficient.equal?(other_line.y_coefficient)
61
+ end
62
+
63
+ ##
64
+ # Checks if two lines are intersecting
65
+ def intersecting?(other_line)
66
+ @x_coefficient != other_line.x_coefficient || @y_coefficient != other_line.y_coefficient
67
+ end
68
+
69
+ ##
70
+ # Checks if two lines are perpendicular
71
+ def perpendicular?(other_line)
72
+ (@x_coefficient * other_line.x_coefficient).equal?(- @y_coefficient * other_line.y_coefficient)
73
+ end
74
+
75
+ ##
76
+ # Checking if the point is on a segment
77
+ def check_point_on_segment(point)
78
+ (@x_coefficient * point.x + @y_coefficient * point.y + @free_coefficient) - 0.0 <= 0.0001
79
+ end
80
+
81
+ ##
82
+ # Returns a point of intersection of two lines
83
+ # If not intersecting returns nil
84
+ def intersection_point(other_line)
85
+ return nil unless intersecting?(other_line)
86
+
87
+ divisor = @x_coefficient * other_line.y_coefficient - other_line.x_coefficient * @y_coefficient
88
+ x = (@y_coefficient * other_line.free_coefficient - other_line.y_coefficient * @free_coefficient) / divisor
89
+ y = (@free_coefficient * other_line.x_coefficient - other_line.free_coefficient * @x_coefficient) / divisor
90
+ Point.new(x, y)
91
+ end
92
+
93
+ ##
94
+ # Returns distance between lines
95
+ def distance_to_line(other_line)
96
+ return 0 if intersecting?(other_line)
97
+
98
+ (@free_coefficient - other_line.free_coefficient).abs / Math.sqrt(@x_coefficient**2 + @y_coefficient**2)
99
+ end
100
+
101
+ ##
102
+ # The distance from a point to a line on a plane
103
+ # return 0 if the equation does not define a line.
104
+ def distance_point_to_line(point)
105
+ return 0 if @x_coefficient.eql?(0) && @y_coefficient.eql?(0)
106
+
107
+ res = (@x_coefficient * point.x + @y_coefficient * point.y + @free_coefficient).abs
108
+ res / Math.sqrt(@x_coefficient**2 + @y_coefficient**2).to_f
109
+ end
110
+ ##
111
+ # Check if array of points is on the same line
112
+ def array_of_points_is_on_line(array)
113
+ raise ArgumentError, 'Array is empty!' if array.length == 0
114
+ res = Array.new
115
+ for i in 0..array.size-1 do
116
+ res.push(point_is_on_line?(array[i]))
117
+ end
118
+ res
119
+ end
120
+
121
+ ##
122
+ # The distance between parallel lines
123
+ def distance_between_parallel_lines(other_line)
124
+ raise ArgumentError, 'Lines are not parallel' if !parallel?(other_line)
125
+
126
+ (other_line.free_coefficient - @free_coefficient).abs / Math.sqrt(@x_coefficient**2 + @y_coefficient**2)
127
+ end
128
+ end
129
+
130
+ ##
131
+ # Function for checking sign of number
132
+ def sign(integer)
133
+ integer >= 0 ? 1 : -1
134
+ end
135
+ # The distance from a point to a line on a plane
136
+ # The line is defined by two points
137
+ # https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
138
+ def distance_point_line2d(p1, p2, a)
139
+ line_segment_length = distance_point_to_point2d(p1, p2)
140
+ ((p2.y - p1.y) * a.x - (p2.x - p1.x) * a.y + p2.x * p1.y - p2.y * p1.x).abs / (line_segment_length * 1.0)
141
+ end
142
+
143
+ ##
144
+ # The distance from a point to a line on a plane
145
+ # Normalized equation of the line
146
+ def distance_point_line_normalized2d(a, b, c, p)
147
+ (p.x * a + p.y * b - c).abs
148
+ end
149
+
150
+ def oriented_area(a, b, c)
151
+ a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)
152
+ end
153
+
154
+ ##
155
+ # Determines if a clockwise crawl is performed
156
+ # for defined order of points
157
+ def clockwise(a, b, c)
158
+ oriented_area(a, b, c).negative?
159
+ end
160
+
161
+ ##
162
+ # Determines if a counter-clockwise crawl is
163
+ # performed for defined order of points
164
+ def counter_clockwise(a, b, c)
165
+ oriented_area(a, b, c).positive?
166
+ end
167
+
168
+ def not_polygon?(points)
169
+ points.empty? || points.size == 1 || points.size == 2
170
+ end
171
+
172
+ def put_point_in_part(part, point, direction)
173
+ direction = method(direction)
174
+ part.pop while part.size >= 2 && !direction.call(part[part.size - 2], part[part.size - 1], point)
175
+ part.push(point)
176
+ end
177
+
178
+ ##
179
+ # Returns an array containing points that are included
180
+ # in the minimal convex hull for a given array of points
181
+ # https://e-maxx.ru/algo/convex_hull_graham
182
+ def minimal_convex_hull_2d(points)
183
+ return points if not_polygon?(points)
184
+
185
+ points.sort_by! { |p| [p.x, p.y] }
186
+ first = points[0]
187
+ last = points.last
188
+ up = [first]
189
+ down = [first]
190
+
191
+ (1...points.size).each do |i|
192
+ point = points[i]
193
+ is_last = i == points.size - 1
194
+ put_point_in_part(up, point, :clockwise) if is_last || clockwise(first, point, last)
195
+ put_point_in_part(down, point, :counter_clockwise) if is_last || counter_clockwise(first, point, last)
196
+ end
197
+ up + down[1...-1]
198
+ end
199
+
200
+ def process_cf(line_equation, variable)
201
+ if line_equation.include?(variable)
202
+ before = line_equation.index('/') + 1
203
+ after = line_equation.index('=')
204
+ line_equation.slice(before..after).gsub('=', '').sub('*', '').gsub('(', '').gsub(')', '').to_f
205
+ else
206
+ 0.0
207
+ end
208
+ end
209
+
210
+ def cut_by_eq(line_equation)
211
+ line_equation.slice(line_equation.index('='), line_equation.length).sub('=', '')
212
+ end
213
+
214
+ def process_line_by_coordinates(line_equation, func)
215
+ copy_line = insert_eq(line_equation)
216
+ func = method(func)
217
+ res = []
218
+ res[0] = func.call(copy_line, 'x')
219
+ copy_line = cut_by_eq(copy_line)
220
+ res[1] = func.call(copy_line, 'y')
221
+ copy_line = cut_by_eq(copy_line)
222
+ res[2] = func.call(copy_line, 'z')
223
+ res
224
+ end
225
+
226
+
227
+
228
+ class VariablesOrderException < RuntimeError
229
+ end
230
+
231
+ def needed_variables_order?(before, after)
232
+ before < after
233
+ end
234
+
235
+ def process_free_member(line_equation, variable)
236
+ if line_equation.include?(variable)
237
+ before = line_equation.index(variable) + 1
238
+ after = line_equation.index('/')
239
+
240
+ throw VariablesOrderException unless needed_variables_order?(before, after)
241
+
242
+ line_equation.slice(before..after).gsub('/', '').to_f * -1
243
+ else
244
+ 0.0
245
+ end
246
+ end
247
+
248
+
249
+
250
+ def vectors_product(v1, v2)
251
+ res = Array.new(3)
252
+ (0..2).each do |i|
253
+ res[i] = v1[(i + 1) % 3] * v2[(i + 2) % 3] - v1[(i + 2) % 3] * v2[(i + 1) % 3]
254
+ end
255
+ res
256
+ end
257
+
258
+ def vector_length(vector)
259
+ Math.sqrt(vector[0]**2 + vector[1]**2 + vector[2]**2)
260
+ end
261
+
262
+
263
+
264
+ # Closest pair of points_________________________
265
+ # find minimum distance between two points in set
266
+ def brute_min(points, current = Float::INFINITY)
267
+ return current if points.length < 2
268
+
269
+ head = points[0]
270
+ points.delete_at(0)
271
+ new_min = points.map { |x| distance_point_to_point2d(head, x)}.min
272
+ new_сurrent = [new_min, current].min
273
+ brute_min(points, new_сurrent)
274
+ end
275
+
276
+ def divide_min(points)
277
+ half = points.length / 2
278
+ points.sort_by! { |p| [p.x, p.y] }
279
+ minimum = [brute_min(points[0..half]), brute_min(points[half..points.length])].min
280
+ near_line = points.select { |x| x > half - minimum and x < half + minimum}
281
+ min([brute_min(near_line), minimum])
282
+ end
283
+
284
+ def insert_eq(line_equation)
285
+ line_equation.gsub(' ', '').insert(line_equation.length, '=')
286
+ end
287
+ end
288
+ end
289
+
290
+