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
@@ -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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# in
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
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
|
+
|