linmeric 0.1.0 → 0.2.0
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/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +51 -0
- data/Rakefile +10 -0
- data/bin/help/Help.rb +184 -0
- data/bin/help/Help_inst.rb +244 -0
- data/bin/linguide +23 -0
- data/bin/linmeric +36 -70
- data/doc/Archive.html +352 -0
- data/doc/Calculator/Evaluator.html +477 -0
- data/doc/Calculator/Lexer.html +186 -0
- data/doc/Calculator/Token.html +257 -0
- data/doc/Calculator.html +181 -0
- data/doc/Dim.html +257 -0
- data/doc/Filename.html +246 -0
- data/doc/Fixnum.html +253 -0
- data/doc/Float.html +253 -0
- data/doc/Function.html +784 -0
- data/doc/InputError.html +102 -0
- data/doc/Instructions_en.txt +6 -7
- data/doc/Instructions_it.txt +6 -9
- data/doc/Integrators.html +436 -0
- data/doc/LU.html +435 -0
- data/doc/Lexer.html +261 -0
- data/doc/Linmeric.html +109 -0
- data/doc/Listener.html +605 -0
- data/doc/Matrix.html +1719 -0
- data/doc/MyArgError.html +102 -0
- data/doc/NilClass.html +202 -0
- data/doc/Numeric.html +251 -0
- data/doc/Parser.html +389 -0
- data/doc/PrintError.html +622 -0
- data/doc/README_md.html +142 -0
- data/doc/Scp.html +530 -0
- data/doc/Sizer.html +652 -0
- data/doc/String.html +540 -0
- data/doc/Token.html +341 -0
- data/doc/Tool.html +394 -0
- data/doc/created.rid +18 -0
- data/doc/css/fonts.css +167 -0
- data/doc/css/rdoc.css +590 -0
- data/doc/fonts/Lato-Light.ttf +0 -0
- data/doc/fonts/Lato-LightItalic.ttf +0 -0
- data/doc/fonts/Lato-Regular.ttf +0 -0
- data/doc/fonts/Lato-RegularItalic.ttf +0 -0
- data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
- data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
- data/doc/images/add.png +0 -0
- data/doc/images/arrow_up.png +0 -0
- data/doc/images/brick.png +0 -0
- data/doc/images/brick_link.png +0 -0
- data/doc/images/bug.png +0 -0
- data/doc/images/bullet_black.png +0 -0
- data/doc/images/bullet_toggle_minus.png +0 -0
- data/doc/images/bullet_toggle_plus.png +0 -0
- data/doc/images/date.png +0 -0
- data/doc/images/delete.png +0 -0
- data/doc/images/find.png +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/macFFBgHack.png +0 -0
- data/doc/images/package.png +0 -0
- data/doc/images/page_green.png +0 -0
- data/doc/images/page_white_text.png +0 -0
- data/doc/images/page_white_width.png +0 -0
- data/doc/images/plugin.png +0 -0
- data/doc/images/ruby.png +0 -0
- data/doc/images/tag_blue.png +0 -0
- data/doc/images/tag_green.png +0 -0
- data/doc/images/transparent.png +0 -0
- data/doc/images/wrench.png +0 -0
- data/doc/images/wrench_orange.png +0 -0
- data/doc/images/zoom.png +0 -0
- data/doc/index.html +190 -0
- data/doc/js/darkfish.js +161 -0
- data/doc/js/jquery.js +9404 -0
- data/doc/js/navigation.js +142 -0
- data/doc/js/navigation.js.gz +0 -0
- data/doc/js/search.js +109 -0
- data/doc/js/search_index.js +1 -0
- data/doc/js/search_index.js.gz +0 -0
- data/doc/js/searcher.js +228 -0
- data/doc/js/searcher.js.gz +0 -0
- data/doc/table_of_contents.html +834 -0
- data/lib/linmeric/Archive.rb +22 -1
- data/lib/linmeric/Calculator.rb +252 -0
- data/lib/linmeric/CnGal_Matrix_class.rb +130 -49
- data/lib/linmeric/CnGal_new_classes.rb +139 -37
- data/lib/linmeric/CnGal_tools.rb +23 -40
- data/lib/linmeric/Error_print.rb +35 -1
- data/lib/linmeric/Function_class.rb +70 -11
- data/lib/linmeric/Integrators.rb +81 -35
- data/lib/linmeric/LU.rb +26 -5
- data/lib/linmeric/Lexer.rb +19 -1
- data/lib/linmeric/Listener.rb +25 -5
- data/lib/linmeric/Parser.rb +23 -1
- data/lib/linmeric/Scopify.rb +52 -31
- data/lib/linmeric/Sizer.rb +43 -10
- data/lib/linmeric/Token.rb +23 -4
- data/lib/linmeric/version.rb +3 -0
- data/lib/linmeric.rb +10 -8
- data/lib/linmeric_bin.rb +12 -0
- metadata +126 -22
- data/doc/Instructions_en.html +0 -231
- data/doc/Instructions_it.html +0 -231
- data/doc/README_en.html +0 -177
- data/doc/README_en.txt +0 -30
- data/doc/README_it.html +0 -187
- data/doc/README_it.txt +0 -32
data/lib/linmeric/Archive.rb
CHANGED
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
#! /usr/bin/env ruby
|
|
2
2
|
|
|
3
|
+
##
|
|
4
|
+
# This class provides a useful object to store the command history
|
|
5
|
+
# of linmeric
|
|
6
|
+
#
|
|
7
|
+
#
|
|
8
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
9
|
+
# License:: Distributed under MIT license
|
|
3
10
|
class Archive
|
|
11
|
+
# Creates a new Archive objects
|
|
4
12
|
def initialize
|
|
5
13
|
@myArray = []
|
|
6
14
|
@i = 0
|
|
7
15
|
end
|
|
8
16
|
|
|
17
|
+
# Adds a new item to the archive (it keeps the last 20 items
|
|
18
|
+
# which have been inserted).
|
|
19
|
+
#
|
|
20
|
+
# * **argument**: item to be added (mainly a String)
|
|
9
21
|
def store(str)
|
|
10
22
|
if @myArray.size == 20
|
|
11
23
|
@myArray = @myArray[1...@myArray.size] + [str]
|
|
12
|
-
@i = @myArray.size
|
|
24
|
+
# @i = @myArray.size
|
|
13
25
|
else
|
|
14
26
|
@myArray[@myArray.size] = str
|
|
15
27
|
@i = @myArray.size
|
|
16
28
|
end
|
|
17
29
|
end
|
|
18
30
|
|
|
31
|
+
# Returns the previous item compared to the pointer position
|
|
32
|
+
#
|
|
33
|
+
# * **returns**: saved object; "" if the pointer is already at the
|
|
34
|
+
# beginning of the archive
|
|
19
35
|
def previous
|
|
20
36
|
if not @i == 0 then
|
|
21
37
|
@i -= 1
|
|
@@ -28,6 +44,10 @@ class Archive
|
|
|
28
44
|
return ""
|
|
29
45
|
end
|
|
30
46
|
|
|
47
|
+
# Returns the next item compared to the pointer position
|
|
48
|
+
#
|
|
49
|
+
# * **returns**: saved object; "" if the pointer is already at the
|
|
50
|
+
# end of the Archive
|
|
31
51
|
def next_
|
|
32
52
|
if @i < (@myArray.size - 1)
|
|
33
53
|
@i += 1
|
|
@@ -40,6 +60,7 @@ class Archive
|
|
|
40
60
|
return ""
|
|
41
61
|
end
|
|
42
62
|
|
|
63
|
+
# Moves the pointer to the top of the archive (the last element inserted)
|
|
43
64
|
def top
|
|
44
65
|
@i = @myArray.size
|
|
45
66
|
end
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require_relative "CnGal_new_classes.rb"
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This file contains a simple expression evaluator
|
|
7
|
+
# to convert math binary operations in a result.
|
|
8
|
+
# It is simply a calculator
|
|
9
|
+
#
|
|
10
|
+
#
|
|
11
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
12
|
+
# License:: Distributed under MIT license
|
|
13
|
+
module Calculator
|
|
14
|
+
|
|
15
|
+
OP = ["+","-","*","/","^"]
|
|
16
|
+
##
|
|
17
|
+
# Definition of a simple token with an attribute (@tag)
|
|
18
|
+
# and a value (@val)
|
|
19
|
+
#
|
|
20
|
+
#
|
|
21
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
22
|
+
# License:: Distributed under MIT license
|
|
23
|
+
class Token
|
|
24
|
+
# * **argument**: value to tokenize (String)
|
|
25
|
+
def initialize(value)
|
|
26
|
+
@val = value
|
|
27
|
+
if OP.include? value then
|
|
28
|
+
@tag = :OPERATOR
|
|
29
|
+
elsif value.number? then
|
|
30
|
+
@tag = :NUMBER
|
|
31
|
+
@val = value.to_n
|
|
32
|
+
elsif value == "(" then
|
|
33
|
+
@tag = :L_PAR
|
|
34
|
+
elsif value == ")" then
|
|
35
|
+
@tag = :R_PAR
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# * **returns**: value of the token
|
|
40
|
+
def value
|
|
41
|
+
return @val
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# * **returns**: tag of the token
|
|
45
|
+
def tag
|
|
46
|
+
return @tag
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
##
|
|
51
|
+
# This lexser creates the tokens splitting the input string
|
|
52
|
+
# according to the operators (OP => see Calculator ) or brackets
|
|
53
|
+
# it returns nil if an unaccepted char (non-number or non-OP or non-bracket)
|
|
54
|
+
# is found
|
|
55
|
+
#
|
|
56
|
+
#
|
|
57
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
58
|
+
# License:: Distributed under MIT license
|
|
59
|
+
class Lexer
|
|
60
|
+
|
|
61
|
+
# It creates the tokens according to `OP` or '(' and ')'
|
|
62
|
+
#
|
|
63
|
+
# * **argument**: the string that needs to be tokenized
|
|
64
|
+
# * **returns**: array of tokens if all the chars are correct; +nil+ else
|
|
65
|
+
def tokenize(string)
|
|
66
|
+
stream = []
|
|
67
|
+
temp = ""
|
|
68
|
+
for i in 0...string.size
|
|
69
|
+
if OP.include? string[i] or ["(",")"].include? string[i] then
|
|
70
|
+
stream << Token.new(temp) unless temp == ""
|
|
71
|
+
stream << Token.new(string[i])
|
|
72
|
+
temp = ""
|
|
73
|
+
elsif string[i].number? then
|
|
74
|
+
temp += string[i]
|
|
75
|
+
else
|
|
76
|
+
return nil
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
stream << Token.new(temp) unless temp == ""
|
|
80
|
+
return stream
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
##
|
|
85
|
+
# Evaluator parses and evaluates at the same time the stream of tokens
|
|
86
|
+
#
|
|
87
|
+
#
|
|
88
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
89
|
+
# License:: Distributed under MIT license
|
|
90
|
+
class Evaluator
|
|
91
|
+
OPERATORS = {
|
|
92
|
+
"+" => lambda do |a,b|
|
|
93
|
+
return (a || 0) + (b || 0)
|
|
94
|
+
end,
|
|
95
|
+
"-" => lambda do |a,b|
|
|
96
|
+
return (a || 0) - (b || 0)
|
|
97
|
+
end,
|
|
98
|
+
"*" => lambda do |a,b|
|
|
99
|
+
return a * b
|
|
100
|
+
end,
|
|
101
|
+
"/" => lambda do |a,b|
|
|
102
|
+
unless b != 0
|
|
103
|
+
@error = true
|
|
104
|
+
return nil
|
|
105
|
+
end
|
|
106
|
+
return a / b.to_f
|
|
107
|
+
end,
|
|
108
|
+
"^" => lambda do |a,b|
|
|
109
|
+
unless a != 0 and b != 0
|
|
110
|
+
@error = true
|
|
111
|
+
return nil
|
|
112
|
+
end
|
|
113
|
+
return a ** b
|
|
114
|
+
end
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# Evaluates the global expression
|
|
118
|
+
#
|
|
119
|
+
# * **argument**: stream of tokens (Array)
|
|
120
|
+
# * **returns**: result of the operations; +nil+ if an error occourred
|
|
121
|
+
def evaluate(stream)
|
|
122
|
+
@stack = []
|
|
123
|
+
@stream = stream
|
|
124
|
+
@i = 0
|
|
125
|
+
@error = false
|
|
126
|
+
return parse
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# It parses the stream of tokens
|
|
130
|
+
#
|
|
131
|
+
# * **argument**: specific end-token (+nil+ default)
|
|
132
|
+
# * **returns**: result of the operations; +nil+ if an error occourred
|
|
133
|
+
def parse(m_end = nil)
|
|
134
|
+
@num = []
|
|
135
|
+
@op = []
|
|
136
|
+
st = state0_1(0)
|
|
137
|
+
return nil if @error
|
|
138
|
+
@i += 1
|
|
139
|
+
while @i < @stream.size and current_tk.value != m_end do
|
|
140
|
+
st = self.send(st)
|
|
141
|
+
return nil if @error
|
|
142
|
+
@i += 1
|
|
143
|
+
end
|
|
144
|
+
return nil if st == :state_0_1
|
|
145
|
+
make_op
|
|
146
|
+
return @num.pop
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# State0_1 accepts only numbers or '('
|
|
150
|
+
#
|
|
151
|
+
# * **argument**: specification of which state must be runned (1 default)
|
|
152
|
+
# * **returns**: next state (symbol)
|
|
153
|
+
def state0_1(state = 1)
|
|
154
|
+
case current_tk.tag
|
|
155
|
+
when :NUMBER
|
|
156
|
+
@num.push current_tk.value
|
|
157
|
+
when :L_PAR
|
|
158
|
+
@i += 1
|
|
159
|
+
@stack.push @op
|
|
160
|
+
@stack.push @num
|
|
161
|
+
res = parse(")")
|
|
162
|
+
@num = @stack.pop
|
|
163
|
+
@num << res
|
|
164
|
+
@op = @stack.pop
|
|
165
|
+
when :OPERATOR
|
|
166
|
+
if (["+","-"].include? current_tk.value) and (state)== 0 then
|
|
167
|
+
@op.push current_tk.value
|
|
168
|
+
return :state0_1
|
|
169
|
+
else
|
|
170
|
+
@error = true
|
|
171
|
+
end
|
|
172
|
+
else
|
|
173
|
+
@error = true
|
|
174
|
+
end
|
|
175
|
+
return :state2
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# State2 accepts only operators
|
|
179
|
+
#
|
|
180
|
+
# * **returns**: next state (symbol)
|
|
181
|
+
def state2
|
|
182
|
+
if current_tk.tag == :OPERATOR then
|
|
183
|
+
if @op.size == 0 then
|
|
184
|
+
@op.push current_tk.value
|
|
185
|
+
elsif priority(current_tk.value) >= priority(@op.last)
|
|
186
|
+
@op.push current_tk.value
|
|
187
|
+
elsif priority(current_tk.value) < priority(@op.last)
|
|
188
|
+
make_op
|
|
189
|
+
@op.push current_tk.value
|
|
190
|
+
end
|
|
191
|
+
else
|
|
192
|
+
@error = true
|
|
193
|
+
end
|
|
194
|
+
return :state0_1
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Solves the operations saved in @op
|
|
198
|
+
def make_op
|
|
199
|
+
while @op.size > 0 and !@error do
|
|
200
|
+
b = @num.pop
|
|
201
|
+
a = @num.pop
|
|
202
|
+
op = @op.pop
|
|
203
|
+
@num.push OPERATORS[op][a,b]
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# * **returns**: token of the current pointer value
|
|
208
|
+
def current_tk
|
|
209
|
+
return @stream[@i]
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Returns the operator priority
|
|
213
|
+
#
|
|
214
|
+
# * **argument**: operator (string)
|
|
215
|
+
# * **returns**: priority (fixnum)
|
|
216
|
+
def priority(op)
|
|
217
|
+
case op
|
|
218
|
+
when "+","-"
|
|
219
|
+
return 1
|
|
220
|
+
when "*","/"
|
|
221
|
+
return 2
|
|
222
|
+
when /\^/
|
|
223
|
+
return 3
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# It solves the expression in string format
|
|
229
|
+
#
|
|
230
|
+
# * **argument**: expression to evaluate
|
|
231
|
+
# * **returns**: result of the expression; +nil+ if an error occourred
|
|
232
|
+
def self.solve(exp)
|
|
233
|
+
lexer = Lexer.new
|
|
234
|
+
evaluator = Evaluator.new
|
|
235
|
+
stream = lexer.tokenize(exp)
|
|
236
|
+
return nil if stream == nil
|
|
237
|
+
return evaluator.evaluate(stream)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
#! /usr/bin/env ruby
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
require_relative 'CnGal_new_classes.rb'
|
|
4
|
-
require_relative 'CnGal_tools.rb'
|
|
5
5
|
require_relative 'Listener.rb'
|
|
6
|
-
|
|
7
|
-
#
|
|
6
|
+
require_relative 'Calculator.rb'
|
|
8
7
|
|
|
9
8
|
class InputError < ArgumentError; end
|
|
10
9
|
class MyArgError < RuntimeError; end
|
|
11
10
|
|
|
11
|
+
##
|
|
12
|
+
# This class provides a simple representation of a matrix with the main
|
|
13
|
+
# features, operations and some useful method to manipulate it or to make
|
|
14
|
+
# its creation easier.
|
|
15
|
+
#
|
|
16
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
17
|
+
# License:: Distributed under MIT license
|
|
12
18
|
class Matrix
|
|
13
19
|
|
|
20
|
+
# Initialization of new matrix in two different ways (chosen by
|
|
21
|
+
# the user):
|
|
22
|
+
# * a block can be given to create a matrix according to a function
|
|
23
|
+
# * the user must insert each value by hand (if block is not given)
|
|
24
|
+
#
|
|
25
|
+
# * **requires**: `#solve` of Calculator
|
|
26
|
+
# * **argument**: number of rows (Fixnum)
|
|
27
|
+
# * **argument**: number of columns (Fixnum)
|
|
28
|
+
# * **block**: yields a function with two arguments (optional)
|
|
14
29
|
def initialize(rws = 0,cls = 0)
|
|
15
30
|
listener = Listener.new
|
|
16
|
-
# @exception = "Matrix "
|
|
17
31
|
if rws == 0 or cls == 0 or rws.is_a? Float or cls.is_a? Float then
|
|
18
32
|
raise MyArgError," Argument Error: invalid dimension #{rws}x#{cls} for Matrix object"
|
|
19
33
|
elsif !(rws.is_a? Fixnum) or !(cls.is_a? Fixnum) then
|
|
@@ -31,21 +45,18 @@ class Matrix
|
|
|
31
45
|
end
|
|
32
46
|
end
|
|
33
47
|
else
|
|
34
|
-
# if @exception == "Matrix " then
|
|
35
48
|
puts "Insert the line values (separated by space) and press return to go on"
|
|
36
49
|
for i in 0...rws
|
|
37
50
|
listener.reset
|
|
38
51
|
cl = listener.gets.split
|
|
39
52
|
raise ArgumentError, " #{cls} element(s) expected but #{cl.size} found. Retry" unless cl.size==cls
|
|
40
53
|
cl.map! { |e|
|
|
41
|
-
cv =
|
|
54
|
+
cv = Calculator.solve(e)
|
|
42
55
|
err = e if cv == nil
|
|
43
56
|
raise MyArgError, " Argument Error: Invalid operation '#{err}' found in matrix rows" unless cv != nil
|
|
44
57
|
e = cv
|
|
45
58
|
}
|
|
46
59
|
@mx +=cl
|
|
47
|
-
# end
|
|
48
|
-
# puts
|
|
49
60
|
end
|
|
50
61
|
end
|
|
51
62
|
end
|
|
@@ -58,8 +69,11 @@ class Matrix
|
|
|
58
69
|
|
|
59
70
|
end
|
|
60
71
|
|
|
72
|
+
# Creates a new matrix loading it from a .csv file
|
|
73
|
+
#
|
|
74
|
+
# * **argument**: `String` of the file path
|
|
75
|
+
# * **returns**: new matrix object
|
|
61
76
|
def Matrix.from_file(filename = "")
|
|
62
|
-
# @exception = "Matrix "
|
|
63
77
|
@mx = []
|
|
64
78
|
@MyCls = 0
|
|
65
79
|
@MyRws = 0
|
|
@@ -70,7 +84,7 @@ class Matrix
|
|
|
70
84
|
@MyRws += 1
|
|
71
85
|
ln = ln.chomp.split(',')
|
|
72
86
|
ln.map! do |el|
|
|
73
|
-
cv =
|
|
87
|
+
cv = Calculator.solve(el)
|
|
74
88
|
err = el if cv == nil
|
|
75
89
|
raise InputError, " Argument Error: Invalid operation '#{err}' found in matrix rows" unless cv != nil
|
|
76
90
|
el = cv
|
|
@@ -78,23 +92,16 @@ class Matrix
|
|
|
78
92
|
@mx += ln
|
|
79
93
|
if @mx.size % ln.size != 0 then
|
|
80
94
|
raise MyArgError, " Argument Error: Irregular matrix rows"
|
|
81
|
-
# break
|
|
82
95
|
end
|
|
83
96
|
@MyCls = ln.length
|
|
84
97
|
end
|
|
85
98
|
end
|
|
86
|
-
# mat = Matrix.new(1,1) {1}
|
|
87
|
-
# mat.update(@mx,@MyRws,@MyCls)
|
|
88
|
-
# mat.inherit_exception(@exception)
|
|
89
99
|
return mat = Matrix.new(@MyRws,@MyCls) {|i,j| @mx[i*@MyCls+j]}
|
|
90
|
-
|
|
91
|
-
# rescue InputError => error
|
|
92
|
-
# @exception += "#{error}"
|
|
93
|
-
# mat = Matrix.new(1,1) {1}
|
|
94
|
-
# mat.inherit_exception(@exception)
|
|
95
|
-
# return mat
|
|
96
100
|
end
|
|
97
101
|
|
|
102
|
+
# Writes the matrix on a file
|
|
103
|
+
#
|
|
104
|
+
# * **argument**: `String` of the file path
|
|
98
105
|
def to_file(filename = "")
|
|
99
106
|
if !(Dir.exist? File.dirname(filename)) or filename == "" then
|
|
100
107
|
raise MyArgError, " Argument Error: Invalid directory; Directory not found"
|
|
@@ -110,40 +117,42 @@ class Matrix
|
|
|
110
117
|
end
|
|
111
118
|
end
|
|
112
119
|
|
|
113
|
-
#
|
|
114
|
-
|
|
115
|
-
# return @exception
|
|
116
|
-
# end
|
|
117
|
-
|
|
118
|
-
# def got_exception()
|
|
119
|
-
# @exception = "Matrix "
|
|
120
|
-
# end
|
|
121
|
-
|
|
122
|
-
def show()
|
|
120
|
+
# converts this matrix object to a string
|
|
121
|
+
def to_s()
|
|
123
122
|
max = 0
|
|
124
|
-
|
|
123
|
+
str = ""
|
|
124
|
+
@mx.each{ |n| max = "#{n.round(3)}".size if "#{n.round(3)}".size > max}
|
|
125
125
|
for i in 0...@MyRws do
|
|
126
|
-
|
|
126
|
+
str += '|'
|
|
127
127
|
for j in (i*(@MyCls))...(i*(@MyCls)+@MyCls) do
|
|
128
|
-
|
|
128
|
+
str += " #{" "*(max-@mx[j].round(3).to_s.size).abs}#{@mx[j].round(3) }"
|
|
129
129
|
end
|
|
130
|
-
|
|
130
|
+
str+= " |\n"
|
|
131
131
|
end
|
|
132
|
-
return
|
|
132
|
+
return str
|
|
133
133
|
end
|
|
134
134
|
|
|
135
|
+
# * **returns**: `Fixnum` of number of columns
|
|
135
136
|
def getCls()
|
|
136
137
|
return @MyCls
|
|
137
138
|
end
|
|
138
139
|
|
|
140
|
+
# * **returns**: `Fixnum` of number of rows
|
|
139
141
|
def getRws()
|
|
140
142
|
return @MyRws
|
|
141
143
|
end
|
|
142
144
|
|
|
145
|
+
# * **returns**: `Array` on which the matrix is saved
|
|
143
146
|
def export()
|
|
144
147
|
return @mx
|
|
145
148
|
end
|
|
146
149
|
|
|
150
|
+
# Updates this matrix after the array in which it was saved has been
|
|
151
|
+
# manually modified
|
|
152
|
+
#
|
|
153
|
+
# * **argument**: `Array` on which the new matrix is saved
|
|
154
|
+
# * **argument**: `Fixnum` of number of rows
|
|
155
|
+
# * **argument**: `Fixnum` of number of columns
|
|
147
156
|
def update(mat,rws,cls)
|
|
148
157
|
if !(mat.is_a? Array) then
|
|
149
158
|
raise MyArgError, " Argument Error: invalid matrix array found"
|
|
@@ -152,17 +161,18 @@ class Matrix
|
|
|
152
161
|
raise MyArgError, " Argument Error: colums and rows in Integer format expected but #{e.class} found" unless e.is_a? Numeric
|
|
153
162
|
end
|
|
154
163
|
end
|
|
155
|
-
# if @exception == "Matrix " then
|
|
156
164
|
@mx = mat
|
|
157
165
|
@MyRws = rws
|
|
158
166
|
@MyCls = cls
|
|
159
|
-
# end
|
|
160
167
|
end
|
|
161
|
-
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
|
|
168
|
+
|
|
169
|
+
# Gives access to each component of a matrix.
|
|
170
|
+
# It accepts two kinds of arguments: `Fixnum` or `Range`
|
|
171
|
+
# to get a specific component or a collection of components (eg. a whole row)
|
|
172
|
+
#
|
|
173
|
+
# * **argument**: `Fixnum` or `Range` of row
|
|
174
|
+
# * **argument**: `Fixnum` or `Range` of column
|
|
175
|
+
# * **returns**: `Numeric` if an only component has been required; `Matrix` else
|
|
166
176
|
def [](x,y)
|
|
167
177
|
if x.is_a? Numeric and y.is_a? Numeric then
|
|
168
178
|
return @mx[x*@MyCls + y]
|
|
@@ -190,10 +200,20 @@ class Matrix
|
|
|
190
200
|
return nil
|
|
191
201
|
end
|
|
192
202
|
|
|
203
|
+
# Allows direct overwriting of a component
|
|
204
|
+
#
|
|
205
|
+
# * **argument**: `Fixnum` of row number
|
|
206
|
+
# * **argument**: `Fixnum` of column number
|
|
207
|
+
# * **argument**: `Numeric` to overwrite the component value
|
|
193
208
|
def []=(i,j,val)
|
|
209
|
+
raise ArgumentError, " Argument Error: Numeric value expected but #{val.class} found" unless val.is_a? Numeric
|
|
194
210
|
@mx[i*@MyCls + j] = val
|
|
195
211
|
end
|
|
196
|
-
|
|
212
|
+
|
|
213
|
+
# Compares the current matrix with another object
|
|
214
|
+
#
|
|
215
|
+
# * **argument**: `Object` to be compared with
|
|
216
|
+
# * **returns**: +true+ if two equal matrix are compered; +false+ else
|
|
197
217
|
def ==(obj)
|
|
198
218
|
if obj.is_a? Matrix then
|
|
199
219
|
if (self.getCls == obj.getCls && self.getRws == obj.getRws ) then
|
|
@@ -203,6 +223,10 @@ class Matrix
|
|
|
203
223
|
return false
|
|
204
224
|
end
|
|
205
225
|
|
|
226
|
+
# Checks if this matrix is different from another object
|
|
227
|
+
#
|
|
228
|
+
# * **argument**: `Object` to be compared with
|
|
229
|
+
# * **returns**: +true+ if the matrix and the object are different; +false+ else
|
|
206
230
|
def !=(obj)
|
|
207
231
|
if obj.is_a? Matrix then
|
|
208
232
|
self == obj ? (return false) : (return true)
|
|
@@ -211,6 +235,11 @@ class Matrix
|
|
|
211
235
|
end
|
|
212
236
|
end
|
|
213
237
|
|
|
238
|
+
# Checks if this matrix and the given object have the same features
|
|
239
|
+
#
|
|
240
|
+
# * **argument**: `Object`
|
|
241
|
+
# * **returns**: +true+ if `obj` is a `Matrix` and has the same rows and colum number;
|
|
242
|
+
# +false+ else
|
|
214
243
|
def similar_to?(obj)
|
|
215
244
|
if obj.is_a? Matrix then
|
|
216
245
|
(self.getCls == obj.getCls &&
|
|
@@ -219,6 +248,10 @@ class Matrix
|
|
|
219
248
|
return false
|
|
220
249
|
end
|
|
221
250
|
|
|
251
|
+
# Sums the current matrix to another
|
|
252
|
+
#
|
|
253
|
+
# * **argument**: `Matrix` to be summed to
|
|
254
|
+
# * **returns**: `Matrix` object
|
|
222
255
|
def +(m)
|
|
223
256
|
if m.is_a? Matrix then
|
|
224
257
|
if m.similar_to? self then
|
|
@@ -231,6 +264,10 @@ class Matrix
|
|
|
231
264
|
end
|
|
232
265
|
end
|
|
233
266
|
|
|
267
|
+
# Subtracts the current matrix to another
|
|
268
|
+
#
|
|
269
|
+
# * **argument**: `Matrix` to be subtracted to
|
|
270
|
+
# * **returns**: `Matrix` object
|
|
234
271
|
def -(m)
|
|
235
272
|
if m.is_a? Matrix then
|
|
236
273
|
if m.similar_to? self then
|
|
@@ -243,6 +280,11 @@ class Matrix
|
|
|
243
280
|
end
|
|
244
281
|
end
|
|
245
282
|
|
|
283
|
+
# Checks if the given object can be multiplied to the matrix
|
|
284
|
+
#
|
|
285
|
+
# * **argument**: `Object`
|
|
286
|
+
# * **returns**: +true++ if `obj` is a `Numeric` or a good `Matrix` for '*' operation;
|
|
287
|
+
# +false+ else
|
|
246
288
|
def can_multiply?(obj)
|
|
247
289
|
if obj.is_a? Matrix then
|
|
248
290
|
(self.getCls == obj.getRws) ? (return true) : (return false)
|
|
@@ -252,6 +294,10 @@ class Matrix
|
|
|
252
294
|
return false
|
|
253
295
|
end
|
|
254
296
|
|
|
297
|
+
# Multiplies the current matrix to another
|
|
298
|
+
#
|
|
299
|
+
# * **argument**: `Matrix` to be multiplied to
|
|
300
|
+
# * **returns**: `Matrix` object
|
|
255
301
|
def *(ob)
|
|
256
302
|
case
|
|
257
303
|
when (ob.is_a? Numeric)
|
|
@@ -276,27 +322,44 @@ class Matrix
|
|
|
276
322
|
end
|
|
277
323
|
end
|
|
278
324
|
|
|
279
|
-
|
|
325
|
+
# Checks if the given object can divide the current matrix
|
|
326
|
+
#
|
|
327
|
+
# * **argument**: `Object`
|
|
328
|
+
# * **returns**: +true+ if `obj` is a Numeric; +false+ else
|
|
280
329
|
def can_divide?(obj)
|
|
281
330
|
return (obj.is_a? Numeric)
|
|
282
331
|
end
|
|
283
332
|
|
|
284
|
-
|
|
333
|
+
# Divides each element of the current matrix to a `Numeric` value
|
|
334
|
+
#
|
|
335
|
+
# * **argument**: `Numeric`
|
|
336
|
+
# * **returns**: `Matrix` object
|
|
285
337
|
def /(obj)
|
|
286
338
|
return Matrix.new(@MyRws,@MyCls) { |i,j| self[i,j] / obj.to_f} if obj.is_a? Numeric
|
|
287
339
|
raise MyArgError, " Argument Error: Invalid division between Matrix and #{obj.class} "
|
|
288
340
|
end
|
|
289
341
|
|
|
342
|
+
# Elevates each element of the current matrix to a `Numeric` exponent
|
|
343
|
+
#
|
|
344
|
+
# * **argument**: `Numeric`
|
|
345
|
+
# * **returns**: `Matrix` object
|
|
290
346
|
def **(obj)
|
|
291
347
|
return Matrix.new(@MyRws,@MyCls) { |i,j| self[i,j] ** obj} if obj.is_a? Numeric
|
|
292
348
|
raise MyArgError, " Argument Error: Invalid power Matrix-#{obj.class} "
|
|
293
349
|
end
|
|
294
350
|
|
|
351
|
+
# Trasposes a matrix
|
|
352
|
+
#
|
|
353
|
+
# **returns**: `Matrix` object
|
|
295
354
|
def tr()
|
|
296
355
|
return Matrix.new(@MyCls,@MyRws) { |i,j| @mx[j * @MyCls + i]}
|
|
297
356
|
end
|
|
298
357
|
|
|
299
|
-
|
|
358
|
+
# Calculates the norm of a matrix, defined as
|
|
359
|
+
# sqrt(sum(m[i,j]**2))
|
|
360
|
+
#
|
|
361
|
+
# * **returns**: `Float` value
|
|
362
|
+
def norm()
|
|
300
363
|
sum=0
|
|
301
364
|
@mx.map do |e|
|
|
302
365
|
sum +=e**2
|
|
@@ -304,10 +367,16 @@ class Matrix
|
|
|
304
367
|
return Math.sqrt(sum)
|
|
305
368
|
end
|
|
306
369
|
|
|
370
|
+
# Checks if the matrix is squared
|
|
371
|
+
#
|
|
372
|
+
# * **returns**: +true+ if the matrix is squared; +false+ else
|
|
307
373
|
def is_squared?()
|
|
308
374
|
self.getCls == self.getRws ? (return true) : (return false)
|
|
309
375
|
end
|
|
310
376
|
|
|
377
|
+
# Calulates the determinant of the matrix using the Laplace's algorithm
|
|
378
|
+
#
|
|
379
|
+
# * **returns**: `Numeric` value
|
|
311
380
|
def laplace
|
|
312
381
|
if self.is_squared? then
|
|
313
382
|
return (self[0,0] * self[1,1]) - (self[0,1] * self[1,0]) if self.getRws == 2
|
|
@@ -322,7 +391,12 @@ class Matrix
|
|
|
322
391
|
end
|
|
323
392
|
end
|
|
324
393
|
|
|
394
|
+
# Builds an identity matrix
|
|
395
|
+
#
|
|
396
|
+
# * **argument**: `Fixnum` of the matrix dimension
|
|
397
|
+
# * **returns**: `Matrix` object
|
|
325
398
|
def Matrix.identity(n)
|
|
399
|
+
raise MyArgError, "Argument Error: expecting Fixnum value, but #{n.class} found" unless n.is_a? Fixnum
|
|
326
400
|
return Matrix.new(n,n) { |i,j| (i == j) ? 1 : 0 }
|
|
327
401
|
end
|
|
328
402
|
|
|
@@ -331,8 +405,17 @@ class Matrix
|
|
|
331
405
|
end
|
|
332
406
|
|
|
333
407
|
private
|
|
334
|
-
|
|
408
|
+
|
|
409
|
+
# Private method to delete rows and columns from a matrix
|
|
410
|
+
#
|
|
411
|
+
# * **argument**: `Matrix`
|
|
412
|
+
# * **argument**: row number (`Fixnum`)
|
|
413
|
+
# * **argument**: column number (`Fixnum`)
|
|
414
|
+
# * **returns**: `Matrix` object
|
|
335
415
|
def del_rwcl(mx,rw,cl)
|
|
416
|
+
[rw,cl].each do |arg|
|
|
417
|
+
raise MyArgError,"Argument Error: row and column in Fixnum format expected, but #{arg.class} found" unless arg.is_a? Fixnum
|
|
418
|
+
end
|
|
336
419
|
rd = mx.export.clone
|
|
337
420
|
cols = mx.getCls
|
|
338
421
|
for i in 0...cols
|
|
@@ -344,8 +427,6 @@ class Matrix
|
|
|
344
427
|
cl = mx.getCls - 1
|
|
345
428
|
return Matrix.new(rw,cl) { |i,j| rd[i*cl+j]}
|
|
346
429
|
end
|
|
347
|
-
|
|
348
|
-
protected
|
|
349
430
|
|
|
350
431
|
|
|
351
432
|
end
|