csrmatrix 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +3 -1
- data/README.md +106 -1
- data/csrmatrix-1.0.0.gem +0 -0
- data/lib/csrmatrix/arithmetic.rb +213 -117
- data/lib/csrmatrix/decompositions.rb +22 -20
- data/lib/csrmatrix/exceptions.rb +18 -5
- data/lib/csrmatrix/functions.rb +52 -16
- data/lib/csrmatrix/helpers.rb +23 -11
- data/lib/csrmatrix/mcontracts.rb +9 -0
- data/lib/csrmatrix/operations.rb +60 -18
- data/lib/csrmatrix/properties.rb +219 -96
- data/lib/csrmatrix/version.rb +1 -1
- data/lib/csrmatrix.rb +204 -94
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 842f69d5be23f5b6a2ea2057504f416eff0648f8
|
4
|
+
data.tar.gz: f05e25a4c9f740e9691e94bc3aeb6b4a476be910
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 767ba6ea5d5bdad6e30e986c052f93b6bd9b3822f28ee98326b132bc9010c01e3a17241ed7fe7ba558395e8853aca3fe9fd782ff36efa77fd43b0fbab825fd7c
|
7
|
+
data.tar.gz: 73afd742117835704942a8cf5202a1cbbd9e3c8eecf013709957191707ca38b9a5574e56082477d7ab6491b95cea71049718a4145699bfc1636c21029a83acfa
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
csrmatrix (1.0.
|
4
|
+
csrmatrix (1.0.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
contracts (0.13.0)
|
9
10
|
diff-lcs (1.2.5)
|
10
11
|
minitest (5.8.3)
|
11
12
|
rake (10.5.0)
|
@@ -28,6 +29,7 @@ PLATFORMS
|
|
28
29
|
|
29
30
|
DEPENDENCIES
|
30
31
|
bundler (~> 1.11)
|
32
|
+
contracts
|
31
33
|
csrmatrix!
|
32
34
|
minitest
|
33
35
|
rake (~> 10.0)
|
data/README.md
CHANGED
@@ -22,7 +22,112 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
25
|
+
## Usage
|
26
|
+
#### Construction
|
27
|
+
|
28
|
+
Start by building the matrix object. This will be a simple shell, on which we can perform our operations on:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
@matrix = TwoDMatrix.new
|
32
|
+
=> #<TwoDMatrix:0x007fa5b2083ba8 @nonzero_count=nil, @row_ptr=nil, @col_ind=nil, @val=nil, @rows=0, @columns=0, @ndim=2>
|
33
|
+
```
|
34
|
+
|
35
|
+
Then, we can fill it out using a variety of manners - either building the functions from arrays:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
@matrix.build_from_array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
|
39
|
+
@matrix.build_from_rows([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
|
40
|
+
@matrix.build_from_columns([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
|
41
|
+
@matrix.build_from_csr([0, 3, 6, 9],[0, 1, 2, 0, 1, 2, 0, 1, 2],[1, 2, 3, 1, 2, 3, 1, 2, 3],3,3)
|
42
|
+
```
|
43
|
+
|
44
|
+
Or from an existing matrix using Ruby's matrix library:
|
45
|
+
```ruby
|
46
|
+
@MatrixBuild = Matrix.rows([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
|
47
|
+
@matrix.build_from_matrix(@MatrixBuild)
|
48
|
+
```
|
49
|
+
|
50
|
+
Or by generating a zero or identity matrix:
|
51
|
+
```ruby
|
52
|
+
@matrix.build_zero_matrix(3, 2)
|
53
|
+
@matrix.build_identity_matrix(3)
|
54
|
+
```
|
55
|
+
|
56
|
+
For more experienced users, build calls can be generated using keywords:
|
57
|
+
```ruby
|
58
|
+
@matrix.build("rows", [[1, 2, 3], [1, 2, 3], [1, 2, 3]])
|
59
|
+
@matrix.build("columns", [[1, 2, 3], [1, 2, 3], [1, 2, 3]])
|
60
|
+
@matrix.build("identity", 3) #rows, columns are same
|
61
|
+
@matrix.build("zero", 2) #rows, columns
|
62
|
+
@matrix.build("csr", [[0, 3, 6, 9],[0, 1, 2, 0, 1, 2, 0, 1, 2],[1, 2, 3, 1, 2, 3, 1, 2, 3],3,3])
|
63
|
+
@matrix.build("array", [[1, 2, 3], [1, 2, 3], [1, 2, 3]])
|
64
|
+
@matrix.build("matrix", @MatrixBuild)
|
65
|
+
```
|
66
|
+
|
67
|
+
#### Properties
|
68
|
+
CsrMatrix offers many property checks for matrices. Test the system by using the following code:
|
69
|
+
```ruby
|
70
|
+
@matrixTrigonal3x3.diagonal?
|
71
|
+
```
|
72
|
+
|
73
|
+
The list of usable properties, as of this point, are as follows:
|
74
|
+
```ruby
|
75
|
+
.diagonal? .empty? .lower_triangular? .normal? .orthogonal? .permutation? .real? .nonsingular? .singular? .square? .symmetric? .unitary? .upper_ .triangular? .zero?
|
76
|
+
```
|
77
|
+
|
78
|
+
#### Arithmetic
|
79
|
+
CsrMatrix offers the full suite of standard arithmetic processes for matrices. With regards to scalar operations:
|
80
|
+
```ruby
|
81
|
+
@matrixConst.scalar_multiply(2)
|
82
|
+
@matrixConst.scalar_add(2)
|
83
|
+
@matrixConst.scalar_subtract(1)
|
84
|
+
@matrixConst.scalar_division(2)
|
85
|
+
@matrixConst.scalar_exp(2)
|
86
|
+
```
|
87
|
+
|
88
|
+
As for matrix-to-matrix processes:
|
89
|
+
```ruby
|
90
|
+
@matrixa.multiply_csr(@matrixb)
|
91
|
+
@matrixa.matrix_add(@matrixb)
|
92
|
+
@matrixa.is_same_dim(@matrixb)
|
93
|
+
@matrixa.matrix_add(@matrixb)
|
94
|
+
@matrixa.matrix_subtract(@matrixb)
|
95
|
+
@matrixa.matrix_inverse_multiply(@matrixd)
|
96
|
+
@matrixa.matrix_multiply_inverse(@matrixd)
|
97
|
+
@matrixa.matrix_division(@matrixd)
|
98
|
+
```
|
99
|
+
|
100
|
+
And for others:
|
101
|
+
```ruby
|
102
|
+
@matrixConst.inverse()
|
103
|
+
@matrixConst.transpose()
|
104
|
+
```
|
105
|
+
|
106
|
+
#### Other
|
107
|
+
CsrMatrix offers standard display and assorted property assertion functions for your sparse matrix:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
@matrixSparse3x3.print_full()
|
111
|
+
@matrixSparse3x3.print_sparse()
|
112
|
+
@matrixSparse3x3.get_value(4)
|
113
|
+
@matrixSparse3x3.index(1,1)
|
114
|
+
@matrixSparse3x3.det()
|
115
|
+
@matrixSparse3x3.determinant()
|
116
|
+
@matrixSparse3x3.rank()
|
117
|
+
@matrixFloat2x2.decompose()
|
118
|
+
@matrixDense3x3.trace()
|
119
|
+
@matrixDense3x3.tr()
|
120
|
+
@matrixSparse3x3.transpose()
|
121
|
+
@matrixSparse3x3.t()
|
122
|
+
```
|
123
|
+
|
124
|
+
#### Exporting CsrMatrix
|
125
|
+
If you would like to integrate the matrix with your other code, you can simply disassemble it and reconstruct it at your leisure:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
@matrix.decompose()
|
129
|
+
@matrix.decomp_to_matrix()
|
130
|
+
```
|
26
131
|
|
27
132
|
## Development
|
28
133
|
|
data/csrmatrix-1.0.0.gem
ADDED
Binary file
|
data/lib/csrmatrix/arithmetic.rb
CHANGED
@@ -1,91 +1,130 @@
|
|
1
1
|
require "matrix"
|
2
2
|
require "csrmatrix/exceptions"
|
3
|
+
require "contracts"
|
4
|
+
require "csrmatrix/mcontracts"
|
3
5
|
|
4
6
|
module CsrMatrix
|
5
7
|
module Arithmetic
|
8
|
+
include Contracts::Core
|
9
|
+
C = Contracts
|
6
10
|
|
11
|
+
# Brings in exception module for exception testing
|
7
12
|
def self.included(exceptions)
|
8
13
|
exceptions.send :include, Exceptions
|
9
14
|
end
|
10
15
|
|
11
|
-
|
12
|
-
# class ArgumentNullException < StandardError; end
|
13
|
-
# class MatrixTypeException < StandardError; end
|
14
|
-
|
15
|
-
# REFERENCE: To use module functions in module
|
16
|
-
# Class.new.extend(Decompositions).lup()
|
17
|
-
|
16
|
+
Contract C::Num => C::ArrayOf[C::Num]
|
18
17
|
def scalar_multiply(value)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
18
|
+
# multiply the matrix by a scalar value
|
19
|
+
is_invariant?
|
20
|
+
|
23
21
|
@val.each_index do |i|
|
24
22
|
@val[i] = @val[i] * value
|
25
23
|
end
|
26
|
-
end
|
24
|
+
end # scalar_multiply
|
27
25
|
|
26
|
+
Contract C::Num => C::ArrayOf[C::Num]
|
28
27
|
def scalar_add(value)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
# create an identity matrix with the value
|
34
|
-
# matrix_add the new identity matrix to the given matrix
|
28
|
+
# manipulate the matrix by adding a value at each index
|
29
|
+
is_invariant?
|
30
|
+
|
35
31
|
@val.each_index do |i|
|
36
32
|
@val[i] = @val[i] + value
|
37
33
|
end
|
38
|
-
end
|
34
|
+
end # scalar_add
|
39
35
|
|
36
|
+
Contract C::Num => C::ArrayOf[C::Num]
|
40
37
|
def scalar_subtract(value)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
# create an identity matrix with the value
|
46
|
-
# matrix_subtract the new identity matrix to the given matrix
|
38
|
+
is_invariant?
|
39
|
+
|
40
|
+
# manipulate the matrix by subtracting the value at each index
|
47
41
|
@val.each_index do |i|
|
48
42
|
@val[i] = @val[i] - value
|
49
43
|
end
|
50
|
-
end
|
44
|
+
end # scalar_subtract
|
51
45
|
|
46
|
+
Contract C::Num => C::ArrayOf[C::Or[Float, Float]]
|
52
47
|
def scalar_division(value)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
48
|
+
is_invariant?
|
49
|
+
# manipulate the matrix by dividing the value at each index
|
50
|
+
# post boolean, updated matrix (in floats, if previously was not)
|
57
51
|
@val.each_index do |i|
|
58
52
|
@val[i] = @val[i] / value.to_f
|
59
53
|
end
|
60
|
-
end
|
54
|
+
end # scalar_division
|
61
55
|
|
56
|
+
Contract C::Num => C::ArrayOf[C::Num]
|
62
57
|
def scalar_exp(value)
|
63
|
-
|
64
|
-
|
65
|
-
return false
|
66
|
-
end
|
58
|
+
is_invariant?
|
59
|
+
# manipulate the matrix by finding the exponential at each index
|
67
60
|
@val.each_index do |i|
|
68
61
|
@val[i] = @val[i] ** value
|
69
62
|
end
|
70
|
-
end
|
63
|
+
end # scalar_exp
|
71
64
|
|
65
|
+
Contract C::Num => C::Bool
|
72
66
|
def inverse()
|
67
|
+
is_invariant?
|
68
|
+
# sets the inverse of this matrix
|
69
|
+
# pre existing matrix (matrix.not_null?)
|
70
|
+
# post inverted matrix
|
73
71
|
m = Matrix.rows(self.decompose)
|
74
72
|
self.build_from_array(m.inv().to_a())
|
75
|
-
end
|
73
|
+
end # inverse
|
76
74
|
|
77
|
-
|
75
|
+
Contract C::None => C::ArrayOf[C::Num]
|
78
76
|
def transpose()
|
79
|
-
|
80
|
-
|
81
|
-
|
77
|
+
is_invariant?
|
78
|
+
# transpose the matrix
|
79
|
+
|
80
|
+
new_row_ptr = Array.new(self.columns+1, 0)
|
81
|
+
new_col_ind = Array.new(self.col_ind.count(), 0)
|
82
|
+
new_val = Array.new(self.val.count(), 0)
|
83
|
+
current_row = 0
|
84
|
+
current_column = 0
|
85
|
+
|
86
|
+
for i in 0..self.columns-1
|
87
|
+
for j in 0..self.col_ind.count(i)-1
|
88
|
+
# get the row
|
89
|
+
index = self.col_ind.find_index(i)
|
90
|
+
self.col_ind[index] = -1
|
91
|
+
for k in 1..self.row_ptr.count()-1
|
92
|
+
if self.row_ptr[k-1] <= index && index < self.row_ptr[k]
|
93
|
+
current_row = k
|
94
|
+
break
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# update values
|
99
|
+
new_row_ptr[i+1] += 1
|
100
|
+
new_val[current_column] = val[index]
|
101
|
+
new_col_ind[current_column] = current_row-1
|
102
|
+
current_column += 1
|
103
|
+
end
|
104
|
+
end
|
82
105
|
|
106
|
+
# fill in row_ptr
|
107
|
+
for i in 1..self.rows-1
|
108
|
+
self.row_ptr[i] = new_row_ptr[i] + new_row_ptr[i-1]
|
109
|
+
end
|
110
|
+
|
111
|
+
@col_ind = new_col_ind
|
112
|
+
@val = new_val
|
113
|
+
end # transpose
|
114
|
+
|
115
|
+
Contract C::None => C::ArrayOf[C::Num]
|
83
116
|
def t()
|
84
|
-
|
85
|
-
|
117
|
+
is_invariant?
|
118
|
+
# transpose the matrix
|
119
|
+
# post array of decomposed matrix values
|
120
|
+
self.transpose()
|
121
|
+
end # t
|
86
122
|
|
123
|
+
Contract C::Num => C::ArrayOf[C::Num]
|
87
124
|
def matrix_vector(vector)
|
88
125
|
# dev based on http://www.mathcs.emory.edu/~cheung/Courses/561/Syllabus/3-C/sparse.html
|
126
|
+
# multiplies the matrix by a vector value (in array form)
|
127
|
+
is_invariant?
|
89
128
|
result = Array.new(vector.length, 0)
|
90
129
|
i = 0
|
91
130
|
while i < vector.length do
|
@@ -97,13 +136,15 @@ module CsrMatrix
|
|
97
136
|
i += 1
|
98
137
|
end
|
99
138
|
return result
|
100
|
-
end
|
139
|
+
end # matrix_vector
|
101
140
|
|
102
141
|
# dev based on http://stackoverflow.com/questions/29598299/csr-matrix-matrix-multiplication
|
103
|
-
|
104
|
-
# key: the dense matrix is LEFT SIDE, the csr matrix is RIGHT SIDE
|
142
|
+
Contract C::ArrayOf[C::ArrayOf[C::Num]] => C::ArrayOf[C::ArrayOf[C::Num]]
|
105
143
|
def matrix_multiply(matrix)
|
106
|
-
# matrix
|
144
|
+
# multiply dense (non-dense) matrix to csr matrix [eg. [1, 2]] x 2d array
|
145
|
+
is_invariant?
|
146
|
+
# pre matrix to multiply, existing matrix (matrix.not_null?)
|
147
|
+
# post array holding resulting matrix
|
107
148
|
res = Array.new(max_row(matrix)) { Array.new(@columns, 0) } # first denotes row, second denotes columns
|
108
149
|
n = matrix.length
|
109
150
|
i = 0
|
@@ -128,114 +169,169 @@ module CsrMatrix
|
|
128
169
|
i += 1
|
129
170
|
end
|
130
171
|
return res
|
131
|
-
end
|
172
|
+
end # matrix_multiply
|
132
173
|
|
133
|
-
|
174
|
+
Contract MContracts::TwoDMatrixType => C::ArrayOf[C::ArrayOf[C::Num]]
|
134
175
|
def multiply_csr(matrix)
|
176
|
+
# multiply two csr together - ref: http://www.mcs.anl.gov/papers/P5007-0813_1.pdf
|
177
|
+
is_invariant?
|
135
178
|
return matrix.matrix_multiply(self.decompose())
|
136
|
-
end
|
179
|
+
end # multiply_csr
|
137
180
|
|
138
|
-
|
181
|
+
Contract MContracts::TwoDMatrixType => C::Bool
|
139
182
|
def is_same_dim(matrix)
|
183
|
+
# helper function to determine dim count is equal
|
184
|
+
is_invariant?
|
140
185
|
return self.dimensions() == matrix.dimensions()
|
141
|
-
end
|
186
|
+
end # is_same_dim
|
142
187
|
|
188
|
+
Contract MContracts::TwoDMatrixType => C::ArrayOf[C::ArrayOf[C::Num]]
|
143
189
|
def matrix_add(matrix)
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
rowa = @row_ptr[row_idx + 1] # eg. 0 2 4 7
|
151
|
-
rowb = matrix.row_ptr[row_idx + 1]
|
152
|
-
while cnta < rowa
|
153
|
-
# keep adding values to res until they're equal
|
154
|
-
res[row_idx][@col_ind[cnta]] += @val[cnta]
|
155
|
-
cnta += 1;
|
156
|
-
end
|
157
|
-
while cntb < rowb
|
158
|
-
res[row_idx][@col_ind[cntb]] += matrix.val[cntb]
|
159
|
-
cntb += 1;
|
160
|
-
end
|
161
|
-
row_idx += 1;
|
162
|
-
end
|
163
|
-
return res
|
164
|
-
end
|
165
|
-
raise Exceptions::MatrixDimException.new, "Matrix does not have same dimensions; cannot add."
|
166
|
-
return false
|
167
|
-
end
|
190
|
+
# adds a matrix to existing matrix
|
191
|
+
is_invariant?
|
192
|
+
if !self.is_same_dim(matrix)
|
193
|
+
raise Exceptions::MatrixDimException.new, "Matrix does not have same dimensions; cannot add."
|
194
|
+
return false
|
195
|
+
end
|
168
196
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
res[row_idx][@col_ind[cnta]] += @val[cnta]
|
181
|
-
cnta += 1;
|
182
|
-
end
|
183
|
-
while cntb < rowb
|
184
|
-
res[row_idx][@col_ind[cntb]] -= matrix.val[cntb]
|
185
|
-
cntb += 1;
|
186
|
-
end
|
187
|
-
row_idx += 1;
|
197
|
+
res = Array.new(@rows) { Array.new(@columns, 0) }
|
198
|
+
row_idx = 0
|
199
|
+
cnta = 0 # total logged entries for matrix a
|
200
|
+
cntb = 0
|
201
|
+
while row_idx < @rows # eg. 0 1 2
|
202
|
+
rowa = @row_ptr[row_idx + 1] # eg. 0 2 4 7
|
203
|
+
rowb = matrix.row_ptr[row_idx + 1]
|
204
|
+
while cnta < rowa
|
205
|
+
# keep adding values to res until they're equal
|
206
|
+
res[row_idx][@col_ind[cnta]] += @val[cnta]
|
207
|
+
cnta += 1;
|
188
208
|
end
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
209
|
+
while cntb < rowb
|
210
|
+
res[row_idx][@col_ind[cntb]] += matrix.val[cntb]
|
211
|
+
cntb += 1;
|
212
|
+
end
|
213
|
+
row_idx += 1;
|
214
|
+
end
|
215
|
+
return res
|
216
|
+
end # matrix_add
|
194
217
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
218
|
+
Contract MContracts::TwoDMatrixType => C::ArrayOf[C::ArrayOf[C::Num]]
|
219
|
+
def matrix_subtract(matrix)
|
220
|
+
# subtracts a matrix to existing matrix
|
221
|
+
is_invariant?
|
222
|
+
if !self.is_same_dim(matrix)
|
223
|
+
raise Exceptions::MatrixDimException.new, "Matrix does not have same dimensions; cannot subtract."
|
200
224
|
return false
|
201
225
|
end
|
226
|
+
|
227
|
+
res = Array.new(@rows) { Array.new(@columns, 0) }
|
228
|
+
row_idx = 0
|
229
|
+
cnta = 0 # total logged entries for matrix a
|
230
|
+
cntb = 0
|
231
|
+
while row_idx < @rows # eg. 0 1 2
|
232
|
+
rowa = @row_ptr[row_idx + 1] # eg. 0 2 4 7
|
233
|
+
rowb = matrix.row_ptr[row_idx + 1]
|
234
|
+
while cnta < rowa
|
235
|
+
# keep adding values to res until they're equal
|
236
|
+
res[row_idx][@col_ind[cnta]] += @val[cnta]
|
237
|
+
cnta += 1;
|
238
|
+
end
|
239
|
+
while cntb < rowb
|
240
|
+
res[row_idx][@col_ind[cntb]] -= matrix.val[cntb]
|
241
|
+
cntb += 1;
|
242
|
+
end
|
243
|
+
row_idx += 1;
|
244
|
+
end
|
245
|
+
return res
|
246
|
+
end # matrix_subtract
|
247
|
+
|
248
|
+
Contract MContracts::TwoDMatrixType => C::ArrayOf[C::ArrayOf[C::Num]]
|
249
|
+
def multiply_inverse(matrix)
|
250
|
+
# divides (multiply by the inverse of ) a matrix to existing matrix
|
251
|
+
# sets y * x^-1, where x is your matrix and y is the accepted matrix
|
252
|
+
is_invariant?
|
202
253
|
if !matrix.square? || !self.square?
|
203
254
|
raise Exceptions::MatrixDimException.new, "Matrices does not have usable dimensions; cannot divide."
|
204
255
|
return false
|
205
256
|
end
|
257
|
+
|
206
258
|
tmpmatrix = TwoDMatrix.new
|
207
259
|
tmpmatrix = matrix
|
208
260
|
tmpmatrix.inverse()
|
209
261
|
return self.multiply_csr(tmpmatrix)
|
210
|
-
end
|
262
|
+
end # matrix_inverse
|
211
263
|
|
212
264
|
# multiply x by y^-1; x * y^-1
|
213
|
-
|
214
|
-
def
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
end
|
265
|
+
Contract MContracts::TwoDMatrixType => C::ArrayOf[C::ArrayOf[C::Num]]
|
266
|
+
def inverse_multiply(matrix)
|
267
|
+
# divides (multiply by the inverse of ) a matrix to existing matrix
|
268
|
+
# sets x * y^-1, where x is your matrix and y is the accepted matrix
|
269
|
+
is_invariant?
|
219
270
|
if !matrix.square? || !self.square?
|
220
271
|
raise Exceptions::MatrixDimException.new, "Matrices does not have usable dimensions; cannot divide."
|
221
272
|
return false
|
222
273
|
end
|
274
|
+
|
223
275
|
tmpmatrix = TwoDMatrix.new
|
224
276
|
tmpmatrix = self
|
225
277
|
tmpmatrix.inverse()
|
226
278
|
return matrix.multiply_csr(tmpmatrix)
|
279
|
+
end # inverse_multiply
|
280
|
+
|
281
|
+
Contract C::None => C::Num
|
282
|
+
def count_in_dim()
|
283
|
+
is_invariant?
|
284
|
+
# helper function, identifies the number of expected values in matrix
|
285
|
+
# eg. 2x2 matrix returns 4 values
|
286
|
+
return self.rows * self.columns
|
227
287
|
end
|
228
288
|
|
229
|
-
|
230
|
-
|
289
|
+
Contract MContracts::TwoDMatrixType => C::ArrayOf[C::ArrayOf[C::Num]]
|
290
|
+
def matrix_division(matrix)
|
291
|
+
# linear division of one matrix to the next
|
292
|
+
is_invariant?
|
293
|
+
if matrix.val.count() != matrix.count_in_dim()
|
294
|
+
raise Exceptions::DivideByZeroException.new, "Calculations return divide by zero error."
|
295
|
+
return false
|
296
|
+
end
|
297
|
+
if !self.is_same_dim(matrix)
|
298
|
+
raise Exceptions::MatrixDimException.new, "Matrix does not have same dimensions; cannot add."
|
299
|
+
return false
|
300
|
+
end
|
301
|
+
|
302
|
+
res = Array.new(@rows) { Array.new(@columns, 0) }
|
303
|
+
row_idx = 0
|
304
|
+
cnta = 0 # total logged entries for matrix a
|
305
|
+
cntb = 0
|
306
|
+
while row_idx < @rows # eg. 0 1 2
|
307
|
+
rowa = @row_ptr[row_idx + 1] # eg. 0 2 4 7
|
308
|
+
rowb = matrix.row_ptr[row_idx + 1]
|
309
|
+
while cnta < rowa
|
310
|
+
# keep adding values to res until they're equal
|
311
|
+
res[row_idx][@col_ind[cnta]] += @val[cnta]
|
312
|
+
cnta += 1;
|
313
|
+
end
|
314
|
+
while cntb < rowb
|
315
|
+
res[row_idx][@col_ind[cntb]] = res[row_idx][@col_ind[cntb]].to_f / matrix.val[cntb]
|
316
|
+
cntb += 1;
|
317
|
+
end
|
318
|
+
row_idx += 1;
|
319
|
+
end
|
320
|
+
return res
|
321
|
+
end # matrix_division
|
322
|
+
|
323
|
+
Contract C::ArrayOf[C::Num] => C::Nat
|
231
324
|
def max_row(array)
|
325
|
+
# Identifies the 'row' value of an array (eg. the number of entries in a row)
|
326
|
+
is_invariant?
|
327
|
+
|
232
328
|
values = array
|
233
329
|
max_count = 0
|
234
330
|
values.each_index do |i|
|
235
331
|
max_count += 1
|
236
332
|
end
|
237
333
|
return max_count
|
238
|
-
end
|
334
|
+
end # max_row
|
239
335
|
|
240
|
-
end
|
241
|
-
end
|
336
|
+
end # Arithmetic
|
337
|
+
end # CsrMatrix
|
@@ -1,22 +1,24 @@
|
|
1
1
|
module CsrMatrix
|
2
|
-
|
2
|
+
module Decompositions
|
3
|
+
include Contracts::Core
|
4
|
+
C = Contracts
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
6
|
+
Contract C::None => C::ArrayOf[C::ArrayOf[C::Num]]
|
7
|
+
def eigen()
|
8
|
+
# alias for eigensystem
|
9
|
+
# returns a list in the form {eigenvalues, eigenvectors}
|
10
|
+
is_invariant?
|
11
|
+
|
12
|
+
self.eigenvalue()
|
13
|
+
end # eigen
|
14
|
+
|
15
|
+
Contract C::None => C::ArrayOf[C::ArrayOf[C::Num]]
|
16
|
+
def eigenvalue()
|
17
|
+
# identifies the eigenvalues of a matrix
|
18
|
+
is_invariant?
|
19
|
+
# post eigenvalues of the matrix
|
20
|
+
m = Matrix.rows(self.decompose)
|
21
|
+
return m.eigensystem().to_a[1].round().to_a
|
22
|
+
end # eigenvalue
|
23
|
+
end # Decompositions
|
24
|
+
end # CsrMatrix
|
data/lib/csrmatrix/exceptions.rb
CHANGED
@@ -1,11 +1,24 @@
|
|
1
1
|
module CsrMatrix
|
2
2
|
module Exceptions
|
3
|
-
|
3
|
+
# Occurs when user enters a null matrix for processing.
|
4
|
+
class NullMatrixException < StandardError; end
|
5
|
+
|
6
|
+
# Occurs when a sparse matrix operation occurs wherein its dimensions result in the operation being unavailable.
|
4
7
|
class MatrixDimException < StandardError; end
|
5
|
-
|
6
|
-
|
8
|
+
|
9
|
+
# Occurs when the matrix builder expects a specific type; and is provided the wrong type to generate the sparse matrix.
|
10
|
+
class MatrixTypeException < StandardError; end
|
11
|
+
|
12
|
+
# Occurs when the system divides by 0; standard arithmetic error.
|
7
13
|
class DivideByZeroException < StandardError; end
|
14
|
+
|
15
|
+
# Occurs when index queried is out of range of the matrix.
|
8
16
|
class IndexOutOfRangeException < StandardError; end
|
17
|
+
|
18
|
+
# Occurs when the sparse matrix is used in processing against a null / nil value.
|
9
19
|
class ArgumentNullException < StandardError; end
|
10
|
-
|
11
|
-
|
20
|
+
|
21
|
+
#
|
22
|
+
class InvariantError < StandardError; end
|
23
|
+
end # exceptions
|
24
|
+
end # csrmatrix
|