rmds 0.2
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.
- data/LICENSE.md +27 -0
- data/README.md +157 -0
- data/Rakefile +77 -0
- data/examples/adaptive_backend.rb +61 -0
- data/examples/extended_metric.rb +82 -0
- data/examples/minimal_metric.rb +52 -0
- data/examples/visualization.rb +75 -0
- data/examples/visualization_cities.rb +84 -0
- data/lib/mds.rb +22 -0
- data/lib/mds/backend.rb +105 -0
- data/lib/mds/interfaces/gsl_interface.rb +140 -0
- data/lib/mds/interfaces/linalg_interface.rb +149 -0
- data/lib/mds/interfaces/stdlib_interface.rb +155 -0
- data/lib/mds/io.rb +29 -0
- data/lib/mds/matrix.rb +258 -0
- data/lib/mds/matrix_interface.rb +358 -0
- data/lib/mds/metric.rb +150 -0
- data/lib/mds/test/bundles/bundle_matrix_interface.rb +199 -0
- data/lib/mds/test/bundles/bundle_metric.rb +82 -0
- data/lib/mds/test/matrix_assertions.rb +54 -0
- data/test/benchmark/benchmark_metric.rb +53 -0
- data/test/test_helper.rb +11 -0
- data/test/unit/dummy_interfaces.rb +20 -0
- data/test/unit/test_backend.rb +44 -0
- data/test/unit/test_gsl_interface.rb +22 -0
- data/test/unit/test_gsl_metric.rb +22 -0
- data/test/unit/test_linalg_interface.rb +22 -0
- data/test/unit/test_linalg_metric.rb +21 -0
- data/test/unit/test_stdlib_interface.rb +22 -0
- data/test/unit/test_stdlib_metric.rb +21 -0
- metadata +101 -0
data/lib/mds/metric.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
#
|
2
|
+
# RMDS - Ruby Multidimensional Scaling Library
|
3
|
+
# Copyright (c) Christoph Heindl, 2010
|
4
|
+
# http://github.com/cheind/rmds
|
5
|
+
#
|
6
|
+
|
7
|
+
module MDS
|
8
|
+
|
9
|
+
#
|
10
|
+
# In metric MDS dissimilarities are interpreted as distances und
|
11
|
+
# the goal is to find an embedding in an Euclidean space that best preserves
|
12
|
+
# the given distances.
|
13
|
+
#
|
14
|
+
# This implementation gives an analytical solution and avoids iterative
|
15
|
+
# optimization. The performance of the algorithm highly depends on the
|
16
|
+
# implementation of the eigen-decomposition provided via {MDS::MatrixInterface}.
|
17
|
+
#
|
18
|
+
# *Examples*
|
19
|
+
# - {Examples.minimal_metric}
|
20
|
+
# - {Examples.extended_metric}
|
21
|
+
#
|
22
|
+
class Metric
|
23
|
+
|
24
|
+
#
|
25
|
+
# Find a Cartesian embedding for the given distances.
|
26
|
+
#
|
27
|
+
# Instead of a fixed dimensionality for the resulting embedding, this
|
28
|
+
# method determines the dimensionality based on the variances of distances
|
29
|
+
# in its input matrix and the parameter passed. The parameter specifies
|
30
|
+
# the percent of variance of distance to preserve in the Cartesian embedding.
|
31
|
+
#
|
32
|
+
# @param [MDS::Matrix] d squared Eulcidean distance matrix of observations
|
33
|
+
# @param [Float] k the percent of variance of distances
|
34
|
+
# to preserve in embedding in the range [0..1].
|
35
|
+
# @return [MDS::Matrix] the matrix containing the cartesian embedding.
|
36
|
+
#
|
37
|
+
def Metric.projectk(d, k)
|
38
|
+
b = Metric.shift(d)
|
39
|
+
eval, evec = b.ed
|
40
|
+
dims = Metric.find_dimensionality(eval, k)
|
41
|
+
Metric.project(eval, evec, dims)
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Find a Cartesian embedding for the given distances.
|
46
|
+
#
|
47
|
+
# @param [MDS::Matrix] d squared Eulcidean distance matrix of observations
|
48
|
+
# @param [Integer] dims the number of dimensions of the embedding.
|
49
|
+
# @return [MDS::Matrix] the matrix containing the cartesian embedding.
|
50
|
+
#
|
51
|
+
def Metric.projectd(d, dims)
|
52
|
+
b = Metric.shift(d)
|
53
|
+
eval, evec = b.ed
|
54
|
+
Metric.project(eval, evec, dims)
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Calculates the squared Euclidean distances for all
|
59
|
+
# pairwise observations in the given matrix. Each observation
|
60
|
+
# corresponds to a matrix row and is provided in Cartesian coordinates.
|
61
|
+
#
|
62
|
+
# The result is a real symmetric matrix of size +NxN+, where +N+ is the
|
63
|
+
# number of observations in the input. Each element +(i,j)+ in this matrix
|
64
|
+
# corresponds to the squared distance between the i-th and j-th observation
|
65
|
+
# in the input matrix.
|
66
|
+
#
|
67
|
+
# @param [MDS::Matrix] x the matrix of observations.
|
68
|
+
# @return [MDS::Matrix] the squared Euclidean distance matrix
|
69
|
+
#
|
70
|
+
def Metric.squared_distances(x)
|
71
|
+
# Product of x with transpose of x
|
72
|
+
xxt = x * x.t
|
73
|
+
# 1xN matrix of ones, where N size of xxt
|
74
|
+
ones = Matrix.create(1, xxt.nrows, 1.0)
|
75
|
+
# Nx1 matrix containing diagonal elements of x
|
76
|
+
diagonals = xxt.diagonals
|
77
|
+
c = Matrix.create_block(xxt.nrows, 1) do |i, j|
|
78
|
+
diagonals[i]
|
79
|
+
end
|
80
|
+
c * ones + (c * ones).t - xxt * 2
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
#
|
87
|
+
# Transform the squared distance matrix into a matrix of Cartesian
|
88
|
+
# coordinates by projecting the distances onto the basis formed by
|
89
|
+
# the eigen-decomposition of the initial matrix.
|
90
|
+
#
|
91
|
+
# @param [MDS::Matrix] d squared Euclidean distance matrix
|
92
|
+
# @param [Float] k percent [0..1] of variances in distances to keep in embedding.
|
93
|
+
# @return [MDS::Matrix] containing the Cartesian embedding.
|
94
|
+
#
|
95
|
+
def Metric.project(eval, evec, dims)
|
96
|
+
lam = eval.minor(0..eval.nrows-1, 0..dims-1)
|
97
|
+
for i in 0..lam.ncols-1
|
98
|
+
v = lam[i,i]
|
99
|
+
if v > 0.0
|
100
|
+
lam[i,i] = Math.sqrt(v)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
evec * lam
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Transforms the distance matrix into an equivalent scalar product
|
108
|
+
# matrix.
|
109
|
+
#
|
110
|
+
# @param [MDS::Matrix] d the squared Euclidean distance matrix
|
111
|
+
# @return [MDS::Matrix] the equivalent scalar product matrix.
|
112
|
+
#
|
113
|
+
def Metric.shift(d)
|
114
|
+
# Nx1 matrix of ones
|
115
|
+
ones = Matrix.create(d.nrows, 1, 1.0)
|
116
|
+
# 1xN weight vector
|
117
|
+
m = Matrix.create(1, d.nrows, 1.0/d.nrows)
|
118
|
+
# NxN centering matrix
|
119
|
+
xi = Matrix.create_identity(d.nrows) - ones * m
|
120
|
+
# NxN shifted distances matrix, B
|
121
|
+
(xi * d * xi.t) * -0.5
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
#
|
126
|
+
# Find the dimensionality of the resulting coordinate space so that
|
127
|
+
# at least +k+ percent of the variance of the distances is preserved.
|
128
|
+
#
|
129
|
+
# @param [MDS::Matrix] eval the diagonal matrix of sorted eigen-values.
|
130
|
+
# @param [Float] k percent of variance to keep.
|
131
|
+
# @return [Integer] minimum number of dimensions to use, to keep k-percent
|
132
|
+
# of variances of distances in embedding.
|
133
|
+
#
|
134
|
+
def Metric.find_dimensionality(eval, k)
|
135
|
+
sum_ev = eval.trace
|
136
|
+
n = eval.nrows
|
137
|
+
|
138
|
+
i = 0
|
139
|
+
sum = 0
|
140
|
+
while ((i < n) &&
|
141
|
+
(eval[i,i] > 0.0) &&
|
142
|
+
(sum / sum_ev) < k)
|
143
|
+
sum += eval[i,i]
|
144
|
+
i += 1
|
145
|
+
end
|
146
|
+
i
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
#
|
2
|
+
# RMDS - Ruby Multidimensional Scaling Library
|
3
|
+
# Copyright (c) Christoph Heindl, 2010
|
4
|
+
# http://github.com/cheind/rmds
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'mds/test/matrix_assertions.rb'
|
8
|
+
|
9
|
+
module MDS
|
10
|
+
module Test
|
11
|
+
|
12
|
+
#
|
13
|
+
# Module containing standarized tests for matrix interfaces.
|
14
|
+
#
|
15
|
+
module BundleMatrixInterface
|
16
|
+
include MDS::Test::MatrixAssertions
|
17
|
+
|
18
|
+
#----------------------------
|
19
|
+
# Matrix creators
|
20
|
+
#----------------------------
|
21
|
+
|
22
|
+
def test_create
|
23
|
+
m = MDS::Matrix.create(2, 3, 0.0)
|
24
|
+
assert_equal(2, m.nrows)
|
25
|
+
assert_equal(3, m.ncols)
|
26
|
+
|
27
|
+
for i in 0..m.nrows-1 do
|
28
|
+
for j in 0..m.ncols-1 do
|
29
|
+
assert_instance_of(Float, m[i,j])
|
30
|
+
assert_equal(0.0, m[i,j])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_create_identity
|
36
|
+
m = MDS::Matrix.create_identity(3)
|
37
|
+
r = MDS::Matrix.create(3, 3, 0.0)
|
38
|
+
r[0,0] = 1.0; r[1,1] = 1.0; r[2,2] = 1.0;
|
39
|
+
assert_equal_matrices(m, r)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_create_diagonal
|
43
|
+
m = MDS::Matrix.create_diagonal(1.0, 2.0, 3.0)
|
44
|
+
r = MDS::Matrix.create(3, 3, 0.0)
|
45
|
+
r[0,0] = 1.0; r[1,1] = 2.0; r[2,2] = 3.0;
|
46
|
+
assert_equal_matrices(m, r)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_create_block
|
50
|
+
m = MDS::Matrix.create_block(2,2) do |i,j|
|
51
|
+
i == j ? 0.0 : 1.0
|
52
|
+
end
|
53
|
+
r = MDS::Matrix.create(3, 3, 1.0)
|
54
|
+
r[0,0] = 0.0; r[1,1] = 0.0;
|
55
|
+
assert_equal_matrices(m, r)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_create_rows
|
59
|
+
m = MDS::Matrix.create_rows([1.0, 2.0, 3.0], [4.0, 5.0, 6.0])
|
60
|
+
r = MDS::Matrix.create_block(2,3) do |i,j|
|
61
|
+
(i*3 + j + 1).to_f
|
62
|
+
end
|
63
|
+
assert_equal_matrices(m, r)
|
64
|
+
end
|
65
|
+
|
66
|
+
#----------------------------
|
67
|
+
# Matrix element accessors
|
68
|
+
#----------------------------
|
69
|
+
|
70
|
+
def test_get_set
|
71
|
+
a = MDS::Matrix.create(2, 2, 1.0)
|
72
|
+
|
73
|
+
a[0,0] = 1.0
|
74
|
+
a[0,1] = 2.0
|
75
|
+
a[1,0] = 3.0
|
76
|
+
a[1,1] = 4.0
|
77
|
+
|
78
|
+
assert_equal(1.0, a[0,0])
|
79
|
+
assert_equal(2.0, a[0,1])
|
80
|
+
assert_equal(3.0, a[1,0])
|
81
|
+
assert_equal(4.0, a[1,1])
|
82
|
+
end
|
83
|
+
|
84
|
+
#----------------------------
|
85
|
+
# Matrix views
|
86
|
+
#----------------------------
|
87
|
+
|
88
|
+
def test_transpose
|
89
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 2.0, 3.0])
|
90
|
+
r = MDS::Matrix.create_rows([2.0, 1.0], [3.0, 2.0], [4.0, 3.0])
|
91
|
+
m = a.t
|
92
|
+
assert_delta_matrices(r, m)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_diagonals
|
96
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 4.0, 3.0])
|
97
|
+
r = MDS::Matrix.create_rows([2.0, 4.0])
|
98
|
+
m = MDS::Matrix.create_rows(a.diagonals)
|
99
|
+
assert_delta_matrices(r, m)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_minor
|
103
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 4.0, 3.0])
|
104
|
+
r = MDS::Matrix.create_rows([4.0],[3.0])
|
105
|
+
m = a.minor(0..1, 2..2)
|
106
|
+
assert_delta_matrices(r, m)
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_trace
|
110
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 4.0, 3.0])
|
111
|
+
assert_equal(6.0, a.trace)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_columns
|
115
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 4.0, 3.0])
|
116
|
+
assert_equal([[2.0, 1.0], [3.0, 4.0], [4.0, 3.0]], a.columns)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_rows
|
120
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 4.0, 3.0])
|
121
|
+
assert_equal([[2.0, 3.0, 4.0], [1.0, 4.0, 3.0]], a.rows)
|
122
|
+
end
|
123
|
+
|
124
|
+
#----------------------------
|
125
|
+
# Matrix operations
|
126
|
+
#----------------------------
|
127
|
+
|
128
|
+
def test_product
|
129
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 2.0, 3.0])
|
130
|
+
b = MDS::Matrix.create_rows([3.0, 1.0], [1.0, 2.0], [3.0, -4.0])
|
131
|
+
r = MDS::Matrix.create_rows([21.0, -8.0], [14.0, -7.0])
|
132
|
+
|
133
|
+
m = a * b
|
134
|
+
assert_delta_matrices(r, m)
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_product_scalar
|
138
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 2.0, 3.0])
|
139
|
+
r = MDS::Matrix.create_rows([4.0, 6.0, 8.0], [2.0, 4.0, 6.0])
|
140
|
+
m = a * 2.0
|
141
|
+
assert_delta_matrices(r, m)
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_add
|
145
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 2.0, 3.0])
|
146
|
+
b = MDS::Matrix.create_rows([1.0, 2.0, 3.0], [0.0, 0.0, 2.0])
|
147
|
+
r = MDS::Matrix.create_rows([3.0, 5.0, 7.0], [1.0, 2.0, 5.0])
|
148
|
+
m = a + b
|
149
|
+
assert_delta_matrices(r, m)
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_sub
|
153
|
+
a = MDS::Matrix.create_rows([2.0, 3.0, 4.0], [1.0, 2.0, 3.0])
|
154
|
+
b = MDS::Matrix.create_rows([1.0, 2.0, 2.0], [0.0, 0.0, 2.0])
|
155
|
+
r = MDS::Matrix.create_rows([1.0, 1.0, 2.0], [1.0, 2.0, 1.0])
|
156
|
+
m = a - b
|
157
|
+
assert_delta_matrices(r, m)
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_ed
|
161
|
+
a = MDS::Matrix.create_rows(
|
162
|
+
[0.0, 10.0, 2.0],
|
163
|
+
[10.0, 0.0, 20.0],
|
164
|
+
[2.0, 20.0, 0.0]
|
165
|
+
)
|
166
|
+
|
167
|
+
eval_a, evec_a = a.ed
|
168
|
+
|
169
|
+
assert_in_delta(23.2051, eval_a[0,0], 1e-3)
|
170
|
+
assert_in_delta(-1.5954, eval_a[1,1], 1e-3)
|
171
|
+
assert_in_delta(-21.6097, eval_a[2,2], 1e-3)
|
172
|
+
|
173
|
+
r0 = MDS::Matrix.create_rows([0.3529, 0.6934, 0.6281])
|
174
|
+
r1 = MDS::Matrix.create_rows([0.8948, -0.0541, -0.4430])
|
175
|
+
r2 = MDS::Matrix.create_rows([-0.2732, 0.7184, -0.6396])
|
176
|
+
|
177
|
+
v0 = evec_a.minor(0..2, 0..0)
|
178
|
+
v1 = evec_a.minor(0..2, 1..1)
|
179
|
+
v2 = evec_a.minor(0..2, 2..2)
|
180
|
+
|
181
|
+
# Norm of vectors
|
182
|
+
assert_in_delta(1.0, (v0.t * v0)[0,0], 1e-3)
|
183
|
+
assert_in_delta(1.0, (v1.t * v1)[0,0], 1e-3)
|
184
|
+
assert_in_delta(1.0, (v2.t * v2)[0,0], 1e-3)
|
185
|
+
|
186
|
+
# Orthogonality of basis vectors
|
187
|
+
assert_in_delta(0.0, (v0.t * v1)[0,0], 1e-3)
|
188
|
+
assert_in_delta(0.0, (v0.t * v2)[0,0], 1e-3)
|
189
|
+
assert_in_delta(0.0, (v1.t * v2)[0,0], 1e-3)
|
190
|
+
|
191
|
+
# Orientation of basis vectors (up to 180° ambiguity)
|
192
|
+
assert_in_delta(1.0, (r0 * v0)[0,0].abs, 1e-3)
|
193
|
+
assert_in_delta(1.0, (r1 * v1)[0,0].abs, 1e-3)
|
194
|
+
assert_in_delta(1.0, (r2 * v2)[0,0].abs, 1e-3)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#
|
2
|
+
# RMDS - Ruby Multidimensional Scaling Library
|
3
|
+
# Copyright (c) Christoph Heindl, 2010
|
4
|
+
# http://github.com/cheind/rmds
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'mds/test/matrix_assertions.rb'
|
8
|
+
|
9
|
+
module MDS
|
10
|
+
module Test
|
11
|
+
|
12
|
+
#
|
13
|
+
# Module containing standarized tests for MDS::Metric.
|
14
|
+
#
|
15
|
+
module BundleMetric
|
16
|
+
include MDS::Test::MatrixAssertions
|
17
|
+
|
18
|
+
def test_squared_distances
|
19
|
+
input = MDS::Matrix.create_rows(
|
20
|
+
[1.0, 2.0],
|
21
|
+
[4.0, 3.0],
|
22
|
+
[0.0, 1.0]
|
23
|
+
)
|
24
|
+
|
25
|
+
output = MDS::Matrix.create_rows(
|
26
|
+
[0.0, 10.0, 2.0],
|
27
|
+
[10.0, 0.0, 20.0],
|
28
|
+
[2.0, 20.0, 0.0]
|
29
|
+
)
|
30
|
+
|
31
|
+
d = MDS::Metric.squared_distances(input)
|
32
|
+
assert_equal_matrices(output, d)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_k_2d
|
36
|
+
x = MDS::Matrix.create_rows(
|
37
|
+
[1.0, 2.0],
|
38
|
+
[4.0, 3.0],
|
39
|
+
[0.0, 1.0]
|
40
|
+
)
|
41
|
+
d = MDS::Metric::squared_distances(x)
|
42
|
+
proj = MDS::Metric.projectk(d, 0.99)
|
43
|
+
dd = MDS::Metric.squared_distances(proj)
|
44
|
+
assert_delta_matrices(d, dd, 1e-5)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_d_2d
|
48
|
+
x = MDS::Matrix.create_rows(
|
49
|
+
[1.0, 2.0],
|
50
|
+
[4.0, 3.0],
|
51
|
+
[0.0, 1.0]
|
52
|
+
)
|
53
|
+
d = MDS::Metric.squared_distances(x)
|
54
|
+
|
55
|
+
proj = MDS::Metric.projectd(d, 2)
|
56
|
+
dd = MDS::Metric.squared_distances(proj)
|
57
|
+
assert_delta_matrices(d, dd, 1e-5)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_k_5d
|
61
|
+
x = MDS::Matrix.create_random(10, 5, -10, 10)
|
62
|
+
d = MDS::Metric.squared_distances(x)
|
63
|
+
|
64
|
+
proj = MDS::Metric.projectk(d, 1.0)
|
65
|
+
dd = MDS::Metric.squared_distances(proj)
|
66
|
+
assert_delta_matrices(d, dd, 1e-5)
|
67
|
+
|
68
|
+
proj = MDS::Metric.projectk(d, 0.8)
|
69
|
+
dd = MDS::Metric.squared_distances(proj)
|
70
|
+
assert_delta_matrices(d, dd, 5e2)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_d_5d
|
74
|
+
x = MDS::Matrix.create_random(10, 5, -10, 10)
|
75
|
+
d = MDS::Metric.squared_distances(x)
|
76
|
+
proj = MDS::Metric.projectd(d, 10)
|
77
|
+
dd = MDS::Metric.squared_distances(proj)
|
78
|
+
assert_delta_matrices(d, dd, 1e-5)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#
|
2
|
+
# RMDS - Ruby Multidimensional Scaling Library
|
3
|
+
# Copyright (c) Christoph Heindl, 2010
|
4
|
+
# http://github.com/cheind/rmds
|
5
|
+
#
|
6
|
+
|
7
|
+
module MDS
|
8
|
+
module Test
|
9
|
+
|
10
|
+
#
|
11
|
+
# Addition assertions for comparing matrices.
|
12
|
+
#
|
13
|
+
module MatrixAssertions
|
14
|
+
|
15
|
+
#
|
16
|
+
# Assert that two matrices are equal
|
17
|
+
#
|
18
|
+
# @param [MDS::Matrix] a first matrix
|
19
|
+
# @param [MDS::Matrix] b second matrix
|
20
|
+
#
|
21
|
+
def assert_equal_matrices(a, b)
|
22
|
+
assert_instance_of(a.matrix.class, b.matrix)
|
23
|
+
assert(a.nrows, b.nrows)
|
24
|
+
assert(a.ncols, b.ncols)
|
25
|
+
|
26
|
+
for i in 0..a.nrows-1 do
|
27
|
+
for j in 0..a.ncols-1 do
|
28
|
+
assert_equal(a[i,j], b[i,j])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Assert that two matrices are equal up to delta
|
35
|
+
#
|
36
|
+
# @param [MDS::Matrix] first matrix
|
37
|
+
# @param [MDS::Matrix] second matrix
|
38
|
+
# @param [Float] delta delta
|
39
|
+
#
|
40
|
+
def assert_delta_matrices(a, b, delta = 1e-10)
|
41
|
+
assert_instance_of(a.matrix.class, b.matrix)
|
42
|
+
assert(a.nrows, b.nrows)
|
43
|
+
assert(a.ncols, b.ncols)
|
44
|
+
|
45
|
+
for i in 0..a.nrows-1 do
|
46
|
+
for j in 0..a.ncols-1 do
|
47
|
+
assert_in_delta(a[i,j], b[i,j], delta)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|