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