From 040374ca134b2f3d962b91a9dac97a7600032685 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 1 Nov 2016 14:36:54 -0400 Subject: [PATCH] Add a new unit test suite for the dunshire.matrices module. --- TODO | 3 +- dunshire/matrices.py | 5 ++- test/__init__.py | 3 ++ test/matrices_test.py | 88 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 test/matrices_test.py diff --git a/TODO b/TODO index 21b47eb..afcffc5 100644 --- a/TODO +++ b/TODO @@ -165,7 +165,8 @@ 3.2630685083642352, 0.8991268260361712] -11. Add random tests for the matrices module. +11. Complete the unit tests for the matrices module. We still need to + document it, and finish adding all of the tests. 12. Investigate this test failure too. It looks like it was really close to being solved, but we would have needed a fudge factor diff --git a/dunshire/matrices.py b/dunshire/matrices.py index 13e8150..bcf8377 100644 --- a/dunshire/matrices.py +++ b/dunshire/matrices.py @@ -140,7 +140,10 @@ def eigenvalues(symmat): domain_dim = symmat.size[0] eigs = matrix(0, (domain_dim, 1), tc='d') - syevr(symmat, eigs) + + # Create a copy of ``symmat`` here because ``syevr`` clobbers it. + dummy = matrix(symmat, symmat.size) + syevr(dummy, eigs) return list(eigs) diff --git a/test/__init__.py b/test/__init__.py index 1d7c9a9..ec1bed0 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -14,6 +14,7 @@ from dunshire import cones from dunshire import errors from dunshire import matrices from dunshire import games +from test import matrices_test from test import randomgen from test import symmetric_linear_game_test @@ -30,6 +31,8 @@ def build_suite(): suite.addTest(DocTestSuite(randomgen)) slg_tests = TestLoader().loadTestsFromModule(symmetric_linear_game_test) suite.addTest(slg_tests) + mat_tests = TestLoader().loadTestsFromModule(matrices_test) + suite.addTest(mat_tests) return suite def run_suite(suite): diff --git a/test/matrices_test.py b/test/matrices_test.py new file mode 100644 index 0000000..195549f --- /dev/null +++ b/test/matrices_test.py @@ -0,0 +1,88 @@ +""" +Unit tests for the functions in the ``matrices`` module. +""" + +from unittest import TestCase + +from cvxopt import matrix + +from dunshire.matrices import (append_col, append_row, condition_number, + eigenvalues, eigenvalues_re, identity, + inner_product, norm) +from dunshire.options import ABS_TOL +from .randomgen import random_matrix, random_natural, random_scalar + +class AppendColTest(TestCase): + + def test_size_increases(self): + """ + If we append a column to a matrix, the result should be bigger + than the original matrix. + """ + dims = random_natural() + mat1 = random_matrix(dims) + mat2 = random_matrix(dims) + bigmat = append_col(mat1, mat2) + self.assertTrue(bigmat.size[0] >= mat1.size[0]) + self.assertTrue(bigmat.size[1] >= mat1.size[1]) + + +class AppendRowTest(TestCase): + + def test_size_increases(self): + """ + If we append a row to a matrix, the result should be bigger + than the original matrix. + """ + dims = random_natural() + mat1 = random_matrix(dims) + mat2 = random_matrix(dims) + bigmat = append_row(mat1, mat2) + self.assertTrue(bigmat.size[0] >= mat1.size[0]) + self.assertTrue(bigmat.size[1] >= mat1.size[1]) + + +class EigenvaluesTest(TestCase): + + def test_eigenvalues_input_not_clobbered(self): + mat = random_matrix(random_natural()) + symmat = mat + mat.trans() + symmat_copy = matrix(symmat, symmat.size) + eigs = eigenvalues(symmat) + self.assertTrue(norm(symmat - symmat_copy) < ABS_TOL) + + def test_eigenvalues_re_input_not_clobbered(self): + mat = random_matrix(random_natural()) + mat_copy = matrix(mat, mat.size) + eigs = eigenvalues_re(mat) + self.assertTrue(norm(mat - mat_copy) < ABS_TOL) + + def test_eigenvalues_of_symmetric_are_real(self): + mat = random_matrix(random_natural()) + symmat = mat + mat.trans() + eigs1 = sorted(eigenvalues(symmat)) + eigs2 = sorted(eigenvalues_re(symmat)) + diffs = [abs(e1-e2) for (e1,e2) in zip(eigs1,eigs2)] + self.assertTrue(all([diff < ABS_TOL for diff in diffs])) + + + def test_eigenvalues_of_identity(self): + mat = identity(random_natural(), typecode='d') + eigs1 = eigenvalues(mat) + eigs2 = eigenvalues_re(mat) + self.assertTrue(all([abs(e1 - 1) < ABS_TOL for e1 in eigs1])) + self.assertTrue(all([abs(e2 - 1) < ABS_TOL for e2 in eigs2])) + + +class InnerProductTest(TestCase): + + def test_norm_is_nonnegative(self): + vec = matrix([random_scalar() for _ in range(random_natural())]) + self.assertTrue(inner_product(vec,vec) >= 0) + + +def ConditionNumberTest(TestCase): + + def test_condition_number_ge_one(self): + mat = random_matrix(random_natural()) + self.assertTrue(condition_number(mat) >= 1) -- 2.44.2