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
@@ -1,147 +1,184 @@
|
|
1
|
-
module Silicium
|
2
|
-
class IntegralDoesntExistError < RuntimeError
|
3
|
-
|
4
|
-
end
|
5
|
-
|
6
|
-
|
7
|
-
class
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
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
|
-
end
|
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
|
-
def self.
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
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
|
-
else
|
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
|
-
|
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
|