/* * testSudoku.cpp * @brief develop code for Sudoku CSP solver * @date Jan 29, 2012 * @author Frank Dellaert */ #include #include #include using boost::assign::insert; #include #include #include using namespace std; using namespace gtsam; #define PRINT false class Sudoku: public CSP { /// sudoku size size_t n_; /// discrete keys typedef std::pair IJ; std::map dkeys_; public: /// return DiscreteKey for cell(i,j) const DiscreteKey& dkey(size_t i, size_t j) const { return dkeys_.at(IJ(i, j)); } /// return Key for cell(i,j) Key key(size_t i, size_t j) const { return dkey(i, j).first; } /// Constructor Sudoku(size_t n, ...) : n_(n) { // Create variables, ordering, and unary constraints va_list ap; va_start(ap, n); Key k=0; for (size_t i = 0; i < n; ++i) { for (size_t j = 0; j < n; ++j, ++k) { // create the key IJ ij(i, j); dkeys_[ij] = DiscreteKey(k, n); // get the unary constraint, if any int value = va_arg(ap, int); // cout << value << " "; if (value != 0) addSingleValue(dkeys_[ij], value - 1); } //cout << endl; } va_end(ap); // add row constraints for (size_t i = 0; i < n; i++) { DiscreteKeys dkeys; for (size_t j = 0; j < n; j++) dkeys += dkey(i, j); addAllDiff(dkeys); } // add col constraints for (size_t j = 0; j < n; j++) { DiscreteKeys dkeys; for (size_t i = 0; i < n; i++) dkeys += dkey(i, j); addAllDiff(dkeys); } // add box constraints size_t N = (size_t)sqrt(double(n)), i0 = 0; for (size_t I = 0; I < N; I++) { size_t j0 = 0; for (size_t J = 0; J < N; J++) { // Box I,J DiscreteKeys dkeys; for (size_t i = i0; i < i0 + N; i++) for (size_t j = j0; j < j0 + N; j++) dkeys += dkey(i, j); addAllDiff(dkeys); j0 += N; } i0 += N; } } /// Print readable form of assignment void printAssignment(DiscreteFactor::sharedValues assignment) const { for (size_t i = 0; i < n_; i++) { for (size_t j = 0; j < n_; j++) { Key k = key(i, j); cout << 1 + assignment->at(k) << " "; } cout << endl; } } /// solve and print solution void printSolution() { DiscreteFactor::sharedValues MPE = optimalAssignment(); printAssignment(MPE); } }; /* ************************************************************************* */ TEST_UNSAFE( Sudoku, small) { Sudoku csp(4, 1,0, 0,4, 0,0, 0,0, 4,0, 2,0, 0,1, 0,0); // Do BP csp.runArcConsistency(4,10,PRINT); // optimize and check CSP::sharedValues solution = csp.optimalAssignment(); CSP::Values expected; insert(expected) (csp.key(0,0), 0)(csp.key(0,1), 1)(csp.key(0,2), 2)(csp.key(0,3), 3) (csp.key(1,0), 2)(csp.key(1,1), 3)(csp.key(1,2), 0)(csp.key(1,3), 1) (csp.key(2,0), 3)(csp.key(2,1), 2)(csp.key(2,2), 1)(csp.key(2,3), 0) (csp.key(3,0), 1)(csp.key(3,1), 0)(csp.key(3,2), 3)(csp.key(3,3), 2); EXPECT(assert_equal(expected,*solution)); //csp.printAssignment(solution); } /* ************************************************************************* */ TEST_UNSAFE( Sudoku, easy) { Sudoku sudoku(9, 0,0,5, 0,9,0, 0,0,1, 0,0,0, 0,0,2, 0,7,3, 7,6,0, 0,0,8, 2,0,0, 0,1,2, 0,0,9, 0,0,4, 0,0,0, 2,0,3, 0,0,0, 3,0,0, 1,0,0, 9,6,0, 0,0,1, 9,0,0, 0,5,8, 9,7,0, 5,0,0, 0,0,0, 5,0,0, 0,3,0, 7,0,0); // Do BP sudoku.runArcConsistency(4,10,PRINT); // sudoku.printSolution(); // don't do it } /* ************************************************************************* */ TEST_UNSAFE( Sudoku, extreme) { Sudoku sudoku(9, 0,0,9, 7,4,8, 0,0,0, 7,0,0, 0,0,0, 0,0,0, 0,2,0, 1,0,9, 0,0,0, 0,0,7, 0,0,0, 2,4,0, 0,6,4, 0,1,0, 5,9,0, 0,9,8, 0,0,0, 3,0,0, 0,0,0, 8,0,3, 0,2,0, 0,0,0, 0,0,0, 0,0,6, 0,0,0, 2,7,5, 9,0,0); // Do BP sudoku.runArcConsistency(9,10,PRINT); #ifdef METIS VariableIndexOrdered index(sudoku); index.print("index"); ofstream os("/Users/dellaert/src/hmetis-1.5-osx-i686/extreme-dual.txt"); index.outputMetisFormat(os); #endif //sudoku.printSolution(); // don't do it } /* ************************************************************************* */ TEST_UNSAFE( Sudoku, AJC_3star_Feb8_2012) { Sudoku sudoku(9, 9,5,0, 0,0,6, 0,0,0, 0,8,4, 0,7,0, 0,0,0, 6,2,0, 5,0,0, 4,0,0, 0,0,0, 2,9,0, 6,0,0, 0,9,0, 0,0,0, 0,2,0, 0,0,2, 0,6,3, 0,0,0, 0,0,9, 0,0,7, 0,6,8, 0,0,0, 0,3,0, 2,9,0, 0,0,0, 1,0,0, 0,3,7); // Do BP sudoku.runArcConsistency(9,10,PRINT); //sudoku.printSolution(); // don't do it } /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */