numo-linalg 0.1.2 → 0.1.3
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/README.md +7 -3
- data/ext/numo/linalg/blas/extconf.rb +1 -2
- data/ext/numo/linalg/blas/numo_blas.h +6 -0
- data/ext/numo/linalg/blas/tmpl/mv.c +3 -2
- data/ext/numo/linalg/lapack/gen/spec.rb +5 -0
- data/ext/numo/linalg/lapack/lapack.c +29 -0
- data/ext/numo/linalg/lapack/numo_lapack.h +3 -0
- data/ext/numo/linalg/lapack/tmpl/gqr.c +1 -1
- data/ext/numo/linalg/lapack/tmpl/sygvx.c +130 -0
- data/ext/numo/linalg/mkmf_linalg.rb +2 -19
- data/lib/numo/linalg/function.rb +168 -77
- data/lib/numo/linalg/loader.rb +6 -14
- data/lib/numo/linalg/version.rb +1 -1
- data/numo-linalg.gemspec +2 -1
- data/spec/linalg/autoloader_spec.rb +27 -0
- data/spec/linalg/function/cho_fact_spec.rb +31 -0
- data/spec/linalg/function/cho_inv_spec.rb +39 -0
- data/spec/linalg/function/cho_solve_spec.rb +66 -0
- data/spec/linalg/function/cholesky_spec.rb +43 -0
- data/spec/linalg/function/cond_spec.rb +57 -0
- data/spec/linalg/function/det_spec.rb +21 -0
- data/spec/linalg/function/dot_spec.rb +84 -0
- data/spec/linalg/function/eig_spec.rb +53 -0
- data/spec/linalg/function/eigh_spec.rb +81 -0
- data/spec/linalg/function/eigvals_spec.rb +27 -0
- data/spec/linalg/function/eigvalsh_spec.rb +60 -0
- data/spec/linalg/function/inv_spec.rb +57 -0
- data/spec/linalg/function/ldl_spec.rb +51 -0
- data/spec/linalg/function/lstsq_spec.rb +80 -0
- data/spec/linalg/function/lu_fact_spec.rb +34 -0
- data/spec/linalg/function/lu_inv_spec.rb +21 -0
- data/spec/linalg/function/lu_solve_spec.rb +40 -0
- data/spec/linalg/function/lu_spec.rb +46 -0
- data/spec/linalg/function/matmul_spec.rb +41 -0
- data/spec/linalg/function/matrix_power_spec.rb +31 -0
- data/spec/linalg/function/matrix_rank_spec.rb +33 -0
- data/spec/linalg/function/norm_spec.rb +81 -0
- data/spec/linalg/function/pinv_spec.rb +48 -0
- data/spec/linalg/function/qr_spec.rb +82 -0
- data/spec/linalg/function/slogdet_spec.rb +21 -0
- data/spec/linalg/function/solve_spec.rb +98 -0
- data/spec/linalg/function/svd_spec.rb +88 -0
- data/spec/linalg/function/svdvals_spec.rb +40 -0
- data/spec/spec_helper.rb +55 -0
- metadata +79 -6
- data/spec/lapack_spec.rb +0 -13
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Numo::Linalg do
|
6
|
+
describe 'lu' do
|
7
|
+
let(:m) { 5 }
|
8
|
+
let(:n) { 3 }
|
9
|
+
let(:mat_a) { rand_rect_real_mat(m, n) }
|
10
|
+
let(:mat_b) { rand_rect_real_mat(n, m) }
|
11
|
+
let(:mat_c) { rand_rect_complex_mat(m, n) }
|
12
|
+
let(:mat_d) { rand_rect_complex_mat(n, m) }
|
13
|
+
|
14
|
+
it 'raises ShapeError given a vector' do
|
15
|
+
expect { described_class.lu(Numo::DFloat.new(3).rand) }.to raise_error(Numo::NArray::ShapeError)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'calculates the LU factorization of a rectangular real matrix' do
|
19
|
+
mat_p, mat_l, mat_u = described_class.lu(mat_a)
|
20
|
+
expect((mat_a - mat_p.dot(mat_l.dot(mat_u))).abs.max).to be < ERR_TOL
|
21
|
+
mat_p, mat_l, mat_u = described_class.lu(mat_b)
|
22
|
+
expect((mat_b - mat_p.dot(mat_l.dot(mat_u))).abs.max).to be < ERR_TOL
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'calculates the LU factorization of a rectangular real matrix including permutation of L' do
|
26
|
+
mat_l, mat_u = described_class.lu(mat_a, permute_l: true)
|
27
|
+
expect((mat_a - mat_l.dot(mat_u)).abs.max).to be < ERR_TOL
|
28
|
+
mat_l, mat_u = described_class.lu(mat_b, permute_l: true)
|
29
|
+
expect((mat_b - mat_l.dot(mat_u)).abs.max).to be < ERR_TOL
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'calculates the LU factorization of a rectangular complex matrix' do
|
33
|
+
mat_p, mat_l, mat_u = described_class.lu(mat_c)
|
34
|
+
expect((mat_c - mat_p.dot(mat_l.dot(mat_u))).abs.max).to be < ERR_TOL
|
35
|
+
mat_p, mat_l, mat_u = described_class.lu(mat_d)
|
36
|
+
expect((mat_d - mat_p.dot(mat_l.dot(mat_u))).abs.max).to be < ERR_TOL
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'calculates the LU factorization of a rectangular complex matrix including permutation of L' do
|
40
|
+
mat_l, mat_u = described_class.lu(mat_c, permute_l: true)
|
41
|
+
expect((mat_c - mat_l.dot(mat_u)).abs.max).to be < ERR_TOL
|
42
|
+
mat_l, mat_u = described_class.lu(mat_d, permute_l: true)
|
43
|
+
expect((mat_d - mat_l.dot(mat_u)).abs.max).to be < ERR_TOL
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Numo::Linalg do
|
6
|
+
describe 'matmul' do
|
7
|
+
let(:m) { 5 }
|
8
|
+
let(:n) { 3 }
|
9
|
+
let(:mat_s) { Numo::SFloat.new(m, n).rand }
|
10
|
+
let(:mat_d) { Numo::DFloat.new(m, n).rand }
|
11
|
+
let(:mat_c) { Numo::SComplex.new(m, n).rand }
|
12
|
+
let(:mat_z) { Numo::DComplex.new(m, n).rand }
|
13
|
+
|
14
|
+
def dot_vec_vec(a, b)
|
15
|
+
Array.new(a.size) { |idx| a[idx] * b[idx] }.reduce(&:+)
|
16
|
+
end
|
17
|
+
|
18
|
+
def dot_mat_vec(a, b)
|
19
|
+
n, = a.shape
|
20
|
+
Numo::NArray.asarray(Array.new(n) { |idx| dot_vec_vec(a[idx, true], b) })
|
21
|
+
end
|
22
|
+
|
23
|
+
def dot_mat_mat(a, b)
|
24
|
+
_m, n = b.shape
|
25
|
+
Numo::NArray.asarray(Array.new(n) { |idx| dot_mat_vec(a, b[true, idx]) })
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'calculates the dot product of matrices' do
|
29
|
+
expect((described_class.matmul(mat_s, mat_s.transpose) - dot_mat_mat(mat_s, mat_s.transpose)).abs).to be < ERR_TOL
|
30
|
+
expect((described_class.matmul(mat_s, mat_d.transpose) - dot_mat_mat(mat_s, mat_d.transpose)).abs).to be < ERR_TOL
|
31
|
+
expect((described_class.matmul(mat_s, mat_c.transpose) - dot_mat_mat(mat_s, mat_c.transpose)).abs).to be < ERR_TOL
|
32
|
+
expect((described_class.matmul(mat_s, mat_z.transpose) - dot_mat_mat(mat_s, mat_z.transpose)).abs).to be < ERR_TOL
|
33
|
+
expect((described_class.matmul(mat_d, mat_d.transpose) - dot_mat_mat(mat_d, mat_d.transpose)).abs).to be < ERR_TOL
|
34
|
+
expect((described_class.matmul(mat_d, mat_c.transpose) - dot_mat_mat(mat_d, mat_c.transpose)).abs).to be < ERR_TOL
|
35
|
+
expect((described_class.matmul(mat_d, mat_z.transpose) - dot_mat_mat(mat_d, mat_z.transpose)).abs).to be < ERR_TOL
|
36
|
+
expect((described_class.matmul(mat_c, mat_c.transpose) - dot_mat_mat(mat_c, mat_c.transpose)).abs).to be < ERR_TOL
|
37
|
+
expect((described_class.matmul(mat_c, mat_z.transpose) - dot_mat_mat(mat_c, mat_z.transpose)).abs).to be < ERR_TOL
|
38
|
+
expect((described_class.matmul(mat_z, mat_z.transpose) - dot_mat_mat(mat_z, mat_z.transpose)).abs).to be < ERR_TOL
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Numo::Linalg do
|
6
|
+
describe 'matrix_power' do
|
7
|
+
let(:m) { 5 }
|
8
|
+
let(:mat_a) { rand_square_real_mat(m) }
|
9
|
+
|
10
|
+
it 'raises ShapeError given a rectangular matrix' do
|
11
|
+
expect { described_class.matrix_power(Numo::DFloat.new(2, 4).rand, 2) }.to raise_error(Numo::NArray::ShapeError)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'raises ArgumentError given a non-integer exponent' do
|
15
|
+
expect { described_class.matrix_power(Numo::DFloat.new(2, 2).rand, 0.5) }.to raise_error(ArgumentError)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'calculates a square matrix to the n-th power' do
|
19
|
+
expect(described_class.matrix_power(mat_a, 0)).to eq(Numo::DFloat.eye(m))
|
20
|
+
pow_mat_a = described_class.matrix_power(mat_a, 2)
|
21
|
+
expect((pow_mat_a - mat_a.dot(mat_a)).abs.max).to be < ERR_TOL
|
22
|
+
pow_mat_a = described_class.matrix_power(mat_a, 5)
|
23
|
+
expect((pow_mat_a - (((mat_a.dot(mat_a)).dot(mat_a)).dot(mat_a)).dot(mat_a)).abs.max).to be < ERR_TOL
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'calculates the inverse of a square matrix' do
|
27
|
+
inv_mat_a = described_class.matrix_power(mat_a, -1)
|
28
|
+
expect((inv_mat_a.dot(mat_a) - Numo::DFloat.eye(m)).abs.max).to be < ERR_TOL
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Numo::Linalg do
|
6
|
+
describe 'matrix_rank' do
|
7
|
+
let(:r) { 2 }
|
8
|
+
let(:m) { 6 }
|
9
|
+
let(:n) { 3 }
|
10
|
+
let(:mat_a) { rand_rect_real_mat(m, r).dot(rand_rect_real_mat(r, n)) }
|
11
|
+
let(:mat_b) { rand_rect_complex_mat(m, r).dot(rand_rect_complex_mat(r, n)) }
|
12
|
+
|
13
|
+
it 'raises ArgumentError given a invalid driver option' do
|
14
|
+
expect { described_class.matrix_rank(mat_a, driver: 'foo') }.to raise_error(ArgumentError)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'calculate the matrix rank of a real matrix' do
|
18
|
+
expect(described_class.matrix_rank(mat_a)).to eq(r)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'calculate the matrix rank of a real matrix with divide and conquer method' do
|
22
|
+
expect(described_class.matrix_rank(mat_a, driver: 'sdd')).to eq(r)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'calculate the matrix rank of a complex matrix' do
|
26
|
+
expect(described_class.matrix_rank(mat_b)).to eq(r)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'calculate the matrix rank of a complex matrix with divide and conquer method' do
|
30
|
+
expect(described_class.matrix_rank(mat_b, driver: 'sdd')).to eq(r)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Numo::Linalg do
|
6
|
+
describe 'norm' do
|
7
|
+
let(:m) { 6 }
|
8
|
+
let(:n) { 3 }
|
9
|
+
let(:mat_a) { rand_rect_real_mat(m, n) }
|
10
|
+
let(:mat_b) { rand_rect_complex_mat(m, n) }
|
11
|
+
let(:vec_a) { rand_real_vec(m) }
|
12
|
+
let(:vec_b) { rand_complex_vec(m) }
|
13
|
+
let(:vec_s) do
|
14
|
+
a = rand_real_vec(10)
|
15
|
+
a * (a > 0.0)
|
16
|
+
end
|
17
|
+
let(:vec_t) do
|
18
|
+
b = rand_real_vec(10) > 0.0
|
19
|
+
rand_complex_vec(10) * b
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'raises ArgumentError given an invalid order option' do
|
23
|
+
expect { described_class.norm(mat_a, 0) }.to raise_error(ArgumentError)
|
24
|
+
expect { described_class.norm(mat_a, 5) }.to raise_error(ArgumentError)
|
25
|
+
expect { described_class.norm(mat_a, 'frobenius') }.to raise_error(ArgumentError)
|
26
|
+
expect { described_class.norm(vec_a, 'fro') }.to raise_error(ArgumentError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'calculates the Froubenius norm of a real matrix' do
|
30
|
+
norm = Math.sqrt(mat_a.transpose.dot(mat_a).trace)
|
31
|
+
expect(described_class.norm(mat_a)).to be_within(norm).of(ERR_TOL)
|
32
|
+
expect(described_class.norm(mat_a, 'fro')).to be_within(norm).of(ERR_TOL)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'calculates the L1 norm of a real matrix' do
|
36
|
+
expect(described_class.norm(mat_a, 1)).to be_within(mat_a.abs.sum(axis: -2).max).of(ERR_TOL)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'calculates the L2 norm of a real matrix' do
|
40
|
+
expect(described_class.norm(mat_a, 2)).to be_within(described_class.svdvals(mat_a).max).of(ERR_TOL)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'calculates the inifinity norm of a real matrix' do
|
44
|
+
expect(described_class.norm(mat_a, 'inf')).to be_within(mat_a.abs.sum(axis: -1).max).of(ERR_TOL)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'calculates the Froubenius norm of a complex matrix' do
|
48
|
+
norm = Math.sqrt(mat_b.transpose.conj.dot(mat_b).trace.real)
|
49
|
+
expect(described_class.norm(mat_b)).to be_within(norm).of(ERR_TOL)
|
50
|
+
expect(described_class.norm(mat_b, 'fro')).to be_within(norm).of(ERR_TOL)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'calculates the L1 norm of a complex matrix' do
|
54
|
+
expect(described_class.norm(mat_b, 1)).to be_within(mat_b.abs.sum(axis: -2).max).of(ERR_TOL)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'calculates the L2 norm of a complex matrix' do
|
58
|
+
expect(described_class.norm(mat_b, 2)).to be_within(described_class.svdvals(mat_b).max).of(ERR_TOL)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'calculates the inifinity norm of a complex matrix' do
|
62
|
+
expect(described_class.norm(mat_b, 'inf')).to be_within(mat_b.abs.sum(axis: -1).max).of(ERR_TOL)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'calculates the L0 norm of a complex vector' do
|
66
|
+
expect(described_class.norm(vec_t, 0).real).to be_within((vec_t.abs.ne(0)).count).of(ERR_TOL)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'calculates the L1 norm of a complex vector' do
|
70
|
+
expect(described_class.norm(vec_b, 1)).to be_within(vec_b.abs.sum).of(ERR_TOL)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'calculates the L2 norm of a complex vector' do
|
74
|
+
expect(described_class.norm(vec_b, 2)).to be_within(Math.sqrt((vec_b.abs**2).sum)).of(ERR_TOL)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'calculates the infinity norm of a complex vector' do
|
78
|
+
expect(described_class.norm(vec_b, 'inf')).to be_within(vec_b.abs.max).of(ERR_TOL)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Numo::Linalg do
|
6
|
+
describe 'pinv' do
|
7
|
+
let(:m) { 5 }
|
8
|
+
let(:n) { 3 }
|
9
|
+
let(:mat_a) { rand_rect_real_mat(m, n) }
|
10
|
+
let(:mat_b) { rand_rect_complex_mat(m, n) }
|
11
|
+
|
12
|
+
it 'raises ArgumentError given a invalid driver option' do
|
13
|
+
expect { described_class.pinv(mat_a, driver: 'foo') }.to raise_error(ArgumentError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'calculates the (Moore-Penrose) pseudo-inverse of a rectangular real matrix using svd' do
|
17
|
+
inv_mat_a = described_class.pinv(mat_a, driver: 'svd')
|
18
|
+
expect((inv_mat_a.dot(mat_a) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
19
|
+
inv_mat_a = described_class.pinv(mat_a, driver: 'sdd')
|
20
|
+
expect((inv_mat_a.dot(mat_a) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'calculates the (Moore-Penrose) pseudo-inverse of a rectangular complex matrix using svd' do
|
24
|
+
inv_mat_b = described_class.pinv(mat_b, driver: 'svd')
|
25
|
+
expect((inv_mat_b.dot(mat_b) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
26
|
+
inv_mat_b = described_class.pinv(mat_b, driver: 'sdd')
|
27
|
+
expect((inv_mat_b.dot(mat_b) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'calculates the (Moore-Penrose) pseudo-inverse of a rectangular real matrix using lstsq' do
|
31
|
+
inv_mat_a = described_class.pinv(mat_a, driver: 'lsd')
|
32
|
+
expect((inv_mat_a.dot(mat_a) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
33
|
+
inv_mat_a = described_class.pinv(mat_a, driver: 'lss')
|
34
|
+
expect((inv_mat_a.dot(mat_a) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
35
|
+
inv_mat_a = described_class.pinv(mat_a, driver: 'lsy')
|
36
|
+
expect((inv_mat_a.dot(mat_a) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'calculates the (Moore-Penrose) pseudo-inverse of a rectangular complex matrix using lstsq' do
|
40
|
+
inv_mat_b = described_class.pinv(mat_b, driver: 'lsd')
|
41
|
+
expect((inv_mat_b.dot(mat_b) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
42
|
+
inv_mat_b = described_class.pinv(mat_b, driver: 'lss')
|
43
|
+
expect((inv_mat_b.dot(mat_b) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
44
|
+
inv_mat_b = described_class.pinv(mat_b, driver: 'lsy')
|
45
|
+
expect((inv_mat_b.dot(mat_b) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Numo::Linalg do
|
6
|
+
describe 'qr' do
|
7
|
+
let(:m) { 5 }
|
8
|
+
let(:n) { 3 }
|
9
|
+
let(:mat_a) { rand_rect_real_mat(m, n) }
|
10
|
+
let(:mat_b) { rand_rect_complex_mat(m, n) }
|
11
|
+
|
12
|
+
it 'raises ArgumentError given a invalid mode option' do
|
13
|
+
expect { described_class.qr(Numo::DFloat.new(2, 4).rand, mode: 'foo') }.to raise_error(ArgumentError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'calculates the QR factorization of a real matrix with reduce mode' do
|
17
|
+
q, r = described_class.qr(mat_a, mode: 'reduce')
|
18
|
+
expect((q.dot(r) - mat_a).abs.max).to be < ERR_TOL
|
19
|
+
expect((q.transpose.dot(q) - Numo::DFloat.eye(m)).abs.max).to be < ERR_TOL
|
20
|
+
q, r = described_class.qr(mat_a.transpose, mode: 'reduce')
|
21
|
+
expect((q.dot(r) - mat_a.transpose).abs.max).to be < ERR_TOL
|
22
|
+
expect((q.transpose.dot(q) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'calculates the QR factorization of a complex matrix with reduce mode' do
|
26
|
+
q, r = described_class.qr(mat_b, mode: 'reduce')
|
27
|
+
expect((q.dot(r) - mat_b).abs.max).to be < ERR_TOL
|
28
|
+
expect((q.transpose.conj.dot(q) - Numo::DFloat.eye(m)).abs.max).to be < ERR_TOL
|
29
|
+
q, r = described_class.qr(mat_b.transpose.conj, mode: 'reduce')
|
30
|
+
expect((q.dot(r) - mat_b.transpose.conj).abs.max).to be < ERR_TOL
|
31
|
+
expect((q.transpose.conj.dot(q) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'calculates the QR factorization of a real matrix with r mode' do
|
35
|
+
q_, r = described_class.qr(mat_a, mode: 'reduce')
|
36
|
+
r2 = described_class.qr(mat_a, mode: 'r')
|
37
|
+
expect((r - r2).abs.max).to be < ERR_TOL
|
38
|
+
q_, r = described_class.qr(mat_a.transpose, mode: 'reduce')
|
39
|
+
r2 = described_class.qr(mat_a.transpose, mode: 'r')
|
40
|
+
expect((r - r2).abs.max).to be < ERR_TOL
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'calculates the QR factorization of a complex matrix with r mode' do
|
44
|
+
q_, r = described_class.qr(mat_b, mode: 'reduce')
|
45
|
+
r2 = described_class.qr(mat_b, mode: 'r')
|
46
|
+
expect((r - r2).abs.max).to be < ERR_TOL
|
47
|
+
q_, r = described_class.qr(mat_b.transpose.conj, mode: 'reduce')
|
48
|
+
r2 = described_class.qr(mat_b.transpose.conj, mode: 'r')
|
49
|
+
expect((r - r2).abs.max).to be < ERR_TOL
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'calculates the QR factorization of a real matrix with economic mode' do
|
53
|
+
q, r = described_class.qr(mat_a, mode: 'economic')
|
54
|
+
expect(q.shape[0]).to eq(m)
|
55
|
+
expect(q.shape[1]).to eq(n)
|
56
|
+
expect(r.shape[0]).to eq(n)
|
57
|
+
expect(r.shape[1]).to eq(n)
|
58
|
+
expect((q.dot(r) - mat_a).abs.max).to be < ERR_TOL
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'calculates the QR factorization of a complex matrix with economic mode' do
|
62
|
+
q, r = described_class.qr(mat_b, mode: 'economic')
|
63
|
+
expect(q.shape[0]).to eq(m)
|
64
|
+
expect(q.shape[1]).to eq(n)
|
65
|
+
expect(r.shape[0]).to eq(n)
|
66
|
+
expect(r.shape[1]).to eq(n)
|
67
|
+
expect((q.dot(r) - mat_b).abs.max).to be < ERR_TOL
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'calculates the QR factorization of a real matrix with raw mode' do
|
71
|
+
q_, r = described_class.qr(mat_a)
|
72
|
+
q, tau = described_class.qr(mat_a, mode: 'raw')
|
73
|
+
expect((q.triu - r).abs.max).to be < ERR_TOL
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'calculates the QR factorization of a complex matrix with raw mode' do
|
77
|
+
q_, r = described_class.qr(mat_b)
|
78
|
+
q, tau = described_class.qr(mat_b, mode: 'raw')
|
79
|
+
expect((q.triu - r).abs.max).to be < ERR_TOL
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Numo::Linalg do
|
6
|
+
describe 'slogdet' do
|
7
|
+
let(:m) { 5 }
|
8
|
+
let(:mat_a) { rand_square_real_mat(m) }
|
9
|
+
let(:mat_b) { rand_square_complex_mat(m) }
|
10
|
+
|
11
|
+
it 'calculates natural logarithm of the dererminant of a square real matrix' do
|
12
|
+
logdet = Math.log(described_class.eigvals(mat_a).prod.abs)
|
13
|
+
expect((described_class.slogdet(mat_a)[1] - logdet).abs).to be < ERR_TOL
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'calculates natural logarithm of the dererminant of a square complex matrix' do
|
17
|
+
logdet = Math.log(described_class.eigvals(mat_b).prod.abs)
|
18
|
+
expect((described_class.slogdet(mat_b)[1] - logdet).abs).to be < ERR_TOL
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Numo::Linalg do
|
6
|
+
describe 'solve' do
|
7
|
+
let(:m) { 5 }
|
8
|
+
let(:n) { 3 }
|
9
|
+
let(:mat_a) { rand_square_real_mat(m) }
|
10
|
+
let(:mat_b) { rand_rect_real_mat(m, n) }
|
11
|
+
let(:vec_b) { rand_real_vec(m) }
|
12
|
+
let(:mat_c) { rand_square_complex_mat(m) }
|
13
|
+
let(:mat_d) { rand_rect_complex_mat(m, n) }
|
14
|
+
let(:vec_d) { rand_complex_vec(m) }
|
15
|
+
let(:mat_s) { rand_symmetric_mat(m) }
|
16
|
+
let(:mat_h) { rand_hermitian_mat(m) }
|
17
|
+
let(:mat_p) { mat_s.dot(mat_s.transpose) }
|
18
|
+
let(:mat_q) { mat_h.dot(mat_h.transpose.conj) }
|
19
|
+
|
20
|
+
it 'raises ArgumentError given a invalid driver option' do
|
21
|
+
expect { described_class.solve(mat_a, vec_b, driver: 'foo') }.to raise_error(ArgumentError)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'raises ShapeError when the number of rows of matrices are different' do
|
25
|
+
expect { described_class.solve(mat_a, mat_b.transpose) }.to raise_error(Numo::NArray::ShapeError)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'raises ShapeError given a rectangular matrix as matrix A' do
|
29
|
+
expect { described_class.solve(mat_b, mat_a) }.to raise_error(Numo::NArray::ShapeError)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'solves the linear equation A x = b with a square real matrix A' do
|
33
|
+
vec_x = described_class.solve(mat_a, vec_b)
|
34
|
+
expect((mat_a.dot(vec_x) - vec_b).abs.max).to be < ERR_TOL
|
35
|
+
mat_x = described_class.solve(mat_a, mat_b)
|
36
|
+
expect((mat_a.dot(mat_x) - mat_b).abs.max).to be < ERR_TOL
|
37
|
+
vec_x = described_class.solve(mat_a, vec_d)
|
38
|
+
expect((mat_a.dot(vec_x) - vec_d).abs.max).to be < ERR_TOL
|
39
|
+
mat_x = described_class.solve(mat_a, mat_d)
|
40
|
+
expect((mat_a.dot(mat_x) - mat_d).abs.max).to be < ERR_TOL
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'solves the linear equation A x = b with a square complex matrix A' do
|
44
|
+
vec_x = described_class.solve(mat_c, vec_b)
|
45
|
+
expect((mat_c.dot(vec_x) - vec_b).abs.max).to be < ERR_TOL
|
46
|
+
mat_x = described_class.solve(mat_c, mat_b)
|
47
|
+
expect((mat_c.dot(mat_x) - mat_b).abs.max).to be < ERR_TOL
|
48
|
+
vec_x = described_class.solve(mat_c, vec_d)
|
49
|
+
expect((mat_c.dot(vec_x) - vec_d).abs.max).to be < ERR_TOL
|
50
|
+
mat_x = described_class.solve(mat_c, mat_d)
|
51
|
+
expect((mat_c.dot(mat_x) - mat_d).abs.max).to be < ERR_TOL
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'solves the linear equation A x = b with a symmetric matrix A' do
|
55
|
+
vec_x = described_class.solve(mat_s, vec_b, driver: 'sym')
|
56
|
+
expect((mat_s.dot(vec_x) - vec_b).abs.max).to be < ERR_TOL
|
57
|
+
mat_x = described_class.solve(mat_s, mat_b, driver: 'sym')
|
58
|
+
expect((mat_s.dot(mat_x) - mat_b).abs.max).to be < ERR_TOL
|
59
|
+
vec_x = described_class.solve(mat_s, vec_d, driver: 'sym')
|
60
|
+
expect((mat_s.dot(vec_x) - vec_d).abs.max).to be < ERR_TOL
|
61
|
+
mat_x = described_class.solve(mat_s, mat_d, driver: 'sym')
|
62
|
+
expect((mat_s.dot(mat_x) - mat_d).abs.max).to be < ERR_TOL
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'solves the linear equation A x = b with a hermitian matrix A' do
|
66
|
+
vec_x = described_class.solve(mat_h, vec_b, driver: 'her')
|
67
|
+
expect((mat_h.dot(vec_x) - vec_b).abs.max).to be < ERR_TOL
|
68
|
+
mat_x = described_class.solve(mat_h, mat_b, driver: 'her')
|
69
|
+
expect((mat_h.dot(mat_x) - mat_b).abs.max).to be < ERR_TOL
|
70
|
+
vec_x = described_class.solve(mat_h, vec_d, driver: 'her')
|
71
|
+
expect((mat_h.dot(vec_x) - vec_d).abs.max).to be < ERR_TOL
|
72
|
+
mat_x = described_class.solve(mat_h, mat_d, driver: 'her')
|
73
|
+
expect((mat_h.dot(mat_x) - mat_d).abs.max).to be < ERR_TOL
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'solves the linear equation A x = b with a symmetric positive-definite matrix A' do
|
77
|
+
vec_x = described_class.solve(mat_p, vec_b, driver: 'pos')
|
78
|
+
expect((mat_p.dot(vec_x) - vec_b).abs.max).to be < ERR_TOL
|
79
|
+
mat_x = described_class.solve(mat_p, mat_b, driver: 'pos')
|
80
|
+
expect((mat_p.dot(mat_x) - mat_b).abs.max).to be < ERR_TOL
|
81
|
+
vec_x = described_class.solve(mat_p, vec_d, driver: 'pos')
|
82
|
+
expect((mat_p.dot(vec_x) - vec_d).abs.max).to be < ERR_TOL
|
83
|
+
mat_x = described_class.solve(mat_p, mat_d, driver: 'pos')
|
84
|
+
expect((mat_p.dot(mat_x) - mat_d).abs.max).to be < ERR_TOL
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'solves the linear equation A x = b with a hermitian positive-definite matrix A' do
|
88
|
+
vec_x = described_class.solve(mat_q, vec_b, driver: 'pos')
|
89
|
+
expect((mat_q.dot(vec_x) - vec_b).abs.max).to be < ERR_TOL
|
90
|
+
mat_x = described_class.solve(mat_q, mat_b, driver: 'pos')
|
91
|
+
expect((mat_q.dot(mat_x) - mat_b).abs.max).to be < ERR_TOL
|
92
|
+
vec_x = described_class.solve(mat_q, vec_d, driver: 'pos')
|
93
|
+
expect((mat_q.dot(vec_x) - vec_d).abs.max).to be < ERR_TOL
|
94
|
+
mat_x = described_class.solve(mat_q, mat_d, driver: 'pos')
|
95
|
+
expect((mat_q.dot(mat_x) - mat_d).abs.max).to be < ERR_TOL
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|