220 lines
5.1 KiB
C++
220 lines
5.1 KiB
C++
/*
|
|
* testSudoku.cpp
|
|
* @brief develop code for Sudoku CSP solver
|
|
* @date Jan 29, 2012
|
|
* @author Frank Dellaert
|
|
*/
|
|
|
|
#include <gtsam_unstable/discrete/CSP.h>
|
|
#include <CppUnitLite/TestHarness.h>
|
|
#include <boost/assign/std/map.hpp>
|
|
using boost::assign::insert;
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <stdarg.h>
|
|
|
|
using namespace std;
|
|
using namespace gtsam;
|
|
|
|
#define PRINT false
|
|
|
|
class Sudoku: public CSP {
|
|
|
|
/// sudoku size
|
|
size_t n_;
|
|
|
|
/// discrete keys
|
|
typedef std::pair<size_t, size_t> IJ;
|
|
std::map<IJ, DiscreteKey> 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);
|
|
}
|
|
/* ************************************************************************* */
|
|
|