Class: Matrix

Inherits:
Object
  • Object
show all
Defined in:
lib/linmeric/CnGal_Matrix_class.rb

Overview

License

Distributed under MIT license

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rws = 0, cls = 0) ⇒ Matrix

Initialization of new matrix in two different ways (chosen by the user):

  • a block can be given to create a matrix according to a function

  • the user must insert each value by hand (if block is not given)

  • requires: ‘#solve` of Calculator

  • argument: number of rows (Fixnum)

  • argument: number of columns (Fixnum)

  • block: yields a function with two arguments (optional)



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
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 35

def initialize(rws = 0,cls = 0)
  listener = Listener.new
  if rws == 0 or cls == 0 or rws.is_a? Float or cls.is_a? Float then 
    raise MyArgError,"   Argument Error: invalid dimension #{rws}x#{cls} for Matrix object" 
  elsif !(rws.is_a? Int) or !(cls.is_a? Int) then
        e = rws unless e.is_a? Int
        e = cls unless cls.is_a? Int
        raise MyArgError,"  Argument Error: colums and rows in Integer format expected but #{e.class} found"
  else
    @MyRws = rws; @MyCls = cls
    @mx=[]
    if block_given? then
      for i in 0...@MyRws
        for j in 0...@MyCls
          value = yield(i,j) if block_given? 
          @mx << value
        end
      end       
    else
        puts "Insert the line values (separated by space) and press return to go on"
        for i in 0...rws
          listener.reset
          cl = listener.gets.split
          raise ArgumentError, "  #{cls} element(s) expected but #{cl.size} found. Retry" unless cl.size==cls
          cl.map! { |e| 
            cv = Calculator.solve(e)
            err = e if cv == nil
            raise MyArgError, "  Argument Error: Invalid operation '#{err}' found in matrix rows" unless cv != nil
            e = cv
          }
          @mx +=cl 
      end
    end
  end
 
    
  rescue ArgumentError => message
    puts message
    @mx=[]
    retry
    
end

Class Method Details

.from_file(filename = "") ⇒ Object

Creates a new matrix loading it from a .csv file

  • argument: ‘String` of the file path

  • returns: new matrix object



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
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 82

def Matrix.from_file(filename = "")
  @mx = []
  @MyCls = 0
  @MyRws = 0
  if !(File.exists? filename) or filename == "" then
    raise MyArgError, "  Argument Error: Invalid directory or filename"
  else
    File.open(filename, "r").each_line do |ln|
      @MyRws += 1
      ln = ln.chomp.split(',')
      ln.map! do |el| 
        cv = Calculator.solve(el)
        err = el if cv == nil
        raise InputError, "  Argument Error: Invalid operation '#{err}' found in matrix rows" unless cv != nil
        el = cv
      end
      @mx += ln
      if @mx.size % ln.size != 0 then
        raise MyArgError, "  Argument Error: Irregular matrix rows"
      end
      @MyCls = ln.length
    end
  end
  return mat = Matrix.new(@MyRws,@MyCls) {|i,j| @mx[i*@MyCls+j]}
end

.identity(n) ⇒ Object

Builds an identity matrix

  • argument: ‘Fixnum` of the matrix dimension

  • returns: ‘Matrix` object

Raises:



404
405
406
407
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 404

def Matrix.identity(n)
  raise MyArgError, "Argument Error: expecting Fixnum value, but #{n.class} found" unless n.is_a? Int
  return Matrix.new(n,n) { |i,j|  (i == j) ? 1 : 0 }
end

Instance Method Details

#!=(obj) ⇒ Object

Checks if this matrix is different from another object

  • argument: ‘Object` to be compared with

  • returns: true if the matrix and the object are different; false else



236
237
238
239
240
241
242
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 236

def !=(obj)
  if obj.is_a? Matrix then
    self == obj ? (return false) : (return true)
  else
    return true
  end
end

#*(ob) ⇒ Object

Multiplies the current matrix to another

  • argument: ‘Matrix` to be multiplied to

  • returns: ‘Matrix` object



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 307

def *(ob)
  case 
    when (ob.is_a? Numeric)
      return Matrix.new(@MyRws,@MyCls){ |i,j| self[i,j] * ob}
    when (ob.is_a? Matrix)
      if self.can_multiply? ob then
        temp = []
        for i in 0...@MyRws
          for j in 0...ob.getCls()
            temp[i*@MyCls + j] = 0
            for k in 0...@MyCls
              temp[i*@MyCls + j] += @mx[i*@MyCls + k] * ob[k,j]
            end
          end
        end
        return Matrix.new(@MyRws,ob.getCls()){ |i,j| temp[i * @MyCls + j]}
      else
        raise MyArgError, "  Argument Error: Cannot multiply #{@MyRws}x#{@MyCls} Matrix with #{ob.getRws}x#{ob.getCls}"
      end
    else
      raise MyArgError, "  Argument Error: Cannot multiply Matrix with #{ob.class}"
  end
end

#**(obj) ⇒ Object

Elevates each element of the current matrix to a ‘Numeric` exponent

  • argument: ‘Numeric`

  • returns: ‘Matrix` object

Raises:



352
353
354
355
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 352

def **(obj)
  return Matrix.new(@MyRws,@MyCls) { |i,j| self[i,j] ** obj} if obj.is_a? Numeric
  raise MyArgError, "  Argument Error: Invalid power Matrix-#{obj.class} "
end

#+(m) ⇒ Object

Sums the current matrix to another

  • argument: ‘Matrix` to be summed to

  • returns: ‘Matrix` object



261
262
263
264
265
266
267
268
269
270
271
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 261

def +(m)
  if m.is_a? Matrix then
    if m.similar_to? self then
      return Matrix.new(@MyRws, @MyCls){ |i,j| self[i,j] + m[i,j]}
    else
      raise MyArgError, "  Argument Error: invalid matrix for + operation"
    end
  else
    raise MyArgError, "  Argument Error: can't sum #{m.class} to Matrix"
  end
end

#-(m) ⇒ Object

Subtracts the current matrix to another

  • argument: ‘Matrix` to be subtracted to

  • returns: ‘Matrix` object



277
278
279
280
281
282
283
284
285
286
287
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 277

def -(m)
  if m.is_a? Matrix then
    if m.similar_to? self then
      return Matrix.new(@MyRws, @MyCls){ |i,j| self[i,j] - m[i,j]}
    else
      raise MyArgError, "  Argument Error: invalid matrix for - operation"
    end
  else
    raise MyArgError, "  Argument Error: can't subtact #{m.class} to Matrix"
  end
end

#/(obj) ⇒ Object

Divides each element of the current matrix to a ‘Numeric` value

  • argument: ‘Numeric`

  • returns: ‘Matrix` object

Raises:



343
344
345
346
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 343

def /(obj)
  return Matrix.new(@MyRws,@MyCls) { |i,j| self[i,j] / obj.to_f} if obj.is_a? Numeric
  raise MyArgError, "  Argument Error: Invalid division between Matrix and #{obj.class} "
end

#==(obj) ⇒ Object

Compares the current matrix with another object

  • argument: ‘Object` to be compared with

  • returns: true if two equal matrix are compered; false else



223
224
225
226
227
228
229
230
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 223

def ==(obj)
 if obj.is_a? Matrix then
   if (self.getCls == obj.getCls && self.getRws == obj.getRws ) then
     (@mx == obj.export) ? (return true) : (return false)
   end
 end
 return false
end

#[](x, y) ⇒ Object

Gives access to each component of a matrix. It accepts two kinds of arguments: ‘Fixnum` or `Range` to get a specific component or a collection of components (eg. a whole row)

  • argument: ‘Fixnum` or `Range` of row

  • argument: ‘Fixnum` or `Range` of column

  • returns: ‘Numeric` if an only component has been required; `Matrix` else



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 182

def [](x,y)
  if x.is_a? Numeric and y.is_a? Numeric then
    return @mx[x*@MyCls + y]
  elsif x.is_a? Range and y.is_a? Numeric
    nm = []
    x.each do |i|
      nm << @mx[i*@MyCls + y]
    end
    return Matrix.new(x.count,1){|i,j| nm[i + j]}
  elsif x.is_a? Numeric and y.is_a? Range
    nm = []
    y.each do |j|
      nm << @mx[x*@MyCls + j]
    end
    return Matrix.new(1,y.count){|i,j| nm[i + j]}
  elsif x.is_a? Range and y.is_a? Range
    nm = []
    x.each do |i|
      y.each do |j|
        nm << @mx[i*@MyCls + j]
      end
    end
    return Matrix.new(x.count,y.count){ |i,j| nm[i*y.count + j]}
  end
  return nil
end

#[]=(i, j, val) ⇒ Object

Allows direct overwriting of a component

  • argument: ‘Fixnum` of row number

  • argument: ‘Fixnum` of column number

  • argument: ‘Numeric` to overwrite the component value

Raises:

  • (ArgumentError)


214
215
216
217
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 214

def []=(i,j,val)
  raise ArgumentError, "  Argument Error: Numeric value expected but #{val.class} found" unless val.is_a? Numeric
  @mx[i*@MyCls + j] = val
end

#can_divide?(obj) ⇒ Boolean

Checks if the given object can divide the current matrix

  • argument: ‘Object`

  • returns: true if ‘obj` is a Numeric; false else

Returns:

  • (Boolean)


335
336
337
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 335

def can_divide?(obj)
  return (obj.is_a? Numeric)
end

#can_multiply?(obj) ⇒ Boolean

Checks if the given object can be multiplied to the matrix

  • argument: ‘Object`

  • returns: true+ if ‘obj` is a `Numeric` or a good `Matrix` for ’*‘ operation;

false else

Returns:

  • (Boolean)


294
295
296
297
298
299
300
301
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 294

def can_multiply?(obj)
  if obj.is_a? Matrix then
    (self.getCls == obj.getRws) ? (return true) : (return false)
  elsif obj.is_a? Numeric
    return true
  end
  return false
end

#coerce(val) ⇒ Object



409
410
411
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 409

def coerce(val)
  return [self, val]
end

#exportObject

  • returns: ‘Array` on which the matrix is saved



152
153
154
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 152

def export()
  return @mx
end

#getClsObject

  • returns: ‘Fixnum` of number of columns



142
143
144
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 142

def getCls()
  return @MyCls
end

#getRwsObject

  • returns: ‘Fixnum` of number of rows



147
148
149
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 147

def getRws()
  return @MyRws
end

#is_squared?Boolean

Checks if the matrix is squared

  • returns: true if the matrix is squared; false else

Returns:

  • (Boolean)


379
380
381
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 379

def is_squared?()
  self.getCls == self.getRws ? (return true) : (return false)
end

#laplaceObject

Calulates the determinant of the matrix using the Laplace’s algorithm

  • returns: ‘Numeric` value



386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 386

def laplace
  if self.is_squared? then
    return (self[0,0] * self[1,1]) - (self[0,1] * self[1,0]) if self.getRws == 2 
    res = 0
    for i in 0...@MyRws
      res += (((-1) ** i) * self[i,0] * del_rwcl(self,i,0).laplace) if self[i,0] != 0
    end
    return res
  else
    raise MyArgError, '  Argument Error: Cannot calculate determinat on a non-squared matrix'
    return nil
  end
end

#normObject

Calculates the norm of a matrix, defined as sqrt(sum(m**2))

  • returns: ‘Float` value



368
369
370
371
372
373
374
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 368

def norm()
 sum=0
 @mx.map do |e|
   sum +=e**2
 end
 return Math.sqrt(sum)
end

#similar_to?(obj) ⇒ Boolean

Checks if this matrix and the given object have the same features

  • argument: ‘Object`

  • returns: true if ‘obj` is a `Matrix` and has the same rows and colum number;

false else

Returns:

  • (Boolean)


249
250
251
252
253
254
255
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 249

def similar_to?(obj)
  if obj.is_a? Matrix then
    (self.getCls == obj.getCls && 
      self.getRws == obj.getRws ) ? (return true) : (return false)
  end
  return false
end

#to_file(filename = "") ⇒ Object

Writes the matrix on a file

  • argument: ‘String` of the file path



111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 111

def to_file(filename = "")
  if !(Dir.exist? File.dirname(filename)) or filename == "" then
    raise MyArgError, "  Argument Error: Invalid directory; Directory not found"
  else
    File.open(filename,"w") do |rw|
      for i in 0...@MyRws do
        for j in 0...(@MyCls - 1) do
          rw.print "#{self[i,j]},"
        end
        rw.puts "#{self[i,j+1]}"
      end
    end
  end
end

#to_sObject

converts this matrix object to a string



127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 127

def to_s()
  max = 0
  str = ""
  @mx.each{ |n| max = "#{n.round(3)}".size if "#{n.round(3)}".size > max}
  for i in 0...@MyRws do
    str += '|'
    for j in (i*(@MyCls))...(i*(@MyCls)+@MyCls) do
      str += "  #{" "*(max-@mx[j].round(3).to_s.size).abs}#{@mx[j].round(3) }"
    end
    str+= "  |\n"
  end
  return str
end

#trObject

Trasposes a matrix

returns: ‘Matrix` object



360
361
362
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 360

def tr()
  return Matrix.new(@MyCls,@MyRws) { |i,j| @mx[j * @MyCls + i]}
end

#update(mat, rws, cls) ⇒ Object

Updates this matrix after the array in which it was saved has been manually modified

  • argument: ‘Array` on which the new matrix is saved

  • argument: ‘Fixnum` of number of rows

  • argument: ‘Fixnum` of number of columns



162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/linmeric/CnGal_Matrix_class.rb', line 162

def update(mat,rws,cls)
  if !(mat.is_a? Array) then
    raise MyArgError, "  Argument Error: invalid matrix array found"
  else
    [cls,rws].each do |e|
      raise MyArgError, "  Argument Error: colums and rows in Integer format expected but #{e.class} found" unless e.is_a? Numeric
    end
  end
   @mx = mat
   @MyRws = rws
   @MyCls = cls
end