stair_car 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +21 -0
  2. data/Gemfile +14 -0
  3. data/Guardfile +18 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +223 -0
  6. data/Rakefile +1 -0
  7. data/lib/matlab/matlabcontrol-4.0.0.jar +0 -0
  8. data/lib/pcolt/lib/arpack-combo.jar +0 -0
  9. data/lib/pcolt/lib/csparsej.jar +0 -0
  10. data/lib/pcolt/lib/jplasma.jar +0 -0
  11. data/lib/pcolt/lib/jtransforms.jar +0 -0
  12. data/lib/pcolt/lib/junit.jar +0 -0
  13. data/lib/pcolt/lib/netlib-java.jar +0 -0
  14. data/lib/pcolt/lib/optimization.jar +0 -0
  15. data/lib/pcolt/parallelcolt-0.9.4.jar +0 -0
  16. data/lib/stair_car/mmatrix/matlab_interface.rb +9 -0
  17. data/lib/stair_car/mmatrix/mmatrix.rb +26 -0
  18. data/lib/stair_car/pmatrix/compare.rb +34 -0
  19. data/lib/stair_car/pmatrix/matrix_math.rb +169 -0
  20. data/lib/stair_car/pmatrix/pmatrix.rb +151 -0
  21. data/lib/stair_car/pmatrix/transforms.rb +74 -0
  22. data/lib/stair_car/pmatrix/types.rb +106 -0
  23. data/lib/stair_car/shared/errors.rb +7 -0
  24. data/lib/stair_car/shared/indicies.rb +33 -0
  25. data/lib/stair_car/shared/init_methods.rb +56 -0
  26. data/lib/stair_car/shared/inspect.rb +113 -0
  27. data/lib/stair_car/shared/iteration.rb +32 -0
  28. data/lib/stair_car/umatrix/compare.rb +34 -0
  29. data/lib/stair_car/umatrix/matrix_math.rb +190 -0
  30. data/lib/stair_car/umatrix/transforms.rb +49 -0
  31. data/lib/stair_car/umatrix/types.rb +42 -0
  32. data/lib/stair_car/umatrix/umatrix.rb +166 -0
  33. data/lib/stair_car.rb +35 -0
  34. data/lib/ujmp/ujmp-complete-0.2.5.jar +0 -0
  35. data/spec/pmatrix/matrix_math_spec.rb +65 -0
  36. data/spec/pmatrix/pmatrix_spec.rb +103 -0
  37. data/spec/pmatrix/transforms_spec.rb +44 -0
  38. data/spec/shared/indicies_spec.rb +52 -0
  39. data/spec/shared/inspect_spec.rb +23 -0
  40. data/spec/shared/iteration_spec.rb +17 -0
  41. data/spec/spec_helper.rb +5 -0
  42. data/spec/umatrix/matrix_math_spec.rb +68 -0
  43. data/spec/umatrix/transform_spec.rb +32 -0
  44. data/spec/umatrix/umatrix_spec.rb +104 -0
  45. data/stair_car.gemspec +19 -0
  46. metadata +120 -0
@@ -0,0 +1,151 @@
1
+ require File.dirname(__FILE__) + '/../../pcolt/parallelcolt-0.9.4'
2
+ require 'stair_car/pmatrix/types'
3
+ require 'stair_car/pmatrix/matrix_math'
4
+ require 'stair_car/pmatrix/transforms'
5
+ require 'stair_car/pmatrix/compare'
6
+ require 'stair_car/shared/iteration'
7
+ require 'stair_car/shared/inspect'
8
+ require 'stair_car/shared/indicies'
9
+ require 'stair_car/shared/init_methods'
10
+ require 'stair_car/shared/errors'
11
+
12
+
13
+ module StairCar
14
+ class PMatrix
15
+ include PMatrixTypes
16
+ include PMatrixMatrixMath
17
+ include PMatrixTransforms
18
+ include PMatrixCompare
19
+ include Iteration
20
+ include Inspect
21
+ include Indicies
22
+ include InitMethods
23
+
24
+ attr_accessor :data
25
+
26
+ # Proxy methods
27
+ [:size, :rows].each do |method_name|
28
+ define_method(method_name) do |*args|
29
+ @data.send(method_name, *args)
30
+ end
31
+ end
32
+
33
+ def cols
34
+ @data.columns
35
+ end
36
+
37
+ def shape
38
+ [rows, cols]
39
+ end
40
+
41
+
42
+ def initialize(rows_or_data=nil, cols=nil, type=:double, sparse=false, initialize_values=:zeros)
43
+ if rows_or_data.is_a?(Array)
44
+ klass = type_class(type, sparse, initialize_values)
45
+
46
+ # Create the matrix from an array
47
+ from_array(rows_or_data, klass)
48
+ elsif rows_or_data.is_a?(Fixnum)
49
+ raise MatrixDimensionsError, "Must specify columns and rows" unless rows_or_data && cols
50
+ klass = type_class(type, sparse, initialize_values)
51
+ if klass.is_a?(Method) || klass.is_a?(Proc)
52
+ # A factory method was returned, call to build
53
+ @data = klass.call(rows_or_data, cols)
54
+ else
55
+ # A class was returned, create new
56
+ @data = klass.new(rows_or_data, cols)
57
+
58
+ setup_default_values(initialize_values)
59
+ end
60
+ else
61
+ # Passing in data directly
62
+ @data = rows_or_data
63
+ end
64
+ end
65
+
66
+ def setup_default_values(initialize_values)
67
+ if initialize_values == :ones
68
+ @data.assign(1.0)
69
+ end
70
+ end
71
+
72
+ def [](rows, cols)
73
+ rows = convert_indicies(rows, self.rows)
74
+ cols = convert_indicies(cols, self.cols)
75
+
76
+ # Returns either the value in a cell or a subview
77
+ if rows && cols && rows.size == 1 && cols.size == 1 && rows.first.is_a?(Fixnum) && cols.first.is_a?(Fixnum)
78
+ @data.get(rows.first, cols.first)
79
+ else
80
+ # Get subview, also convert rows/cols to java arrays
81
+ self.class.new(@data.view_selection(rows && rows.to_java(:int), cols && cols.to_java(:int)))
82
+ end
83
+ end
84
+
85
+ def []=(rows, cols, value)
86
+ rows = convert_indicies(rows, self.rows)
87
+ cols = convert_indicies(cols, self.cols)
88
+
89
+ # Set either the value in a cell or a subview with a matrix
90
+ if rows && cols && rows.size == 1 && cols.size == 1 && rows.first.is_a?(Fixnum) && cols.first.is_a?(Fixnum)
91
+ @data.set(rows.first, cols.first, value)
92
+ else
93
+ subview = @data.view_selection(rows && rows.to_java(:int), cols && cols.to_java(:int))
94
+
95
+ # Assign a single array or a nested array
96
+ if value.is_a?(Array)
97
+ value_rows, value_cols = array_dimensions(value)
98
+
99
+ # If one dimentional, and they want to set cols
100
+ if value_rows == 1 && subview.columns == 1
101
+ # Transpose so we can place an array vertically
102
+ subview = subview.view_dice
103
+ end
104
+
105
+ # Check to make sure the sizes match
106
+ if value_rows != subview.rows || value_cols != subview.columns
107
+ raise MatrixDimensionsError, "the array you are trying to assign is not the correct size"
108
+ end
109
+ end
110
+
111
+ if value.is_a?(PMatrix)
112
+ value = value.data
113
+ end
114
+
115
+ if value.is_a?(Array)
116
+ assign_values(subview, value)
117
+ else
118
+ subview.assign(value)
119
+ end
120
+ end
121
+ end
122
+
123
+
124
+ # Loop through each non-zero value, pass in the value, row, column
125
+ def each_non_zero(&block)
126
+ @data.for_each_non_zero do |row, col, value|
127
+ yield(value, row, col)
128
+
129
+ value
130
+ end
131
+ end
132
+
133
+
134
+ # Takes an array and assigns it to the right cells in the subview
135
+ def assign_values(subview, value)
136
+ unless value.first.is_a?(Array)
137
+ value = [value]
138
+ end
139
+
140
+ value.each_with_index do |row,row_index|
141
+ row.each_with_index do |val,col_index|
142
+ subview.set(row_index, col_index, val.to_java(:double))
143
+ end
144
+ end
145
+ end
146
+
147
+ def dup
148
+ PMatrix.new(@data.copy)
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,74 @@
1
+ module StairCar
2
+ module PMatrixTransforms
3
+ def transpose
4
+ return PMatrix.new(@data.view_dice.copy)
5
+ end
6
+
7
+ def ~
8
+ return transpose
9
+ end
10
+
11
+ def inv
12
+ algebra = Java::cern.colt.matrix.tdouble.algo.DenseDoubleAlgebra.new
13
+ begin
14
+ return PMatrix.new(algebra.inverse(@data))
15
+ rescue Java::JavaLang::IllegalArgumentException => e
16
+ if e.message == 'Matrix is singular.' || e.message == 'A is singular.'
17
+ raise InverseMatrixIsSignular, e.message
18
+ else
19
+ raise
20
+ end
21
+ end
22
+ end
23
+
24
+ def map(&block)
25
+ dup.map!(&block)
26
+ end
27
+
28
+ def map!
29
+ result = self.each_with_index do |val,row,col|
30
+ self[row,col] = yield(val, row, col)
31
+ end
32
+
33
+ return self
34
+ end
35
+
36
+ def map_non_zero(&block)
37
+ dup.map_non_zero!(&block)
38
+ end
39
+
40
+ def map_non_zero!
41
+ result = @data.for_each_non_zero do |row,col,val|
42
+ yield(val, row, col)
43
+ end
44
+
45
+ PMatrix.new(result)
46
+ end
47
+
48
+ def count
49
+ count = 0
50
+
51
+ each do |val,row,col|
52
+ if yield(val,row,col)
53
+ count += 1
54
+ end
55
+ end
56
+
57
+ return count
58
+ end
59
+
60
+ # Converts the matrix into an array
61
+ def to_a
62
+ array = []
63
+ rows.times do |row|
64
+ col_array = []
65
+ cols.times do |col|
66
+ col_array << self[row,col]
67
+ end
68
+ array << col_array
69
+ end
70
+
71
+ return array
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,106 @@
1
+ # Lookup the type for the underlying matrix implementation
2
+ module StairCar
3
+ module PMatrixTypes
4
+
5
+ def type
6
+ klass = @data.class
7
+ if klass == Java::CernColtMatrixTdoubleImpl::DenseDoubleMatrix2D
8
+ return :double
9
+ elsif klass == Java::CernColtMatrixTdoubleImpl::SparseDoubleMatrix2D
10
+ return :double
11
+ elsif klass == Java::CernColtMatrixTfloatImpl::DenseFloatMatrix2D
12
+ return :float
13
+ elsif klass == Java::CernColtMatrixTfloatImpl::SparseFloatMatrix2D
14
+ return :float
15
+ end
16
+ end
17
+
18
+ def sparse?
19
+ klass = @data.class
20
+ if klass == Java::CernColtMatrixTdoubleImpl::DenseDoubleMatrix2D
21
+ return false
22
+ elsif klass == Java::CernColtMatrixTdoubleImpl::SparseDoubleMatrix2D
23
+ return true
24
+ elsif klass == Java::CernColtMatrixTfloatImpl::DenseFloatMatrix2D
25
+ return false
26
+ elsif klass == Java::CernColtMatrixTfloatImpl::SparseFloatMatrix2D
27
+ return true
28
+ end
29
+ end
30
+
31
+
32
+ def type_class(type, sparse, initialize_values)
33
+ types = {
34
+ :zeros => {
35
+ false => {
36
+ # dense
37
+ :double => Java::cern.colt.matrix.tdouble.impl.DenseDoubleMatrix2D,
38
+ :float => Java::cern.colt.matrix.tfloat.impl.DenseFloatMatrix2D
39
+ },
40
+ true => {
41
+ # sparse
42
+ :double => Java::cern.colt.matrix.tdouble.impl.SparseDoubleMatrix2D,
43
+ # :double => Proc.new {|rows,cols| Java::cern.colt.matrix.tdouble.impl.SparseDoubleMatrix2D.new(rows,cols,10000.to_java(:int),0.0.to_java(:double),0.999999999.to_java(:double)) },
44
+ :float => Java::cern.colt.matrix.tfloat.impl.SparseFloatMatrix2D
45
+ }
46
+ },
47
+ :ones => {
48
+ false => {
49
+ # dense
50
+ :double => Java::cern.colt.matrix.tdouble.impl.DenseDoubleMatrix2D,
51
+ :float => Java::cern.colt.matrix.tfloat.impl.DenseFloatMatrix2D
52
+ },
53
+ true => {
54
+ # sparse
55
+ :double => Java::cern.colt.matrix.tdouble.impl.SparseDoubleMatrix2D,
56
+ :float => Java::cern.colt.matrix.tfloat.impl.SparseFloatMatrix2D
57
+ }
58
+ },
59
+ :rand => {
60
+ false => {
61
+ # dense
62
+ :double => Java::cern.colt.matrix.tdouble.DoubleFactory2D.dense.method(:random),
63
+ :float => Java::cern.colt.matrix.tfloat.FloatFactory2D.dense.method(:random)
64
+ },
65
+ true => {
66
+ # sparse
67
+ :double => Java::cern.colt.matrix.tdouble.DoubleFactory2D.sparse.method(:random),
68
+ :float => Java::cern.colt.matrix.tfloat.FloatFactory2D.sparse.method(:random)
69
+ }
70
+ },
71
+ :desc => {
72
+ false => {
73
+ # dense
74
+ :double => Java::cern.colt.matrix.tdouble.DoubleFactory2D.dense.method(:descending),
75
+ :float => Java::cern.colt.matrix.tfloat.FloatFactory2D.dense.method(:descending)
76
+ },
77
+ true => {
78
+ # sparse
79
+ :double => Java::cern.colt.matrix.tdouble.DoubleFactory2D.sparse.method(:descending),
80
+ :float => Java::cern.colt.matrix.tfloat.FloatFactory2D.sparse.method(:descending)
81
+ }
82
+ },
83
+ :asc => {
84
+ false => {
85
+ # dense
86
+ :double => Java::cern.colt.matrix.tdouble.DoubleFactory2D.dense.method(:ascending),
87
+ :float => Java::cern.colt.matrix.tfloat.FloatFactory2D.dense.method(:ascending)
88
+ },
89
+ true => {
90
+ # sparse
91
+ :double => Java::cern.colt.matrix.tdouble.DoubleFactory2D.sparse.method(:ascending),
92
+ :float => Java::cern.colt.matrix.tfloat.FloatFactory2D.sparse.method(:ascending)
93
+ }
94
+ }
95
+ }
96
+
97
+ klass = types[initialize_values][sparse][type]
98
+
99
+ unless klass
100
+ raise "Could not make a #{sparse ? 'sparse' : 'dense'} #{type} matrix"
101
+ end
102
+
103
+ return klass
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,7 @@
1
+ module StairCar
2
+ class MatrixDimensionsError < RuntimeError
3
+ end
4
+
5
+ class InverseMatrixIsSignular < RuntimeError
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ # Handles converting indicies into arrays of row or column offsets
2
+ module StairCar
3
+ module Indicies
4
+ def convert_indicies(index, max_index)
5
+ if index.is_a?(Fixnum)
6
+ if index < 0
7
+ return [max_index + index]
8
+ else
9
+ return [index]
10
+ end
11
+ elsif index.is_a?(Array)
12
+ # Map to indicies and convert into one array
13
+ return index.map {|i| convert_indicies(i, max_index) }.flatten
14
+ elsif index.is_a?(Range)
15
+ if index.end < 0
16
+ start = index.begin
17
+ new_end = max_index + index.end
18
+
19
+ # Recreate with the end value
20
+ if index.exclude_end?
21
+ index = (start...new_end)
22
+ else
23
+ index = (start..new_end)
24
+ end
25
+ end
26
+
27
+ return index.to_a
28
+ elsif index.is_a?(NilClass)
29
+ return nil.to_java#convert_indicies(0...max_index, max_index)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,56 @@
1
+ module StairCar
2
+ module InitMethods
3
+ def from_array(array, klass)
4
+ rows, cols = array_dimensions(array)
5
+
6
+ if klass.is_a?(Method) || klass.is_a?(Proc)
7
+ @data = klass.call(rows, cols)
8
+ else
9
+ @data = klass.new(rows, cols)
10
+ end
11
+ self[nil,nil] = array
12
+ end
13
+
14
+
15
+ def array_dimensions(array)
16
+ if array.first.is_a?(Array)
17
+ # Nested array
18
+ rows = array.size
19
+ cols = array.first.size
20
+ else
21
+ # 1 dimensional array
22
+ cols = array.size
23
+ rows = 1
24
+ end
25
+
26
+ return rows, cols
27
+ end
28
+
29
+ module ClassMethods
30
+ def init_method_names
31
+ [true, false].each do |sparse|
32
+ [:double, :float].each do |type|
33
+ [:zeros, :ones, :rand, :desc, :asc].each do |initialize_values|
34
+ method_name = :"#{sparse ? 'sp' : ''}#{initialize_values}#{type == :float ? 'f' : ''}"
35
+
36
+ yield(method_name, sparse, type, initialize_values)
37
+ end
38
+ end
39
+ end
40
+
41
+ # Also add float and double shortcuts
42
+ yield(:float, false, :float, :zeros)
43
+ yield(:double, false, :float, :zeros)
44
+ end
45
+ end
46
+
47
+ def self.included(klass)
48
+ klass.extend(ClassMethods)
49
+ klass.init_method_names do |method_name, sparse, type, initialize_values|
50
+ klass.define_singleton_method(method_name) do |cols, rows|
51
+ klass.new(cols, rows, type, sparse, initialize_values)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,113 @@
1
+ module StairCar
2
+ module Inspect
3
+ def inspect(screen_width = 80, rows_to_show=12)
4
+ lines = []
5
+ lines << "<#PMatrix(#{type}) #{rows}x#{cols} #{sparse? ? 'sparse' : 'dense'}>"
6
+
7
+ # To print cleanly, we should make the rows as big as the max width
8
+ # cell. We greedly loop through the columns and keep track of where
9
+ # we are.
10
+ formatter = Proc.new { |number| sprintf('%.3f', number).gsub(/[.]?0+$/, '') }
11
+
12
+ # Sometimes we only have a 1x1 matrix, and lookups will return a float
13
+ if rows == 1 && cols == 1
14
+ lines << formatter.call(self[0,0])
15
+ return lines.join("\n")
16
+ end
17
+
18
+ # Max rows, minus the last row
19
+ max_rows = [rows_to_show-1, rows].min
20
+
21
+ # We need to find the biggest cell we're going to need to display. So
22
+ # we grab the last row, then all of the other rows, by the last column,
23
+ # followed by all of the other columns. We go down columns until we go
24
+ # past the screen width.
25
+ cell_width = self[[-1,0...(max_rows-1)],[-1,0...(cols-1)]].max_char_width(formatter, max_rows, screen_width)
26
+
27
+ # Compute how many columns we can show in the screen area, min with cols
28
+ # incase we could fit more than we have
29
+ max_columns = (screen_width / cell_width).floor
30
+ if max_columns >= self.cols
31
+ # We can display all of the cells, set the screen width to the new width
32
+ hidden_columns = false
33
+ screen_width = (cell_width * self.cols) - 1
34
+ else
35
+ # We can't fit all cells, hide the columns
36
+ hidden_columns = true
37
+ max_columns = ((screen_width - 3 - cell_width) / cell_width).floor
38
+ end
39
+
40
+ # See if we need to hide rows
41
+ hidden_rows = (self.rows > max_rows)
42
+
43
+ # Add all rows, except the last
44
+ [max_rows, self.rows-1].min.times do |row|
45
+ lines << row_line_text(row, formatter, max_columns, screen_width, cell_width, hidden_columns)
46
+ end
47
+
48
+ # Put a line in saying how rows we've hidden
49
+ if hidden_rows
50
+ lines << "#{self.rows - max_rows} rows".center(screen_width, '.')
51
+ end
52
+
53
+ # Say how many rows we're leaving out
54
+ if hidden_columns
55
+ # Go in and replace the .'s with text
56
+ message = "#{self.cols - max_columns} cols".center(max_rows, '.')
57
+
58
+ # convert message to an array
59
+ message = message.split(//)
60
+ (max_rows-1).times do |row|
61
+ next_char = message.slice!(0)
62
+ break unless next_char
63
+ lines[row+1][(cell_width + 2) * -1] = next_char
64
+ end
65
+ end
66
+
67
+ # Add last row
68
+ lines << row_line_text(-1, formatter, max_columns, screen_width, cell_width, hidden_columns)
69
+
70
+ return lines.join("\n")
71
+ end
72
+
73
+ # Figure out how big the cells should be, stop early when we reach the
74
+ # end of the screen
75
+ def max_char_width(formatter, max_rows, max_char_width)
76
+ max_cell_width = 0
77
+ rows.times do |row|
78
+ cols.times do |column|
79
+ cell_value = self[row, column]
80
+ width = formatter.call(cell_value).size + 1
81
+
82
+ # Track the biggest cell width we've seen so far
83
+ max_cell_width = width if width > max_cell_width
84
+
85
+ if max_cell_width * column > max_char_width
86
+ # We have now passed the width of the screen or section, break
87
+ # to next row
88
+ break
89
+ end
90
+ end
91
+ end
92
+
93
+ return max_cell_width
94
+ end
95
+
96
+ private
97
+ def row_line_text(row_number, formatter, max_columns, screen_width, cell_width, hidden_columns)
98
+ line = ''
99
+ [self.cols-1, max_columns].min.times do |column|
100
+ cell_value = self[row_number, column]
101
+ line << formatter.call(cell_value).ljust(cell_width)
102
+ end
103
+
104
+ last_cell = formatter.call(self[row_number, -1]).ljust(cell_width-1)
105
+ padding_size = screen_width - line.size - last_cell.size - 1
106
+ line << ('.' * padding_size) + ' ' if hidden_columns
107
+
108
+ line << last_cell
109
+
110
+ return line
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,32 @@
1
+ module StairCar
2
+ module Iteration
3
+ def each(&block)
4
+ rows.times do |row|
5
+ cols.times do |col|
6
+ yield(self[row,col])
7
+ end
8
+ end
9
+ end
10
+
11
+ def each_with_index(&block)
12
+ rows.times do |row|
13
+ cols.times do |col|
14
+ yield(self[row,col], row, col)
15
+ end
16
+ end
17
+ end
18
+
19
+ def each_column
20
+ cols.times do |col_number|
21
+ yield(self[nil,col_number],col_number)
22
+ end
23
+ end
24
+
25
+ def each_row
26
+ rows.times do |row_number|
27
+ yield(self[row_number,nil],row_number)
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ module StairCar
2
+ module UMatrixCompare
3
+ # def >(val)
4
+ # map {|v| (v > val) ? 1 : 0 }
5
+ # end
6
+ #
7
+ # def >=(val)
8
+ # map {|v| (v >= val) ? 1 : 0 }
9
+ # end
10
+ #
11
+ # def <(val)
12
+ # map {|v| (v < val) ? 1 : 0 }
13
+ # end
14
+ #
15
+ # def <=(val)
16
+ # map {|v| (v <= val) ? 1 : 0 }
17
+ # end
18
+ #
19
+ # def find(matrix)
20
+ #
21
+ # end
22
+ #
23
+ # def any?
24
+ # @data.cardinality > 0
25
+ # end
26
+
27
+
28
+ # Compares this matrix to another to see if they are the same (in values)
29
+ def ==(matrix2)
30
+ self.data.equalsContent(matrix2.data)
31
+ end
32
+
33
+ end
34
+ end