silicium 0.0.2
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 +7 -0
- data/.codeclimate.yml +4 -0
- data/.gitignore +13 -0
- data/.travis.yml +25 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/Makefile +269 -0
- data/README.md +46 -0
- data/Rakefile +17 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docs/Object.html +117 -0
- data/docs/README_md.html +142 -0
- data/docs/Silicium/Combinatorics.html +270 -0
- data/docs/Silicium/Dice/Polyhedron.html +315 -0
- data/docs/Silicium/Dice/PolyhedronSet.html +321 -0
- data/docs/Silicium/Dice.html +99 -0
- data/docs/Silicium/Error.html +106 -0
- data/docs/Silicium/Geometry/Line2dCanon.html +243 -0
- data/docs/Silicium/Geometry/VariablesOrderException.html +106 -0
- data/docs/Silicium/Geometry.html +940 -0
- data/docs/Silicium/Graphs/GraphError.html +106 -0
- data/docs/Silicium/Graphs/OrientedGraph.html +775 -0
- data/docs/Silicium/Graphs/UnorientedGraph.html +284 -0
- data/docs/Silicium/Graphs.html +164 -0
- data/docs/Silicium/IntegralDoesntExistError.html +106 -0
- data/docs/Silicium/NumericalIntegration.html +521 -0
- data/docs/Silicium/Optimization.html +639 -0
- data/docs/Silicium/Plotter/Image.html +297 -0
- data/docs/Silicium/Plotter.html +186 -0
- data/docs/Silicium.html +101 -0
- data/docs/created.rid +9 -0
- data/docs/css/fonts.css +167 -0
- data/docs/css/rdoc.css +619 -0
- data/docs/fonts/Lato-Light.ttf +0 -0
- data/docs/fonts/Lato-LightItalic.ttf +0 -0
- data/docs/fonts/Lato-Regular.ttf +0 -0
- data/docs/fonts/Lato-RegularItalic.ttf +0 -0
- data/docs/fonts/SourceCodePro-Bold.ttf +0 -0
- data/docs/fonts/SourceCodePro-Regular.ttf +0 -0
- data/docs/images/add.png +0 -0
- data/docs/images/arrow_up.png +0 -0
- data/docs/images/brick.png +0 -0
- data/docs/images/brick_link.png +0 -0
- data/docs/images/bug.png +0 -0
- data/docs/images/bullet_black.png +0 -0
- data/docs/images/bullet_toggle_minus.png +0 -0
- data/docs/images/bullet_toggle_plus.png +0 -0
- data/docs/images/date.png +0 -0
- data/docs/images/delete.png +0 -0
- data/docs/images/find.png +0 -0
- data/docs/images/loadingAnimation.gif +0 -0
- data/docs/images/macFFBgHack.png +0 -0
- data/docs/images/package.png +0 -0
- data/docs/images/page_green.png +0 -0
- data/docs/images/page_white_text.png +0 -0
- data/docs/images/page_white_width.png +0 -0
- data/docs/images/plugin.png +0 -0
- data/docs/images/ruby.png +0 -0
- data/docs/images/tag_blue.png +0 -0
- data/docs/images/tag_green.png +0 -0
- data/docs/images/transparent.png +0 -0
- data/docs/images/wrench.png +0 -0
- data/docs/images/wrench_orange.png +0 -0
- data/docs/images/zoom.png +0 -0
- data/docs/index.html +132 -0
- data/docs/js/darkfish.js +84 -0
- data/docs/js/navigation.js +105 -0
- data/docs/js/navigation.js.gz +0 -0
- data/docs/js/search.js +110 -0
- data/docs/js/search_index.js +1 -0
- data/docs/js/search_index.js.gz +0 -0
- data/docs/js/searcher.js +229 -0
- data/docs/js/searcher.js.gz +0 -0
- data/docs/table_of_contents.html +608 -0
- data/lib/geometry.rb +236 -0
- data/lib/graph.rb +164 -0
- data/lib/numerical_integration.rb +147 -0
- data/lib/optimization.rb +144 -0
- data/lib/plotter.rb +96 -0
- data/lib/silicium/version.rb +3 -0
- data/lib/silicium.rb +5 -0
- data/lib/theory_of_probability.rb +227 -0
- data/silicium.gemspec +39 -0
- metadata +185 -0
data/lib/geometry.rb
ADDED
@@ -0,0 +1,236 @@
|
|
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
|
data/lib/graph.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
#require 'set'
|
2
|
+
#require 'silicium'
|
3
|
+
|
4
|
+
module Silicium
|
5
|
+
module Graphs
|
6
|
+
Pair = Struct.new(:first, :second)
|
7
|
+
|
8
|
+
class GraphError < Error
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
class OrientedGraph
|
13
|
+
def initialize(initializer = [])
|
14
|
+
@vertices = {}
|
15
|
+
@edge_labels = {}
|
16
|
+
@vertex_labels = {}
|
17
|
+
initializer.each do |v|
|
18
|
+
add_vertex!(v[:v])
|
19
|
+
v[:i].each { |iv| add_edge_force!(v[:v], iv)}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_vertex!(vertex_id)
|
24
|
+
if @vertices.has_key?(vertex_id)
|
25
|
+
return
|
26
|
+
end
|
27
|
+
@vertices[vertex_id] = [].to_set
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_edge!(from, to)
|
31
|
+
if @vertices.has_key?(from) && @vertices.has_key?(to)
|
32
|
+
@vertices[from] << to
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# should only be used in constructor
|
37
|
+
def add_edge_force!(from, to)
|
38
|
+
add_vertex!(from)
|
39
|
+
add_vertex!(to)
|
40
|
+
add_edge!(from, to)
|
41
|
+
end
|
42
|
+
|
43
|
+
def adjacted_with(vertex)
|
44
|
+
unless @vertices.has_key?(vertex)
|
45
|
+
raise GraphError.new("Graph does not contain vertex #{vertex}")
|
46
|
+
end
|
47
|
+
|
48
|
+
@vertices[vertex].clone
|
49
|
+
end
|
50
|
+
|
51
|
+
def label_edge!(from, to, label)
|
52
|
+
unless @vertices.has_key?(from) && @vertices[from].include?(to)
|
53
|
+
raise GraphError.new("Graph does not contain edge (#{from}, #{to})")
|
54
|
+
end
|
55
|
+
|
56
|
+
@edge_labels[Pair.new(from, to)] = label
|
57
|
+
end
|
58
|
+
|
59
|
+
def label_vertex!(vertex, label)
|
60
|
+
unless @vertices.has_key?(vertex)
|
61
|
+
raise GraphError.new("Graph does not contain vertex #{vertex}")
|
62
|
+
end
|
63
|
+
|
64
|
+
@vertex_labels[vertex] = label
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_edge_label(from, to)
|
68
|
+
if !@vertices.has_key?(from) || ! @vertices[from].include?(to)
|
69
|
+
raise GraphError.new("Graph does not contain edge (#{from}, #{to})")
|
70
|
+
end
|
71
|
+
|
72
|
+
@edge_labels[Pair.new(from, to)]
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_vertex_label(vertex)
|
76
|
+
unless @vertices.has_key?(vertex)
|
77
|
+
raise GraphError.new("Graph does not contain vertex #{vertex}")
|
78
|
+
end
|
79
|
+
|
80
|
+
@vertex_labels[vertex]
|
81
|
+
end
|
82
|
+
|
83
|
+
def vertex_number
|
84
|
+
@vertices.count
|
85
|
+
end
|
86
|
+
|
87
|
+
def edge_number
|
88
|
+
res = 0
|
89
|
+
@vertices.values.each do |item|
|
90
|
+
res += item.count
|
91
|
+
end
|
92
|
+
res
|
93
|
+
end
|
94
|
+
|
95
|
+
def vertex_label_number
|
96
|
+
@vertex_labels.count
|
97
|
+
end
|
98
|
+
|
99
|
+
def edge_label_number
|
100
|
+
@edge_labels.count
|
101
|
+
end
|
102
|
+
|
103
|
+
def has_vertex?(vertex)
|
104
|
+
@vertices.has_key?(vertex)
|
105
|
+
end
|
106
|
+
|
107
|
+
def has_edge?(from, to)
|
108
|
+
@vertices.has_key?(from) && @vertices[from].include?(to)
|
109
|
+
end
|
110
|
+
|
111
|
+
def delete_vertex!(vertex)
|
112
|
+
if has_vertex?(vertex)
|
113
|
+
@vertices.keys.each do |key|
|
114
|
+
delete_edge!(key, vertex)
|
115
|
+
end
|
116
|
+
@vertices.delete(vertex)
|
117
|
+
@vertex_labels.delete(vertex)
|
118
|
+
|
119
|
+
@vertices.keys.each do |key|
|
120
|
+
@edge_labels.delete(Pair.new(vertex, key))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def delete_edge!(from, to)
|
126
|
+
if has_edge?(from, to)
|
127
|
+
@vertices[from].delete(to)
|
128
|
+
@edge_labels.delete(Pair.new(from, to))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
class UnorientedGraph < OrientedGraph
|
135
|
+
def add_edge!(from, to)
|
136
|
+
super(from, to)
|
137
|
+
super(to, from)
|
138
|
+
end
|
139
|
+
|
140
|
+
def label_edge!(from, to, label)
|
141
|
+
super(from, to, label)
|
142
|
+
super(to, from, label)
|
143
|
+
end
|
144
|
+
|
145
|
+
def delete_edge!(from, to)
|
146
|
+
super(from, to)
|
147
|
+
super(to, from)
|
148
|
+
end
|
149
|
+
|
150
|
+
def edge_number
|
151
|
+
res = 0
|
152
|
+
@vertices.each do |from, tos|
|
153
|
+
tos.each {|to| res += (to == from ? 2 : 1)}
|
154
|
+
end
|
155
|
+
res / 2
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def dijkstra_algorythm(graph, starting_vertex)
|
160
|
+
#
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
@@ -0,0 +1,147 @@
|
|
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
|
+
|
data/lib/optimization.rb
ADDED
@@ -0,0 +1,144 @@
|
|
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
|