]> gitweb.michael.orlitzky.com - dunshire.git/blob - test/matrices_test.py
ce57c7dc32a845b38af4dbad75e362c9e1da9b6f
[dunshire.git] / test / matrices_test.py
1 """
2 Unit tests for the functions in the ``matrices`` module.
3 """
4
5 from copy import copy
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:`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:`eigenvalues` function.
62 """
63
64 def test_eigenvalues_input_untouched(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 mat = random_matrix(random_natural())
72 symmat = mat + mat.trans()
73 symmat_copy = copy(symmat)
74 dummy = eigenvalues(symmat)
75 self.assertTrue(norm(symmat - symmat_copy) < ABS_TOL)
76
77 def test_eigenvalues_of_symmat_are_real(self):
78 """
79 A real symmetric matrix has real eigenvalues, so if we start
80 with a symmetric matrix, then the two functions :func:`eigenvalues`
81 and :func:`eigenvalues_re` should agree on it.
82 """
83 mat = random_matrix(random_natural())
84 symmat = mat + mat.trans()
85 eigs1 = sorted(eigenvalues(symmat))
86 eigs2 = sorted(eigenvalues_re(symmat))
87 diffs = [abs(e1 - e2) for (e1, e2) in zip(eigs1, eigs2)]
88 self.assertTrue(all([diff < ABS_TOL for diff in diffs]))
89
90 def test_eigenvalues_of_identity(self):
91 """
92 All eigenvalues of the identity matrix should be one.
93 """
94 mat = identity(random_natural(), typecode='d')
95 eigs = eigenvalues(mat)
96 self.assertTrue(all([abs(ev - 1) < ABS_TOL for ev in eigs]))
97
98
99 class EigenvaluesRealPartTest(TestCase):
100 """
101 Tests for the :func:`eigenvalues_re` function.
102 """
103
104 def test_eigenvalues_re_input_not_clobbered(self):
105 """
106 The eigenvalue functions provided by CVXOPT/LAPACK like to
107 overwrite the matrices that you pass into them as
108 arguments. This test makes sure that our :func:`eigenvalues_re`
109 function does not do the same.
110 """
111 mat = random_matrix(random_natural())
112 mat_copy = copy(mat)
113 dummy = eigenvalues_re(mat)
114 self.assertTrue(norm(mat - mat_copy) < ABS_TOL)
115
116 def test_eigenvalues_re_of_identity(self):
117 """
118 All eigenvalues of the identity matrix should be one.
119 """
120 mat = identity(random_natural(), typecode='d')
121 eigs = eigenvalues_re(mat)
122 self.assertTrue(all([abs(ev - 1) < ABS_TOL for ev in eigs]))
123
124
125 class InnerProductTest(TestCase):
126 """
127 Tests for the :func:`inner_product` function.
128 """
129
130 def test_inner_product_with_self_is_norm_squared(self):
131 """
132 Ensure that the func:`inner_product` and :func:`norm` functions
133 are compatible by checking that the square of the norm of a
134 vector is its inner product with itself.
135 """
136 vec = random_matrix(random_natural(), 1)
137 actual = inner_product(vec, vec)
138 expected = norm(vec)**2
139 self.assertTrue(abs(actual - expected) < ABS_TOL)
140
141
142 class NormTest(TestCase):
143 """
144 Tests for the :func:`norm` function.
145 """
146
147 def test_norm_is_nonnegative(self):
148 """
149 Test one of the properties of a norm, that it is nonnegative.
150 """
151 mat = random_matrix(random_natural(), random_natural())
152 self.assertTrue(norm(mat) >= 0)
153
154
155 class ConditionNumberTest(TestCase):
156 """
157 Tests for the :func:`condition_number` function.
158 """
159
160 def test_condition_number_ge_one(self):
161 """
162 From the way that it is defined, the condition number should
163 always be greater than or equal to one.
164 """
165 mat = random_matrix(random_natural(), random_natural())
166 self.assertTrue(condition_number(mat) >= 1)