Class: MDS::MatrixInterface

Inherits:
Object
  • Object
show all
Defined in:
lib/mds/matrix_interface.rb

Overview

Provides a common interface to matrix operations.

RMDS does not implement any linear algebra routine itself, but rather provides a non intrusive mechanism to plugin third party linear algebra packages. MatrixInterface defines a minimal set of required methods to be implemented for any linear algebra packages which are to be used with RMDS.

Making linear algebra backends compatible with RMDS is easy: simply subclass from MatrixInterface and implement all abstract methods. Not all of MatrixInterface methods are abstract, some come with a default implementation. If your linear algebra package does better at some of those methods, you should override them in your interface subclass.

RMDS helps you in testing your matrix interfaces through test bundles that ship with RMDS. Each test bundle contains a set of tests that work independently of the matrix interface chosen. The following file unit tests a matrix interface.

require 'test/unit'
require 'mds/test/bundles/bundle_matrix_interface.rb'
require 'mds/interfaces/linalg_interface'

class TestLinalgInteface < Test::Unit::TestCase
  include MDS::Test::BundleMatrixInterface

  def setup
    MDS::Backend.push_active(MDS::LinalgInterface)
  end

  def teardown
    MDS::Backend.pop_active
  end

end

Finally, tell RMDS to use your matrix interface by setting the default matrix interface, like so

# Set active interface
MDS::Backend.active = YourMatrixInterface

# Push onto interface stack and set active interface
MDS::Backend.push_active(YourMatrixInterface)

# Restore the previously active interface
MDS::Backend.pop_active

See Also:

  • MDS::Backend

Direct Known Subclasses

GSLInterface, LinalgInterface, StdlibInterface

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.add(m, n) ⇒ Object

This method is abstract.

Componentwise addition of two matrices.

Parameters:

  • m

    first matrix

  • n

    second matrix

Returns:

  • the matrix addition as newly allocated matrix

Raises:

  • (NotImplementedError)


154
155
156
# File 'lib/mds/matrix_interface.rb', line 154

def MatrixInterface.add(m, n)
  raise NotImplementedError
end

.columns(m) ⇒ Array<Array>

Returns matrix as array of columns.

Returns:

  • (Array<Array>)

    the array of columns where each column is an array



306
307
308
309
310
311
312
313
314
# File 'lib/mds/matrix_interface.rb', line 306

def MatrixInterface.columns(m)
  a = Array.new(self.ncols(m)) {Array.new(self.nrows(m))}
  for i in 0..self.nrows(m)-1 do
    for j in 0..self.ncols(m)-1 do
      a[j][i] = self.get(m, i, j)
    end
  end
  a
end

.create(n, m, s) ⇒ Object

This method is abstract.

Create a new matrix having all elements equal values.

Parameters:

  • n (Integer)

    the number of rows

  • m (Integer)

    the number of columns

  • s (Float)

    the scalar value of each matrix component

Returns:

  • the newly created matrix.

Raises:

  • (NotImplementedError)


83
84
85
# File 'lib/mds/matrix_interface.rb', line 83

def MatrixInterface.create(n, m, s)
  raise NotImplementedError
end

.create_block(n, m, &block) ⇒ Object

Create a new matrix and assign each element as the result of invoking the given block.

Parameters:

  • n (Integer)

    the number of rows

  • m (Integer)

    the number of columns.

Returns:

  • the newly created matrix.



211
212
213
214
215
216
217
218
219
# File 'lib/mds/matrix_interface.rb', line 211

def MatrixInterface.create_block(n, m, &block)
  mat = self.create(n, m, 0.0)
  for i in 0..self.nrows(mat)-1
    for j in 0..self.ncols(mat)-1
      self.set(mat, i, j, block.call(i,j))
    end
  end
  mat
end

.create_diagonal(*elements) ⇒ Object

Create a new diagonal matrix.

Parameters:

  • *elements

    the diagonal elements

Returns:

  • the newly created matrix



253
254
255
256
257
258
259
260
# File 'lib/mds/matrix_interface.rb', line 253

def MatrixInterface.create_diagonal(*elements)
  n = elements.length
  m = self.create(n, n, 0.0)
  for i in 0..self.nrows(m)-1
    self.set(m, i, i, elements[i])
  end
  m
end

.create_identity(n) ⇒ Object

Create a new identity matrix.

Parameters:

  • n (Integer)

    matrix dimension

Returns:

  • the newly created matrix.



243
244
245
# File 'lib/mds/matrix_interface.rb', line 243

def MatrixInterface.create_identity(n)
  self.create_diagonal(*[1.0]*n)
end

.create_random(n, m, smin = -1.0,, smax = 1.0) ⇒ Object

Create a new matrix with uniform random elements.

Parameters:

  • n (Integer)

    the number of rows

  • m (Integer)

    the number of columns

  • smin (Float) (defaults to: -1.0,)

    the minimum element value (inclusive).

  • smax (Float) (defaults to: 1.0)

    the maximum element value (inclusive).

Returns:

  • the newly created matrix.



230
231
232
233
234
235
# File 'lib/mds/matrix_interface.rb', line 230

def MatrixInterface.create_random(n, m, smin = -1.0, smax = 1.0)
  range = smax - smin
  self.create_block(n, m) do |i,j|
    smin + range*rand()
  end
end

.create_rows(*rows) ⇒ Object

Create matrix from rows.

Parameters:

  • rows (Array)

    the rows

Returns:

  • the newly created matrix



268
269
270
271
272
273
274
275
# File 'lib/mds/matrix_interface.rb', line 268

def MatrixInterface.create_rows(*rows)
  nrows = rows.length

  ncols = rows.first.length
  self.create_block(nrows, ncols) do |i,j|
    rows[i][j]
  end
end

.diagonals(m) ⇒ Object

Retrieve the diagonal elements as an array.

The number of diagonals of an NxM matrix is defined as min(N,M).

Parameters:

  • m

    the matrix

Returns:

  • diagonals of matrix as array.



286
287
288
289
# File 'lib/mds/matrix_interface.rb', line 286

def MatrixInterface.diagonals(m)
  size = [self.nrows(m), self.ncols(m)].min
  (0..size-1).map{|i| self.get(m,i,i)}
end

.ed(m) ⇒ Array

This method is abstract.

Compute the eigen-decomposition of a real symmetric matrix.

The eigen-decomposition consists of a diagonal matrix D containing the eigen values and a square matrix N having the normalized eigenvectors in columns. It is assumed that the result of MatrixInterface#ed yields the matrices as an array and that the eigen-vectors and values are sorted in descending order of importance.

Parameters:

  • m

    the matrix to decompose

Returns:

  • (Array)

    the array containing the matrix of eigen-values and eigen-vector

Raises:

  • (NotImplementedError)


194
195
196
# File 'lib/mds/matrix_interface.rb', line 194

def MatrixInterface.ed(m)
  raise NotImplementedError
end

.get(m, i, j) ⇒ Float

This method is abstract.

Get value of matrix element.

Parameters:

  • m

    the matrix

  • i (Integer)

    the i-th row, zero-based indexing

  • j (Integer)

    the j-th column, zero-based indexing

Returns:

  • (Float)

    value of element

Raises:

  • (NotImplementedError)


130
131
132
# File 'lib/mds/matrix_interface.rb', line 130

def MatrixInterface.get(m, i, j)
  raise NotImplementedError
end

.inherited(subclass) ⇒ Object

Record creation of a subclass of this class at the MDS::Backend



65
66
67
# File 'lib/mds/matrix_interface.rb', line 65

def MatrixInterface.inherited(subclass)
  MDS::Backend.add(subclass)
end

.minor(m, row_range, col_range) ⇒ Object

Calculate minor matrix.

Parameters:

  • m

    matrix to calculate minor from

  • row_range (Range)

    linear row range with step size equal to one.

  • col_range (Range)

    linear column range with step size equal to one.



338
339
340
341
342
343
344
# File 'lib/mds/matrix_interface.rb', line 338

def MatrixInterface.minor(m, row_range, col_range)
  nrows = (row_range.last - row_range.first) + 1
  ncols = (col_range.last - col_range.first) + 1
  self.create_block(nrows, ncols) do |i,j|
    self.get(m, i + row_range.first, j + col_range.first)
  end
end

.ncols(m) ⇒ Object

This method is abstract.

Return the number of matrix columns

Parameters:

  • m

    the matrix

Returns:

  • number of columns in matrix

Raises:

  • (NotImplementedError)


105
106
107
# File 'lib/mds/matrix_interface.rb', line 105

def MatrixInterface.ncols(m)
  raise NotImplementedError
end

.nrows(m) ⇒ Object

This method is abstract.

Return the number of matrix rows

Parameters:

  • m

    the matrix

Returns:

  • number of rows in matrix

Raises:

  • (NotImplementedError)


94
95
96
# File 'lib/mds/matrix_interface.rb', line 94

def MatrixInterface.nrows(m)
  raise NotImplementedError
end

.prod(m, n) ⇒ Object

This method is abstract.

Calculate the product of two matrices or the product of a matrix and a scalar.

Parameters:

  • m

    first matrix

  • n

    second matrix or scalar

Returns:

  • the matrix product as newly allocated matrix

Raises:

  • (NotImplementedError)


143
144
145
# File 'lib/mds/matrix_interface.rb', line 143

def MatrixInterface.prod(m, n)
  raise NotImplementedError
end

.rows(m) ⇒ Array<Array>

Returns matrix as array of rows.

Returns:

  • (Array<Array>)

    the array of rows where each rows is an array



321
322
323
324
325
326
327
328
329
# File 'lib/mds/matrix_interface.rb', line 321

def MatrixInterface.rows(m)
  a = Array.new(self.nrows(m)) {Array.new(self.ncols(m))}
  for i in 0..self.nrows(m)-1 do
    for j in 0..self.ncols(m)-1 do
      a[i][j] = self.get(m, i, j)
    end
  end
  a
end

.set(m, i, j, s) ⇒ Object

This method is abstract.

Set value of matrix element.

Parameters:

  • m

    the matrix

  • i (Integer)

    the i-th row, zero-based indexing

  • j (Integer)

    the j-th column, zero-based indexing

  • s (Float)

    scalar value to set

Raises:

  • (NotImplementedError)


117
118
119
# File 'lib/mds/matrix_interface.rb', line 117

def MatrixInterface.set(m, i, j, s)
  raise NotImplementedError
end

.sub(m, n) ⇒ Object

This method is abstract.

Componentwise subtraction of two matrices.

Parameters:

  • m

    first matrix

  • n

    second matrix

Returns:

  • the matrix subtraction as newly allocated matrix

Raises:

  • (NotImplementedError)


166
167
168
# File 'lib/mds/matrix_interface.rb', line 166

def MatrixInterface.sub(m, n)
  raise NotImplementedError
end

.t(m) ⇒ Object

This method is abstract.

Transpose a matrix.

Parameters:

  • m

    the matrix to transpose

Returns:

  • the transposed matrix as newly allocated matrix

Raises:

  • (NotImplementedError)


177
178
179
# File 'lib/mds/matrix_interface.rb', line 177

def MatrixInterface.t(m)
  raise NotImplementedError
end

.trace(m) ⇒ Object

Calculate the sum of diagonal matrix elements.

Parameters:

  • m

    the matrix

Returns:

  • trace of matrix



297
298
299
# File 'lib/mds/matrix_interface.rb', line 297

def MatrixInterface.trace(m)
  self.diagonals(m).inject(0) {|sum,e| sum += e}
end

Instance Method Details

#to_s(m) ⇒ Object

Convert to string.

Invokes #to_s from wrapped matrix.

Returns:

  • wrapped matrix as string.



353
354
355
# File 'lib/mds/matrix_interface.rb', line 353

def to_s(m)
  m.to_s
end