kxi 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kxi.rb +44 -39
  3. data/lib/kxi/application/config.rb +177 -177
  4. data/lib/kxi/application/config_reader.rb +16 -16
  5. data/lib/kxi/application/event.rb +35 -35
  6. data/lib/kxi/application/logger.rb +155 -155
  7. data/lib/kxi/application/version.rb +106 -74
  8. data/lib/kxi/application/version_expression.rb +94 -69
  9. data/lib/kxi/application/workspace.rb +105 -0
  10. data/lib/kxi/cli/anonymous_argument.rb +50 -50
  11. data/lib/kxi/cli/argument.rb +56 -56
  12. data/lib/kxi/cli/argument_values.rb +83 -83
  13. data/lib/kxi/cli/explicit_argument.rb +38 -38
  14. data/lib/kxi/cli/flag_argument.rb +15 -15
  15. data/lib/kxi/cli/named_argument.rb +59 -59
  16. data/lib/kxi/cli/property_list.rb +57 -48
  17. data/lib/kxi/cli/table.rb +82 -62
  18. data/lib/kxi/cli/verb.rb +282 -280
  19. data/lib/kxi/collections/array_collection.rb +106 -106
  20. data/lib/kxi/collections/enumerable.rb +527 -527
  21. data/lib/kxi/collections/enumerator.rb +31 -31
  22. data/lib/kxi/collections/hash_collection.rb +100 -100
  23. data/lib/kxi/collections/protected_collection.rb +20 -19
  24. data/lib/kxi/exceptions/abstract_exception.rb +34 -34
  25. data/lib/kxi/exceptions/argument_exception.rb +21 -21
  26. data/lib/kxi/exceptions/collection_exception.rb +13 -13
  27. data/lib/kxi/exceptions/configuration_exception.rb +36 -25
  28. data/lib/kxi/exceptions/dimension_mismatch_exception.rb +29 -0
  29. data/lib/kxi/exceptions/invalid_type_exception.rb +32 -32
  30. data/lib/kxi/exceptions/no_argument_exception.rb +20 -20
  31. data/lib/kxi/exceptions/not_implemented_exception.rb +12 -12
  32. data/lib/kxi/exceptions/out_of_range_exception.rb +43 -43
  33. data/lib/kxi/exceptions/parse_exception.rb +28 -20
  34. data/lib/kxi/exceptions/verb_expected_exception.rb +20 -20
  35. data/lib/kxi/exceptions/workspace_collision_exception.rb +21 -0
  36. data/lib/kxi/math/math.rb +45 -0
  37. data/lib/kxi/math/matrix.rb +303 -0
  38. data/lib/kxi/math/polynomial.rb +141 -101
  39. data/lib/kxi/math/vector.rb +181 -0
  40. data/lib/kxi/platform.rb +103 -57
  41. data/lib/kxi/reflection/stack_frame.rb +80 -80
  42. data/lib/kxi/version.rb +4 -4
  43. metadata +8 -3
  44. data/lib/kxi/exceptions/invalid_operation_exception.rb +0 -11
@@ -0,0 +1,303 @@
1
+ # Created by Matyáš Pokorný on 2018-04-12.
2
+
3
+ module KXI
4
+ module Math
5
+ # Represents a matrix
6
+ class Matrix
7
+ # Returns a square identity matrix
8
+ # @param [Integer] n Dimension of matrix
9
+ # @return [KXI::Math::Matrix] Square identity matrix of given dimension
10
+ def self.identity(n)
11
+ return KXI::Math::Matrix.new(n, n) { |c, r| c == r ? 1 : 0 }
12
+ end
13
+
14
+ # Returns the number of rows
15
+ # @return [Integer] Number of rows
16
+ def rows
17
+ @rows
18
+ end
19
+
20
+ # Returns the number of columns
21
+ # @return [Integer] Number of columns
22
+ def columns
23
+ @cols
24
+ end
25
+
26
+ # Instantiates the {KXI::Math::Matrix} class
27
+ # @overload initialize(cols)
28
+ # Creates a square matrix
29
+ # @param [Integer] cols Dimension of matrix
30
+ # @overload initialize(cols, rows)
31
+ # Creates a matrix
32
+ # @param [Integer] cols Number of columns in the matrix
33
+ # @param [Integer] rows Number of rows in the matrix
34
+ def initialize(cols, rows = nil)
35
+ rows = cols if rows == nil
36
+ @data = []
37
+ cols.times do |i|
38
+ if block_given?
39
+ @data[i] = []
40
+ rows.times do |j|
41
+ v = yield(i, j)
42
+ raise(KXI::Exceptions::InvalidTypeException.new(v.type, Numeric)) unless v.is_a?(Numeric)
43
+ @data[i].push(v)
44
+ end
45
+ else
46
+ @data[i] = [0.0] * rows
47
+ end
48
+ end
49
+ @cols = cols
50
+ @rows = rows
51
+ end
52
+
53
+ # Swaps two rows of the matrix
54
+ # @param [Integer] a First row to swap
55
+ # @param [Integer] b Second row to swap with
56
+ # @raise [KXI::Exceptions::OutOfRangeException] When one of arguments is out of range
57
+ # @return [KXI::Math::Matrix] New matrix with swapped rows
58
+ def row_swap(a, b)
59
+ raise(KXI::Exceptions::OutOfRangeException.new(a, 0, @rows - 1)) if a < 0 or a >= @rows
60
+ raise(KXI::Exceptions::OutOfRangeException.new(b, 0, @rows - 1)) if b < 0 or b >= @rows
61
+ return KXI::Math::Matrix.new(@cols, @rows) do |c, r|
62
+ next get(c, b) if r == a
63
+ next get(c, a) if r == b
64
+ get(c, r)
65
+ end
66
+ end
67
+
68
+ # Multiplies a row of matrix with specific coefficient
69
+ # @overload row_mult(src, cof)
70
+ # Multiplies a row by coefficient into that row
71
+ # @param [Integer] src Row to multiply
72
+ # @param [Numeric] cof Coefficient to multiply with
73
+ # @raise [KXI::Exceptions::OutOfRangeException] When one of arguments is out of range
74
+ # @return [Matrix] New matrix with multiplied row
75
+ # @overload row_mult(src, cof, dst)
76
+ # Multiplies a row by coefficient into other row
77
+ # @param [Integer] src Row to multiply
78
+ # @param [Numeric] cof Coefficient to multiply with
79
+ # @param [Numeric] dst Row to write the results of multiplication
80
+ # @raise [KXI::Exceptions::OutOfRangeException] When one of arguments is out of range
81
+ # @return [Matrix] New matrix with multiplied row
82
+ def row_mult!(src, cof, dst = nil)
83
+ dst = src if dst == nil
84
+ raise(KXI::Exceptions::OutOfRangeException.new(src, 0, @rows - 1)) if src < 0 or src >= @rows
85
+ raise(KXI::Exceptions::OutOfRangeException.new(dst, 0, @rows - 1)) if dst < 0 or dst >= @rows
86
+ return KXI::Math::Matrix.new(@cols, @rows) do |c, r|
87
+ next cof * get(c, src) if r == dst
88
+ get(c, r)
89
+ end
90
+ end
91
+
92
+ # Multiplies a row of matrix with specific coefficient
93
+ # @overload row_mult(src, cof)
94
+ # Multiplies a row by coefficient and adds that to the row
95
+ # @param [Integer] src Row to multiply
96
+ # @param [Numeric] cof Coefficient to multiply with
97
+ # @raise [KXI::Exceptions::OutOfRangeException] When one of arguments is out of range
98
+ # @return [Matrix] New matrix with multiplied row
99
+ # @overload row_mult(src, cof, dst)
100
+ # Multiplies a row by coefficient and adds that to other row
101
+ # @param [Integer] src Row to multiply
102
+ # @param [Numeric] cof Coefficient to multiply with
103
+ # @param [Numeric] dst Row to write the results of multiplication
104
+ # @raise [KXI::Exceptions::OutOfRangeException] When one of arguments is out of range
105
+ # @return [Matrix] New matrix with multiplied row
106
+ def row_mult(src, cof, dst = nil)
107
+ dst = src if dst == nil
108
+ return KXI::Math::Matrix.new(@cols, @rows) do |c, r|
109
+ next get(c, r) + cof * get(c, src) if r == dst
110
+ get(c, r)
111
+ end
112
+ end
113
+
114
+ def sign(col, row)
115
+ return ((col % 2 == 0) == (row % 2 == 0)) ? 1 : -1
116
+ end
117
+
118
+ # Computes the determinant of matrix
119
+ # @return [Numeric] Determinant of matrix
120
+ def determinant
121
+ return get(0, 0) * get(1, 1) - get(1, 0) * get(0, 1) if @cols == 2
122
+ ci = 0
123
+ cz = 0
124
+ @cols.times do |col|
125
+ zeros = 0
126
+ @rows.times { |row| zeros += 1 if get(col, row) == 0 }
127
+ if zeros > cz
128
+ ci = col
129
+ cz = zeros
130
+ end
131
+ end
132
+ ret = 0
133
+ @rows.times do |row|
134
+ if get(ci, row) != 0
135
+ ret += sign(ci, row) * get(ci, row) * sub(ci, row).determinant
136
+ end
137
+ end
138
+ return ret
139
+ end
140
+
141
+ # Computes the inverse of matrix
142
+ # @return [KXI::Math::Matrix] Inverse matrix
143
+ def inverse
144
+ return (KXI::Math::Matrix.new(@cols, @rows) { |c, r| sign(c, r) * sub(c, r).determinant }).transpose * (1 / determinant)
145
+ end
146
+
147
+ def sub(col, row)
148
+ return KXI::Math::Matrix.new(@cols - 1, @rows - 1) do |c, r|
149
+ c = c + 1 if c >= col
150
+ r = r + 1 if r >= row
151
+ next get(c, r)
152
+ end
153
+ end
154
+
155
+ # Gets the value of matrix at given column and row
156
+ # @param [Integer] col Column to get
157
+ # @param [Integer] row Row to get
158
+ # @raise [KXI::Exceptions::OutOfRangeException] When one of arguments is out of range
159
+ # @return [Numeric] Value of matrix at given column and row
160
+ def get(col, row)
161
+ raise(KXI::Exceptions::OutOfRangeException.new(col, 0, @cols - 1)) if col < 0 or col >= @cols
162
+ raise(KXI::Exceptions::OutOfRangeException.new(row, 0, @rows - 1)) if row < 0 or row >= @rows
163
+ return @data[col][row]
164
+ end
165
+
166
+ # Sets the value of vector at specific dimension
167
+ # @overload set(col, row, val)
168
+ # Sets the value of vector at specific dimension
169
+ # @param [Integer] col Column to set
170
+ # @param [Integer] row Row to set
171
+ # @param [Integer] val Value to set the matrix to
172
+ # @raise [KXI::Exceptions::OutOfRangeException] When one of arguments is out of range
173
+ # @raise [KXI::Exceptions::InvalidTypeException] When value has invalid type
174
+ # @return [Numeric] Value passed to function
175
+ # @overload set(col, row, val)
176
+ # Sets the values of vector to range of values starting from specific dimension
177
+ # @param [Integer] col Column to set
178
+ # @param [Integer] row Row to set
179
+ # @param [Array] val Values to set the matrix to
180
+ # @raise [KXI::Exceptions::OutOfRangeException] When one of arguments is out of range
181
+ # @raise [KXI::Exceptions::InvalidTypeException] When value has invalid type
182
+ # @return [Numeric] Value passed to function
183
+ def set(col, row, value)
184
+ raise(KXI::Exceptions::OutOfRangeException.new(col, 0, @cols - 1)) if col < 0 or col >= @cols
185
+ raise(KXI::Exceptions::OutOfRangeException.new(row, 0, @rows - 1)) if row < 0 or row >= @rows
186
+ if value.is_a?(Array)
187
+ i = 0
188
+ while i + col < @cols and i < value.length
189
+ j = 0
190
+ while j + row < @rows and j < value[i].length
191
+ @data[col + i][row + j] = value[i][j].to_f
192
+ j += 1
193
+ end
194
+ i += 1
195
+ end
196
+ elsif value.is_a?(Numeric)
197
+ @data[col][row] = value.to_f
198
+ else
199
+ raise(KXI::Exceptions::InvalidTypeException.new(value.type, Numeric, Array))
200
+ end
201
+ return value
202
+ end
203
+
204
+ # Iterates over each element of matrix
205
+ # @yield [col, row, val] Iterator function
206
+ # @yieldparam [Integer] col Column passed to iterator
207
+ # @yieldparam [Integer] row Row passed to iterator
208
+ # @yieldparam [Numeric] val Value of matrix at given column and row
209
+ def each
210
+ @cols.times do |col|
211
+ @rows.times do |row|
212
+ yield(col, row, @data[col][row])
213
+ end
214
+ end
215
+ end
216
+
217
+ # Returns the transpose of matrix
218
+ # @return [KXI::Math::Matrix] Transposed matrix
219
+ def transpose
220
+ ret = KXI::Math::Matrix.new(@rows, @cols)
221
+ each do |col, row, value|
222
+ ret.set(row, col, value)
223
+ end
224
+ return ret
225
+ end
226
+
227
+ # Multiplies matrix
228
+ # @overload *(other)
229
+ # Scales matrix
230
+ # @param [Numeric] other Scalar to multiply with
231
+ # @raise [KXI::Exceptions::InvalidTypeException] When value is of invalid type
232
+ # @return [KXI::Math::Matrix] Scaled matrix
233
+ # @overload *(other)
234
+ # Multiplies matrix by another matrix
235
+ # @param [KXI::Math::Matrix] other Right-side matrix to multiply with
236
+ # @raise [KXI::Exceptions::InvalidTypeException] When value is of invalid type
237
+ # @return [KXI::Math::Matrix] Multiplied matrix
238
+ # @overload *(other)
239
+ # Multiplies matrix by vector
240
+ # @param [KXI::Math::Vector] other Vector to multiply with
241
+ # @raise [KXI::Exceptions::InvalidTypeException] When value is of invalid type
242
+ # @return [KXI::Math::Vector] Result of multiplication
243
+ def *(other)
244
+ if other.is_a?(Numeric)
245
+ return KXI::Math::Matrix.new(@cols, @rows) { |c, r| other * get(c, r) }
246
+ elsif other.is_a?(KXI::Math::Matrix)
247
+ return KXI::Math::Matrix.new(other.columns, @rows) do |c, r|
248
+ sum = 0
249
+ @cols.times { |i| sum += get(i, r) * other.get(c, i) }
250
+ next sum
251
+ end
252
+ elsif other.is_a?(KXI::Math::Vector)
253
+ return KXI::Math::Vector.new(@rows) do |d|
254
+ sum = 0
255
+ @cols.times { |c| sum += get(c, d) * other[c] }
256
+ next sum
257
+ end
258
+ else
259
+ raise(KXI::Exceptions::InvalidTypeException.new(other.class, Numeric, KXI::Math::Matrix, KXI::Math::Vector))
260
+ end
261
+ end
262
+
263
+ # Compares matrix
264
+ # @param [void] other Value to compare to
265
+ # @return [Boolean] True if matrix is equivalent to given value; false otherwise
266
+ def ==(other)
267
+ return false unless other.is_a?(KXI::Math::Matrix)
268
+ return false if @cols != other.columns or @row != other.rows
269
+ @cols.times do |col|
270
+ @rows.times do |row|
271
+ return false if get(col, row) != other.get(col, row)
272
+ end
273
+ end
274
+ end
275
+
276
+ def str(num)
277
+ return (num == num.to_i ? num.to_i : num).to_s
278
+ end
279
+
280
+ # Converts matrix to string
281
+ # @param [Boolean] d Determines whether string should be decorated
282
+ # @return [String] String representation of matrix
283
+ def to_s(d = true)
284
+ ret = ''
285
+ just = [0] * @cols
286
+ each { |c, r, v| d = str(v).length; just[c] = d if d > just[c] }
287
+ @rows.times do |row|
288
+ ret += $/ unless row == 0
289
+ ret += '|' if d
290
+ @cols.times do |col|
291
+ ret += ' ' unless col == 0
292
+ ret += str(get(col, row)).rjust(just[col], ' ')
293
+ end
294
+ ret += '|' if d
295
+ end
296
+
297
+ return ret
298
+ end
299
+
300
+ private :sign, :sub, :str
301
+ end
302
+ end
303
+ end
@@ -1,102 +1,142 @@
1
- # Created by Matyáš Pokorný on 2018-01-26.
2
-
3
- module KXI
4
- module Math
5
- class Polynomial
6
- def degree
7
- @cfs.length - 1
8
- end
9
-
10
- def coefficients
11
- @cfs
12
- end
13
-
14
- def initialize(*cfs)
15
- cfs.shift while cfs[0] == 0
16
- @cfs = cfs.collect { |i| i.to_f }
17
- end
18
-
19
- def to_s
20
- ret = nil
21
- foreach do |k, d|
22
- if d > 0
23
- if k != 0
24
- if ret == nil
25
- ret = k >= 0 ? '' : '-'
26
- else
27
- ret += k >= 0 ? ' + ' : ' - '
28
- end
29
- ret += (k >= 0 ? k : -k).to_s if k != 1 and k != -1
30
- ret += "x#{d > 1 ? "^#{d.to_s}" : ''}"
31
- end
32
- else
33
- if ret == nil
34
- ret = k >= 0 ? '' : '-'
35
- else
36
- ret += k >= 0 ? ' + ' : ' - '
37
- end
38
- ret += (k >= 0 ? k : -k).to_s
39
- end
40
- end
41
- return ret
42
- end
43
-
44
- def derivative
45
- cfs = []
46
- foreach do |k, d|
47
- if d > 0
48
- cfs.push(k * d)
49
- end
50
- end
51
- return Polynomial.new(*cfs)
52
- end
53
-
54
- def integral
55
- cfs = []
56
- foreach do |k, d|
57
- cfs.push(k / (d + 1))
58
- end
59
- cfs.push(0)
60
- return Polynomial.new(*cfs)
61
- end
62
-
63
- def integrate(x1, x2)
64
- min = x1 > x2 ? x2 : x1
65
- max = x1 > x2 ? x1 : x2
66
- i = integral
67
- return i.at(max) - i.at(min)
68
- end
69
-
70
- def at(x)
71
- sum = 0
72
- foreach do |k, d|
73
- sum += k * (x ** d)
74
- end
75
- return sum
76
- end
77
-
78
- def foreach
79
- d = degree
80
- @cfs.each do |k|
81
- yield(k, d)
82
- d -= 1
83
- end
84
- end
85
-
86
- def *(other)
87
- if other.is_a?(Polynomial)
88
- cfs = [0] * (degree + other.degree)
89
- foreach do |k1, d1|
90
- other.foreach do |k2, d2|
91
- cfs[d1 + d2] += k1 * k2
92
- end
93
- end
94
- return Polynomial.new(*cfs)
95
- elsif other.is_a?(Numeric)
96
- return @cfs.collect { |k| k * other }
97
- end
98
- raise(Exception.new('Polynomial multiplication error!'))
99
- end
100
- end
101
- end
1
+ # Created by Matyáš Pokorný on 2018-01-26.
2
+
3
+ module KXI
4
+ module Math
5
+ # Represents a polynomial
6
+ class Polynomial
7
+ # Returns the degree of polynomial
8
+ # @return [Integer] Degree of polynomial
9
+ def degree
10
+ @cfs.length - 1
11
+ end
12
+
13
+ # Returns the coefficients of polynomial
14
+ # @return [Array<Numeric>] Coefficients of polynomial
15
+ def coefficients
16
+ @cfs
17
+ end
18
+
19
+ # Instantiates the {KXI::Math::Polynomial} class
20
+ # @param [Numeric] cfs Coefficients of polynomial
21
+ def initialize(*cfs)
22
+ cfs.shift while cfs.length > 1 and cfs[0] == 0
23
+ @cfs = cfs.collect do |i|
24
+ raise(KXI::Exceptions::InvalidTypeException.new(i.class, Numeric)) unless i.is_a?(Numeric)
25
+ i.to_f
26
+ end
27
+ end
28
+
29
+ # Converts polynomial to string
30
+ # @return [String] String equivalent to polynomial
31
+ def to_s
32
+ return (@cfs[0] == @cfs[0].to_i ? @cfs[0].to_i : @cfs[0]) if degree == 0
33
+ ret = nil
34
+ foreach do |k, d|
35
+ if k != 0
36
+ k = k.to_i if k.to_i == k
37
+ if d > 0
38
+ if ret == nil
39
+ ret = k >= 0 ? '' : '-'
40
+ else
41
+ ret += k >= 0 ? ' + ' : ' - '
42
+ end
43
+ ret += (k >= 0 ? k : -k).to_s if k != 1 and k != -1
44
+ ret += "x#{d > 1 ? "^#{d.to_s}" : ''}"
45
+ else
46
+ if ret == nil
47
+ ret = k >= 0 ? '' : '-'
48
+ else
49
+ ret += k >= 0 ? ' + ' : ' - '
50
+ end
51
+ ret += (k >= 0 ? k : -k).to_s
52
+ end
53
+ end
54
+ end
55
+ return ret
56
+ end
57
+
58
+ # Takes the derivative of polynomial
59
+ # @param [Integer] n Order of derivation
60
+ # @return [KXI::Math::Polynomial] Polynomial that represents the n-th derivative
61
+ def derivative(n = 1)
62
+ return Polynomial.new(0) if degree <= n
63
+ cfs = []
64
+ foreach do |k, d|
65
+ if d >= n
66
+ cfs.push(k * KXI::Math.pfact(d, d - n))
67
+ end
68
+ end
69
+ return Polynomial.new(*cfs)
70
+ end
71
+
72
+ # Takes the integral of polynomial
73
+ # @return [KXI::Math::Polynomial] Polynomial that represents the integral
74
+ def integral
75
+ cfs = []
76
+ foreach do |k, d|
77
+ cfs.push(k / (d + 1))
78
+ end
79
+ cfs.push(0)
80
+ return Polynomial.new(*cfs)
81
+ end
82
+
83
+ # Integrates the polynomial
84
+ # @param [Numeric] x1 First bound of integration
85
+ # @param [Numeric] x2 Second bound of integration
86
+ # @return [Numeric] Result of integration
87
+ def integrate(x1, x2)
88
+ min = x1 > x2 ? x2 : x1
89
+ max = x1 > x2 ? x1 : x2
90
+ i = integral
91
+ return i.at(max) - i.at(min)
92
+ end
93
+
94
+ # Returns the value of polynomial
95
+ # @param [Numeric] x Value of x
96
+ # @return [Numeric] Value of polynomial at x
97
+ def at(x)
98
+ sum = 0
99
+ foreach do |k, d|
100
+ sum += k * (x ** d)
101
+ end
102
+ return sum
103
+ end
104
+
105
+ # Iterates over every coefficient of polynomial (from higher powers to lower powers)
106
+ # @yield [k] Iterator
107
+ # @yieldparam [Numeric] k Coefficient of polynomial
108
+ def foreach
109
+ d = degree
110
+ @cfs.each do |k|
111
+ yield(k, d)
112
+ d -= 1
113
+ end
114
+ end
115
+
116
+ # Multiplies polynomial
117
+ # @overload *(other)
118
+ # Multiplies polynomial with coefficient
119
+ # @param [Numeric] other Coefficient to multiply with
120
+ # @return [KXI::Math::Polynomial] Result of multiplication
121
+ # @overload *(other)
122
+ # Multiplies polynomial with other polynomial
123
+ # @param [KXI::Math::Polynomial] other Polynomial to multiply with
124
+ # @return [KXI::Math::Polynomial] Result of multiplication
125
+ def *(other)
126
+ if other.is_a?(Polynomial)
127
+ cfs = [0] * (degree + other.degree + 1)
128
+ foreach do |k1, d1|
129
+ other.foreach do |k2, d2|
130
+ cfs[d1 + d2] += k1 * k2
131
+ end
132
+ end
133
+ return Polynomial.new(*cfs)
134
+ elsif other.is_a?(Numeric)
135
+ return @cfs.collect { |k| k * other }
136
+ else
137
+ raise(KXI::Exceptions::InvalidTypeException.new(other.class, Numeric, KXI::Math::Polynomial))
138
+ end
139
+ end
140
+ end
141
+ end
102
142
  end