1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.

1660 lines
56 KiB
C++
Executable File

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Christopher Mears <chris.mears@monash.edu>
*
* 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 <gecode/kernel.hh>
#include <gecode/int.hh>
#include <gecode/int/branch.hh>
#ifdef GECODE_HAS_SET_VARS
#include <gecode/set.hh>
#include <gecode/set/branch.hh>
#include <stdarg.h>
#endif
#include <gecode/minimodel.hh>
#include "test/test.hh"
#include <vector>
/**
* \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 <class T, class VarArgsType>
bool
check(DFS<T>& e, std::vector<VarArgsType> 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 T>
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<OneArray> e(s,o);
bool r = check(e, T::expectedSolutions());
delete s;
return r;
}
};
#ifdef GECODE_HAS_SET_VARS
/// %Test for %LDSB infrastructure
template <class T>
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<OneArraySet> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntVarArray> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntVarArray> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntVarArray> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntVarArray> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntVarArray> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntVarArray> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntVarArray> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntVarArray> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<Latin> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntSetArgs> expectedSolutions(void) {
static std::vector<IntSetArgs> 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<IntSetArgs> expectedSolutions(void) {
static std::vector<IntSetArgs> 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<IntSetArgs> expectedSolutions(void) {
static std::vector<IntSetArgs> 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<IntSetArgs> expectedSolutions(void) {
static std::vector<IntSetArgs> 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<IntSetArgs> expectedSolutions(void) {
static std::vector<IntSetArgs> 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<IntVarArray> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> 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<IntArgs> expectedSolutions(void) {
static std::vector<IntArgs> expected;
expected.clear();
expected.push_back(IntArgs({0,1,2,3}));
return expected;
}
};
#endif
LDSB<VarSym1> varsym1("VarSym1");
LDSB<VarSym1b> varsym1b("VarSym1b");
LDSB<VarSym2> varsym2("VarSym2");
LDSB<VarSym3> varsym3("VarSym3");
LDSB<VarSym4> varsym4("VarSym4");
LDSB<VarSym5> varsym5("VarSym5");
LDSB<MatSym1> matsym1("MatSym1");
LDSB<MatSym2> matsym2("MatSym2");
LDSB<MatSym3> matsym3("MatSym3");
LDSB<MatSym4> matsym4("MatSym4");
LDSB<SimIntVarSym1> simintvarsym1("SimIntVarSym1");
LDSB<SimIntVarSym2> simintvarsym2("SimIntVarSym2");
LDSB<SimIntValSym1> simintvalsym1("SimIntValSym1");
LDSB<SimIntValSym2> simintvalsym2("SimIntValSym2");
LDSB<SimIntValSym3> simintvalsym3("SimIntValSym3");
LDSB<ValSym1> valsym1("ValSym1");
LDSB<ValSym1b> valsym1b("ValSym1b");
LDSB<ValSym1c> valsym1c("ValSym1c");
LDSB<ValSym2> valsym2("ValSym2");
LDSB<ValSym2b> valsym2b("ValSym2b");
LDSB<ValSym3> valsym3("ValSym3");
LDSB<ValSym4> valsym4("ValSym4");
LDSB<ValSym5> valsym5("ValSym5");
LDSB<VarValSym1> varvalsym1("VarValSym1");
LDSBLatin latin("Latin");
LDSB<Recomputation> recomp("Recomputation", 999,999);
LDSB<TieBreak> tiebreak("TieBreak");
#ifdef GECODE_HAS_SET_VARS
LDSB<ReflectSym1> reflectsym1("ReflectSym1");
LDSB<ReflectSym2> reflectsym2("ReflectSym2");
LDSB<Action1> action1("Action1");
LDSBSet<SetVarSym1> setvarsym1("SetVarSym1");
LDSBSet<SetValSym1> setvalsym1("SetValSym1");
LDSBSet<SetValSym2> setvalsym2("SetValSym2", 0, 1);
LDSBSet<SetVarSeqSym1> setvarseqsym1("SetVarSeqSym1");
LDSBSet<SetVarSeqSym2> setvarseqsym2("SetVarSeqSym2");
#endif
}}
// STATISTICS: test-core