rmds 0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|