stair_car 0.0.1

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.
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