brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | import numpy |
| 4 | from numpy.testing import * |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 5 | import unittest |
| 6 | |
Brian Silverman | 9c89c0a | 2016-01-08 01:04:57 -0800 | [diff] [blame] | 7 | import frc971.control_loops.python.polytope as polytope |
| 8 | |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 9 | __author__ = 'Austin Schuh (austin.linux@gmail.com)' |
| 10 | |
| 11 | def MakePoint(*args): |
| 12 | """Makes a point from a set of arguments.""" |
| 13 | return numpy.matrix([[arg] for arg in args]) |
| 14 | |
| 15 | class TestHPolytope(unittest.TestCase): |
| 16 | def setUp(self): |
| 17 | """Builds a simple box polytope.""" |
| 18 | self.H = numpy.matrix([[1, 0], |
| 19 | [-1, 0], |
| 20 | [0, 1], |
| 21 | [0, -1]]) |
| 22 | self.k = numpy.matrix([[12], |
| 23 | [12], |
| 24 | [12], |
| 25 | [12]]) |
| 26 | self.p = polytope.HPolytope(self.H, self.k) |
| 27 | |
| 28 | def test_Hk(self): |
| 29 | """Tests that H and k are saved correctly.""" |
| 30 | assert_array_equal(self.p.H, self.H) |
| 31 | assert_array_equal(self.p.k, self.k) |
| 32 | |
| 33 | def test_IsInside(self): |
| 34 | """Tests IsInside for various points.""" |
| 35 | inside_points = [ |
| 36 | MakePoint(0, 0), |
| 37 | MakePoint(6, 6), |
| 38 | MakePoint(12, 6), |
| 39 | MakePoint(-6, 10)] |
| 40 | outside_points = [ |
| 41 | MakePoint(14, 0), |
| 42 | MakePoint(-14, 0), |
| 43 | MakePoint(0, 14), |
| 44 | MakePoint(0, -14), |
| 45 | MakePoint(14, -14)] |
| 46 | |
| 47 | for inside_point in inside_points: |
| 48 | self.assertTrue(self.p.IsInside(inside_point), |
| 49 | msg='Point is' + str(inside_point)) |
| 50 | |
| 51 | for outside_point in outside_points: |
| 52 | self.assertFalse(self.p.IsInside(outside_point), |
| 53 | msg='Point is' + str(outside_point)) |
| 54 | |
| 55 | def AreVertices(self, p, vertices): |
| 56 | """Checks that all the vertices are on corners of the set.""" |
| 57 | for i in xrange(vertices.shape[0]): |
| 58 | # Check that all the vertices have the correct number of active |
| 59 | # constraints. |
| 60 | lmda = p.H * vertices[i,:].T - p.k |
| 61 | num_active_constraints = 0 |
| 62 | for j in xrange(lmda.shape[0]): |
| 63 | # Verify that the constraints are either active, or not violated. |
| 64 | if numpy.abs(lmda[j, 0]) <= 1e-9: |
| 65 | num_active_constraints += 1 |
| 66 | else: |
| 67 | self.assertLessEqual(lmda[j, 0], 0.0) |
| 68 | |
| 69 | self.assertEqual(p.ndim, num_active_constraints) |
| 70 | |
| 71 | def HasSamePoints(self, expected, actual): |
| 72 | """Verifies that the points in expected are in actual.""" |
| 73 | found_points = set() |
| 74 | self.assertEqual(expected.shape, actual.shape) |
| 75 | for index in xrange(expected.shape[0]): |
| 76 | expected_point = expected[index, :] |
| 77 | for actual_index in xrange(actual.shape[0]): |
| 78 | actual_point = actual[actual_index, :] |
| 79 | if numpy.abs(expected_point - actual_point).max() <= 1e-4: |
| 80 | found_points.add(actual_index) |
| 81 | break |
| 82 | |
| 83 | self.assertEqual(len(found_points), actual.shape[0], |
| 84 | msg="Expected:\n" + str(expected) + "\nActual:\n" + str(actual)) |
| 85 | |
| 86 | def test_Skewed_Nonsym_Vertices(self): |
| 87 | """Tests the vertices of a severely skewed space.""" |
| 88 | self.H = numpy.matrix([[10, -1], |
| 89 | [-1, -1], |
| 90 | [-1, 10], |
| 91 | [10, 10]]) |
| 92 | self.k = numpy.matrix([[2], |
| 93 | [2], |
| 94 | [2], |
| 95 | [2]]) |
| 96 | self.p = polytope.HPolytope(self.H, self.k) |
| 97 | vertices = self.p.Vertices() |
| 98 | self.AreVertices(self.p, vertices) |
| 99 | |
| 100 | self.HasSamePoints( |
| 101 | numpy.matrix([[0., 0.2], |
| 102 | [0.2, 0.], |
| 103 | [-2., 0.], |
| 104 | [0., -2.]]), |
| 105 | vertices) |
| 106 | |
| 107 | def test_Vertices_Nonsym(self): |
| 108 | """Tests the vertices of a nonsymetric space.""" |
| 109 | self.k = numpy.matrix([[6], |
| 110 | [12], |
| 111 | [2], |
| 112 | [10]]) |
| 113 | self.p = polytope.HPolytope(self.H, self.k) |
| 114 | vertices = self.p.Vertices() |
| 115 | self.AreVertices(self.p, vertices) |
| 116 | |
| 117 | self.HasSamePoints( |
| 118 | numpy.matrix([[6., 2.], |
| 119 | [6., -10.], |
| 120 | [-12., -10.], |
| 121 | [-12., 2.]]), |
| 122 | vertices) |
| 123 | |
| 124 | def test_Vertices(self): |
| 125 | """Tests the vertices of a nonsymetric space.""" |
| 126 | self.HasSamePoints(self.p.Vertices(), |
| 127 | numpy.matrix([[12., 12.], |
| 128 | [12., -12.], |
| 129 | [-12., -12.], |
| 130 | [-12., 12.]])) |
| 131 | |
| 132 | def test_concat(self): |
| 133 | """Tests that the concat function works for simple inputs.""" |
| 134 | self.assertEqual(["asd", "qwe"], |
| 135 | polytope._PiecewiseConcat(["a", "q"], |
| 136 | ["s", "w"], |
| 137 | ["d", "e"])) |
| 138 | |
| 139 | def test_str(self): |
| 140 | """Verifies that the str method works for the provided p.""" |
| 141 | self.assertEqual('[[ 1 0] [[12] \n' |
| 142 | ' [-1 0] [[x0] <= [12] \n' |
| 143 | ' [ 0 1] [x1]] [12] \n' |
| 144 | ' [ 0 -1]] [12]] ', |
| 145 | str(self.p)) |
| 146 | |
| 147 | def MakePWithDims(self, num_constraints, num_dims): |
| 148 | """Makes a zeroed out polytope with the correct size.""" |
| 149 | self.p = polytope.HPolytope( |
| 150 | numpy.matrix(numpy.zeros((num_constraints, num_dims))), |
| 151 | numpy.matrix(numpy.zeros((num_constraints, 1)))) |
| 152 | |
| 153 | def test_few_constraints_odd_constraint_even_dims_str(self): |
| 154 | """Tests printing out the set with odd constraints and even dimensions.""" |
| 155 | self.MakePWithDims(num_constraints=5, num_dims=2) |
| 156 | self.assertEqual('[[ 0. 0.] [[ 0.] \n' |
| 157 | ' [ 0. 0.] [[x0] [ 0.] \n' |
| 158 | ' [ 0. 0.] [x1]] <= [ 0.] \n' |
| 159 | ' [ 0. 0.] [ 0.] \n' |
| 160 | ' [ 0. 0.]] [ 0.]] ', |
| 161 | str(self.p)) |
| 162 | |
| 163 | def test_few_constraints_odd_constraint_small_dims_str(self): |
| 164 | """Tests printing out the set with odd constraints and odd dimensions.""" |
| 165 | self.MakePWithDims(num_constraints=5, num_dims=1) |
| 166 | self.assertEqual('[[ 0.] [[ 0.] \n' |
| 167 | ' [ 0.] [ 0.] \n' |
| 168 | ' [ 0.] [[x0]] <= [ 0.] \n' |
| 169 | ' [ 0.] [ 0.] \n' |
| 170 | ' [ 0.]] [ 0.]] ', |
| 171 | str(self.p)) |
| 172 | |
| 173 | def test_few_constraints_odd_constraint_odd_dims_str(self): |
| 174 | """Tests printing out the set with odd constraints and odd dimensions.""" |
| 175 | self.MakePWithDims(num_constraints=5, num_dims=3) |
| 176 | self.assertEqual('[[ 0. 0. 0.] [[ 0.] \n' |
| 177 | ' [ 0. 0. 0.] [[x0] [ 0.] \n' |
| 178 | ' [ 0. 0. 0.] [x1] <= [ 0.] \n' |
| 179 | ' [ 0. 0. 0.] [x2]] [ 0.] \n' |
| 180 | ' [ 0. 0. 0.]] [ 0.]] ', |
| 181 | str(self.p)) |
| 182 | |
| 183 | def test_many_constraints_even_constraint_odd_dims_str(self): |
| 184 | """Tests printing out the set with even constraints and odd dimensions.""" |
| 185 | self.MakePWithDims(num_constraints=2, num_dims=3) |
| 186 | self.assertEqual('[[ 0. 0. 0.] [[x0] [[ 0.] \n' |
| 187 | ' [ 0. 0. 0.]] [x1] <= [ 0.]] \n' |
| 188 | ' [x2]] ', |
| 189 | str(self.p)) |
| 190 | |
| 191 | |
| 192 | if __name__ == '__main__': |
| 193 | unittest.main() |