/* * 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. * */ #ifndef flatzinc_h #define flatzinc_h #include #include #include #include #include #include #include #include #include #include #include extern std::map intVarString; extern std::map boolVarString; // Controls whether expressions like bool_sum_eq([x[i] = j | i in 1..n], 1) // access the underlying literals x[i] = j or new ones via int_eq_reif(...) // NOTE: Implemention isn't 100% ideal at this stage so kept it conditional #define EXPOSE_INT_LITS 0 namespace FlatZinc { /// Alias for a variable specification class Alias { public: const int v; Alias(int v0) : v(v0) {} }; /// Optional value template struct Option { private: bool _some; Val _v; public: bool operator()(void) const { return _some; } const Val& some(void) const { return _v; } static Option none(void) { Option o; o._some = false; new (&o._v) Val(); return o; } static Option some(const Val& v) { Option o; o._some = true; o._v = v; return o; } }; /// Base class for variable specifications class VarSpec { public: /// Whether the variable has an "output" annotation bool output; /// Whether the variable was introduced in the mzn2fzn translation bool introduced; /// Whether the variable *looks* introduced by the mzn2fzn translation bool looks_introduced; /// Destructor virtual ~VarSpec(void) {} /// Variable index int i; /// Whether the variable aliases another variable bool alias; /// Whether the variable is assigned bool assigned; /// Constructor VarSpec(bool output0, bool introduced0, bool looks0) : output(output0), introduced(introduced0), looks_introduced(looks0) {} void set_looks_introduced(bool b) { looks_introduced = b; } }; /// Specification for integer variables class IntVarSpec : public VarSpec { public: Option domain; IntVarSpec(const Option& d, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = false; assigned = false; domain = d; } IntVarSpec(int i0, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = false; assigned = true; i = i0; } IntVarSpec(const Alias& eq, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = true; i = eq.v; } ~IntVarSpec(void) { if (!alias && !assigned && domain()) delete domain.some(); } }; /// Specification for Boolean variables class BoolVarSpec : public VarSpec { public: Option domain; #if EXPOSE_INT_LITS // whether it aliases an int literal such as [x <= 5]: (-1=no) int alias_var; IntRelType alias_irt; int alias_val; #endif BoolVarSpec(Option& d, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = false; assigned = false; domain = d; #if EXPOSE_INT_LITS alias_var = -1; #endif } BoolVarSpec(bool b, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = false; assigned = true; i = b; #if EXPOSE_INT_LITS alias_var = -1; #endif } BoolVarSpec(const Alias& eq, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = true; i = eq.v; #if EXPOSE_INT_LITS alias_var = -1; #endif } ~BoolVarSpec(void) { if (!alias && !assigned && domain()) delete domain.some(); } }; /// Specification for set variables class SetVarSpec : public VarSpec { public: Option upperBound; SetVarSpec(bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = false; assigned = false; upperBound = Option::none(); } SetVarSpec(const Option& v, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = false; assigned = false; upperBound = v; } SetVarSpec(AST::SetLit* v, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = false; assigned = true; upperBound = Option::some(v); } SetVarSpec(const Alias& eq, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = true; i = eq.v; } ~SetVarSpec(void) { if (!alias && upperBound()) delete upperBound.some(); } }; /// Specification for floating point variables class FloatVarSpec : public VarSpec { public: Option* > domain; FloatVarSpec(Option* >& d, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = false; assigned = false; domain = d; } FloatVarSpec(bool b, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = false; assigned = true; i = b; } FloatVarSpec(const Alias& eq, bool output, bool introduced, bool looks = false) : VarSpec(output, introduced, looks) { alias = true; i = eq.v; } ~FloatVarSpec(void) { if (!alias && !assigned && domain()) delete domain.some(); } }; /// Abstract representation of a constraint class ConExpr { public: /// Identifier for the constraint std::string id; /// Constraint arguments AST::Array* args; /// Constructor ConExpr(const std::string& id0, AST::Array* args0) : id(id0), args(args0) {} /// Return argument \a i AST::Node* operator[](int i) const { return args->a[i]; } /// Destructor ~ConExpr(void) { delete args; } }; /// Map from constraint identifier to constraint posting functions class Registry { public: /// Type of constraint posting function typedef void (*poster) (const ConExpr&, AST::Node*); /// Add posting function \a p with identifier \a id void add(const std::string& id, poster p); /// Post constraint specified by \a ce void post(const ConExpr& ce, AST::Node* ann); private: /// The actual registry std::map r; }; /// Return global registry object Registry& registry(void); /// Symbol table mapping identifiers (strings) to values template class SymbolTable { private: std::map m; public: /// Insert \a val with \a key void put(const std::string& key, const Val& val) { m[key] = val; } /// Return whether \a key exists, and set \a val if it does exist bool get(const std::string& key, Val& val) const { typename std::map::const_iterator i = m.find(key); if (i == m.end()) return false; val = i->second; return true; } }; class FlatZincSpace : public Problem { public: /// Number of integer variables int intVarCount; /// Number of Boolean variables int boolVarCount; /// The integer variables vec iv; /// Indicates whether an integer variable is introduced by mzn2fzn std::vector iv_introduced; /// The Boolean variables vec bv; /// Indicates whether a Boolean variable is introduced by mzn2fzn std::vector bv_introduced; AST::Array* output; /// Construct problem with given number of variables FlatZincSpace(int intVars, int boolVars, int setVars); /// Create priority branch group PriorityBranchGroup* priorityBranch(vec x, AST::Array* ann, VarBranch var_branch); /// Parse the solve annotations and create corresponding branchings void parseSolveAnn(AST::Array* ann); /// Create final branching that fixes all variables void fixAllSearch(); /// Create new integer variable from specification void newIntVar(IntVarSpec* vs); /// Create new Boolean variable from specification void newBoolVar(BoolVarSpec* vs); /// Create new set variable from specification void newSetVar(SetVarSpec* vs); /// Post a constraint specified by \a ce void postConstraint(const ConExpr& ce, AST::Node* annotation); /// Post the solve item void solve(AST::Array* annotation); /// Post that integer variable \a var should be minimized void minimize(int var, AST::Array* annotation); /// Post that integer variable \a var should be maximized void maximize(int var, AST::Array* annotation); /// Define output variables void setOutputElem(AST::Node* ai) const; void setOutput(); void printElem(AST::Node* ai, std::ostream& out = std::cout) const; // Needed by the profiler void print(std::ostream& out) { if (output == NULL) return; for (unsigned int i=0; i< output->a.size(); i++) { AST::Node* ai = output->a[i]; if (ai->isArray()) { AST::Array* aia = ai->getArray(); int size = aia->a.size(); out << "["; for (int j=0; ja[j], out); if (jisCall("ifthenelse")) { AST::Array* aia = ai->getCall("ifthenelse")->getArgs(3); if (aia->a[0]->isBool()) { if (aia->a[0]->getBool()) printElem(aia->a[1], out); else printElem(aia->a[2], out); } else if (aia->a[0]->isBoolVar()) { BoolView b = bv[aia->a[0]->getBoolVar()]; if (b.isTrue()) printElem(aia->a[1], out); else if (b.isFalse()) printElem(aia->a[2], out); else std::cerr << "% Error: Condition not fixed." << std::endl; } else { std::cerr << "% Error: Condition not Boolean." << std::endl; } } else { printElem(ai, out); } } }; void printStream(std::ostream& out); // Needed by the profiler void printDomains(std::ostream& out = std::cout) { out << "{"; bool outerFirst = true; for (int i = 0 ; i < iv.size() ; i++) { if (iv_introduced[i]) continue; IntVar* var = iv[i]; std::string varName = intVarString[var]; if (varName.empty() || varName.find(so.filter_domains) == std::string::npos) continue; if (!outerFirst) out << ","; outerFirst = false; out << '"' << varName << '"' << ":"; out << "["; if (var->vals != NULL) { bool first = true; for (int val = var->getMin() ; val <= var->getMax() ; val++) { if (var->vals[val]) { if (!first) out << ","; first = false; out << val; } } } else { out << '[' << var->getMin() << "," << var->getMax() << ']'; } out << "]"; } for (int i = 0 ; i < bv.size() ; i++) { if (bv_introduced[i]) continue; BoolView bview = bv[i]; std::string bvstring = boolVarString[bview]; if (bvstring.find(so.filter_domains) == std::string::npos) { continue; } // TODO: see if this is actually necessary if (bvstring.empty()) { // Try the other value BoolView otherval = bview; otherval.setSign(!otherval.getSign()); bvstring = boolVarString[otherval]; } if (bvstring.compare("ASSIGNED_AT_ROOT") == 0) continue; if (!outerFirst) out << ","; outerFirst = false; out << boolVarString[bview] << ":"; /* out << litString[toInt(bview.getLit(true))] << ":"; */ /* out << litString[toInt(bview.getLit(false))] << ":"; */ bool first = true; if (!bview.isFixed()) out << "'undef'"; else if (bview.isTrue()) out << "'true'"; else if (bview.isFalse()) out << "'false'"; else abort(); } out << "}"; }; // Needed by the profiler std::string getDomainsString(void) { std::stringstream ss; printDomains(ss); return ss.str(); } // Private membership functions private: /// Auxiliary functions for parsing the solve annotations and creating corresponding branchings void parseSolveAnn(AST::Array* ann, BranchGroup* branching, int& nbNonEmptySearchAnnotations); void parseSolveAnnAux(AST::Node* elemAnn, BranchGroup* branching, int& nbNonEmptySearchAnnotations); void parseSolveAnnIntSearch(AST::Node* elemAnn, BranchGroup* branching, int& nbNonEmptySearchAnnotations); void parseSolveAnnBoolSearch(AST::Node* elemAnn, BranchGroup* branching, int& nbNonEmptySearchAnnotations); void parseSolveAnnPrioritySearch(AST::Node* elemAnn, BranchGroup* branching, int& nbNonEmptySearchAnnotations); }; extern FlatZincSpace *s; typedef std::pair* > > intvartype; typedef std::pair varspec; /// State of the FlatZinc parser class ParserState { public: ParserState(const std::string& b, std::ostream& err0) : buf(b.c_str()), pos(0), length(b.size()), fg(NULL), hadError(false), err(err0) {} ParserState(char* buf0, int length0, std::ostream& err0) : buf(buf0), pos(0), length(length0), fg(NULL), hadError(false), err(err0) {} void* yyscanner; const char* buf; unsigned int pos, length; FlatZinc::FlatZincSpace* fg; std::vector > _output; SymbolTable intvarTable; SymbolTable boolvarTable; SymbolTable floatvarTable; SymbolTable setvarTable; SymbolTable > intvararrays; SymbolTable > boolvararrays; SymbolTable > floatvararrays; SymbolTable > setvararrays; SymbolTable > intvalarrays; SymbolTable > boolvalarrays; SymbolTable intvals; SymbolTable boolvals; SymbolTable setvals; SymbolTable > setvalarrays; std::vector intvars; std::vector boolvars; std::vector setvars; std::vector domainConstraints; #if EXPOSE_INT_LITS // for some reason the above list is posted in reverse order, // don't want to disturb things so add the following (forward): std::vector > domainConstraints2; #endif bool hadError; std::ostream& err; int fillBuffer(char* lexBuf, unsigned int lexBufSize) { if (pos >= length) return 0; int num = std::min(length - pos, lexBufSize); memcpy(lexBuf,buf+pos,num); pos += num; return num; } void output(std::string x, AST::Node* n) { _output.push_back(std::pair(x,n)); } AST::Array* getOutput(void) { std::sort(_output.begin(), _output.end()); AST::Array* a = new AST::Array(); for (unsigned int i=0; i<_output.size(); i++) { a->a.push_back(new AST::String(_output[i].first+" = ")); if (_output[i].second->isArray()) { AST::Array* oa = _output[i].second->getArray(); for (unsigned int j=0; ja.size(); j++) { a->a.push_back(oa->a[j]); oa->a[j] = NULL; } delete _output[i].second; } else { a->a.push_back(_output[i].second); } a->a.push_back(new AST::String(";\n")); } return a; } }; /// Exception class for FlatZinc errors class Error { private: const std::string msg; public: Error(const std::string& where, const std::string& what) : msg(where+": "+what) {} const std::string& toString(void) const { return msg; } }; void solve(const std::string& filename, std::ostream& err = std::cerr); void solve(std::istream& is, std::ostream& err = std::cerr); } #endif