class ProblemTest(unittest.TestCase):
    """
    Tests for l1sudoku Problem class
    """
    def setUp(self):
        """
        Instantiate one Problem at random from TOP95
        """
        self.sudoku = Problem(random_puzzle())
        self.N = 9

    def test_puzzle(self):
        """
        Test we create a Problem correctly from a string
        """
        print(unicode(self.sudoku))
        self.assertEqual(self.N, self.sudoku.N)
        self.assertTrue(len(unicode(self.sudoku)) > self.sudoku.N**2)

    def test_box_size(self):
        """
        Test we get correct boxsize if N is square and large enough.
        """
        self.assertEqual(3, Problem("." * 81, N=9).get_box_size())
        self.assertEqual(2, Problem("." * 16, N=4).get_box_size())
        self.assertEqual(0, Problem("." * 4, N=2).get_box_size())
        self.assertEqual(0, Problem("." * 100, N=10).get_box_size())

    def test_nentries(self):
        """
        Check the Problem correctly counts the number
        of clue entries.        
        """
        sudoku = Problem('1' + '.' * (self.N**2 - 1), N=self.N)
        self.assertEqual(1, sudoku.num_entries())

        rp = random_puzzle().strip()
        nentries_rp = len([e for e in rp if e != '.'])
        sudoku = Problem(rp)
        self.assertEqual(nentries_rp, sudoku.num_entries())

    def test_matrix(self):
        """
        Test the problem matrix generated by the Problem
        """
        m = self.sudoku.matrix()
        self.assertTrue(isinstance(m, matrix))

        nentries = len([e for e in self.sudoku.entries if e])
        N = self.sudoku.N
        self.assertEqual((4 * N**2 + nentries, N**3), m.size)

    def test_to_indicator(self):
        """
        Test the problem matrix generated by the Problem
        """
        N = self.N
        num = randint(1, N)
        pos = randint(0, N**2 - 1)
        sudoku = make_problem(chr(ord('0') + num), pos)

        iv = sudoku.to_indicator_vector()
        self.assertTrue(isinstance(iv, matrix))
        self.assertEqual((N**3, 1), iv.size)
        self.assertEqual(1, sum(iv))
        self.assertEqual(N * pos + num - 1, list(iv).index(1))

        s2 = Problem.from_indicator_vector(iv)

        self.assertEqual(unicode(sudoku), unicode(s2))

    def test_all_cells_constraint(self):
        """
        Check the matrix constraint that ensures
        all cells are filled.
        """
        # - Construct a Problem with all cells filled
        # - Get the all_cells matrix
        # - Multiply it with the indicator vector
        # - check the result is all ones
        # - blank a cell, repeat
        # - check the result is not all ones
        N = self.N
        sudoku = Problem("1" * N**2)
        v = sudoku.get_result(all_cells=True)
        self.assertOnes(v)
        v = self.sudoku.get_result(all_cells=True)
        self.assertNotOnes(v)

    def test_row_digits_constraint(self):
        """
        Check the matrix constraint that ensures
        each row contains all digits
        """
        # - Construct a Problem with all cells filled
        # - Get the all_cells matrix
        # - Multiply it with the indicator vector
        # - check the result is all ones
        # - blank a cell, repeat
        # - check the result is not all ones
        N = 9
        sudoku = Problem("123456789" * N)
        v = sudoku.get_result(row_digits=True)
        self.assertOnes(v)
        v = self.sudoku.get_result(row_digits=True)
        self.assertNotOnes(v)

    def test_col_digits_constraint(self):
        """
        Check the matrix constraint that ensures
        each row contains all digits
        """
        # - Construct a Problem with all cells filled
        # - Get the all_cells matrix
        # - Multiply it with the indicator vector
        # - check the result is all ones
        # - blank a cell, repeat
        # - check the result is not all ones
        N = 9

        entries = reduce(
            operator.__add__,
            [list(itertools.repeat(i, N)) for i in range(1, N + 1)])
        sudoku = Problem(entries)
        v = sudoku.get_result(col_digits=True)
        self.assertOnes(v)
        v = self.sudoku.get_result(col_digits=True)
        self.assertNotOnes(v)

    def test_box_digits_constraint(self):
        """
        Check the matrix constraint that ensures
        each box contains all digits
        """
        # - Construct a Problem with all cells filled
        # - Get the all_cells matrix
        # - Multiply it with the indicator vector
        # - check the result is all ones
        # - blank a cell, repeat
        # - check the result is not all ones
        N = 9
        sudoku = Problem("123123123"
                         "456456456"
                         "789789789"
                         "123123123"
                         "456456456"
                         "789789789"
                         "123123123"
                         "456456456"
                         "789789789")
        v = sudoku.get_result(box_digits=True)
        self.assertOnes(v)
        v = self.sudoku.get_result(box_digits=True)
        self.assertNotOnes(v)

    def test_clues_constraint(self):
        """
        Check the matrix constraint that ensures
        the answer is consistent with the clues.
        """
        N = 9
        num = randint(1, N)
        pos = randint(0, N**2 - 1)
        sudoku = make_problem(chr(ord('0') + num), pos)

        v = sudoku.get_result(clues=True)
        self.assertOnes(v)

    def assertOnes(self, vector):
        """
        Assert the vector consists entirely of ones.
        """
        self.assertTrue(all_ones(vector))

    def assertNotOnes(self, vector):
        """
        Assert the vector does not consist entirely of ones.
        """
        self.assertFalse(all([e == 1 for e in vector]))

    def test_solve(self):
        """
        Test solving the Problem.
        """
        # Easy test
        self.sudoku = Problem(
            '.81.749....4.193.7379.85.14..7831...238456179..69274..843562791762198543..5743862'
        )
        answer = self.sudoku.solve()
        checkAnswer = Problem(
            '681374925524619387379285614497831256238456179156927438843562791762198543915743862'
        )

        self.assertEqual(unicode(checkAnswer), unicode(answer))

        answer = self.sudoku.solve()
        checkAnswer = Problem(
            '681374925524619387379285614497831256238456179156927438843562791762198543915743862'
        )

        self.assertEqual(unicode(checkAnswer), unicode(answer))

    def test_solve_plainl1(self):
        """
        Test the solve_min function.
        """

        M = matrix([1, 1, 1, 1, 0, 1], (2, 3), 'd')
        b = ones_v(2)
        x = solve_plain_l1(M, b)
        self.assertEqual(tuple(b), tuple(M * x))
Esempio n. 2
0
class ProblemTest(unittest.TestCase):
    """
    Tests for l1sudoku Problem class
    """
    def setUp(self):
        """
        Instantiate one Problem at random from TOP95
        """
        self.sudoku = Problem(random_puzzle())
        self.N = 9
    
    def test_puzzle(self):
        """
        Test we create a Problem correctly from a string
        """
        print unicode(self.sudoku)
        self.assertEqual(self.N, self.sudoku.N)
        self.assertTrue(len(unicode(self.sudoku)) > self.sudoku.N **2)

    def test_box_size(self):
        """
        Test we get correct boxsize if N is square and large enough.
        """
        self.assertEqual(3, Problem("."*81,N=9).get_box_size())
        self.assertEqual(2, Problem("."*16,N=4).get_box_size())
        self.assertEqual(0, Problem("."*4,N=2).get_box_size())
        self.assertEqual(0, Problem("."*100,N=10).get_box_size())

    def test_nentries(self):
        """
        Check the Problem correctly counts the number
        of clue entries.        
        """
        sudoku = Problem('1' + '.'*(self.N **2 -1), N=self.N)
        self.assertEqual(1, sudoku.num_entries())
        
        rp = random_puzzle().strip()
        nentries_rp = len([e for e in rp if e != '.'])
        sudoku = Problem(rp)
        self.assertEqual(nentries_rp, sudoku.num_entries())
        
    def test_matrix(self):
        """
        Test the problem matrix generated by the Problem
        """
        m = self.sudoku.matrix()
        self.assertTrue(isinstance(m ,matrix ))
        
        nentries = len([e for e in self.sudoku.entries if e])
        N = self.sudoku.N
        self.assertEqual((4 * N**2 + nentries, N**3), m.size)                
        
    def test_to_indicator(self):
        """
        Test the problem matrix generated by the Problem
        """
        N = self.N
        num = randint(1,N)
        pos = randint(0,N**2-1)
        sudoku = make_problem(chr(ord('0') + num), pos)
        
        iv = sudoku.to_indicator_vector()
        self.assertTrue(isinstance(iv ,matrix ))
        self.assertEqual((N**3,1), iv.size)
        self.assertEqual(1, sum(iv))
        self.assertEqual(N*pos+num-1, list(iv).index(1))

        s2 = Problem.from_indicator_vector(iv)
        
        self.assertEqual(unicode(sudoku),unicode(s2))

    def test_all_cells_constraint(self):
        """
        Check the matrix constraint that ensures
        all cells are filled.
        """
        # - Construct a Problem with all cells filled
        # - Get the all_cells matrix
        # - Multiply it with the indicator vector
        # - check the result is all ones
        # - blank a cell, repeat
        # - check the result is not all ones
        N = self.N
        sudoku = Problem("1"*N**2)
        v = sudoku.get_result(all_cells=True)
        self.assertOnes(v)
        v = self.sudoku.get_result(all_cells=True)
        self.assertNotOnes(v)

    def test_row_digits_constraint(self):
        """
        Check the matrix constraint that ensures
        each row contains all digits
        """
        # - Construct a Problem with all cells filled
        # - Get the all_cells matrix
        # - Multiply it with the indicator vector
        # - check the result is all ones
        # - blank a cell, repeat
        # - check the result is not all ones
        N = 9
        sudoku = Problem("123456789"*N)
        v = sudoku.get_result(row_digits=True)
        self.assertOnes(v)
        v = self.sudoku.get_result(row_digits=True)
        self.assertNotOnes(v)

    def test_col_digits_constraint(self):
        """
        Check the matrix constraint that ensures
        each row contains all digits
        """
        # - Construct a Problem with all cells filled
        # - Get the all_cells matrix
        # - Multiply it with the indicator vector
        # - check the result is all ones
        # - blank a cell, repeat
        # - check the result is not all ones
        N = 9

        entries = reduce(operator.__add__,
                         [list(itertools.repeat(i,N)) for  i in range(1,N+1)])
        sudoku = Problem(entries)        
        v = sudoku.get_result(col_digits=True)
        self.assertOnes(v)
        v = self.sudoku.get_result(col_digits=True)
        self.assertNotOnes(v)

    def test_box_digits_constraint(self):
        """
        Check the matrix constraint that ensures
        each box contains all digits
        """
        # - Construct a Problem with all cells filled
        # - Get the all_cells matrix
        # - Multiply it with the indicator vector
        # - check the result is all ones
        # - blank a cell, repeat
        # - check the result is not all ones
        N = 9
        sudoku = Problem("123123123"
                         "456456456"
                         "789789789"
                         "123123123"
                         "456456456"
                         "789789789"
                         "123123123"
                         "456456456"
                         "789789789")
        v = sudoku.get_result(box_digits=True)
        self.assertOnes(v)
        v = self.sudoku.get_result(box_digits=True)
        self.assertNotOnes(v)


    def test_clues_constraint(self):
        """
        Check the matrix constraint that ensures
        the answer is consistent with the clues.
        """
        N = 9
        num = randint(1,N)
        pos = randint(0,N**2-1)
        sudoku = make_problem(chr(ord('0') + num), pos)

        v = sudoku.get_result(clues=True)
        self.assertOnes(v)

    def assertOnes(self, vector):
        """
        Assert the vector consists entirely of ones.
        """
        self.assertTrue(all_ones(vector))

    def assertNotOnes(self, vector):
        """
        Assert the vector does not consist entirely of ones.
        """
        self.assertFalse(all([e==1 for e in vector]))
        
    def test_solve(self):
        """
        Test solving the Problem.
        """
        # Easy test
        self.sudoku = Problem('.81.749....4.193.7379.85.14..7831...238456179..69274..843562791762198543..5743862')
        answer = self.sudoku.solve()
        checkAnswer = Problem('681374925524619387379285614497831256238456179156927438843562791762198543915743862')
        
        self.assertEqual(unicode(checkAnswer), unicode(answer) )

        answer = self.sudoku.solve()
        checkAnswer = Problem('681374925524619387379285614497831256238456179156927438843562791762198543915743862')
        
        self.assertEqual(unicode(checkAnswer), unicode(answer) )

    def test_solve_plainl1(self):
        """
        Test the solve_min function.
        """
        
        M = matrix([1,1,1,1,0,1],(2,3),'d')
        b = ones_v(2)
        x = solve_plain_l1(M, b)
        self.assertEqual(tuple(b), tuple(M*x))