git-subtree-dir: software/mza git-subtree-split: f970a59b177c13ca3dd8aaef8cc6681d83b7e813
206 lines
6.7 KiB
C++
206 lines
6.7 KiB
C++
/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
|
|
|
/*
|
|
* Main authors:
|
|
* Pierre WILKE (wilke.pierre@gmail.com)
|
|
* Andrea Rendl (andrea.rendl@nicta.com.au)
|
|
*/
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef __GECODE_AUX_BRANCHER_HH__
|
|
#define __GECODE_AUX_BRANCHER_HH__
|
|
|
|
#include <gecode/int.hh>
|
|
#include <gecode/kernel.hh>
|
|
#include <gecode/search.hh>
|
|
#ifdef GECODE_HAS_SET_VARS
|
|
#include <gecode/set.hh>
|
|
#endif
|
|
|
|
#ifdef GECODE_HAS_FLOAT_VARS
|
|
#include <gecode/float.hh>
|
|
#endif
|
|
|
|
#include <minizinc/solvers/gecode_solverinstance.hh>
|
|
|
|
#include <gecode/driver.hh>
|
|
|
|
/**
|
|
* \brief Branching on the introduced variables
|
|
*
|
|
* This brancher makes sure that when a solution is found for the model
|
|
* variables, all introduced variables are either assigned, or the solution
|
|
* can be extended to a solution of the introduced variables.
|
|
*
|
|
* The advantage over simply branching over the introduced variables is that
|
|
* only one such extension will be searched for, instead of enumerating all
|
|
* possible (equivalent) extensions.
|
|
*
|
|
*/
|
|
namespace MiniZinc {
|
|
|
|
class AuxVarBrancher : public Gecode::Brancher {
|
|
protected:
|
|
/// Flag whether brancher is done
|
|
bool done;
|
|
/// Construct brancher
|
|
AuxVarBrancher(Gecode::Home home, Gecode::TieBreak<Gecode::IntVarBranch> int_varsel0,
|
|
Gecode::IntValBranch int_valsel0,
|
|
Gecode::TieBreak<Gecode::BoolVarBranch> bool_varsel0,
|
|
Gecode::BoolValBranch bool_valsel0
|
|
#ifdef GECODE_HAS_SET_VARS
|
|
,
|
|
Gecode::SetVarBranch set_varsel0, Gecode::SetValBranch set_valsel0
|
|
#endif
|
|
#ifdef GECODE_HAS_FLOAT_VARS
|
|
,
|
|
Gecode::TieBreak<Gecode::FloatVarBranch> float_varsel0,
|
|
Gecode::FloatValBranch float_valsel0
|
|
#endif
|
|
)
|
|
: Brancher(home),
|
|
done(false),
|
|
int_varsel(int_varsel0),
|
|
int_valsel(int_valsel0),
|
|
bool_varsel(bool_varsel0),
|
|
bool_valsel(bool_valsel0)
|
|
#ifdef GECODE_HAS_SET_VARS
|
|
,
|
|
set_varsel(set_varsel0),
|
|
set_valsel(set_valsel0)
|
|
#endif
|
|
#ifdef GECODE_HAS_FLOAT_VARS
|
|
,
|
|
float_varsel(float_varsel0),
|
|
float_valsel(float_valsel0)
|
|
#endif
|
|
{
|
|
}
|
|
/// Copy constructor
|
|
AuxVarBrancher(Gecode::Space& home, AuxVarBrancher& b) : Brancher(home, b), done(b.done) {}
|
|
|
|
/// %Choice that only signals failure or success
|
|
class Choice : public Gecode::Choice {
|
|
public:
|
|
/// Whether brancher should fail
|
|
bool fail;
|
|
/// Initialize choice for brancher \a b
|
|
Choice(const Brancher& b, bool fail0) : Gecode::Choice(b, 1), fail(fail0) {}
|
|
/// Report size occupied
|
|
virtual size_t size(void) const { return sizeof(Choice); }
|
|
/// Archive into \a e
|
|
virtual void archive(Gecode::Archive& e) const {
|
|
Gecode::Choice::archive(e);
|
|
e.put(fail);
|
|
}
|
|
};
|
|
|
|
Gecode::TieBreak<Gecode::IntVarBranch> int_varsel;
|
|
Gecode::IntValBranch int_valsel;
|
|
Gecode::TieBreak<Gecode::BoolVarBranch> bool_varsel;
|
|
Gecode::BoolValBranch bool_valsel;
|
|
#ifdef GECODE_HAS_SET_VARS
|
|
Gecode::SetVarBranch set_varsel;
|
|
Gecode::SetValBranch set_valsel;
|
|
#endif
|
|
#ifdef GECODE_HAS_FLOAT_VARS
|
|
Gecode::TieBreak<Gecode::FloatVarBranch> float_varsel;
|
|
Gecode::FloatValBranch float_valsel;
|
|
#endif
|
|
|
|
public:
|
|
/// Check status of brancher, return true if alternatives left.
|
|
virtual bool status(const Gecode::Space& _home) const {
|
|
if (done) return false;
|
|
const MiniZinc::FznSpace& home = static_cast<const MiniZinc::FznSpace&>(_home);
|
|
for (int i = 0; i < home.iv_aux.size(); i++)
|
|
if (!home.iv_aux[i].assigned()) return true;
|
|
for (int i = 0; i < home.bv_aux.size(); i++)
|
|
if (!home.bv_aux[i].assigned()) return true;
|
|
#ifdef GECODE_HAS_SET_VARS
|
|
for (int i = 0; i < home.sv_aux.size(); i++)
|
|
if (!home.sv_aux[i].assigned()) return true;
|
|
#endif
|
|
#ifdef GECODE_HAS_FLOAT_VARS
|
|
for (int i = 0; i < home.fv_aux.size(); i++)
|
|
if (!home.fv_aux[i].assigned()) return true;
|
|
#endif
|
|
// No non-assigned variables left
|
|
return false;
|
|
}
|
|
/// Return choice
|
|
virtual Choice* choice(Gecode::Space& home) {
|
|
done = true;
|
|
MiniZinc::FznSpace& fzs = static_cast<MiniZinc::FznSpace&>(*home.clone());
|
|
fzs._copyAuxVars = false;
|
|
Gecode::branch(fzs, fzs.iv_aux, int_varsel, int_valsel);
|
|
Gecode::branch(fzs, fzs.bv_aux, bool_varsel, bool_valsel);
|
|
#ifdef GECODE_HAS_SET_VARS
|
|
Gecode::branch(fzs, fzs.sv_aux, set_varsel, set_valsel);
|
|
#endif
|
|
#ifdef GECODE_HAS_FLOAT_VARS
|
|
Gecode::branch(fzs, fzs.fv_aux, float_varsel, float_valsel);
|
|
#endif
|
|
Gecode::Search::Options opt;
|
|
opt.clone = false;
|
|
MiniZinc::FznSpace* sol = Gecode::dfs(&fzs, opt);
|
|
if (sol) {
|
|
delete sol;
|
|
return new Choice(*this, false);
|
|
} else {
|
|
return new Choice(*this, true);
|
|
}
|
|
}
|
|
/// Return choice
|
|
virtual Choice* choice(const Gecode::Space&, Gecode::Archive& e) {
|
|
bool fail;
|
|
e >> fail;
|
|
return new Choice(*this, fail);
|
|
}
|
|
/// Perform commit for choice \a c
|
|
virtual Gecode::ExecStatus commit(Gecode::Space&, const Gecode::Choice& c, unsigned int) {
|
|
return static_cast<const Choice&>(c).fail ? Gecode::ES_FAILED : Gecode::ES_OK;
|
|
}
|
|
/// Print explanation
|
|
virtual void print(const Gecode::Space&, const Gecode::Choice& c, unsigned int,
|
|
std::ostream& o) const {
|
|
o << "FlatZinc(" << (static_cast<const Choice&>(c).fail ? "fail" : "ok") << ")";
|
|
}
|
|
/// Copy brancher
|
|
virtual Actor* copy(Gecode::Space& home) { return new (home) AuxVarBrancher(home, *this); }
|
|
/// Post brancher
|
|
static void post(Gecode::Home home, Gecode::TieBreak<Gecode::IntVarBranch> int_varsel,
|
|
Gecode::IntValBranch int_valsel,
|
|
Gecode::TieBreak<Gecode::BoolVarBranch> bool_varsel,
|
|
Gecode::BoolValBranch bool_valsel
|
|
#ifdef GECODE_HAS_SET_VARS
|
|
,
|
|
Gecode::SetVarBranch set_varsel, Gecode::SetValBranch set_valsel
|
|
#endif
|
|
#ifdef GECODE_HAS_FLOAT_VARS
|
|
,
|
|
Gecode::TieBreak<Gecode::FloatVarBranch> float_varsel,
|
|
Gecode::FloatValBranch float_valsel
|
|
#endif
|
|
) {
|
|
(void)new (home) AuxVarBrancher(home, int_varsel, int_valsel, bool_varsel, bool_valsel
|
|
#ifdef GECODE_HAS_SET_VARS
|
|
,
|
|
set_varsel, set_valsel
|
|
#endif
|
|
#ifdef GECODE_HAS_FLOAT_VARS
|
|
,
|
|
float_varsel, float_valsel
|
|
#endif
|
|
);
|
|
}
|
|
/// Delete brancher and return its size
|
|
virtual size_t dispose(Gecode::Space&) { return sizeof(*this); }
|
|
};
|
|
|
|
} // namespace MiniZinc
|
|
#endif
|