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
@@ -1,147 +1,184 @@
1
- module Silicium
2
- class IntegralDoesntExistError < RuntimeError
3
-
4
- end
5
- ##
6
- # A class providing numerical integration methods
7
- class NumericalIntegration
8
-
9
- # Computes integral from +a+ to +b+ of +block+ with accuracy +eps+
10
- def self.three_eights_integration(a, b, eps = 0.0001, &block)
11
- wrapper_method([a, b], eps, :three_eights_integration_n, &block)
12
- end
13
-
14
- # Computes integral from +a+ to +b+ of +block+ with +n+ segmentations
15
- def self.three_eights_integration_n(a, b, n, &block)
16
- dx = (b - a) / n.to_f
17
- result = 0
18
- x = a
19
- n.times do
20
- result +=
21
- (block.call(x) + 3 * block.call((2 * x + x + dx) / 3.0) +
22
- 3 * block.call((x + 2 * (x + dx)) / 3.0) + block.call(x + dx)) / 8.0 * dx
23
- x += dx
24
- end
25
- result
26
- end
27
-
28
-
29
- # Simpson integration with a segment
30
- def self.simpson_integration_with_a_segment(a, b, n, &block)
31
- dx = (b - a) / n.to_f
32
- result = 0
33
- i = 0
34
- while i < n
35
- result += (block.call(a + i * dx) + 4 * block.call(((a + i * dx) +
36
- (a + (i + 1) * dx)) / 2.0) + block.call(a + (i + 1) * dx)) / 6.0 * dx
37
- i += 1
38
- end
39
- result
40
- end
41
-
42
- # Simpson integration with specified accuracy
43
- def self.simpson_integration(a, b, eps = 0.0001, &block)
44
- wrapper_method([a, b], eps, :simpson_integration_with_a_segment, &block)
45
- end
46
-
47
- # Left Rectangle Method and Right Rectangle Method
48
- def self.left_rect_integration(left_p, right_p, eps = 0.0001, &block)
49
- splits = 1
50
- res1 = left_rect_integration_n(left_p, right_p, 1, &block)
51
- res2 = left_rect_integration_n(left_p, right_p, 5, &block)
52
- while (res1 - res2).abs > eps
53
- res1 = left_rect_integration_n(left_p, right_p, splits, &block)
54
- splits *= 5
55
- res2 = left_rect_integration_n(left_p, right_p, splits, &block)
56
- end
57
- (res1 + res2) / 2.0
58
- end
59
-
60
- # Left Rectangle Auxiliary Method and Right Rectangle Auxiliary Method
61
- def self.left_rect_integration_n(left_p, right_p, splits, &block)
62
- dx = (right_p - left_p) / splits.to_f
63
- result = 0
64
- i = 0
65
- while i < splits
66
- result += block.call(left_p + i * dx)
67
- i += 1
68
- end
69
- result * dx
70
- end
71
-
72
-
73
- # Middle Rectangles Method with a segment
74
- def self.middle_rectangles_with_a_segment(a, b, n, &block)
75
- dx = (b - a) / n.to_f
76
- result = 0
77
- i = 0
78
- n.times do
79
- result += block.call(a + dx * (i + 1 / 2)) * dx
80
- i += 1
81
- end
82
- result
83
- end
84
-
85
- # Middle Rectangles Method with specified accuracy
86
- def self.middle_rectangles(a, b, eps = 0.0001, &block)
87
- wrapper_method([a, b], eps, :middle_rectangles_with_a_segment, &block)
88
- end
89
-
90
-
91
- # Trapezoid Method with a segment
92
- def self.trapezoid_with_a_segment(a, b, n, &block)
93
- dx = (b - a) / n.to_f
94
- result = 0
95
- i = 1
96
- (n - 1).times do
97
- result += block.call(a + dx * i)
98
- i += 1
99
- end
100
- result += (block.call(a) + block.call(b)) / 2.0
101
- result * dx
102
- end
103
-
104
- # Trapezoid Method with specified accuracy
105
- def self.trapezoid(a, b, eps = 0.0001, &block)
106
- wrapper_method([a, b], eps, :trapezoid_with_a_segment ,&block)
107
- end
108
-
109
- private
110
-
111
- ##
112
- # Wrapper method for num_integratons methods
113
- # @param [Array] a_b integration range
114
- # @param [Numeric] eps
115
- # @param [Proc] proc - integration Proc
116
- # @param [Block] block - integrated function as Block
117
- def self.wrapper_method(a_b, eps, method_name, &block)
118
- n = 1
119
- a, b = a_b
120
- begin
121
- begin
122
- result = send(method_name, a, b, n, &block)
123
- check_value(result)
124
- n *= 5
125
- result1 = send(method_name, a, b, n, &block)
126
- check_value(result1)
127
- end until (result - result1).abs < eps
128
- rescue Math::DomainError
129
- raise IntegralDoesntExistError, 'Domain error in math function'
130
- rescue ZeroDivisionError
131
- raise IntegralDoesntExistError, 'Divide by zero'
132
- end
133
- (result + result1) / 2.0
134
- end
135
-
136
- def self.check_value(value)
137
- if value.nan?
138
- raise IntegralDoesntExistError, 'We have not-a-number result :('
139
- end
140
- if value == Float::INFINITY
141
- raise IntegralDoesntExistError, 'We have infinity :('
142
- end
143
- end
144
- end
145
- end
146
-
147
-
1
+ module Silicium
2
+ class IntegralDoesntExistError < RuntimeError; end
3
+
4
+ class NumberofIterOutofRangeError < RuntimeError; end
5
+
6
+ ##
7
+ # A class providing numerical integration methods
8
+ class NumericalIntegration
9
+
10
+ ##
11
+ # Computes integral by the 3/8 rule
12
+ # from +a+ to +b+ of +block+ with accuracy +eps+
13
+ def self.three_eights_integration(a, b, eps = 0.0001, &block)
14
+ wrapper_method([a, b], eps, :three_eights_integration_n, &block)
15
+ end
16
+
17
+ ##
18
+ # Computes integral by the 3/8 rule
19
+ # from +a+ to +b+ of +block+ with +n+ segmentations
20
+ def self.three_eights_integration_n(a, b, n, &block)
21
+ dx = (b - a) / n.to_f
22
+ result = 0
23
+ x = a
24
+ n.times do
25
+ result +=
26
+ (block.call(x) + 3 * block.call((2 * x + x + dx) / 3.0) +
27
+ 3 * block.call((x + 2 * (x + dx)) / 3.0) + block.call(x + dx)) / 8.0 * dx
28
+ x += dx
29
+ end
30
+ result
31
+ end
32
+
33
+ ##
34
+ # Computes integral by the Simpson's rule
35
+ # from +a+ to +b+ of +block+ with +n+ segmentations
36
+ def self.simpson_integration_with_a_segment(a, b, n, &block)
37
+ dx = (b - a) / n.to_f
38
+ result = 0
39
+ i = 0
40
+ while i < n
41
+ result += (block.call(a + i * dx) + 4 * block.call(((a + i * dx) +
42
+ (a + (i + 1) * dx)) / 2.0) + block.call(a + (i + 1) * dx)) / 6.0 * dx
43
+ i += 1
44
+ end
45
+ result
46
+ end
47
+
48
+ ##
49
+ # Computes integral by the Simpson's rule
50
+ # from +a+ to +b+ of +block+ with accuracy +eps+
51
+ def self.simpson_integration(a, b, eps = 0.0001, &block)
52
+ wrapper_method([a, b], eps, :simpson_integration_with_a_segment, &block)
53
+ end
54
+
55
+ ##
56
+ # Computes integral by the Left Rectangles method
57
+ # from +a+ to +b+ of +block+ with accuracy +eps+
58
+ def self.left_rect_integration(a, b, eps = 0.0001, &block)
59
+ wrapper_method([a, b], eps, :left_rect_integration_n, &block)
60
+ end
61
+
62
+ ##
63
+ # Computes integral by the Left Rectangles method
64
+ # from +a+ to +b+ of +block+ with +n+ segmentations
65
+ def self.left_rect_integration_n(a, b, n, &block)
66
+ dx = (b - a) / n.to_f
67
+ amount_calculation(a, [0, n], dx, &block)
68
+ end
69
+
70
+ ##
71
+ # Computes integral by the Right Rectangles method
72
+ # from +a+ to +b+ of +block+ with accuracy +eps+
73
+ def self.right_rect_integration(a, b, eps = 0.0001, &block)
74
+ wrapper_method([a, b], eps, :right_rect_integration_n, &block)
75
+ end
76
+
77
+ ##
78
+ # Computes integral by the Right Rectangles method
79
+ # from +a+ to +b+ of +block+ with +n+ segmentations
80
+ def self.right_rect_integration_n(a, b, n, &block)
81
+ dx = (b - a) / n.to_f
82
+ amount_calculation(a, [1, n + 1], dx, &block)
83
+ end
84
+
85
+ ##
86
+ # Computes integral by the Middle Rectangles method
87
+ # from +a+ to +b+ of +block+ with +n+ segmentations
88
+ def self.middle_rectangles_with_a_segment(a, b, n, &block)
89
+ dx = (b - a) / n.to_f
90
+ result = 0
91
+ i = 0
92
+ n.times do
93
+ result += block.call(a + dx * (i + 1 / 2)) * dx
94
+ i += 1
95
+ end
96
+ result
97
+ end
98
+
99
+ ##
100
+ # Computes integral by the Middle Rectangles method
101
+ # from +a+ to +b+ of +block+ with accuracy +eps+
102
+ def self.middle_rectangles(a, b, eps = 0.0001, &block)
103
+ wrapper_method([a, b], eps, :middle_rectangles_with_a_segment, &block)
104
+ end
105
+
106
+ ##
107
+ # Computes integral by the Trapezoid method
108
+ # from +a+ to +b+ of +block+ with +n+ segmentations
109
+ def self.trapezoid_with_a_segment(a, b, n, &block)
110
+ dx = (b - a) / n.to_f
111
+ result = 0
112
+ i = 1
113
+ (n - 1).times do
114
+ result += block.call(a + dx * i)
115
+ i += 1
116
+ end
117
+ result += (block.call(a) + block.call(b)) / 2.0
118
+ result * dx
119
+ end
120
+
121
+ ##
122
+ # Computes integral by the Trapezoid method
123
+ # from +a+ to +b+ of +block+ with accuracy +eps+
124
+ def self.trapezoid(a, b, eps = 0.0001, &block)
125
+ wrapper_method([a, b], eps, :trapezoid_with_a_segment ,&block)
126
+ end
127
+
128
+ private
129
+
130
+ ##
131
+ # Wrapper method for num_integratons methods
132
+ # @param [Array] a_b integration range
133
+ # @param [Numeric] eps
134
+ # @param [Proc] proc - integration Proc
135
+ # @param [Block] block - integrated function as Block
136
+ def self.wrapper_method(a_b, eps, method_name, &block)
137
+ n = 1
138
+ max_it = 10_000
139
+ begin
140
+ begin
141
+ result = send(method_name, a_b[0], a_b[1], n, &block)
142
+ check_value(result)
143
+ n *= 5
144
+ raise NumberofIterOutofRangeError if n > max_it
145
+ result1 = send(method_name, a_b[0], a_b[1], n, &block)
146
+ check_value(result1)
147
+ end until (result - result1).abs < eps
148
+
149
+ rescue Math::DomainError
150
+ raise IntegralDoesntExistError, 'Domain error in math function'
151
+ rescue ZeroDivisionError
152
+ raise IntegralDoesntExistError, 'Divide by zero'
153
+ end
154
+ (result + result1) / 2.0
155
+ end
156
+
157
+ def self.check_value(value)
158
+ if value.nan?
159
+ raise IntegralDoesntExistError, 'We have not-a-number result :('
160
+ end
161
+ if value == Float::INFINITY
162
+ raise IntegralDoesntExistError, 'We have infinity :('
163
+ end
164
+ end
165
+
166
+ ##
167
+ # Computes the sum of n rectangles on a segment
168
+ # of length dx at points of the form a + i * dx
169
+ # @param [Numeric] a - first division point
170
+ # @param [Array] i_n number of divisions
171
+ # @param [Numeric] dx - length of integration segment
172
+ # @param [Block] block - integrated function as Block
173
+ def self.amount_calculation(a, i_n, dx, &block)
174
+ result = 0
175
+ while i_n[0] < i_n[1]
176
+ result += block.call(a + i_n[0] * dx)
177
+ i_n[0] += 1
178
+ end
179
+ result * dx
180
+ end
181
+ end
182
+ end
183
+
184
+
data/lib/optimization.rb CHANGED
@@ -1,144 +1,209 @@
1
- require "silicium"
2
- require 'fast_matrix'
3
-
4
- module Silicium
5
- module Optimization
6
-
7
-
8
- # reflector function
9
- def re_lu(x)
10
- x.negative? ? 0 : x
11
- end
12
-
13
- #sigmoid function
14
- def sigmoid(x)
15
- 1.0 / (1 + Math.exp(-x))
16
- end
17
-
18
- #integrating using method Monte Carlo (f - function, a, b - integrating limits, n - amount of random numbers)
19
- def integrating_Monte_Carlo_base(a, b, n = 100000, &block)
20
- res = 0
21
- range = a..b.to_f
22
- for i in 1..(n + 1)
23
- x = rand(range)
24
- res += (b - a) * 1.0 / n * block.call(x)
25
- end
26
- res
27
- end
28
-
29
- #return true if array is sorted
30
- def sorted?(a)
31
- return false if a.nil?
32
- for i in 0..a.length - 2
33
- if (a[i + 1] < a[i])
34
- return false
35
- end
36
- end
37
- true
38
- end
39
-
40
- #fastest(but it is not exactly) sort, modify sequance
41
- def bogosort!(a)
42
- if (a.nil?)
43
- raise ArgumentError, "Nil array in bogosort"
44
- end
45
- while (!sorted?(a))
46
- a.shuffle!
47
- end
48
- a
49
- end
50
-
51
- #fastest(but it is not exactly) sort
52
- def bogosort(a)
53
- if (a.nil?)
54
- raise ArgumentError, "Nil array in bogosort"
55
- end
56
- crutch = a
57
- while (!sorted?(crutch))
58
- crutch = a.shuffle
59
- end
60
- crutch
61
- end
62
-
63
- #calculate current accuracy in Hook - Jeeves method
64
- def accuracy(step)
65
- acc = 0
66
- step.each { |a| acc += a * a }
67
- Math.sqrt(acc)
68
- end
69
-
70
- #do one Hook - Jeeves step
71
- def hook_jeeves_step(x, i, step, &block)
72
- x[i] += step[i]
73
- tmp1 = block.call(x)
74
- x[i] = x[i] - 2 * step[i]
75
- tmp2 = block.call(x)
76
- if (tmp1 > tmp2)
77
- cur_f = tmp2
78
- else
79
- x[i] = x[i] + step[i] * 2
80
- cur_f = tmp1
81
- end
82
- [cur_f, x[i]]
83
- end
84
-
85
- #switch step if current func value > previous func value
86
- def switch_step(cur_f, prev_f, step, i)
87
- return step[i] / 2.0 if cur_f >= prev_f #you can switch 2.0 on something else
88
- step[i]
89
- end
90
- #Hook - Jeeves method for find minimum point (x - array of start variables, step - step of one iteration, eps - allowable error, alfa - slowdown of step,
91
- #block - function which takes array x, WAENING function doesn't control correctness of input
92
- def hook_jeeves(x, step, eps = 0.1, &block)
93
- prev_f = block.call(x)
94
- acc = accuracy(step)
95
- while (acc > eps)
96
- for i in 0..x.length - 1
97
- tmp = hook_jeeves_step(x, i, step, &block)
98
- cur_f = tmp[0]
99
- x[i] = tmp[1]
100
- step[i] = switch_step(cur_f, prev_f, step, i)
101
- prev_f = cur_f
102
- end
103
- acc = accuracy(step)
104
- end
105
- x
106
- end
107
-
108
- #find centr of interval
109
- def middle(a, b)
110
- (a + b) / 2.0
111
- end
112
-
113
- #do one half division step
114
- def half_division_step(a, b, c, &block)
115
- if (block.call(a) * block.call(c) < 0)
116
- b = c
117
- c = middle(a, c)
118
- else
119
- a = c
120
- c = middle(b, c)
121
- end
122
- [a, b, c]
123
- end
124
-
125
- #find root in [a, b], if he exist, if number of iterations > iters -> error
126
- def half_division(a, b, eps = 0.001, &block)
127
- iters = 1000000
128
- c = middle(a, b)
129
- while ((block.call(c).abs) > eps)
130
- tmp = half_division_step(a, b, c, &block)
131
- a = tmp[0]
132
- b = tmp[1]
133
- c = tmp[2]
134
- iters -= 1
135
- if iters == 0
136
- raise RuntimeError, "Root not found! Check does he exist, or change eps or iters"
137
- end
138
- end
139
- c
140
- end
141
-
142
-
143
- end
144
- end
1
+ require "silicium"
2
+ require 'fast_matrix'
3
+
4
+ module Silicium
5
+ module Optimization
6
+ # reflector function
7
+ def re_lu(x)
8
+ x.negative? ? 0 : x
9
+ end
10
+
11
+ # sigmoid function
12
+ def sigmoid(x)
13
+ 1.0 / (1 + Math.exp(-x))
14
+ end
15
+
16
+ # integrating using method Monte Carlo (f - function, a, b - integrating limits, n - amount of random numbers)
17
+ def integrating_Monte_Carlo_base(a, b, n = 100000, &block)
18
+ res = 0
19
+ range = a..b.to_f
20
+ (0..n).each do
21
+ x = rand(range)
22
+ res += (b - a) * 1.0 / n * block.call(x)
23
+ end
24
+ res
25
+ end
26
+
27
+ # return true if array is sorted
28
+ def sorted?(a)
29
+ return false if a.nil?
30
+
31
+ for i in 0..a.length - 2
32
+ return false if (a[i + 1] < a[i])
33
+ end
34
+ true
35
+ end
36
+
37
+ # fastest(but it is not exactly) sort, modify sequance
38
+ def bogosort!(a)
39
+ raise ArgumentError, "Nil array in bogosort" if a.nil?
40
+
41
+ a.shuffle! until sorted?(a)
42
+ a
43
+ end
44
+
45
+ # fastest(but it is not exactly) sort
46
+ def bogosort(a)
47
+ raise ArgumentError, "Nil array in bogosort" if a.nil?
48
+
49
+ crutch = a
50
+ (crutch = a.shuffle) until sorted?(crutch)
51
+ crutch
52
+ end
53
+
54
+ # calculate current accuracy in Hook - Jeeves method
55
+ def accuracy(step)
56
+ acc = 0
57
+ step.each { |a| acc += a * a }
58
+ Math.sqrt(acc)
59
+ end
60
+
61
+ # do one Hook - Jeeves step
62
+ def hook_jeeves_step(x, i, step, &block)
63
+ x[i] += step[i]
64
+ tmp1 = block.call(x)
65
+ x[i] = x[i] - 2 * step[i]
66
+ tmp2 = block.call(x)
67
+ if (tmp1 > tmp2)
68
+ cur_f = tmp2
69
+ else
70
+ x[i] = x[i] + step[i] * 2
71
+ cur_f = tmp1
72
+ end
73
+ [cur_f, x[i]]
74
+ end
75
+
76
+ # switch step if current func value > previous func value
77
+ def switch_step(cur_f, prev_f, step, i)
78
+ return step[i] / 2.0 if cur_f >= prev_f # you can switch 2.0 on something else
79
+
80
+ step[i]
81
+ end
82
+
83
+ # Hook - Jeeves method for find minimum point (x - array of start variables, step - step of one iteration, eps - allowable error, alfa - slowdown of step,
84
+ # block - function which takes array x, WAENING function doesn't control correctness of input
85
+ def hook_jeeves(x, step, eps = 0.1, &block)
86
+ prev_f = block.call(x)
87
+ acc = accuracy(step)
88
+ while (acc > eps)
89
+ for i in 0..x.length - 1
90
+ tmp = hook_jeeves_step(x, i, step, &block)
91
+ cur_f = tmp[0]
92
+ x[i] = tmp[1]
93
+ step[i] = switch_step(cur_f, prev_f, step, i)
94
+ prev_f = cur_f
95
+ end
96
+ acc = accuracy(step)
97
+ end
98
+ x
99
+ end
100
+
101
+ # find centr of interval
102
+ def middle(a, b)
103
+ (a + b) / 2.0
104
+ end
105
+
106
+ # do one half division step
107
+ def half_division_step(a, b, c, &block)
108
+ if (block.call(a) * block.call(c)).negative?
109
+ b = c
110
+ c = middle(a, c)
111
+ else
112
+ a = c
113
+ c = middle(b, c)
114
+ end
115
+ [a, b, c]
116
+ end
117
+
118
+ # find root in [a, b], if he exist, if number of iterations > iters -> error
119
+ def half_division(a, b, eps = 0.001, &block)
120
+ iters = 1000000
121
+ c = middle(a, b)
122
+ while (block.call(c).abs) > eps
123
+ tmp = half_division_step(a, b, c, &block)
124
+ a = tmp[0]
125
+ b = tmp[1]
126
+ c = tmp[2]
127
+ iters -= 1
128
+ raise RuntimeError, 'Root not found! Check does he exist, or change eps or iters' if iters == 0
129
+ end
130
+ c
131
+ end
132
+
133
+ # Find determinant 3x3 matrix
134
+ def determinant_sarryus(matrix)
135
+ raise ArgumentError, "Matrix size must be 3x3" if (matrix.row_count != 3 || matrix.column_count != 3)
136
+
137
+ matrix[0, 0] * matrix[1, 1] * matrix[2, 2] + matrix[0, 1] * matrix[1, 2] * matrix[2, 0] + matrix[0, 2] * matrix[1, 0] * matrix[2, 1] -
138
+ matrix[0, 2] * matrix[1, 1] * matrix[2, 0] - matrix[0, 0] * matrix[1, 2] * matrix[2, 1] - matrix[0, 1] * matrix[1, 0] * matrix[2, 2]
139
+ end
140
+
141
+ # return probability to accept
142
+ def accept_annealing(z, min, t, d)
143
+ p = (min - z) / (d * t * 1.0)
144
+ Math.exp(p)
145
+ end
146
+
147
+ # do one annealing step
148
+ def annealing_step(x, min_board, max_board)
149
+ x += rand(-0.5..0.5)
150
+ x = max_board if (x > max_board)
151
+ x = min_board if (x < min_board)
152
+ x
153
+ end
154
+
155
+ # update current min and xm if cond
156
+ def annealing_cond(z, min, t, d)
157
+ (z < min || accept_annealing(z, min, t, d) > rand(0.0..1.0))
158
+ end
159
+
160
+ # Annealing method to find min of function with one argument, between min_board max_board,
161
+ def simulated_annealing(min_board, max_board, t = 10000, &block)
162
+ d = Math.exp(-5) # Constant of annealing
163
+ x = rand(min_board * 1.0..max_board * 1.0)
164
+ xm = x
165
+ min = block.call(x)
166
+ while (t > 0.00001)
167
+ x = xm
168
+ x = annealing_step(x, min_board, max_board)
169
+ z = block.call(x)
170
+ if (annealing_cond(z, min, t, d))
171
+ min = z
172
+ xm = x
173
+ end
174
+ t *= 0.9999 # tempreture drops
175
+ end
176
+ xm
177
+ end
178
+
179
+ # Fast multiplication of num1 and num2.
180
+ def karatsuba(num1, num2)
181
+ return num1 * num2 if num1 < 10 || num2 < 10
182
+
183
+ max_size = [num1.to_s.length, num2.to_s.length].max
184
+
185
+ first_half1, last_half1 = make_equal(num1, max_size)
186
+ first_half2, last_half2 = make_equal(num2, max_size)
187
+
188
+ t0 = karatsuba(last_half1, last_half2)
189
+ t1 = karatsuba((first_half1 + last_half1), (first_half2 + last_half2))
190
+ t2 = karatsuba(first_half1, first_half2)
191
+
192
+ compute_karatsuba(t0, t1, t2, max_size / 2)
193
+ end
194
+
195
+ private
196
+
197
+ # Helper for karatsuba method. Divides num into two halves.
198
+ def make_equal(num, size)
199
+ mid = (size + 1) / 2
200
+ string = num.to_s.rjust(size, '0')
201
+ [string.slice(0...mid).to_i, string.slice(mid..-1).to_i]
202
+ end
203
+
204
+ # Helper for karatsuba method. Computes the result of karatsuba's multiplication.
205
+ def compute_karatsuba(tp0, tp1, tp2, num)
206
+ tp2 * 10**(2 * num) + ((tp1 - tp0 - tp2) * 10**num) + tp0
207
+ end
208
+ end
209
+ end