/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christopher Mears * * Copyright: * Christopher Mears, 2012 * * This file is part of Gecode, the generic constraint * development environment: * http://www.gecode.org * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #ifdef GECODE_HAS_SET_VARS #include #include #include #endif #include #include "test/test.hh" #include /** * \namespace Test::LDSB * \brief Testing for LDSB */ namespace Test { namespace LDSB { using namespace Gecode; /// Returns true iff a and b are equal (they have the same size and /// the same elements in the same positions). bool equal(const IntArgs& a, const IntArgs& b) { if (a.size() != b.size()) return false; for (int i = 0 ; i < a.size() ; ++i) if (a[i] != b[i]) return false; return true; } #ifdef GECODE_HAS_SET_VARS /// Returns true iff a and b are equal (they have the same size and /// the same elements in the same positions). bool equal(const IntSetArgs& a, const IntSetArgs& b) { if (a.size() != b.size()) return false; for (int i = 0 ; i < a.size() ; ++i) { // Compare the two sets a[i] and b[i]. // Perhaps TODO: use Iter::Ranges::equal instead. if (a[i].size() != b[i].size()) return false; IntSetValues x(a[i]); IntSetValues y(b[i]); while (x() && y()) { if (x.val() != y.val()) return false; ++x; ++y; } } return true; } #endif /** * \brief Checks found solutions against expected solutions * * Iterates through the solutions returned by the search engine and * checks each one against the array of expected solutions. The * order of solutions must be the same. Returns true if the * expected solutions match the found solutions exactly, otherwise * prints an explanation to standard error and returns false. */ template bool check(DFS& e, std::vector expected) { int nexpected = expected.size(); for (int i = 0 ; i < nexpected ; ++i) { T* s = e.next(); if (s == nullptr) { if (opt.log) { olog << "Expected a solution but there are no more solutions." << std::endl; olog << "(Expected " << nexpected << " but only found " << i << ")" << std::endl; olog << "Expected: " << expected[i] << std::endl; } return false; } if (!equal(s->solution(), expected[i])) { if (opt.log) { olog << "Solution does not match expected." << std::endl; olog << "Solution: " << s->solution() << std::endl; olog << "Expected: " << expected[i] << std::endl; } return false; } delete s; } T* s = e.next(); if (s != nullptr) { if (opt.log) { olog << "More solutions than expected:" << std::endl; olog << "(Expected only " << nexpected << ")" << std::endl; olog << s->solution() << std::endl; } return false; } // Nothing went wrong. return true; } /// %Test space class OneArray : public Space { public: /// Variables IntVarArray xs; /// Constructor for creation OneArray(int n, int l, int u) : xs(*this,n,l,u) { } /// Constructor for cloning \a s OneArray(OneArray& s) : Space(s) { xs.update(*this,s.xs); } /// Copy during cloning virtual Space* copy(void) { return new OneArray(*this); } /// Return the solution as IntArgs IntArgs solution(void) { IntArgs a(xs.size()); for (int i = 0 ; i < a.size() ; ++i) a[i] = xs[i].val(); return a; } /// Expected solutions virtual IntArgs* expectedSolutions(void) { return nullptr; } }; #ifdef GECODE_HAS_SET_VARS /// %Test space (set version) class OneArraySet : public Space { public: /// Variables SetVarArray xs; /// Constructor for creation OneArraySet(int n, int l, int u) : xs(*this,n, IntSet::empty, l,u) { } /// Constructor for cloning \a s OneArraySet(OneArraySet& s) : Space(s) { xs.update(*this,s.xs); } /// Copy during cloning virtual Space* copy(void) { return new OneArraySet(*this); } /// Return the solution as IntSetArgs IntSetArgs solution(void) { IntSetArgs a(xs.size()); for (int i = 0 ; i < a.size() ; ++i) { SetVarGlbRanges glbranges(xs[i]); a[i] = IntSet(glbranges); } return a; } /// Expected solutions virtual IntSetArgs* expectedSolutions(void) { return nullptr; } }; #endif /// %Test for %LDSB infrastructure template class LDSB : public Base { public: /// Recomputation distance unsigned int c_d; /// Adaptation distance unsigned int a_d; /// Initialize test LDSB(std::string label, unsigned int c=0, unsigned int a=0) : Test::Base("LDSB::" + label), c_d(c), a_d(a) {} /// Perform actual tests bool run(void) { OneArray *s = new OneArray(T::n, T::l, T::u); T::setup(*s, s->xs); Search::Options o = Search::Options::def; if (c_d != 0) o.c_d = c_d; if (a_d != 0) o.a_d = a_d; DFS e(s,o); bool r = check(e, T::expectedSolutions()); delete s; return r; } }; #ifdef GECODE_HAS_SET_VARS /// %Test for %LDSB infrastructure template class LDSBSet : public Base { public: /// Recomputation distance unsigned int c_d; /// Adaptation distance unsigned int a_d; /// Initialize test LDSBSet(std::string label, unsigned int c=0, unsigned int a=0) : Test::Base("LDSB::" + label), c_d(c), a_d(a) {} /// Perform actual tests bool run(void) { OneArraySet *s = new OneArraySet(T::n, T::l, T::u); T::setup(*s, s->xs); Search::Options o = Search::Options::def; if (c_d != 0) o.c_d = c_d; if (a_d != 0) o.a_d = a_d; DFS e(s,o); bool r = check(e, T::expectedSolutions()); delete s; return r; } }; #endif // Test cases /// %Test for variable symmetry class VarSym1 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Symmetries syms; IntArgs indices({0,1,2,3}); syms << VariableSymmetry(xs, indices); distinct(home, xs); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3})); return expected; } }; /// %Test for variable symmetry class VarSym1b { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Symmetries syms; syms << VariableSymmetry(xs); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3})); return expected; } }; /// %Test for variable symmetry class VarSym2 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Symmetries syms; IntArgs indices({0,1,2,3}); syms << VariableSymmetry(xs); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0,0,0})); expected.push_back(IntArgs({0,0,0,1})); expected.push_back(IntArgs({0,0,0,2})); expected.push_back(IntArgs({0,0,0,3})); expected.push_back(IntArgs({0,0,1,1})); expected.push_back(IntArgs({0,0,1,2})); expected.push_back(IntArgs({0,0,1,3})); expected.push_back(IntArgs({0,0,2,2})); expected.push_back(IntArgs({0,0,2,3})); expected.push_back(IntArgs({0,0,3,3})); expected.push_back(IntArgs({0,1,1,1})); expected.push_back(IntArgs({0,1,1,2})); expected.push_back(IntArgs({0,1,1,3})); expected.push_back(IntArgs({0,1,2,2})); expected.push_back(IntArgs({0,1,2,3})); expected.push_back(IntArgs({0,1,3,3})); expected.push_back(IntArgs({0,2,2,2})); expected.push_back(IntArgs({0,2,2,3})); expected.push_back(IntArgs({0,2,3,3})); expected.push_back(IntArgs({0,3,3,3})); expected.push_back(IntArgs({1,1,1,1})); expected.push_back(IntArgs({1,1,1,2})); expected.push_back(IntArgs({1,1,1,3})); expected.push_back(IntArgs({1,1,2,2})); expected.push_back(IntArgs({1,1,2,3})); expected.push_back(IntArgs({1,1,3,3})); expected.push_back(IntArgs({1,2,2,2})); expected.push_back(IntArgs({1,2,2,3})); expected.push_back(IntArgs({1,2,3,3})); expected.push_back(IntArgs({1,3,3,3})); expected.push_back(IntArgs({2,2,2,2})); expected.push_back(IntArgs({2,2,2,3})); expected.push_back(IntArgs({2,2,3,3})); expected.push_back(IntArgs({2,3,3,3})); expected.push_back(IntArgs({3,3,3,3})); return expected; } }; /// %Test for variable symmetry class VarSym3 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Symmetries syms; distinct(home, xs); syms << VariableSymmetry(IntVarArgs() << xs[0] << xs[1]); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3})); expected.push_back(IntArgs({0,1,3,2})); expected.push_back(IntArgs({0,2,1,3})); expected.push_back(IntArgs({0,2,3,1})); expected.push_back(IntArgs({0,3,1,2})); expected.push_back(IntArgs({0,3,2,1})); expected.push_back(IntArgs({1,2,0,3})); expected.push_back(IntArgs({1,2,3,0})); expected.push_back(IntArgs({1,3,0,2})); expected.push_back(IntArgs({1,3,2,0})); expected.push_back(IntArgs({2,3,0,1})); expected.push_back(IntArgs({2,3,1,0})); return expected; } }; /// %Test for variable symmetry class VarSym4 { public: /// Number of variables static const int n = 3; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 2; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Symmetries s; IntVarArgs symvars; symvars << xs[0]; s << VariableSymmetry(symvars); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2})); expected.push_back(IntArgs({0,2,1})); expected.push_back(IntArgs({1,0,2})); expected.push_back(IntArgs({1,2,0})); expected.push_back(IntArgs({2,0,1})); expected.push_back(IntArgs({2,1,0})); return expected; } }; /// %Test for variable symmetry class VarSym5 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Matrix m(xs, 4, 1); Symmetries s; s << VariableSymmetry(m.slice(0,2, 0,1)); s << VariableSymmetry(m.slice(2,4, 0,1)); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3})); expected.push_back(IntArgs({0,2,1,3})); expected.push_back(IntArgs({0,3,1,2})); expected.push_back(IntArgs({1,2,0,3})); expected.push_back(IntArgs({1,3,0,2})); expected.push_back(IntArgs({2,3,0,1})); return expected; } }; /// %Test for matrix symmetry class MatSym1 { public: /// Number of variables static const int n = 6; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 1; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Matrix m(xs, 2, 3); Symmetries s; s << rows_interchange(m); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0, 0,0, 0,0})); expected.push_back(IntArgs({0,0, 0,0, 0,1})); expected.push_back(IntArgs({0,0, 0,0, 1,0})); expected.push_back(IntArgs({0,0, 0,0, 1,1})); expected.push_back(IntArgs({0,0, 0,1, 0,0})); expected.push_back(IntArgs({0,0, 0,1, 0,1})); expected.push_back(IntArgs({0,0, 0,1, 1,0})); expected.push_back(IntArgs({0,0, 0,1, 1,1})); expected.push_back(IntArgs({0,0, 1,0, 1,0})); expected.push_back(IntArgs({0,0, 1,0, 1,1})); expected.push_back(IntArgs({0,0, 1,1, 1,1})); expected.push_back(IntArgs({0,1, 0,0, 0,0})); expected.push_back(IntArgs({0,1, 0,0, 0,1})); expected.push_back(IntArgs({0,1, 0,0, 1,0})); expected.push_back(IntArgs({0,1, 0,0, 1,1})); expected.push_back(IntArgs({0,1, 0,1, 0,0})); expected.push_back(IntArgs({0,1, 0,1, 0,1})); expected.push_back(IntArgs({0,1, 0,1, 1,0})); expected.push_back(IntArgs({0,1, 0,1, 1,1})); expected.push_back(IntArgs({0,1, 1,0, 1,0})); expected.push_back(IntArgs({0,1, 1,0, 1,1})); expected.push_back(IntArgs({0,1, 1,1, 1,1})); expected.push_back(IntArgs({1,0, 1,0, 1,0})); expected.push_back(IntArgs({1,0, 1,0, 1,1})); expected.push_back(IntArgs({1,0, 1,1, 1,1})); expected.push_back(IntArgs({1,1, 1,1, 1,1})); return expected; } }; /// %Test for matrix symmetry class MatSym2 { public: /// Number of variables static const int n = 6; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 1; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Matrix m(xs, 2, 3); Symmetries s; s << columns_interchange(m); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0, 0,0, 0,0})); expected.push_back(IntArgs({0,0, 0,0, 0,1})); expected.push_back(IntArgs({0,0, 0,0, 1,1})); expected.push_back(IntArgs({0,0, 0,1, 0,0})); expected.push_back(IntArgs({0,0, 0,1, 0,1})); expected.push_back(IntArgs({0,0, 0,1, 1,0})); expected.push_back(IntArgs({0,0, 0,1, 1,1})); expected.push_back(IntArgs({0,0, 1,1, 0,0})); expected.push_back(IntArgs({0,0, 1,1, 0,1})); expected.push_back(IntArgs({0,0, 1,1, 1,1})); expected.push_back(IntArgs({0,1, 0,0, 0,0})); expected.push_back(IntArgs({0,1, 0,0, 0,1})); expected.push_back(IntArgs({0,1, 0,0, 1,0})); expected.push_back(IntArgs({0,1, 0,0, 1,1})); expected.push_back(IntArgs({0,1, 0,1, 0,0})); expected.push_back(IntArgs({0,1, 0,1, 0,1})); expected.push_back(IntArgs({0,1, 0,1, 1,0})); expected.push_back(IntArgs({0,1, 0,1, 1,1})); expected.push_back(IntArgs({0,1, 1,0, 0,0})); expected.push_back(IntArgs({0,1, 1,0, 0,1})); expected.push_back(IntArgs({0,1, 1,0, 1,0})); expected.push_back(IntArgs({0,1, 1,0, 1,1})); expected.push_back(IntArgs({0,1, 1,1, 0,0})); expected.push_back(IntArgs({0,1, 1,1, 0,1})); expected.push_back(IntArgs({0,1, 1,1, 1,0})); expected.push_back(IntArgs({0,1, 1,1, 1,1})); expected.push_back(IntArgs({1,1, 0,0, 0,0})); expected.push_back(IntArgs({1,1, 0,0, 0,1})); expected.push_back(IntArgs({1,1, 0,0, 1,1})); expected.push_back(IntArgs({1,1, 0,1, 0,0})); expected.push_back(IntArgs({1,1, 0,1, 0,1})); expected.push_back(IntArgs({1,1, 0,1, 1,0})); expected.push_back(IntArgs({1,1, 0,1, 1,1})); expected.push_back(IntArgs({1,1, 1,1, 0,0})); expected.push_back(IntArgs({1,1, 1,1, 0,1})); expected.push_back(IntArgs({1,1, 1,1, 1,1})); return expected; } }; /// %Test for matrix symmetry class MatSym3 { public: /// Number of variables static const int n = 6; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 1; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Matrix m(xs, 2, 3); Symmetries s; s << rows_interchange(m); s << columns_interchange(m); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0, 0,0, 0,0})); expected.push_back(IntArgs({0,0, 0,0, 0,1})); expected.push_back(IntArgs({0,0, 0,0, 1,1})); expected.push_back(IntArgs({0,0, 0,1, 0,0})); expected.push_back(IntArgs({0,0, 0,1, 0,1})); expected.push_back(IntArgs({0,0, 0,1, 1,0})); expected.push_back(IntArgs({0,0, 0,1, 1,1})); expected.push_back(IntArgs({0,0, 1,1, 1,1})); expected.push_back(IntArgs({0,1, 0,0, 0,0})); expected.push_back(IntArgs({0,1, 0,0, 0,1})); expected.push_back(IntArgs({0,1, 0,0, 1,0})); expected.push_back(IntArgs({0,1, 0,0, 1,1})); expected.push_back(IntArgs({0,1, 0,1, 0,0})); expected.push_back(IntArgs({0,1, 0,1, 0,1})); expected.push_back(IntArgs({0,1, 0,1, 1,0})); expected.push_back(IntArgs({0,1, 0,1, 1,1})); expected.push_back(IntArgs({0,1, 1,0, 1,0})); expected.push_back(IntArgs({0,1, 1,0, 1,1})); expected.push_back(IntArgs({0,1, 1,1, 1,1})); expected.push_back(IntArgs({1,1, 1,1, 1,1})); return expected; } }; /// %Test for matrix symmetry class MatSym4 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 1; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Matrix m(xs, 1, 4); Symmetries s; s << rows_reflect(m); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0, 0, 0, 0})); expected.push_back(IntArgs({0, 0, 0, 1})); expected.push_back(IntArgs({0, 0, 1, 0})); expected.push_back(IntArgs({0, 0, 1, 1})); expected.push_back(IntArgs({0, 1, 0, 0})); expected.push_back(IntArgs({0, 1, 0, 1})); expected.push_back(IntArgs({0, 1, 1, 0})); expected.push_back(IntArgs({0, 1, 1, 1})); expected.push_back(IntArgs({1, 0, 0, 1})); expected.push_back(IntArgs({1, 0, 1, 1})); expected.push_back(IntArgs({1, 1, 1, 1})); return expected; } }; /// %Test for variable sequence symmetry class SimIntVarSym1 { public: /// Number of variables static const int n = 12; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Matrix m(xs, 3, 4); // The values in the first column are distinct. distinct(home, m.col(0)); // Each row sums to 3. for (int i = 0 ; i < 4 ; ++i) linear(home, m.row(i), IRT_EQ, 3); // Rows are interchangeable. Symmetries s; s << VariableSequenceSymmetry(xs, 3); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0,3, 1,0,2, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,0,3, 1,0,2, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,0,3, 1,1,1, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,0,3, 1,1,1, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,0,3, 1,2,0, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,0,3, 1,2,0, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,1,2, 1,0,2, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,1,2, 1,0,2, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,1,2, 1,1,1, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,1,2, 1,1,1, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,1,2, 1,2,0, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,1,2, 1,2,0, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,2,1, 1,0,2, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,2,1, 1,0,2, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,2,1, 1,1,1, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,2,1, 1,1,1, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,2,1, 1,2,0, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,2,1, 1,2,0, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,3,0, 1,0,2, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,3,0, 1,0,2, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,3,0, 1,1,1, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,3,0, 1,1,1, 2,1,0, 3,0,0})); expected.push_back(IntArgs({0,3,0, 1,2,0, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,3,0, 1,2,0, 2,1,0, 3,0,0})); return expected; } }; /// %Test for variable sequence symmetry class SimIntVarSym2 { /// Number of rows static const int nrows = 4; /// Number of columns static const int ncols = 3; public: /// Number of variables static const int n = nrows*ncols; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Matrix m(xs, 3, 4); // The values in the first column are distinct. distinct(home, m.col(0)); // Each row sums to 3. for (int i = 0 ; i < nrows ; ++i) linear(home, m.row(i), IRT_EQ, 3); Symmetries s; IntArgs a = IntArgs::create(n, 0); // Rows are interchangeable. s << VariableSequenceSymmetry(xs, 3); // Elements (i,1) and (i,2) in row i are interchangeable, // separately for each row. for (int i = 0 ; i < nrows ; i++) { IntVarArgs symvars; symvars << m(1,i) << m(2,i); s << VariableSymmetry(symvars); } branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0,3, 1,0,2, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,0,3, 1,1,1, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,1,2, 1,0,2, 2,0,1, 3,0,0})); expected.push_back(IntArgs({0,1,2, 1,1,1, 2,0,1, 3,0,0})); return expected; } }; /// %Test for value sequence symmetry class SimIntValSym1 { public: /// Number of variables static const int n = 2; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 6; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { rel(home, xs[0] + xs[1] == 6); // Values 0,1,2 are symmetric with 6,5,4. IntArgs values({0,1,2, 6,5,4}); Symmetries s; s << ValueSequenceSymmetry(values, 3); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,6})); expected.push_back(IntArgs({1,5})); expected.push_back(IntArgs({2,4})); expected.push_back(IntArgs({3,3})); return expected; } }; /// %Test for value sequence symmetry class SimIntValSym2 { public: /// Number of variables static const int n = 3; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 8; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { TupleSet tuples(3); tuples.add({1,1,1}).add({4,4,4}).add({7,7,7}) .add({0,1,5}).add({0,1,8}).add({3,4,2}) .add({3,4,8}).add({6,7,2}).add({6,7,5}) .finalize(); extensional(home, xs, tuples); // Values 0,1,2 are symmetric with 3,4,5, and with 6,7,8. IntArgs values({0,1,2, 3,4,5, 6,7,8}); Symmetries s; s << ValueSequenceSymmetry(values, 3); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,5})); expected.push_back(IntArgs({1,1,1})); return expected; } }; /// %Test for value sequence symmetry class SimIntValSym3 { public: /// Number of variables static const int n = 2; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 6; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { rel(home, xs[0] + xs[1] == 6); Symmetries s; // Values 0,1,2 are symmetric with 6,5,4. s << values_reflect(0,6); branch(home, xs, INT_VAR_NONE(), INT_VAL_MED(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({3,3})); expected.push_back(IntArgs({2,4})); expected.push_back(IntArgs({1,5})); expected.push_back(IntArgs({0,6})); return expected; } }; /// %Test for value symmetry class ValSym1 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Symmetries s; IntArgs indices({0,1,2,3}); s << ValueSymmetry(indices); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3})); return expected; } }; /// %Test for value symmetry class ValSym1b { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Symmetries s; s << ValueSymmetry(xs[0]); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3})); return expected; } }; /// %Test for value symmetry class ValSym1c { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Symmetries s; s << ValueSymmetry(xs[0]); branch(home, xs, INT_VAR_NONE(), INT_VAL_MAX(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({3,2,1,0})); return expected; } }; /// %Test for value symmetry class ValSym2 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Symmetries s; IntArgs indices({0,1,2,3}); s << ValueSymmetry(indices); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0,0,0})); expected.push_back(IntArgs({0,0,0,1})); expected.push_back(IntArgs({0,0,1,0})); expected.push_back(IntArgs({0,0,1,1})); expected.push_back(IntArgs({0,0,1,2})); expected.push_back(IntArgs({0,1,0,0})); expected.push_back(IntArgs({0,1,0,1})); expected.push_back(IntArgs({0,1,0,2})); expected.push_back(IntArgs({0,1,1,0})); expected.push_back(IntArgs({0,1,1,1})); expected.push_back(IntArgs({0,1,1,2})); expected.push_back(IntArgs({0,1,2,0})); expected.push_back(IntArgs({0,1,2,1})); expected.push_back(IntArgs({0,1,2,2})); expected.push_back(IntArgs({0,1,2,3})); return expected; } }; /// %Test for value symmetry class ValSym2b { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Symmetries s; s << ValueSymmetry(xs[0]); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0,0,0})); expected.push_back(IntArgs({0,0,0,1})); expected.push_back(IntArgs({0,0,1,0})); expected.push_back(IntArgs({0,0,1,1})); expected.push_back(IntArgs({0,0,1,2})); expected.push_back(IntArgs({0,1,0,0})); expected.push_back(IntArgs({0,1,0,1})); expected.push_back(IntArgs({0,1,0,2})); expected.push_back(IntArgs({0,1,1,0})); expected.push_back(IntArgs({0,1,1,1})); expected.push_back(IntArgs({0,1,1,2})); expected.push_back(IntArgs({0,1,2,0})); expected.push_back(IntArgs({0,1,2,1})); expected.push_back(IntArgs({0,1,2,2})); expected.push_back(IntArgs({0,1,2,3})); return expected; } }; /// %Test for value symmetry class ValSym3 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Symmetries s; IntArgs indices({0,1}); s << ValueSymmetry(indices); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3})); expected.push_back(IntArgs({0,1,3,2})); expected.push_back(IntArgs({0,2,1,3})); expected.push_back(IntArgs({0,2,3,1})); expected.push_back(IntArgs({0,3,1,2})); expected.push_back(IntArgs({0,3,2,1})); expected.push_back(IntArgs({2,0,1,3})); expected.push_back(IntArgs({2,0,3,1})); expected.push_back(IntArgs({2,3,0,1})); expected.push_back(IntArgs({3,0,1,2})); expected.push_back(IntArgs({3,0,2,1})); expected.push_back(IntArgs({3,2,0,1})); return expected; } }; /// %Test for value symmetry class ValSym4 { public: /// Number of variables static const int n = 3; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 2; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Symmetries s; IntArgs indices({0}); s << ValueSymmetry(indices); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2})); expected.push_back(IntArgs({0,2,1})); expected.push_back(IntArgs({1,0,2})); expected.push_back(IntArgs({1,2,0})); expected.push_back(IntArgs({2,0,1})); expected.push_back(IntArgs({2,1,0})); return expected; } }; /// %Test for value symmetry class ValSym5 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Symmetries s; IntArgs indices0({0,1}); IntArgs indices1({2,3}); s << ValueSymmetry(indices0); s << ValueSymmetry(indices1); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3})); expected.push_back(IntArgs({0,2,1,3})); expected.push_back(IntArgs({0,2,3,1})); expected.push_back(IntArgs({2,0,1,3})); expected.push_back(IntArgs({2,0,3,1})); expected.push_back(IntArgs({2,3,0,1})); return expected; } }; /// %Test for variable and value symmetry class VarValSym1 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Symmetries s; s << VariableSymmetry(xs); s << ValueSymmetry(IntArgs::create(4,0)); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0,0,0})); expected.push_back(IntArgs({0,0,0,1})); expected.push_back(IntArgs({0,0,1,1})); expected.push_back(IntArgs({0,0,1,2})); expected.push_back(IntArgs({0,1,1,1})); expected.push_back(IntArgs({0,1,1,2})); expected.push_back(IntArgs({0,1,2,2})); // This solution is symmetric to the previous one. expected.push_back(IntArgs({0,1,2,3})); return expected; } }; /// %Test for %LDSB infrastructure with %Latin square problem class LDSBLatin : public Base { public: /// %Latin square space class Latin : public Space { public: IntVarArray xs; Latin(int n = 4) : xs(*this, n*n, 1, n) { Matrix m(xs, n, n); for (int i = 0 ; i < n ; i++) { distinct(*this, m.col(i)); distinct(*this, m.row(i)); } Symmetries s; s << rows_interchange(m); s << columns_interchange(m); s << ValueSymmetry(IntSet(1,n)); branch(*this, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } // Search support. Latin(Latin& s) : Space(s) { xs.update(*this, s.xs); } virtual Space* copy(void) { return new Latin(*this); } IntArgs solution(void) { IntArgs a(xs.size()); for (int i = 0 ; i < a.size() ; ++i) a[i] = xs[i].val(); return a; } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({1,2,3,4, 2,1,4,3, 3,4,1,2, 4,3,2,1})); expected.push_back(IntArgs({1,2,3,4, 2,1,4,3, 3,4,2,1, 4,3,1,2})); expected.push_back(IntArgs({1,2,3,4, 2,3,4,1, 3,4,1,2, 4,1,2,3})); expected.push_back(IntArgs({1,2,3,4, 2,4,1,3, 3,1,4,2, 4,3,2,1})); return expected; } }; /// Initialize test LDSBLatin(std::string label) : Test::Base("LDSB::" + label) {} /// Perform actual tests bool run(void) { Latin *s = new Latin(); DFS e(s); bool r = check(e, Latin::expectedSolutions()); delete s; return r; } }; /* This test should fail if the recomputation-handling does not work * properly. * * Why recomputation can be a problem * ================================== * * Every branch point in LDSB is binary, with a left and a right * branch. Whenever backtracking happens -- when a right branch is * explored -- LDSB computes a set of symmetric literals to * exclude. * * !!! This calculation may depend on the current domains of the * !!! variables. * * During recomputation, parts of the search tree are replayed. To * be specific, the branching constraints are posted, but no * propagation happens. This means that at a given branch point, * the domains during recomputation may be different (weaker) than * they were the first time during search. * * !!! This *cannot* cause solutions to be missed --- LDSB will not * !!! be incorrect --- but it *does* change what will be pruned. * * If recomputation is not handled properly, the difference in * domains will cause extra solutions to be found. This is a result * of symmetries failing to be broken. * */ /// %Test for handling of recomputation class Recomputation { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 1; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { TupleSet t(2); t.add({0,0}).add({1,1}).finalize(); IntVarArgs va; va << xs[0] << xs[2]; extensional(home, va, t); Symmetries syms; syms << VariableSequenceSymmetry(xs, 2); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0,0,0})); expected.push_back(IntArgs({0,0,0,1})); // This is the solution that will be found if recomputation is // not handled. After branching on x[0]=0, we try x[1]=0. When // x[1]=0 backtracks, the symmetry [x[0],x[1]] <-> [x[2],x[3]] // is active --- but only after propagation! (Without // propagation, we do not have x[2]=0.) If propagation happens, // we know that symmetry is active and we can post x[3]!=0. If // it doesn't, we don't use the symmetry and we find a solution // where x[3]=0. // expected.push_back(IntArgs({0,1,0,0})); expected.push_back(IntArgs({0,1,0,1})); expected.push_back(IntArgs({1,0,1,0})); expected.push_back(IntArgs({1,0,1,1})); expected.push_back(IntArgs({1,1,1,1})); return expected; } }; double position(const Space& home, IntVar x, int i) { (void) home; (void) x; return i; } /// %Test tiebreaking variable heuristic. class TieBreak { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Symmetries syms; IntArgs indices({0,1,2,3}); syms << VariableSymmetry(xs, indices); distinct(home, xs); // This redundant constraint is to trick the variable // heuristic. rel(home, xs[1] != xs[2]); // xs[1] and xs[2] have higher degree than the others, so they // are considered first. xs[2] is higher than x[1] by the merit // function, so it is assigned first. Now all remaining // variables have the same degree, so they are searched in // reverse order (according to the merit function). So, the // solution found is {3, 2, 0, 1}. branch(home, xs, tiebreak(INT_VAR_DEGREE_MAX(), INT_VAR_MERIT_MAX(position)), INT_VAL_MIN(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({3,2,0,1})); return expected; } }; #ifdef GECODE_HAS_SET_VARS /// Convenient way to make IntSetArgs IntSetArgs ISA(int n, ...) { IntSetArgs sets; va_list args; va_start(args, n); int i = 0; IntArgs a; while (i < n) { int x = va_arg(args,int); if (x == -1) { i++; sets << IntSet(a); a = IntArgs(); } else { a << x; } } va_end(args); return sets; } /// %Test for set variable symmetry class SetVarSym1 { public: /// Number of variables static const int n = 2; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 1; /// Setup problem constraints and symmetries static void setup(Home home, SetVarArray& xs) { Symmetries syms; syms << VariableSymmetry(xs); branch(home, xs, SET_VAR_NONE(), SET_VAL_MIN_INC(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(ISA(2, 0,1,-1, 0,1,-1)); expected.push_back(ISA(2, 0,1,-1, 0, -1)); expected.push_back(ISA(2, 0,1,-1, 1,-1)); expected.push_back(ISA(2, 0,1,-1, -1)); expected.push_back(ISA(2, 0, -1, 0,1,-1)); expected.push_back(ISA(2, 0, -1, 0, -1)); expected.push_back(ISA(2, 0, -1, 1,-1)); expected.push_back(ISA(2, 0, -1, -1)); // expected.push_back(ISA(2, 1,-1, 0,1,-1)); // expected.push_back(ISA(2, 1,-1, 0, -1)); expected.push_back(ISA(2, 1,-1, 1,-1)); expected.push_back(ISA(2, 1,-1, -1)); // expected.push_back(ISA(2, -1, 0,1,-1)); // expected.push_back(ISA(2, -1, 0, -1)); // expected.push_back(ISA(2, -1, 1,-1)); expected.push_back(ISA(2, -1, -1)); return expected; } }; /* * This tests the special handling of value symmetries on set * values. Look at the third solution (commented out) below. The * first variable has been assigned to {0,1}. If the value symmetry * is not handled specially, then we will consider the value * symmetry broken because the search has touched each value. * However, because both values have been assigned to the same * variable, 0 and 1 are still symmetric. Therefore, the third * solution is symmetric to the second one and should be excluded. */ /// %Test for set value symmetry class SetValSym1 { public: /// Number of variables static const int n = 2; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 1; /// Setup problem constraints and symmetries static void setup(Home home, SetVarArray& xs) { Symmetries syms; syms << ValueSymmetry(IntArgs({0,1})); branch(home, xs, SET_VAR_NONE(), SET_VAL_MIN_INC(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(ISA(2, 0,1,-1, 0,1,-1)); expected.push_back(ISA(2, 0,1,-1, 0, -1)); // expected.push_back(ISA(2, 0,1,-1, 1,-1)); // XXXXX bad solution expected.push_back(ISA(2, 0,1,-1, -1)); expected.push_back(ISA(2, 0, -1, 0,1,-1)); expected.push_back(ISA(2, 0, -1, 0, -1)); expected.push_back(ISA(2, 0, -1, 1,-1)); expected.push_back(ISA(2, 0, -1, -1)); // expected.push_back(ISA(2, 1,-1, 0,1,-1)); // expected.push_back(ISA(2, 1,-1, 0, -1)); // expected.push_back(ISA(2, 1,-1, 1,-1)); // expected.push_back(ISA(2, 1,-1, -1)); expected.push_back(ISA(2, -1, 0,1,-1)); expected.push_back(ISA(2, -1, 0, -1)); // expected.push_back(ISA(2, -1, 1,-1)); expected.push_back(ISA(2, -1, -1)); return expected; } }; /// %Test for set value symmetry class SetValSym2 { public: /// Number of variables static const int n = 3; /// Lower bound of values static const int l = 1; /// Upper bound of values static const int u = 4; /// Setup problem constraints and symmetries static void setup(Home home, SetVarArray& xs) { Symmetries syms; syms << ValueSymmetry(IntArgs({1,2,3,4})); for (int i = 0 ; i < 3 ; i++) cardinality(home, xs[i], 1, 1); branch(home, xs, SET_VAR_NONE(), SET_VAL_MIN_INC(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(ISA(3, 1,-1, 1,-1, 1,-1)); expected.push_back(ISA(3, 1,-1, 1,-1, 2,-1)); expected.push_back(ISA(3, 1,-1, 2,-1, 1,-1)); expected.push_back(ISA(3, 1,-1, 2,-1, 2,-1)); expected.push_back(ISA(3, 1,-1, 2,-1, 3,-1)); return expected; } }; /// %Test for set variable sequence symmetry class SetVarSeqSym1 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 1; /// Setup problem constraints and symmetries static void setup(Home home, SetVarArray& xs) { Symmetries syms; syms << VariableSequenceSymmetry(xs,2); rel(home, xs[0], SOT_INTER, xs[1], SRT_EQ, IntSet::empty); rel(home, xs[2], SOT_INTER, xs[3], SRT_EQ, IntSet::empty); for (int i = 0 ; i < 4 ; i++) cardinality(home, xs[i], 1, 1); branch(home, xs, SET_VAR_NONE(), SET_VAL_MIN_INC(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(ISA(4, 0,-1, 1,-1, 0,-1, 1,-1)); expected.push_back(ISA(4, 0,-1, 1,-1, 1,-1, 0,-1)); // expected.push_back(ISA(4, 1,-1, 0,-1, 0,-1, 1,-1)); expected.push_back(ISA(4, 1,-1, 0,-1, 1,-1, 0,-1)); return expected; } }; /// %Test for set variable sequence symmetry class SetVarSeqSym2 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 0; /// Setup problem constraints and symmetries static void setup(Home home, SetVarArray& xs) { Symmetries syms; syms << VariableSequenceSymmetry(xs,2); rel(home, xs[0], SRT_EQ, xs[2]); branch(home, xs, SET_VAR_NONE(), SET_VAL_MIN_INC(), syms); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); // Symmetric solutions are commented out. expected.push_back(ISA(4, 0, -1,0,-1,0,-1,0,-1)); expected.push_back(ISA(4, 0, -1,0,-1,0,-1, -1)); // expected.push_back(ISA(4, 0, -1,0,-1, -1,0,-1)); // expected.push_back(ISA(4, 0, -1,0,-1, -1, -1)); // expected.push_back(ISA(4, 0, -1, -1,0,-1,0,-1)); expected.push_back(ISA(4, 0, -1, -1,0,-1, -1)); // expected.push_back(ISA(4, 0, -1, -1, -1,0,-1)); // expected.push_back(ISA(4, 0, -1, -1, -1, -1)); // expected.push_back(ISA(4, -1,0,-1,0,-1,0,-1)); // expected.push_back(ISA(4, -1,0,-1,0,-1, -1)); expected.push_back(ISA(4, -1,0,-1, -1,0,-1)); expected.push_back(ISA(4, -1,0,-1, -1, -1)); // expected.push_back(ISA(4, -1, -1,0,-1,0,-1)); // expected.push_back(ISA(4, -1, -1,0,-1, -1)); // expected.push_back(ISA(4, -1, -1, -1,0,-1)); expected.push_back(ISA(4, -1, -1, -1, -1)); return expected; } }; /// %Test for reflection symmetry class ReflectSym1 { public: /// Number of variables static const int n = 6; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 6; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Matrix m(xs, 3, 2); distinct(home, xs); rel(home, abs(m(0,0)-m(1,0))==1); rel(home, abs(m(0,1)-m(1,1))==1); rel(home, abs(m(1,0)-m(2,0))==1); rel(home, abs(m(1,1)-m(2,1))==1); Symmetries s; s << values_reflect(l, u); s << rows_interchange(m); s << columns_reflect(m); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3,4,5})); expected.push_back(IntArgs({0,1,2,4,5,6})); expected.push_back(IntArgs({0,1,2,5,4,3})); expected.push_back(IntArgs({0,1,2,6,5,4})); return expected; } }; /// %Test for reflection symmetry class ReflectSym2 { public: /// Number of variables static const int n = 2; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { Symmetries s; s << values_reflect(l, u); branch(home, xs, INT_VAR_NONE(), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,0})); expected.push_back(IntArgs({0,1})); expected.push_back(IntArgs({0,2})); expected.push_back(IntArgs({0,3})); expected.push_back(IntArgs({1,0})); expected.push_back(IntArgs({1,1})); expected.push_back(IntArgs({1,2})); expected.push_back(IntArgs({1,3})); return expected; } }; /// %Test with action class Action1 { public: /// Number of variables static const int n = 4; /// Lower bound of values static const int l = 0; /// Upper bound of values static const int u = 3; /// Setup problem constraints and symmetries static void setup(Home home, IntVarArray& xs) { distinct(home, xs); Symmetries s; s << VariableSymmetry(xs); s << ValueSymmetry(IntArgs::create(4,0)); branch(home, xs, INT_VAR_ACTION_MIN(0.8), INT_VAL_MIN(), s); } /// Compute list of expected solutions static std::vector expectedSolutions(void) { static std::vector expected; expected.clear(); expected.push_back(IntArgs({0,1,2,3})); return expected; } }; #endif LDSB varsym1("VarSym1"); LDSB varsym1b("VarSym1b"); LDSB varsym2("VarSym2"); LDSB varsym3("VarSym3"); LDSB varsym4("VarSym4"); LDSB varsym5("VarSym5"); LDSB matsym1("MatSym1"); LDSB matsym2("MatSym2"); LDSB matsym3("MatSym3"); LDSB matsym4("MatSym4"); LDSB simintvarsym1("SimIntVarSym1"); LDSB simintvarsym2("SimIntVarSym2"); LDSB simintvalsym1("SimIntValSym1"); LDSB simintvalsym2("SimIntValSym2"); LDSB simintvalsym3("SimIntValSym3"); LDSB valsym1("ValSym1"); LDSB valsym1b("ValSym1b"); LDSB valsym1c("ValSym1c"); LDSB valsym2("ValSym2"); LDSB valsym2b("ValSym2b"); LDSB valsym3("ValSym3"); LDSB valsym4("ValSym4"); LDSB valsym5("ValSym5"); LDSB varvalsym1("VarValSym1"); LDSBLatin latin("Latin"); LDSB recomp("Recomputation", 999,999); LDSB tiebreak("TieBreak"); #ifdef GECODE_HAS_SET_VARS LDSB reflectsym1("ReflectSym1"); LDSB reflectsym2("ReflectSym2"); LDSB action1("Action1"); LDSBSet setvarsym1("SetVarSym1"); LDSBSet setvalsym1("SetValSym1"); LDSBSet setvalsym2("SetValSym2", 0, 1); LDSBSet setvarseqsym1("SetVarSeqSym1"); LDSBSet setvarseqsym2("SetVarSeqSym2"); #endif }} // STATISTICS: test-core