]> gitweb.michael.orlitzky.com - dunshire.git/blob - test/matrices_test.py
A bunch more doc fixes.
[dunshire.git] / test / matrices_test.py
1 """
2 Unit tests for the functions in the :mod:`dunshire.matrices` module.
3 """
4
5 from copy import deepcopy
6 from unittest import TestCase
7
8 from dunshire.matrices import (append_col, append_row, condition_number,
9 eigenvalues, eigenvalues_re, identity,
10 inner_product, norm)
11 from dunshire.options import ABS_TOL
12 from .randomgen import random_matrix, random_natural
13
14
15 class AppendColTest(TestCase):
16 """
17 Tests for the :func:`append_col` function.
18 """
19
20 def test_new_dimensions(self):
21 """
22 If we append one matrix to another side-by-side, then the result
23 should have the same number of rows as the two original
24 matrices. However, the number of their columns should add up to
25 the number of columns in the new combined matrix.
26 """
27 rows = random_natural()
28 cols1 = random_natural()
29 cols2 = random_natural()
30 mat1 = random_matrix(rows, cols1)
31 mat2 = random_matrix(rows, cols2)
32 bigmat = append_col(mat1, mat2)
33 self.assertTrue(bigmat.size[0] == rows)
34 self.assertTrue(bigmat.size[1] == cols1+cols2)
35
36
37 class AppendRowTest(TestCase):
38 """
39 Tests for the :func:`dunshire.matrices.append_row` function.
40 """
41
42 def test_new_dimensions(self):
43 """
44 If we append one matrix to another top-to-bottom, then
45 the result should have the same number of columns as the two
46 original matrices. However, the number of their rows should add
47 up to the number of rows in the the new combined matrix.
48 """
49 rows1 = random_natural()
50 rows2 = random_natural()
51 cols = random_natural()
52 mat1 = random_matrix(rows1, cols)
53 mat2 = random_matrix(rows2, cols)
54 bigmat = append_row(mat1, mat2)
55 self.assertTrue(bigmat.size[0] == rows1+rows2)
56 self.assertTrue(bigmat.size[1] == cols)
57
58
59 class EigenvaluesTest(TestCase):
60 """
61 Tests for the :func:`dunshire.matrices.eigenvalues` function.
62 """
63
64 def test_eigenvalues_input_not_clobbered(self):
65 """
66 The eigenvalue functions provided by CVXOPT/LAPACK like to
67 overwrite the matrices that you pass into them as
68 arguments. This test makes sure that our :func:`eigenvalues`
69 function does not do the same.
70
71 We use a ``deepcopy`` here in case the ``copy`` used in the
72 :func:`eigenvalues` function is insufficient. If ``copy`` didn't
73 work and this test used it too, then this test would pass when
74 it shouldn't.
75 """
76 mat = random_matrix(random_natural())
77 symmat = mat + mat.trans()
78 symmat_copy = deepcopy(symmat)
79 dummy = eigenvalues(symmat)
80 self.assertTrue(norm(symmat - symmat_copy) < ABS_TOL)
81
82 def test_eigenvalues_of_symmat_are_real(self):
83 """
84 A real symmetric matrix has real eigenvalues, so if we start
85 with a symmetric matrix, then the two functions
86 :func:`dunshire.matrices.eigenvalues` and
87 :func:`dunshire.matrices.eigenvalues_re` should agree on it.
88 """
89 mat = random_matrix(random_natural())
90 symmat = mat + mat.trans()
91 eigs1 = sorted(eigenvalues(symmat))
92 eigs2 = sorted(eigenvalues_re(symmat))
93 diffs = [abs(e1 - e2) for (e1, e2) in zip(eigs1, eigs2)]
94 self.assertTrue(all([diff < ABS_TOL for diff in diffs]))
95
96 def test_eigenvalues_of_identity(self):
97 """
98 All eigenvalues of the identity matrix should be one.
99 """
100 mat = identity(random_natural(), typecode='d')
101 eigs = eigenvalues(mat)
102 self.assertTrue(all([abs(ev - 1) < ABS_TOL for ev in eigs]))
103
104
105 class EigenvaluesRealPartTest(TestCase):
106 """
107 Tests for the :func:`dunshire.matrices.eigenvalues_re` function.
108 """
109
110 def test_eigenvalues_re_input_not_clobbered(self):
111 """
112 The eigenvalue functions provided by CVXOPT/LAPACK like
113 to overwrite the matrices that you pass into them as
114 arguments. This test makes sure that our
115 :func:`dunshire.matrices.eigenvalues_re` function does not do
116 the same.
117
118 We use a ``deepcopy`` here in case the ``copy`` used in the
119 :func:`dunshire.matrices.eigenvalues_re` function is
120 insufficient. If ``copy`` didn't work and this test used it too,
121 then this test would pass when it shouldn't.
122 """
123 mat = random_matrix(random_natural())
124 mat_copy = deepcopy(mat)
125 dummy = eigenvalues_re(mat)
126 self.assertTrue(norm(mat - mat_copy) < ABS_TOL)
127
128 def test_eigenvalues_re_of_identity(self):
129 """
130 All eigenvalues of the identity matrix should be one.
131 """
132 mat = identity(random_natural(), typecode='d')
133 eigs = eigenvalues_re(mat)
134 self.assertTrue(all([abs(ev - 1) < ABS_TOL for ev in eigs]))
135
136
137 class InnerProductTest(TestCase):
138 """
139 Tests for the :func:`dunshire.matrices.inner_product` function.
140 """
141
142 def test_inner_product_with_self_is_norm_squared(self):
143 """
144 Ensure that the func:`dunshire.matrices.inner_product` and
145 :func:`dunshire.matrices.norm` functions are compatible by
146 checking that the square of the norm of a vector is its inner
147 product with itself.
148 """
149 vec = random_matrix(random_natural(), 1)
150 actual = inner_product(vec, vec)
151 expected = norm(vec)**2
152 self.assertTrue(abs(actual - expected) < ABS_TOL)
153
154
155 class NormTest(TestCase):
156 """
157 Tests for the :func:`dunshire.matrices.norm` function.
158 """
159
160 def test_norm_is_nonnegative(self):
161 """
162 Test one of the properties of a norm, that it is nonnegative.
163 """
164 mat = random_matrix(random_natural(), random_natural())
165 self.assertTrue(norm(mat) >= 0)
166
167
168 class ConditionNumberTest(TestCase):
169 """
170 Tests for the :func:`dunshire.matrices.condition_number` function.
171 """
172
173 def test_condition_number_ge_one(self):
174 """
175 From the way that it is defined, the condition number should
176 always be greater than or equal to one.
177 """
178 mat = random_matrix(random_natural(), random_natural())
179 self.assertTrue(condition_number(mat) >= 1)