libminizinc-2.0.11/0000755000175000017500000000000012646732512012550 5ustar kaolkaollibminizinc-2.0.11/lib/0000755000175000017500000000000012646030173013310 5ustar kaolkaollibminizinc-2.0.11/lib/file_utils.cpp0000644000175000017500000000641212646030173016156 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #ifdef HAS_PIDPATH #include #include #include #include #include #elif defined(HAS_GETMODULEFILENAME) || defined(HAS_GETFILEATTRIBUTES) #include #else #include #endif #include #include namespace MiniZinc { namespace FileUtils { #ifdef HAS_PIDPATH std::string progpath(void) { pid_t pid = getpid(); char path[PROC_PIDPATHINFO_MAXSIZE]; int ret = proc_pidpath (pid, path, sizeof(path)); if ( ret <= 0 ) { return ""; } else { std::string p(path); size_t slash = p.find_last_of("/"); if (slash != std::string::npos) { p = p.substr(0,slash); } return p; } } #elif defined(HAS_GETMODULEFILENAME) std::string progpath(void) { char path[MAX_PATH]; int ret = GetModuleFileName(NULL, path, MAX_PATH); if ( ret <= 0 ) { return ""; } else { std::string p(path); size_t slash = p.find_last_of("/\\"); if (slash != std::string::npos) { p = p.substr(0,slash); } return p; } } #else std::string progpath(void) { const int bufsz = 2000; char path[bufsz+1]; ssize_t sz = readlink("/proc/self/exe", path, bufsz); if ( sz < 0 ) { return ""; } else { path[sz] = '\0'; std::string p(path); size_t slash = p.find_last_of("/"); if (slash != std::string::npos) { p = p.substr(0,slash); } return p; } } #endif bool file_exists(const std::string& filename) { #if defined(HAS_GETFILEATTRIBUTES) DWORD dwAttrib = GetFileAttributes(filename.c_str()); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); #else struct stat info; return stat(filename.c_str(), &info)==0 && (info.st_mode & S_IFREG); #endif } bool directory_exists(const std::string& dirname) { #if defined(HAS_GETFILEATTRIBUTES) DWORD dwAttrib = GetFileAttributes(dirname.c_str()); return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); #else struct stat info; return stat(dirname.c_str(), &info)==0 && (info.st_mode & S_IFDIR); #endif } std::string file_path(const std::string& filename) { #ifdef _MSC_VER LPSTR lpBuffer, lpFilePart; DWORD nBufferLength = GetFullPathName(filename.c_str(), 0,0,&lpFilePart); if (!(lpBuffer = (LPTSTR)LocalAlloc(LMEM_FIXED, sizeof(TCHAR) * nBufferLength))) return 0; std::string ret; if (!GetFullPathName(filename.c_str(), nBufferLength, lpBuffer, &lpFilePart)) { ret = ""; } else { ret = std::string(lpBuffer); } LocalFree(lpBuffer); return ret; #else char* rp = realpath(filename.c_str(), NULL); std::string rp_s(rp); free(rp); return rp_s; #endif } }} libminizinc-2.0.11/lib/prettyprinter.cpp0000644000175000017500000015563712646030173016770 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Pierre Wilke * Guido Tack */ /* 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/. */ #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { int precedence(const Expression* e) { if (const BinOp* bo = e->dyn_cast()) { switch (bo->op()) { case BOT_EQUIV: return 1200; case BOT_IMPL: return 1100; case BOT_RIMPL: return 1100; case BOT_OR: return 1000; case BOT_XOR: return 1000; case BOT_AND: return 900; case BOT_LE: return 800; case BOT_LQ: return 800; case BOT_GR: return 800; case BOT_GQ: return 800; case BOT_EQ: return 800; case BOT_NQ: return 800; case BOT_IN: return 700; case BOT_SUBSET: return 700; case BOT_SUPERSET: return 700; case BOT_UNION: return 600; case BOT_DIFF: return 600; case BOT_SYMDIFF: return 600; case BOT_DOTDOT: return 500; case BOT_PLUS: return 400; case BOT_MINUS: return 400; case BOT_MULT: return 300; case BOT_IDIV: return 300; case BOT_MOD: return 300; case BOT_DIV: return 300; case BOT_INTERSECT: return 300; case BOT_PLUSPLUS: return 200; default: assert(false); return -1; } } else if (e->isa()) { return 1300; } else { return 0; } } enum Assoc { AS_LEFT, AS_RIGHT, AS_NONE }; Assoc assoc(const BinOp* bo) { switch (bo->op()) { case BOT_LE: case BOT_LQ: case BOT_GR: case BOT_GQ: case BOT_NQ: case BOT_EQ: case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: case BOT_DOTDOT: return AS_NONE; case BOT_PLUSPLUS: return AS_RIGHT; default: return AS_LEFT; } } enum Parentheses { PN_LEFT = 1, PN_RIGHT = 2 }; Parentheses needParens(const BinOp* bo, const Expression* left, const Expression* right) { int pbo = precedence(bo); int pl = precedence(left); int pr = precedence(right); int ret = (pbo < pl) || (pbo == pl && assoc(bo) != AS_LEFT); ret += 2 * ((pbo < pr) || (pbo == pr && assoc(bo) != AS_RIGHT)); return static_cast(ret); } std::string Printer::escapeStringLit(const ASTString& s) { const char* sc = s.c_str(); std::string ret; for (unsigned int i=0; ieid()) { case Expression::E_INTLIT: os << e->cast()->v(); break; case Expression::E_FLOATLIT: { std::ostringstream oss; oss << std::setprecision(std::numeric_limits::digits10+1); oss << e->cast()->v(); if (oss.str().find("e") == std::string::npos && oss.str().find(".") == std::string::npos) oss << ".0"; os << oss.str(); } break; case Expression::E_SETLIT: { const SetLit& sl = *e->cast(); if (sl.isv()) { if (sl.isv()->size()==0) { os << (_flatZinc ? "1..0" : "{}"); } else if (sl.isv()->size()==1) { os << sl.isv()->min(0) << ".." << sl.isv()->max(0); } else { if (!sl.isv()->min(0).isFinite()) os << sl.isv()->min(0) << ".." << sl.isv()->max(0) << "++"; os << "{"; for (IntSetRanges isr(sl.isv()); isr();) { if (isr.min().isFinite() && isr.max().isFinite()) { for (IntVal i=isr.min(); i<=isr.max(); i++) { os << i; if (imax(sl.isv()->size()-1).isFinite()) os << "++" << sl.isv()->min(sl.isv()->size()-1) << ".." << sl.isv()->max(sl.isv()->size()-1); } } else { os << "{"; for (unsigned int i = 0; i < sl.v().size(); i++) { p(sl.v()[i]); if (icast()->v() ? "true" : "false"); break; case Expression::E_STRINGLIT: os << "\"" << Printer::escapeStringLit(e->cast()->v()) << "\""; break; case Expression::E_ID: { if (e==constants().absent) { os << "<>"; } else { const Id* id = e->cast(); if (id->idn() == -1) { os << id->v(); } else { os << "X_INTRODUCED_" << id->idn(); } } } break; case Expression::E_TIID: os << "$" << e->cast()->v(); break; case Expression::E_ANON: os << "_"; break; case Expression::E_ARRAYLIT: { const ArrayLit& al = *e->cast(); int n = al.dims(); if (n == 1 && al.min(0) == 1) { os << "["; for (unsigned int i = 0; i < al.v().size(); i++) { p(al.v()[i]); if (icast(); p(aa.v()); os << "["; for (unsigned int i = 0; i < aa.idx().size(); i++) { p(aa.idx()[i]); if (icast(); os << (c.set() ? "{" : "["); p(c.e()); os << " | "; for (int i=0; iid()->v(); if (j < c.n_decls(i)-1) os << ","; } os << " in "; p(c.in(i)); if (i < c.n_generators()) os << ", "; } if (c.where() != NULL) { os << " where "; p(c.where()); } os << (c.set() ? "}" : "]"); } break; case Expression::E_ITE: { const ITE& ite = *e->cast(); for (int i = 0; i < ite.size(); i++) { os << (i == 0 ? "if " : " elseif "); p(ite.e_if(i)); os << " then "; p(ite.e_then(i)); } os << " else "; p(ite.e_else()); os << " endif"; } break; case Expression::E_BINOP: { const BinOp& bo = *e->cast(); Parentheses ps = needParens(&bo, bo.lhs(), bo.rhs()); if (ps & PN_LEFT) os << "("; p(bo.lhs()); if (ps & PN_LEFT) os << ")"; switch (bo.op()) { case BOT_PLUS: os<<"+"; break; case BOT_MINUS: os<<"-"; break; case BOT_MULT: os<<"*"; break; case BOT_DIV: os<<"/"; break; case BOT_IDIV: os<<" div "; break; case BOT_MOD: os<<" mod "; break; case BOT_LE: os<<" < "; break; case BOT_LQ: os<<"<="; break; case BOT_GR: os<<" > "; break; case BOT_GQ: os<<">="; break; case BOT_EQ: os<<"=="; break; case BOT_NQ: os<<"!="; break; case BOT_IN: os<<" in "; break; case BOT_SUBSET: os<<" subset "; break; case BOT_SUPERSET: os<<" superset "; break; case BOT_UNION: os<<" union "; break; case BOT_DIFF: os<<" diff "; break; case BOT_SYMDIFF: os<<" symdiff "; break; case BOT_INTERSECT: os<<" intersect "; break; case BOT_PLUSPLUS: os<<"++"; break; case BOT_EQUIV: os<<" <-> "; break; case BOT_IMPL: os<<" -> "; break; case BOT_RIMPL: os<<" <- "; break; case BOT_OR: os<<" \\/ "; break; case BOT_AND: os<<" /\\ "; break; case BOT_XOR: os<<" xor "; break; case BOT_DOTDOT: os<<".."; break; default: assert(false); break; } if (ps & PN_RIGHT) os << "("; p(bo.rhs()); if (ps & PN_RIGHT) os << ")"; } break; case Expression::E_UNOP: { const UnOp& uo = *e->cast(); switch (uo.op()) { case UOT_NOT: os << "not "; break; case UOT_PLUS: os << "+"; break; case UOT_MINUS: os << "-"; break; default: assert(false); break; } bool needParen = (uo.e()->isa() || uo.e()->isa() || !uo.ann().isEmpty()); if (needParen) os << "("; p(uo.e()); if (needParen) os << ")"; } break; case Expression::E_CALL: { const Call& c = *e->cast(); os << c.id() << "("; for (unsigned int i = 0; i < c.args().size(); i++) { p(c.args()[i]); if (i < c.args().size()-1) os << ","; } os << ")"; } break; case Expression::E_VARDECL: { const VarDecl& vd = *e->cast(); p(vd.ti()); if (vd.id()->idn() != -1) { os << ": X_INTRODUCED_" << vd.id()->idn(); } else if (vd.id()->v().size() != 0) os << ": " << vd.id()->v(); if (vd.introduced()) { os << " ::var_is_introduced "; } p(vd.ann()); if (vd.e()) { os << " = "; p(vd.e()); } } break; case Expression::E_LET: { const Let& l = *e->cast(); os << "let {"; for (unsigned int i = 0; i < l.let().size(); i++) { const Expression* li = l.let()[i]; if (!li->isa()) os << "constraint "; p(li); if (icast(); if (ti.isarray()) { os << "array ["; for (unsigned int i = 0; i < ti.ranges().size(); i++) { p(Type::parint(), ti.ranges()[i]); if (i < ti.ranges().size()-1) os << ","; } os << "] of "; } p(ti.type(),ti.domain()); } } if (!e->isa()) { p(e->ann()); } } void p(const Item* i) { if (i==NULL) return; if (i->removed()) os << "% "; switch (i->iid()) { case Item::II_INC: os << "include \"" << i->cast()->f() << "\""; break; case Item::II_VD: p(i->cast()->e()); break; case Item::II_ASN: os << i->cast()->id() << " = "; p(i->cast()->e()); break; case Item::II_CON: os << "constraint "; p(i->cast()->e()); break; case Item::II_SOL: { const SolveI* si = i->cast(); os << "solve "; p(si->ann()); switch (si->st()) { case SolveI::ST_SAT: os << " satisfy"; break; case SolveI::ST_MIN: os << " minimize "; p(si->e()); break; case SolveI::ST_MAX: os << " maximize "; p(si->e()); break; } } break; case Item::II_OUT: os << "output "; p(i->cast()->e()); break; case Item::II_FUN: { const FunctionI& fi = *i->cast(); if (fi.ti()->type().isann() && fi.e() == NULL) { os << "annotation "; } else if (fi.ti()->type() == Type::parbool()) { os << "test "; } else if (fi.ti()->type() == Type::varbool()) { os << "predicate "; } else { os << "function "; p(fi.ti()); os << " : "; } os << fi.id(); if (fi.params().size() > 0) { os << "("; for (unsigned int i = 0; i < fi.params().size(); i++) { p(fi.params()[i]); if (i class ExpressionMapper { protected: T& _t; public: ExpressionMapper(T& t) : _t(t) { } typename T::ret map(const Expression* e) { switch (e->eid()) { case Expression::E_INTLIT: return _t.mapIntLit(*e->cast()); case Expression::E_FLOATLIT: return _t.mapFloatLit(*e->cast()); case Expression::E_SETLIT: return _t.mapSetLit(*e->cast()); case Expression::E_BOOLLIT: return _t.mapBoolLit(*e->cast()); case Expression::E_STRINGLIT: return _t.mapStringLit(*e->cast()); case Expression::E_ID: return _t.mapId(*e->cast()); case Expression::E_ANON: return _t.mapAnonVar(*e->cast()); case Expression::E_ARRAYLIT: return _t.mapArrayLit(*e->cast()); case Expression::E_ARRAYACCESS: return _t.mapArrayAccess(*e->cast()); case Expression::E_COMP: return _t.mapComprehension(*e->cast()); case Expression::E_ITE: return _t.mapITE(*e->cast()); case Expression::E_BINOP: return _t.mapBinOp(*e->cast()); case Expression::E_UNOP: return _t.mapUnOp(*e->cast()); case Expression::E_CALL: return _t.mapCall(*e->cast()); case Expression::E_VARDECL: return _t.mapVarDecl(*e->cast()); case Expression::E_LET: return _t.mapLet(*e->cast()); case Expression::E_TI: return _t.mapTypeInst(*e->cast()); case Expression::E_TIID: return _t.mapTIId(*e->cast()); default: assert(false); return typename T::ret(); break; } } }; class Document { private: int level; public: Document() : level(0) {} virtual ~Document() {} int getLevel() { return level; } // Make this object a child of "d". virtual void setParent(Document* d) { level = d->level + 1; } }; class BreakPoint: public Document { private: bool dontSimplify; public: BreakPoint() { dontSimplify = false; } BreakPoint(bool ds) { dontSimplify = ds; } virtual ~BreakPoint() {} void setDontSimplify(bool b) { dontSimplify = b; } bool getDontSimplify() { return dontSimplify; } }; class StringDocument: public Document { private: std::string stringDocument; public: StringDocument() {} virtual ~StringDocument() {} StringDocument(std::string s) : stringDocument(s) {} std::string getString() { return stringDocument; } void setString(std::string s) { stringDocument = s; } }; class DocumentList: public Document { private: std::vector docs; std::string beginToken; std::string separator; std::string endToken; bool unbreakable; bool alignment; public: virtual ~DocumentList() { std::vector::iterator it; for (it = docs.begin(); it != docs.end(); it++) { delete *it; } } DocumentList(std::string _beginToken = "", std::string _separator = "", std::string _endToken = "", bool _alignment = true); void addDocumentToList(Document* d) { docs.push_back(d); d->setParent(this); } void setParent(Document* d) { Document::setParent(d); std::vector::iterator it; for (it = docs.begin(); it != docs.end(); it++) { (*it)->setParent(this); } } void addStringToList(std::string s) { addDocumentToList(new StringDocument(s)); } void addBreakPoint(bool b = false) { addDocumentToList(new BreakPoint(b)); } std::vector getDocs() { return docs; } void setList(std::vector ld) { docs = ld; } std::string getBeginToken() { return beginToken; } std::string getEndToken() { return endToken; } std::string getSeparator() { return separator; } bool getUnbreakable() { return unbreakable; } void setUnbreakable(bool b) { unbreakable = b; } bool getAlignment() { return alignment; } }; DocumentList::DocumentList(std::string _beginToken, std::string _separator, std::string _endToken, bool _alignment) { beginToken = _beginToken; separator = _separator; endToken = _endToken; alignment = _alignment; unbreakable = false; } class Line { private: int indentation; int lineLength; std::vector text; public: Line() : indentation(0), lineLength(0), text(0) {} Line(const Line& l) : indentation(l.indentation), lineLength(l.lineLength), text(l.text) {} Line(const int indent) : indentation(indent), lineLength(0), text(0) {} bool operator==(const Line& l) { return &l == this; } void setIndentation(int i) { indentation = i; } int getLength() const { return lineLength; } int getIndentation() const { return indentation; } int getSpaceLeft(int maxwidth); void addString(const std::string& s); void concatenateLines(Line& l); void print(std::ostream& os) const { for (int i = 0; i < getIndentation(); i++) { os << " "; } std::vector::const_iterator it; for (it = text.begin(); it != text.end(); it++) { os << (*it); } os << "\n"; } }; int Line::getSpaceLeft(int maxwidth) { return maxwidth - lineLength - indentation; } void Line::addString(const std::string& s) { lineLength += s.size(); text.push_back(s); } void Line::concatenateLines(Line& l) { text.insert(text.end(), l.text.begin(), l.text.end()); lineLength += l.lineLength; } class LinesToSimplify { private: std::map > lines; // (i,j) in parent <=> j can only be simplified if i is simplified std::vector > parent; /* * if i can't simplify, remove j and his parents */ //mostRecentlyAdded[level] = line of the most recently added std::map mostRecentlyAdded; public: std::vector* getLinesForPriority(int p) { std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { if (it->first == p) return &(it->second); } return NULL; } void addLine(int p, int l, int par = -1) { if (par == -1) { for (int i = p - 1; i >= 0; i--) { std::map::iterator it = mostRecentlyAdded.find(i); if (it != mostRecentlyAdded.end()) { par = it->second; break; } } } if (par != -1) parent.push_back(std::pair(l, par)); mostRecentlyAdded.insert(std::pair(p,l)); std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { if (it->first == p) { it->second.push_back(l); return; } } std::vector v; v.push_back(l); lines.insert(std::pair >(p, v)); } void decrementLine(std::vector* vec, int l) { std::vector::iterator vit; if (vec != NULL) { for (vit = vec->begin(); vit != vec->end(); vit++) { if (*vit >= l) *vit = *vit - 1; } } //Now the map std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { for (vit = it->second.begin(); vit != it->second.end(); vit++) { if (*vit >= l) *vit = *vit - 1; } } //And the parent table std::vector >::iterator vpit; for (vpit = parent.begin(); vpit != parent.end(); vpit++) { if (vpit->first >= l) vpit->first--; if (vpit->second >= l) vpit->second--; } } void remove(LinesToSimplify& lts){ std::map >::iterator it; for(it = lts.lines.begin(); it != lts.lines.end(); it++){ std::vector::iterator vit; for(vit = it->second.begin(); vit != it->second.end(); vit++){ remove(NULL, *vit, false); } } } void remove(std::vector* v, int i, bool success = true) { if (v != NULL) { v->erase(std::remove(v->begin(), v->end(), i), v->end()); } std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { std::vector* v = &(it->second); v->erase(std::remove(v->begin(), v->end(), i), v->end()); } //Call on its parent if (!success) { std::vector >::iterator vpit; for (vpit = parent.begin(); vpit != parent.end(); vpit++) { if (vpit->first == i && vpit->second != i && vpit->second != -1) { remove(v, vpit->second, false); } } } } std::vector* getLinesToSimplify() { std::vector* vec = new std::vector(); std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { std::vector& svec = it->second; vec->insert(vec->begin(), svec.begin(), svec.end()); } return vec; } }; Document* expressionToDocument(const Expression* e); Document* annotationToDocument(const Annotation& ann); Document* tiexpressionToDocument(const Type& type, const Expression* e) { DocumentList* dl = new DocumentList("","","",false); switch (type.ti()) { case Type::TI_PAR: break; case Type::TI_VAR: dl->addStringToList("var "); break; } if (type.ot()==Type::OT_OPTIONAL) dl->addStringToList("opt "); if (type.st()==Type::ST_SET) dl->addStringToList("set of "); if (e==NULL) { switch (type.bt()) { case Type::BT_INT: dl->addStringToList("int"); break; case Type::BT_BOOL: dl->addStringToList("bool"); break; case Type::BT_FLOAT: dl->addStringToList("float"); break; case Type::BT_STRING: dl->addStringToList("string"); break; case Type::BT_ANN: dl->addStringToList("ann"); break; case Type::BT_BOT: dl->addStringToList("bot"); break; case Type::BT_TOP: dl->addStringToList("top"); break; case Type::BT_UNKNOWN: dl->addStringToList("???"); break; } } else { dl->addDocumentToList(expressionToDocument(e)); } return dl; } class ExpressionDocumentMapper { public: typedef Document* ret; ret mapIntLit(const IntLit& il) { std::ostringstream oss; oss << il.v(); return new StringDocument(oss.str()); } ret mapFloatLit(const FloatLit& fl) { std::ostringstream oss; oss << std::setprecision(std::numeric_limits::digits10+1); oss << fl.v(); if (oss.str().find("e") == std::string::npos && oss.str().find(".") == std::string::npos) oss << ".0"; return new StringDocument(oss.str()); } ret mapSetLit(const SetLit& sl) { DocumentList* dl; if (sl.isv()) { if (sl.isv()->size()==0) { dl = new DocumentList("1..0","",""); } else if (sl.isv()->size()==1) { dl = new DocumentList("", "..", ""); { std::ostringstream oss; oss << sl.isv()->min(0); dl->addDocumentToList(new StringDocument(oss.str())); } { std::ostringstream oss; oss << sl.isv()->max(0); dl->addDocumentToList(new StringDocument(oss.str())); } } else { dl = new DocumentList("{", ", ", "}", true); IntSetRanges isr(sl.isv()); for (Ranges::ToValues isv(isr); isv(); ++isv) { std::ostringstream oss; oss << isv.val(); dl->addDocumentToList(new StringDocument(oss.str())); } } } else { dl = new DocumentList("{", ", ", "}", true); for (unsigned int i = 0; i < sl.v().size(); i++) { dl->addDocumentToList(expressionToDocument((sl.v()[i]))); } } return dl; } ret mapBoolLit(const BoolLit& bl) { return new StringDocument(std::string(bl.v() ? "true" : "false")); } ret mapStringLit(const StringLit& sl) { std::ostringstream oss; oss << "\"" << Printer::escapeStringLit(sl.v()) << "\""; return new StringDocument(oss.str()); } ret mapId(const Id& id) { if (&id == constants().absent) return new StringDocument("<>"); if (id.idn()==-1) return new StringDocument(id.v().str()); else { std::ostringstream oss; oss << "X_INTRODUCED_" << id.idn(); return new StringDocument(oss.str()); } } ret mapTIId(const TIId& id) { return new StringDocument("$"+id.v().str()); } ret mapAnonVar(const AnonVar&) { return new StringDocument("_"); } ret mapArrayLit(const ArrayLit& al) { /// TODO: test multi-dimensional arrays handling DocumentList* dl; int n = al.dims(); if (n == 1 && al.min(0) == 1) { dl = new DocumentList("[", ", ", "]"); for (unsigned int i = 0; i < al.v().size(); i++) dl->addDocumentToList(expressionToDocument(al.v()[i])); } else if (n == 2 && al.min(0) == 1 && al.min(1) == 1) { dl = new DocumentList("[| ", " | ", " |]"); for (int i = 0; i < al.max(0); i++) { DocumentList* row = new DocumentList("", ", ", ""); for (int j = 0; j < al.max(1); j++) { row-> addDocumentToList(expressionToDocument(al.v()[i * al.max(1) + j])); } dl->addDocumentToList(row); if (i != al.max(0) - 1) dl->addBreakPoint(true); // dont simplify } } else { dl = new DocumentList("", "", ""); std::stringstream oss; oss << "array" << n << "d"; dl->addStringToList(oss.str()); DocumentList* args = new DocumentList("(", ", ", ")"); for (int i = 0; i < al.dims(); i++) { oss.str(""); oss << al.min(i) << ".." << al.max(i); args->addStringToList(oss.str()); } DocumentList* array = new DocumentList("[", ", ", "]"); for (unsigned int i = 0; i < al.v().size(); i++) array->addDocumentToList(expressionToDocument(al.v()[i])); args->addDocumentToList(array); dl->addDocumentToList(args); } return dl; } ret mapArrayAccess(const ArrayAccess& aa) { DocumentList* dl = new DocumentList("", "", ""); dl->addDocumentToList(expressionToDocument(aa.v())); DocumentList* args = new DocumentList("[", ", ", "]"); for (unsigned int i = 0; i < aa.idx().size(); i++) { args->addDocumentToList(expressionToDocument(aa.idx()[i])); } dl->addDocumentToList(args); return dl; } ret mapComprehension(const Comprehension& c) { std::ostringstream oss; DocumentList* dl; if (c.set()) dl = new DocumentList("{ ", " | ", " }"); else dl = new DocumentList("[ ", " | ", " ]"); dl->addDocumentToList(expressionToDocument(c.e())); DocumentList* head = new DocumentList("", " ", ""); DocumentList* generators = new DocumentList("", ", ", ""); for (int i = 0; i < c.n_generators(); i++) { DocumentList* gen = new DocumentList("", "", ""); DocumentList* idents = new DocumentList("", ", ", ""); for (int j = 0; j < c.n_decls(i); j++) { idents->addStringToList(c.decl(i, j)->id()->v().str()); } gen->addDocumentToList(idents); gen->addStringToList(" in "); gen->addDocumentToList(expressionToDocument(c.in(i))); generators->addDocumentToList(gen); } head->addDocumentToList(generators); if (c.where() != NULL) { head->addStringToList("where"); head->addDocumentToList(expressionToDocument(c.where())); } dl->addDocumentToList(head); return dl; } ret mapITE(const ITE& ite) { DocumentList* dl = new DocumentList("", "", ""); for (int i = 0; i < ite.size(); i++) { std::string beg = (i == 0 ? "if " : " elseif "); dl->addStringToList(beg); dl->addDocumentToList(expressionToDocument(ite.e_if(i))); dl->addStringToList(" then "); DocumentList* ifdoc = new DocumentList("", "", "", false); ifdoc->addBreakPoint(); ifdoc->addDocumentToList(expressionToDocument(ite.e_then(i))); dl->addDocumentToList(ifdoc); dl->addStringToList(" "); } dl->addBreakPoint(); dl->addStringToList("else "); DocumentList* elsedoc = new DocumentList("", "", "", false); elsedoc->addBreakPoint(); elsedoc->addDocumentToList(expressionToDocument(ite.e_else())); dl->addDocumentToList(elsedoc); dl->addStringToList(" "); dl->addBreakPoint(); dl->addStringToList("endif"); return dl; } ret mapBinOp(const BinOp& bo) { Parentheses ps = needParens(&bo, bo.lhs(), bo.rhs()); DocumentList* opLeft; DocumentList* dl; DocumentList* opRight; bool linebreak = false; if (ps & PN_LEFT) opLeft = new DocumentList("(", " ", ")"); else opLeft = new DocumentList("", " ", ""); opLeft->addDocumentToList(expressionToDocument(bo.lhs())); std::string op; switch (bo.op()) { case BOT_PLUS: op = "+"; break; case BOT_MINUS: op = "-"; break; case BOT_MULT: op = "*"; break; case BOT_DIV: op = "/"; break; case BOT_IDIV: op = " div "; break; case BOT_MOD: op = " mod "; break; case BOT_LE: op = " < "; break; case BOT_LQ: op = "<="; break; case BOT_GR: op = " > "; break; case BOT_GQ: op = ">="; break; case BOT_EQ: op = "=="; break; case BOT_NQ: op = "!="; break; case BOT_IN: op = " in "; break; case BOT_SUBSET: op = " subset "; break; case BOT_SUPERSET: op = " superset "; break; case BOT_UNION: op = " union "; break; case BOT_DIFF: op = " diff "; break; case BOT_SYMDIFF: op = " symdiff "; break; case BOT_INTERSECT: op = " intersect "; break; case BOT_PLUSPLUS: op = "++"; linebreak = true; break; case BOT_EQUIV: op = " <-> "; break; case BOT_IMPL: op = " -> "; break; case BOT_RIMPL: op = " <- "; break; case BOT_OR: op = " \\/ "; linebreak = true; break; case BOT_AND: op = " /\\ "; linebreak = true; break; case BOT_XOR: op = " xor "; break; case BOT_DOTDOT: op = ".."; break; default: assert(false); break; } dl = new DocumentList("", op, ""); if (ps & PN_RIGHT) opRight = new DocumentList("(", " ", ")"); else opRight = new DocumentList("", "", ""); opRight->addDocumentToList(expressionToDocument(bo.rhs())); dl->addDocumentToList(opLeft); if (linebreak) dl->addBreakPoint(); dl->addDocumentToList(opRight); return dl; } ret mapUnOp(const UnOp& uo) { DocumentList* dl = new DocumentList("", "", ""); std::string op; switch (uo.op()) { case UOT_NOT: op = "not "; break; case UOT_PLUS: op = "+"; break; case UOT_MINUS: op = "-"; break; default: assert(false); break; } dl->addStringToList(op); DocumentList* unop; bool needParen = (uo.e()->isa() || uo.e()->isa()); if (needParen) unop = new DocumentList("(", " ", ")"); else unop = new DocumentList("", " ", ""); unop->addDocumentToList(expressionToDocument(uo.e())); dl->addDocumentToList(unop); return dl; } ret mapCall(const Call& c) { if (c.args().size() == 1) { /* * if we have only one argument, and this is an array comprehension, * we convert it into the following syntax * forall (f(i,j) | i in 1..10) * --> * forall (i in 1..10) (f(i,j)) */ const Expression* e = c.args()[0]; if (e->isa()) { const Comprehension* com = e->cast(); if (!com->set()) { DocumentList* dl = new DocumentList("", " ", ""); dl->addStringToList(c.id().str()); DocumentList* args = new DocumentList("", " ", "", false); DocumentList* generators = new DocumentList("", ", ", ""); for (int i = 0; i < com->n_generators(); i++) { DocumentList* gen = new DocumentList("", "", ""); DocumentList* idents = new DocumentList("", ", ", ""); for (int j = 0; jn_decls(i); j++) { idents->addStringToList( com->decl(i,j)->id()->v().str()); } gen->addDocumentToList(idents); gen->addStringToList(" in "); gen->addDocumentToList(expressionToDocument(com->in(i))); generators->addDocumentToList(gen); } args->addStringToList("("); args->addDocumentToList(generators); if (com->where() != NULL) { args->addStringToList("where"); args->addDocumentToList(expressionToDocument(com->where())); } args->addStringToList(")"); args->addStringToList("("); args->addBreakPoint(); args->addDocumentToList(expressionToDocument(com->e())); dl->addDocumentToList(args); dl->addBreakPoint(); dl->addStringToList(")"); return dl; } } } std::string beg = c.id().str() + "("; DocumentList* dl = new DocumentList(beg, ", ", ")"); for (unsigned int i = 0; i < c.args().size(); i++) { dl->addDocumentToList(expressionToDocument(c.args()[i])); } return dl; } ret mapVarDecl(const VarDecl& vd) { std::ostringstream oss; DocumentList* dl = new DocumentList("", "", ""); dl->addDocumentToList(expressionToDocument(vd.ti())); dl->addStringToList(": "); if (vd.id()->idn()==-1) { dl->addStringToList(vd.id()->v().str()); } else { std::ostringstream oss; oss << "X_INTRODUCED_" << vd.id()->idn(); dl->addStringToList(oss.str()); } if (vd.introduced()) { dl->addStringToList(" ::var_is_introduced "); } if (!vd.ann().isEmpty()) { dl->addDocumentToList(annotationToDocument(vd.ann())); } if (vd.e()) { dl->addStringToList(" = "); dl->addDocumentToList(expressionToDocument(vd.e())); } return dl; } ret mapLet(const Let& l) { DocumentList* letin = new DocumentList("", "", "", false); DocumentList* lets = new DocumentList("", " ", "", true); DocumentList* inexpr = new DocumentList("", "", ""); bool ds = l.let().size() > 1; for (unsigned int i = 0; i < l.let().size(); i++) { if (i != 0) lets->addBreakPoint(ds); DocumentList* exp = new DocumentList("", " ", ","); const Expression* li = l.let()[i]; if (!li->isa()) exp->addStringToList("constraint"); exp->addDocumentToList(expressionToDocument(li)); lets->addDocumentToList(exp); } inexpr->addDocumentToList(expressionToDocument(l.in())); letin->addBreakPoint(ds); letin->addDocumentToList(lets); DocumentList* letin2 = new DocumentList("", "", "", false); letin2->addBreakPoint(); letin2->addDocumentToList(inexpr); DocumentList* dl = new DocumentList("", "", ""); dl->addStringToList("let {"); dl->addDocumentToList(letin); dl->addBreakPoint(ds); dl->addStringToList("} in ("); dl->addDocumentToList(letin2); //dl->addBreakPoint(); dl->addStringToList(")"); return dl; } ret mapTypeInst(const TypeInst& ti) { DocumentList* dl = new DocumentList("", "", ""); if (ti.isarray()) { dl->addStringToList("array ["); DocumentList* ran = new DocumentList("", ", ", ""); for (unsigned int i = 0; i < ti.ranges().size(); i++) { ran->addDocumentToList(tiexpressionToDocument(Type::parint(), ti.ranges()[i])); } dl->addDocumentToList(ran); dl->addStringToList("] of "); } dl->addDocumentToList(tiexpressionToDocument(ti.type(),ti.domain())); return dl; } }; Document* annotationToDocument(const Annotation& ann) { DocumentList* dl = new DocumentList(" :: ", " :: ", ""); for (ExpressionSetIter it = ann.begin(); it != ann.end(); ++it) { dl->addDocumentToList(expressionToDocument(*it)); } return dl; } Document* expressionToDocument(const Expression* e) { if (e==NULL) return new StringDocument("NULL"); ExpressionDocumentMapper esm; ExpressionMapper em(esm); DocumentList* dl = new DocumentList("", "", ""); Document* s = em.map(e); dl->addDocumentToList(s); if (!e->isa() && !e->ann().isEmpty()) { dl->addDocumentToList(annotationToDocument(e->ann())); } return dl; } class ItemDocumentMapper { public: typedef Document* ret; ret mapIncludeI(const IncludeI& ii) { std::ostringstream oss; oss << "include \"" << ii.f() << "\";"; return new StringDocument(oss.str()); } ret mapVarDeclI(const VarDeclI& vi) { DocumentList* dl = new DocumentList("", " ", ";"); dl->addDocumentToList(expressionToDocument(vi.e())); return dl; } ret mapAssignI(const AssignI& ai) { DocumentList* dl = new DocumentList("", " = ", ";"); dl->addStringToList(ai.id().str()); dl->addDocumentToList(expressionToDocument(ai.e())); return dl; } ret mapConstraintI(const ConstraintI& ci) { DocumentList* dl = new DocumentList("constraint ", " ", ";"); dl->addDocumentToList(expressionToDocument(ci.e())); return dl; } ret mapSolveI(const SolveI& si) { DocumentList* dl = new DocumentList("", "", ";"); dl->addStringToList("solve"); if (!si.ann().isEmpty()) dl->addDocumentToList(annotationToDocument(si.ann())); switch (si.st()) { case SolveI::ST_SAT: dl->addStringToList(" satisfy"); break; case SolveI::ST_MIN: dl->addStringToList(" minimize "); dl->addDocumentToList(expressionToDocument(si.e())); break; case SolveI::ST_MAX: dl->addStringToList(" maximize "); dl->addDocumentToList(expressionToDocument(si.e())); break; } return dl; } ret mapOutputI(const OutputI& oi) { DocumentList* dl = new DocumentList("output ", " ", ";"); dl->addDocumentToList(expressionToDocument(oi.e())); return dl; } ret mapFunctionI(const FunctionI& fi) { DocumentList* dl; if (fi.ti()->type().isann() && fi.e() == NULL) { dl = new DocumentList("annotation ", " ", ";", false); } else if (fi.ti()->type() == Type::parbool()) { dl = new DocumentList("test ", "", ";", false); } else if (fi.ti()->type() == Type::varbool()) { dl = new DocumentList("predicate ", "", ";", false); } else { dl = new DocumentList("function ", "", ";", false); dl->addDocumentToList(expressionToDocument(fi.ti())); dl->addStringToList(": "); } dl->addStringToList(fi.id().str()); if (fi.params().size() > 0) { DocumentList* params = new DocumentList("(", ", ", ")"); for (unsigned int i = 0; i < fi.params().size(); i++) { DocumentList* par = new DocumentList("", "", ""); par->setUnbreakable(true); par->addDocumentToList(expressionToDocument(fi.params()[i])); params->addDocumentToList(par); } dl->addDocumentToList(params); } if (!fi.ann().isEmpty()) { dl->addDocumentToList(annotationToDocument(fi.ann())); } if (fi.e()) { dl->addStringToList(" = "); dl->addBreakPoint(); dl->addDocumentToList(expressionToDocument(fi.e())); } return dl; } }; class PrettyPrinter { public: /* * \brief Constructor for class Pretty Printer * \param maxwidth (default 80) : number of rows * \param indentationBase : spaces that represent the atomic number of spaces * \param sim : whether we want to simplify the result * \param deepSimp : whether we want to simplify at each breakpoint or not */ PrettyPrinter(int _maxwidth = 80, int _indentationBase = 4, bool sim = false, bool deepSimp = false); void print(Document* d); void print(std::ostream& os) const; private: int maxwidth; int indentationBase; int currentLine; int currentItem; std::vector > items; std::vector linesToSimplify; std::vector linesNotToSimplify; bool simp; bool deeplySimp; void addItem(); void addLine(int indentation, bool bp = false, bool ds = false, int level = 0); static std::string printSpaces(int n); const std::vector& getCurrentItemLines() const; void printDocument(Document* d, bool alignment, int startColAlignment, const std::string& before = "", const std::string& after = ""); void printDocList(DocumentList* d, int startColAlignment, const std::string& before = "", const std::string& after = ""); void printStringDoc(StringDocument* d, bool alignment, int startColAlignment, const std::string& before = "", const std::string& after = ""); void printString(const std::string& s, bool alignment, int startColAlignment); bool simplify(int item, int line, std::vector* vec); void simplifyItem(int item); }; void PrettyPrinter::print(Document* d) { addItem(); addLine(0); printDocument(d, true, 0); if (simp) simplifyItem(currentItem); } PrettyPrinter::PrettyPrinter(int _maxwidth, int _indentationBase, bool sim, bool deepsim) { maxwidth = _maxwidth; indentationBase = _indentationBase; currentLine = -1; currentItem = -1; simp = sim; deeplySimp = deepsim; } const std::vector& PrettyPrinter::getCurrentItemLines() const { return items[currentItem]; } void PrettyPrinter::addLine(int indentation, bool bp, bool simpl, int level) { items[currentItem].push_back(Line(indentation)); currentLine++; if (bp && deeplySimp) { linesToSimplify[currentItem].addLine(level, currentLine); if (!simpl) linesNotToSimplify[currentItem].addLine(0, currentLine); } } void PrettyPrinter::addItem() { items.push_back(std::vector()); linesToSimplify.push_back(LinesToSimplify()); linesNotToSimplify.push_back(LinesToSimplify()); currentItem++; currentLine = -1; } void PrettyPrinter::print(std::ostream& os) const { std::vector::const_iterator it; int nItems = items.size(); for (int item = 0; item < nItems; item++) { for (it = items[item].begin(); it != items[item].end(); it++) { it->print(os); } // os << std::endl; } } std::string PrettyPrinter::printSpaces(int n) { std::string result; for (int i = 0; i < n; i++) { result += " "; } return result; } void PrettyPrinter::printDocument(Document* d, bool alignment, int alignmentCol, const std::string& before, const std::string& after) { if (DocumentList* dl = dynamic_cast(d)) { printDocList(dl, alignmentCol, before, after); } else if (StringDocument* sd = dynamic_cast(d)) { printStringDoc(sd, alignment, alignmentCol, before, after); } else if (BreakPoint* bp = dynamic_cast(d)) { printString(before, alignment, alignmentCol); addLine(alignmentCol, deeplySimp, !bp->getDontSimplify(), d->getLevel()); printString(after, alignment, alignmentCol); } else { throw InternalError("PrettyPrinter::print : Wrong type of document"); } } void PrettyPrinter::printStringDoc(StringDocument* d, bool alignment, int alignmentCol, const std::string& before, const std::string& after) { std::string s; if (d != NULL) s = d->getString(); s = before + s + after; printString(s, alignment, alignmentCol); } void PrettyPrinter::printString(const std::string& s, bool alignment, int alignmentCol) { Line& l = items[currentItem][currentLine]; int size = s.size(); if (size <= l.getSpaceLeft(maxwidth)) { l.addString(s); } else { int col = alignment && maxwidth - alignmentCol >= size ? alignmentCol : indentationBase; addLine(col); items[currentItem][currentLine].addString(s); } } void PrettyPrinter::printDocList(DocumentList* d, int alignmentCol, const std::string& super_before, const std::string& super_after) { std::vector ld = d->getDocs(); std::string beginToken = d->getBeginToken(); std::string separator = d->getSeparator(); std::string endToken = d->getEndToken(); bool _alignment = d->getAlignment(); if (d->getUnbreakable()) { addLine(alignmentCol); } int currentCol = items[currentItem][currentLine].getIndentation() + items[currentItem][currentLine].getLength(); int newAlignmentCol = _alignment ? currentCol + beginToken.size() : alignmentCol; int vectorSize = ld.size(); int lastVisibleElementIndex; for (int i = 0; i < vectorSize; i++) { if (!dynamic_cast(ld[i])) lastVisibleElementIndex = i; } if (vectorSize == 0) { printStringDoc(NULL, true, newAlignmentCol, super_before + beginToken, endToken + super_after); } for (int i = 0; i < vectorSize; i++) { Document* subdoc = ld[i]; bool bp = false; if (dynamic_cast(subdoc)) { if (!_alignment) newAlignmentCol += indentationBase; bp = true; } std::string af, be; if (i != vectorSize - 1) { if (bp || lastVisibleElementIndex <= i) af = ""; else af = separator; } else { af = endToken + super_after; } if (i == 0) { be = super_before + beginToken; } else { be = ""; } printDocument(subdoc, _alignment, newAlignmentCol, be, af); } if (d->getUnbreakable()) { simplify(currentItem, currentLine, NULL); } } void PrettyPrinter::simplifyItem(int item) { linesToSimplify[item].remove(linesNotToSimplify[item]); std::vector* vec = (linesToSimplify[item].getLinesToSimplify()); while (!vec->empty()) { if (!simplify(item, (*vec)[0], vec)) break; } delete vec; } bool PrettyPrinter::simplify(int item, int line, std::vector* vec) { if (line == 0) { linesToSimplify[item].remove(vec, line, false); return false; } if (items[item][line].getLength() > items[item][line - 1].getSpaceLeft(maxwidth)) { linesToSimplify[item].remove(vec, line, false); return false; } else { linesToSimplify[item].remove(vec, line, true); items[item][line - 1].concatenateLines(items[item][line]); items[item].erase(items[item].begin() + line); linesToSimplify[item].decrementLine(vec, line); currentLine--; } return true; } Printer::Printer(std::ostream& os, int width, bool flatZinc) : ism(NULL), printer(NULL), _os(os), _width(width), _flatZinc(flatZinc) {} void Printer::init(void) { if (ism==NULL) { ism = new ItemDocumentMapper(); printer = new PrettyPrinter(_width, 4, true, true); } } Printer::~Printer(void) { delete printer; delete ism; } void Printer::p(Document* d) { printer->print(d); printer->print(_os); delete printer; printer = new PrettyPrinter(_width,4,true,true); } void Printer::p(const Item* i) { Document* d; switch (i->iid()) { case Item::II_INC: d = ism->mapIncludeI(*i->cast()); break; case Item::II_VD: d = ism->mapVarDeclI(*i->cast()); break; case Item::II_ASN: d = ism->mapAssignI(*i->cast()); break; case Item::II_CON: d = ism->mapConstraintI(*i->cast()); break; case Item::II_SOL: d = ism->mapSolveI(*i->cast()); break; case Item::II_OUT: d = ism->mapOutputI(*i->cast()); break; case Item::II_FUN: d = ism->mapFunctionI(*i->cast()); break; } p(d); delete d; } void Printer::print(const Expression* e) { if (_width==0) { PlainPrinter p(_os,_flatZinc); p.p(e); } else { init(); Document* d = expressionToDocument(e); p(d); delete d; } } void Printer::print(const Item* i) { if (_width==0) { PlainPrinter p(_os,_flatZinc); p.p(i); } else { init(); p(i); } } void Printer::print(const Model* m) { if (_width==0) { PlainPrinter p(_os,_flatZinc); for (unsigned int i = 0; i < m->size(); i++) { p.p((*m)[i]); } } else { init(); for (unsigned int i = 0; i < m->size(); i++) { p((*m)[i]); } } } } void debugprint(MiniZinc::Expression* e) { std::cerr << *e << "\n"; } void debugprint(MiniZinc::Item* i) { std::cerr << *i; } void debugprint(MiniZinc::Model* m) { MiniZinc::Printer p(std::cerr,0); p.print(m); } void debugprint(const MiniZinc::Location& loc) { std::cerr << loc << std::endl; } libminizinc-2.0.11/lib/builtins.cpp0000644000175000017500000025331112646030173015652 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_e b) { FunctionI* fi = m->matchFn(env,id,t); if (fi) { fi->_builtins.e = b; } else { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_f b) { FunctionI* fi = m->matchFn(env,id,t); if (fi) { fi->_builtins.f = b; } else { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_i b) { FunctionI* fi = m->matchFn(env,id,t); if (fi) { fi->_builtins.i = b; } else { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_b b) { FunctionI* fi = m->matchFn(env,id,t); if (fi) { fi->_builtins.b = b; } else { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_s b) { FunctionI* fi = m->matchFn(env,id,t); if (fi) { fi->_builtins.s = b; } else { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_str b) { FunctionI* fi = m->matchFn(env,id,t); if (fi) { fi->_builtins.str = b; } else { throw InternalError("no definition found for builtin "+id.str()); } } IntVal b_int_min(EnvI& env, Call* call) { ASTExprVec args = call->args(); switch (args.size()) { case 1: if (args[0]->type().is_set()) { throw EvalError(env, args[0]->loc(), "sets not supported"); } else { GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) throw EvalError(env, al->loc(), "Array is empty"); IntVal m = eval_int(env,al->v()[0]); for (unsigned int i=1; iv().size(); i++) m = std::min(m, eval_int(env,al->v()[i])); return m; } case 2: { return std::min(eval_int(env,args[0]),eval_int(env,args[1])); } default: throw EvalError(env, Location(), "dynamic type error"); } } IntVal b_int_max(EnvI& env, Call* call) { ASTExprVec args = call->args(); switch (args.size()) { case 1: if (args[0]->type().is_set()) { throw EvalError(env, args[0]->loc(), "sets not supported"); } else { GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) throw EvalError(env, al->loc(), "Array is empty"); IntVal m = eval_int(env,al->v()[0]); for (unsigned int i=1; iv().size(); i++) m = std::max(m, eval_int(env,al->v()[i])); return m; } case 2: { return std::max(eval_int(env,args[0]),eval_int(env,args[1])); } default: throw EvalError(env, Location(), "dynamic type error"); } } IntVal b_arg_min_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) throw EvalError(env, al->loc(), "Array is empty"); IntVal m = eval_int(env,al->v()[0]); int m_idx = 0; for (unsigned int i=1; iv().size(); i++) { IntVal mi = eval_int(env,al->v()[i]); if (mi < m) { m = mi; m_idx = i; } } return m_idx+1; } IntVal b_arg_max_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) throw EvalError(env, al->loc(), "Array is empty"); IntVal m = eval_int(env,al->v()[0]); int m_idx = 0; for (unsigned int i=1; iv().size(); i++) { IntVal mi = eval_int(env,al->v()[i]); if (mi > m) { m = mi; m_idx = i; } } return m_idx+1; } IntVal b_arg_min_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) throw EvalError(env, al->loc(), "Array is empty"); FloatVal m = eval_float(env,al->v()[0]); int m_idx = 0; for (unsigned int i=1; iv().size(); i++) { FloatVal mi = eval_float(env,al->v()[i]); if (mi < m) { m = mi; m_idx = i; } } return m_idx+1; } IntVal b_arg_max_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) throw EvalError(env, al->loc(), "Array is empty"); FloatVal m = eval_float(env,al->v()[0]); int m_idx = 0; for (unsigned int i=1; iv().size(); i++) { FloatVal mi = eval_float(env,al->v()[i]); if (mi > m) { m = mi; m_idx = i; } } return m_idx+1; } IntVal b_abs_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); return std::abs(eval_int(env,args[0])); } FloatVal b_abs_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); return std::abs(eval_float(env,args[0])); } bool b_has_bounds_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "dynamic type error"); IntBounds ib = compute_int_bounds(env,args[0]); return ib.valid && ib.l.isFinite() && ib.u.isFinite(); } bool b_has_bounds_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "dynamic type error"); FloatBounds fb = compute_float_bounds(env,args[0]); return fb.valid; } IntVal lb_varoptint(EnvI& env, Expression* e) { IntBounds b = compute_int_bounds(env,e); if (b.valid) return b.l; else return -IntVal::infinity(); } IntVal b_lb_varoptint(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "dynamic type error"); return lb_varoptint(env,args[0]); } bool b_occurs(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; return eval_par(env,args[0]) != constants().absent; } IntVal b_deopt_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; Expression* e = eval_par(env,args[0]); if (e==constants().absent) throw EvalError(env, e->loc(), "cannot evaluate deopt on absent value"); return eval_int(env,e); } bool b_deopt_bool(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; Expression* e = eval_par(env,args[0]); if (e==constants().absent) throw EvalError(env, e->loc(), "cannot evaluate deopt on absent value"); return eval_bool(env,e); } IntVal b_array_lb_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); Expression* e = follow_id_to_decl(args[0]); bool foundMin = false; IntVal array_lb = -IntVal::infinity(); if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,vd->ti()->domain()); if (isv->size()!=0) { array_lb = isv->min(); foundMin = true; } } e = vd->e(); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->v().size()==0) throw EvalError(env, Location(), "lower bound of empty array undefined"); IntVal min = IntVal::infinity(); for (unsigned int i=0; iv().size(); i++) { IntBounds ib = compute_int_bounds(env,al->v()[i]); if (!ib.valid) goto b_array_lb_int_done; min = std::min(min, ib.l); } if (foundMin) array_lb = std::max(array_lb, min); else array_lb = min; foundMin = true; } b_array_lb_int_done: if (foundMin) { return array_lb; } else { return -IntVal::infinity(); } } IntVal ub_varoptint(EnvI& env, Expression* e) { IntBounds b = compute_int_bounds(env,e); if (b.valid) return b.u; else return IntVal::infinity(); } IntVal b_ub_varoptint(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "dynamic type error"); return ub_varoptint(env,args[0]); } IntVal b_array_ub_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); Expression* e = follow_id_to_decl(args[0]); bool foundMax = false; IntVal array_ub = IntVal::infinity(); if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,vd->ti()->domain()); if (isv->size()!=0) { array_ub = isv->max(); foundMax = true; } } e = vd->e(); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->v().size()==0) throw EvalError(env, Location(), "upper bound of empty array undefined"); IntVal max = -IntVal::infinity(); for (unsigned int i=0; iv().size(); i++) { IntBounds ib = compute_int_bounds(env,al->v()[i]); if (!ib.valid) goto b_array_ub_int_done; max = std::max(max, ib.u); } if (foundMax) array_ub = std::min(array_ub, max); else array_ub = max; foundMax = true; } b_array_ub_int_done: if (foundMax) { return array_ub; } else { return IntVal::infinity(); } } IntVal b_sum_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) return 0; IntVal m = 0; for (unsigned int i=0; iv().size(); i++) m += eval_int(env,al->v()[i]); return m; } IntVal b_product_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) return 1; IntVal m = 1; for (unsigned int i=0; iv().size(); i++) m *= eval_int(env,al->v()[i]); return m; } FloatVal b_product_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) return 1; FloatVal m = 1.0; for (unsigned int i=0; iv().size(); i++) m *= eval_float(env,al->v()[i]); return m; } FloatVal lb_varoptfloat(EnvI& env, Expression* e) { FloatBounds b = compute_float_bounds(env,e); if (b.valid) return b.l; else throw EvalError(env, e->loc(),"cannot determine bounds"); } FloatVal ub_varoptfloat(EnvI& env, Expression* e) { FloatBounds b = compute_float_bounds(env,e); if (b.valid) return b.u; else throw EvalError(env, e->loc(),"cannot determine bounds"); } FloatVal b_lb_varoptfloat(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "dynamic type error"); return lb_varoptfloat(env,args[0]); } FloatVal b_ub_varoptfloat(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "dynamic type error"); return ub_varoptfloat(env,args[0]); } FloatVal b_array_lb_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); Expression* e = follow_id_to_decl(args[0]); bool foundMin = false; FloatVal array_lb = 0.0; if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { BinOp* bo = vd->ti()->domain()->cast(); assert(bo->op() == BOT_DOTDOT); array_lb = eval_float(env,bo->lhs()); foundMin = true; } e = vd->e(); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->v().size()==0) throw EvalError(env, Location(), "lower bound of empty array undefined"); bool min_valid = false; FloatVal min = 0.0; for (unsigned int i=0; iv().size(); i++) { FloatBounds fb = compute_float_bounds(env,al->v()[i]); if (!fb.valid) goto b_array_lb_float_done; if (min_valid) { min = std::min(min, fb.l); } else { min_valid = true; min = fb.l; } } assert(min_valid); if (foundMin) array_lb = std::max(array_lb, min); else array_lb = min; foundMin = true; } b_array_lb_float_done: if (foundMin) { return array_lb; } else { throw EvalError(env, e->loc(),"cannot determine lower bound"); } } FloatVal b_array_ub_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); Expression* e = follow_id_to_decl(args[0]); bool foundMax = false; FloatVal array_ub = 0.0; if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { BinOp* bo = vd->ti()->domain()->cast(); assert(bo->op() == BOT_DOTDOT); array_ub = eval_float(env,bo->rhs()); foundMax = true; } e = vd->e(); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->v().size()==0) throw EvalError(env, Location(), "upper bound of empty array undefined"); bool max_valid = false; FloatVal max = 0.0; for (unsigned int i=0; iv().size(); i++) { FloatBounds fb = compute_float_bounds(env,al->v()[i]); if (!fb.valid) goto b_array_ub_float_done; if (max_valid) { max = std::max(max, fb.u); } else { max_valid = true; max = fb.u; } } assert(max_valid); if (foundMax) array_ub = std::min(array_ub, max); else array_ub = max; foundMax = true; } b_array_ub_float_done: if (foundMax) { return array_ub; } else { throw EvalError(env, e->loc(),"cannot determine upper bound"); } } FloatVal b_sum_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) return 0; FloatVal m = 0; for (unsigned int i=0; iv().size(); i++) m += eval_float(env,al->v()[i]); return m; } FloatVal b_float_min(EnvI& env, Call* call) { ASTExprVec args = call->args(); switch (args.size()) { case 1: if (args[0]->type().is_set()) { throw EvalError(env, args[0]->loc(), "sets not supported"); } else { GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) throw EvalError(env, al->loc(), "min on empty array undefined"); FloatVal m = eval_float(env,al->v()[0]); for (unsigned int i=1; iv().size(); i++) m = std::min(m, eval_float(env,al->v()[i])); return m; } case 2: { return std::min(eval_float(env,args[0]),eval_float(env,args[1])); } default: throw EvalError(env, Location(), "dynamic type error"); } } FloatVal b_float_max(EnvI& env, Call* call) { ASTExprVec args = call->args(); switch (args.size()) { case 1: if (args[0]->type().is_set()) { throw EvalError(env, args[0]->loc(), "sets not supported"); } else { GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) throw EvalError(env, al->loc(), "max on empty array undefined"); FloatVal m = eval_float(env,al->v()[0]); for (unsigned int i=1; iv().size(); i++) m = std::max(m, eval_float(env,al->v()[i])); return m; } case 2: { return std::max(eval_float(env,args[0]),eval_float(env,args[1])); } default: throw EvalError(env, Location(), "dynamic type error"); } } IntSetVal* b_index_set(EnvI& env, Expression* e, int i) { if (e->eid() != Expression::E_ID) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->dims() < i) throw EvalError(env, e->loc(), "index_set: wrong dimension"); return IntSetVal::a(al->min(i-1),al->max(i-1)); } Id* id = e->cast(); if (id->decl() == NULL) throw EvalError(env, id->loc(), "undefined identifier"); if ( ( id->decl()->ti()->ranges().size()==1 && id->decl()->ti()->ranges()[0]->domain() != NULL && id->decl()->ti()->ranges()[0]->domain()->isa() ) || ( static_cast(id->decl()->ti()->ranges().size()) >= i && ( id->decl()->ti()->ranges()[i-1]->domain() == NULL || id->decl()->ti()->ranges()[i-1]->domain()->isa()) )) { GCLock lock; ArrayLit* al = eval_array_lit(env,id); if (al->dims() < i) throw EvalError(env, id->loc(), "index_set: wrong dimension"); return IntSetVal::a(al->min(i-1),al->max(i-1)); } if (static_cast(id->decl()->ti()->ranges().size()) < i) throw EvalError(env, id->loc(), "index_set: wrong dimension"); return eval_intset(env,id->decl()->ti()->ranges()[i-1]->domain()); } bool b_index_sets_agree(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 2) throw EvalError(env, Location(), "index_sets_agree needs exactly two arguments"); GCLock lock; ArrayLit* al0 = eval_array_lit(env,args[0]); ArrayLit* al1 = eval_array_lit(env,args[1]); if (al0->type().dim() != al1->type().dim()) return false; for (int i=1; i<=al0->type().dim(); i++) { IntSetVal* index0 = b_index_set(env, al0, i); IntSetVal* index1 = b_index_set(env, al1, i); if (!index0->equal(index1)) return false; } return true; } IntSetVal* b_index_set1(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,args[0],1); } IntSetVal* b_index_set2(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,args[0],2); } IntSetVal* b_index_set3(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,args[0],3); } IntSetVal* b_index_set4(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,args[0],4); } IntSetVal* b_index_set5(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,args[0],5); } IntSetVal* b_index_set6(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,args[0],6); } IntVal b_min_parsetint(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); IntSetVal* isv = eval_intset(env,args[0]); return isv->min(); } IntVal b_max_parsetint(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); IntSetVal* isv = eval_intset(env,args[0]); return isv->max(); } IntSetVal* b_lb_set(EnvI& env, Call* e) { Expression* ee = eval_par(env, e->args()[0]); if (ee->type().ispar()) { return eval_intset(env, ee); } return IntSetVal::a(); } IntSetVal* b_ub_set(EnvI& env, Expression* e) { IntSetVal* isv = compute_intset_bounds(env,e); if (isv) return isv; throw EvalError(env, e->loc(), "cannot determine bounds of set expression"); } IntSetVal* b_ub_set(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); return b_ub_set(env,args[0]); } bool b_has_ub_set(EnvI& env, Call* call) { ASTExprVec args = call->args(); Expression* e = args[0]; for (;;) { switch (e->eid()) { case Expression::E_SETLIT: return true; case Expression::E_ID: { Id* id = e->cast(); if (id->decl()==NULL) throw EvalError(env, id->loc(),"undefined identifier"); if (id->decl()->e()==NULL) return id->decl()->ti()->domain() != NULL; else e = id->decl()->e(); } break; default: throw EvalError(env, e->loc(),"invalid argument to has_ub_set"); } } } IntSetVal* b_array_ub_set(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) throw EvalError(env, Location(), "upper bound of empty array undefined"); IntSetVal* ub = b_ub_set(env,al->v()[0]); for (unsigned int i=1; iv().size(); i++) { IntSetRanges isr(ub); IntSetRanges r(b_ub_set(env,al->v()[i])); Ranges::Union u(isr,r); ub = IntSetVal::ai(u); } return ub; } IntSetVal* b_dom_varint(EnvI& env, Expression* e) { Id* lastid = NULL; Expression* cur = e; for (;;) { if (cur==NULL) { if (lastid==NULL) { throw EvalError(env, e->loc(),"invalid argument to dom"); } else { if (lastid->decl()->ti()->domain()==NULL) { throw EvalError(env, e->loc(),"invalid argument to dom"); } return eval_intset(env,lastid->decl()->ti()->domain()); } } switch (cur->eid()) { case Expression::E_INTLIT: { IntVal v = cur->cast()->v(); return IntSetVal::a(v,v); } case Expression::E_ID: { lastid = cur->cast(); if (lastid->decl()==NULL) throw EvalError(env, lastid->loc(),"undefined identifier"); cur = lastid->decl()->e(); } break; case Expression::E_ARRAYACCESS: { bool success; cur = eval_arrayaccess(env,cur->cast(), success); if (!success) { cur = NULL; } } break; default: cur = NULL; break; } } } IntSetVal* b_dom_varint(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); return b_dom_varint(env,args[0]); } IntSetVal* b_dom_bounds_array(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); Expression* arg_e = args[0]; Expression* e = follow_id_to_decl(arg_e); bool foundBounds = false; IntVal array_lb = -IntVal::infinity(); IntVal array_ub = IntVal::infinity(); if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,vd->ti()->domain()); if (isv->size()!=0) { array_lb = isv->min(); array_ub = isv->max(); foundBounds = true; } } e = vd->e(); } if (foundBounds) { return IntSetVal::a(array_lb,array_ub); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->v().size()==0) throw EvalError(env, Location(), "lower bound of empty array undefined"); IntVal min = IntVal::infinity(); IntVal max = -IntVal::infinity(); for (unsigned int i=0; iv().size(); i++) { IntBounds ib = compute_int_bounds(env,al->v()[i]); if (!ib.valid) goto b_array_lb_int_done; min = std::min(min, ib.l); max = std::max(max, ib.u); } array_lb = std::max(array_lb, min); array_ub = std::min(array_ub, max); foundBounds = true; } b_array_lb_int_done: if (foundBounds) { return IntSetVal::a(array_lb,array_ub); } else { throw EvalError(env, e->loc(),"cannot determine lower bound"); } } IntSetVal* b_dom_array(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); Expression* ae = args[0]; ArrayLit* al = NULL; while (al==NULL) { switch (ae->eid()) { case Expression::E_ARRAYLIT: al = ae->cast(); break; case Expression::E_ID: { Id* id = ae->cast(); if (id->decl()==NULL) throw EvalError(env, id->loc(),"undefined identifier"); if (id->decl()->e()==NULL) throw EvalError(env, id->loc(),"array without initialiser"); else ae = id->decl()->e(); } break; default: throw EvalError(env, ae->loc(),"invalid argument to dom"); } } if (al->v().size()==0) return IntSetVal::a(); IntSetVal* isv = b_dom_varint(env,al->v()[0]); for (unsigned int i=1; iv().size(); i++) { IntSetRanges isr(isv); IntSetRanges r(b_dom_varint(env,al->v()[i])); Ranges::Union u(isr,r); isv = IntSetVal::ai(u); } return isv; } IntSetVal* b_compute_div_bounds(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==2); IntBounds bx = compute_int_bounds(env,args[0]); if (!bx.valid) throw EvalError(env, args[0]->loc(),"cannot determine bounds"); /// TODO: better bounds if only some input bounds are infinite if (!bx.l.isFinite() || !bx.u.isFinite()) return constants().infinity->isv(); IntBounds by = compute_int_bounds(env,args[1]); if (!by.valid) throw EvalError(env, args[1]->loc(),"cannot determine bounds"); if (!by.l.isFinite() || !by.u.isFinite()) return constants().infinity->isv(); Ranges::Const byr(by.l,by.u); Ranges::Const by0(0,0); Ranges::Diff byr0(byr,by0); IntVal min=IntVal::maxint(); IntVal max=IntVal::minint(); if (byr0()) { min = std::min(min, bx.l / byr0.min()); min = std::min(min, bx.l / byr0.max()); min = std::min(min, bx.u / byr0.min()); min = std::min(min, bx.u / byr0.max()); max = std::max(max, bx.l / byr0.min()); max = std::max(max, bx.l / byr0.max()); max = std::max(max, bx.u / byr0.min()); max = std::max(max, bx.u / byr0.max()); ++byr0; if (byr0()) { min = std::min(min, bx.l / byr0.min()); min = std::min(min, bx.l / byr0.max()); min = std::min(min, bx.u / byr0.min()); min = std::min(min, bx.u / byr0.max()); max = std::max(max, bx.l / byr0.min()); max = std::max(max, bx.l / byr0.max()); max = std::max(max, bx.u / byr0.min()); max = std::max(max, bx.u / byr0.max()); } } return IntSetVal::a(min,max); } ArrayLit* b_arrayXd(EnvI& env, ASTExprVec args, int d) { GCLock lock; ArrayLit* al = eval_array_lit(env,args[d]); std::vector > dims(d); unsigned int dim1d = 1; for (int i=0; isize()==0) { dims[i] = std::pair(1,0); dim1d = 0; } else if (di->size() != 1) { throw EvalError(env, args[i]->loc(), "arrayXd only defined for ranges"); } else { dims[i] = std::pair(static_cast(di->min(0).toInt()), static_cast(di->max(0).toInt())); dim1d *= dims[i].second-dims[i].first+1; } } if (dim1d != al->v().size()) throw EvalError(env, al->loc(), "mismatch in array dimensions"); ArrayLit* ret = new ArrayLit(al->loc(), al->v(), dims); Type t = al->type(); t.dim(d); ret->type(t); ret->flat(al->flat()); return ret; } Expression* b_array1d_list(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->dims()==1 && al->min(0)==1) { return args[0]->isa() ? args[0] : al; } ArrayLit* ret = new ArrayLit(al->loc(), al->v()); Type t = al->type(); t.dim(1); ret->type(t); ret->flat(al->flat()); return ret; } Expression* b_array1d(EnvI& env, Call* call) { ASTExprVec args = call->args(); return b_arrayXd(env,args,1); } Expression* b_array2d(EnvI& env, Call* call) { ASTExprVec args = call->args(); return b_arrayXd(env,args,2); } Expression* b_array3d(EnvI& env, Call* call) { ASTExprVec args = call->args(); return b_arrayXd(env,args,3); } Expression* b_array4d(EnvI& env, Call* call) { ASTExprVec args = call->args(); return b_arrayXd(env,args,4); } Expression* b_array5d(EnvI& env, Call* call) { ASTExprVec args = call->args(); return b_arrayXd(env,args,5); } Expression* b_array6d(EnvI& env, Call* call) { ASTExprVec args = call->args(); return b_arrayXd(env,args,6); } Expression* b_arrayXd(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; ArrayLit* al0 = eval_array_lit(env,args[0]); ArrayLit* al1 = eval_array_lit(env,args[1]); if (al0->dims()==al1->dims()) { bool sameDims = true; for (unsigned int i=al0->dims(); i--;) { if (al0->min(i)!=al1->min(i) || al0->max(i)!=al1->max(i)) { sameDims = false; break; } } if (sameDims) return args[1]->isa() ? args[1] : al1; } std::vector > dims(al0->dims()); for (unsigned int i=al0->dims(); i--;) { dims[i] = std::make_pair(al0->min(i), al0->max(i)); } ArrayLit* ret = new ArrayLit(al1->loc(), al1->v(), dims); Type t = al1->type(); t.dim(dims.size()); ret->type(t); ret->flat(al1->flat()); return ret; } IntVal b_length(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); return al->v().size(); } IntVal b_bool2int(EnvI& env, Call* call) { ASTExprVec args = call->args(); return eval_bool(env,args[0]) ? 1 : 0; } bool b_forall_par(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size()!=1) throw EvalError(env, Location(), "forall needs exactly one argument"); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); for (unsigned int i=al->v().size(); i--;) if (!eval_bool(env,al->v()[i])) return false; return true; } bool b_exists_par(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size()!=1) throw EvalError(env, Location(), "exists needs exactly one argument"); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); for (unsigned int i=al->v().size(); i--;) if (eval_bool(env,al->v()[i])) return true; return false; } bool b_clause_par(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size()!=2) throw EvalError(env, Location(), "clause needs exactly two arguments"); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); for (unsigned int i=al->v().size(); i--;) if (eval_bool(env,al->v()[i])) return true; al = eval_array_lit(env,args[1]); for (unsigned int i=al->v().size(); i--;) if (!eval_bool(env,al->v()[i])) return true; return false; } bool b_xorall_par(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size()!=1) throw EvalError(env, Location(), "xorall needs exactly one argument"); GCLock lock; int count = 0; ArrayLit* al = eval_array_lit(env,args[0]); for (unsigned int i=al->v().size(); i--;) count += eval_bool(env,al->v()[i]); return count % 2 == 1; } bool b_iffall_par(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size()!=1) throw EvalError(env, Location(), "xorall needs exactly one argument"); GCLock lock; int count = 0; ArrayLit* al = eval_array_lit(env,args[0]); for (unsigned int i=al->v().size(); i--;) count += eval_bool(env,al->v()[i]); return count % 2 == 0; } IntVal b_card(EnvI& env, Call* call) { ASTExprVec args = call->args(); if (args.size()!=1) throw EvalError(env, Location(), "card needs exactly one argument"); IntSetVal* isv = eval_intset(env,args[0]); IntSetRanges isr(isv); return Ranges::size(isr); } Expression* exp_is_fixed(EnvI& env, Expression* e) { GCLock lock; Expression* cur = eval_par(env,e); for (;;) { if (cur==NULL) return NULL; if (cur->type().ispar()) return cur; switch (cur->eid()) { case Expression::E_ID: cur = cur->cast()->decl(); break; case Expression::E_VARDECL: if (cur->type().st() != Type::ST_SET) { Expression* dom = cur->cast()->ti()->domain(); if (dom && (dom->isa() || dom->isa() || dom->isa())) return dom; } cur = cur->cast()->e(); break; default: return NULL; } } } bool b_is_fixed(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); return exp_is_fixed(env,args[0]) != NULL; } bool b_is_fixed_array(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) return true; for (unsigned int i=0; iv().size(); i++) { if (exp_is_fixed(env,al->v()[i])==NULL) return false; } return true; } Expression* b_fix(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); Expression* ret = exp_is_fixed(env,args[0]); if (ret==NULL) throw EvalError(env, args[0]->loc(), "expression is not fixed"); return ret; } IntVal b_fix_int(EnvI& env, Call* call) { return eval_int(env,b_fix(env,call)); } bool b_fix_bool(EnvI& env, Call* call) { return eval_bool(env,b_fix(env,call)); } FloatVal b_fix_float(EnvI& env, Call* call) { return eval_float(env,b_fix(env,call)); } IntSetVal* b_fix_set(EnvI& env, Call* call) { return eval_intset(env,b_fix(env,call)); } Expression* b_fix_array(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); std::vector fixed(al->v().size()); for (unsigned int i=0; iv()[i]); if (fixed[i]==NULL) throw EvalError(env, al->v()[i]->loc(), "expression is not fixed"); } ArrayLit* ret = new ArrayLit(Location(), fixed); Type tt = al->type(); tt.ti(Type::TI_PAR); ret->type(tt); return ret; } FloatVal b_int2float(EnvI& env, Call* call) { ASTExprVec args = call->args(); IntVal iv = eval_int(env,args[0]); if (iv.isFinite()) { long long int i = iv.toInt(); return static_cast(i); } if (iv.isPlusInfinity()) return std::numeric_limits::infinity(); return -std::numeric_limits::infinity(); } IntVal b_ceil(EnvI& env, Call* call) { ASTExprVec args = call->args(); return static_cast(std::ceil(eval_float(env,args[0]))); } IntVal b_floor(EnvI& env, Call* call) { ASTExprVec args = call->args(); return static_cast(std::floor(eval_float(env,args[0]))); } IntVal b_round(EnvI& env, Call* call) { ASTExprVec args = call->args(); return static_cast(eval_float(env,args[0])+0.5); } FloatVal b_log10(EnvI& env, Call* call) { ASTExprVec args = call->args(); return std::log10(eval_float(env,args[0])); } FloatVal b_log2(EnvI& env, Call* call) { ASTExprVec args = call->args(); return std::log(eval_float(env,args[0])) / std::log(2.0); } FloatVal b_ln(EnvI& env, Call* call) { ASTExprVec args = call->args(); return std::log(eval_float(env,args[0])); } FloatVal b_log(EnvI& env, Call* call) { ASTExprVec args = call->args(); return std::log(eval_float(env,args[1])) / std::log(eval_float(env,args[0])); } FloatVal b_exp(EnvI& env, Call* call) { ASTExprVec args = call->args(); return std::exp(eval_float(env,args[0])); } FloatVal b_pow(EnvI& env, Call* call) { ASTExprVec args = call->args(); return std::pow(eval_float(env,args[0]),eval_float(env,args[1])); } IntVal b_pow_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); IntVal p = eval_int(env,args[0]); IntVal r = 1; long long int e = eval_int(env,args[1]).toInt(); if (e < 0) throw EvalError(env, args[1]->loc(), "Cannot raise integer to a negative power"); for (long long int i=e; i--;) r = r*p; return r; } FloatVal b_sqrt(EnvI& env, Call* call) { ASTExprVec args = call->args(); return std::sqrt(eval_float(env,args[0])); } bool b_assert_bool(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==2); GCLock lock; if (eval_bool(env,args[0])) return true; StringLit* err = eval_par(env,args[1])->cast(); throw EvalError(env, args[0]->loc(),"Assertion failed: "+err->v().str()); } Expression* b_assert(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==3); GCLock lock; if (eval_bool(env,args[0])) return args[2]; StringLit* err = eval_par(env,args[1])->cast(); throw EvalError(env, args[0]->loc(),"Assertion failed: "+err->v().str()); } bool b_abort(EnvI& env, Call* call) { ASTExprVec args = call->args(); StringLit* err = eval_par(env,args[0])->cast(); throw EvalError(env, args[0]->loc(),"Abort: "+err->v().str()); } Expression* b_trace(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; StringLit* msg = eval_par(env,args[0])->cast(); std::cerr << msg->v(); return args.size()==1 ? constants().lit_true : args[1]; } bool b_in_redundant_constraint(EnvI& env, Call*) { return env.in_redundant_constraint > 0; } Expression* b_set2array(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; IntSetVal* isv = eval_intset(env,args[0]); std::vector elems; IntSetRanges isr(isv); for (Ranges::ToValues isr_v(isr); isr_v(); ++isr_v) elems.push_back(IntLit::a(isr_v.val())); ArrayLit* al = new ArrayLit(args[0]->loc(),elems); al->type(Type::parint(1)); return al; } IntVal b_string_length(EnvI& env, Call* call) { ASTExprVec args = call->args(); GCLock lock; std::string s = eval_string(env,args[0]); return s.size(); } std::string show(EnvI& env, Expression* exp) { std::ostringstream oss; GCLock lock; Expression* e = eval_par(env,exp); if (e->type().isvar()) { Printer p(oss,0,false); p.print(e); } else { e = eval_par(env,e); if (StringLit* sl = e->dyn_cast()) { return sl->v().str(); } Printer p(oss,0,false); if (ArrayLit* al = e->dyn_cast()) { oss << "["; for (unsigned int i=0; iv().size(); i++) { p.print(al->v()[i]); if (iv().size()-1) oss << ", "; } oss << "]"; } else { p.print(e); } } return oss.str(); } std::string b_show(EnvI& env, Call* call) { ASTExprVec args = call->args(); return show(env,args[0]); } std::string b_format(EnvI& env, Call* call) { ASTExprVec args = call->args(); int width = 0; int prec = -1; GCLock lock; Expression* e; if (args.size()>1) { width = eval_int(env,args[0]).toInt(); if (args.size()==2) { e = eval_par(env,args[1]); } else { assert(args.size()==3); prec = eval_int(env,args[1]).toInt(); if (prec < 0) throw EvalError(env, args[1]->loc(),"output precision cannot be negative"); e = eval_par(env,args[2]); } } else { e = eval_par(env,args[0]); } if (e->type() == Type::parint()) { long long int i = eval_int(env,e).toInt(); std::ostringstream formatted; if (width > 0) { formatted.width(width); } else if (width < 0) { formatted.width(-width); formatted.flags(std::ios::left); } if (prec != -1) formatted.precision(prec); formatted << i; return formatted.str(); } else if (e->type() == Type::parfloat()) { FloatVal i = eval_float(env,e); std::ostringstream formatted; if (width > 0) { formatted.width(width); } else if (width < 0) { formatted.width(-width); formatted.flags(std::ios::left); } formatted.setf(std::ios::fixed); formatted.precision(std::numeric_limits::digits10+2); if (prec != -1) formatted.precision(prec); formatted << i; return formatted.str(); } else { std::string s = show(env,e); if (prec >= 0 && prec < s.size()) s = s.substr(0,prec); std::ostringstream oss; if (s.size() < std::abs(width)) { int addLeft = width < 0 ? 0 : (width - s.size()); if (addLeft < 0) addLeft = 0; int addRight = width < 0 ? (-width-s.size()) : 0; if (addRight < 0) addRight = 0; for (int i=addLeft; i--;) oss << " "; oss << s; for (int i=addRight; i--;) oss << " "; return oss.str(); } else { return s; } } } std::string b_show_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==2); GCLock lock; Expression* e = eval_par(env,args[1]); std::ostringstream oss; if (IntLit* iv = e->dyn_cast()) { int justify = static_cast(eval_int(env,args[0]).toInt()); std::ostringstream oss_length; oss_length << iv->v(); int iv_length = static_cast(oss_length.str().size()); int addLeft = justify < 0 ? 0 : (justify - iv_length); if (addLeft < 0) addLeft = 0; int addRight = justify < 0 ? (-justify-iv_length) : 0; if (addRight < 0) addRight = 0; for (int i=addLeft; i--;) oss << " "; oss << iv->v(); for (int i=addRight; i--;) oss << " "; } else { Printer p(oss,0,false); p.print(e); } return oss.str(); } std::string b_show_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==3); GCLock lock; Expression* e = eval_par(env,args[2]); std::ostringstream oss; if (FloatLit* fv = e->dyn_cast()) { int justify = static_cast(eval_int(env,args[0]).toInt()); int prec = static_cast(eval_int(env,args[1]).toInt()); if (prec < 0) throw EvalError(env, args[1]->loc(), "number of digits in show_float cannot be negative"); std::ostringstream oss_length; oss_length << std::setprecision(prec) << std::fixed << fv->v(); int fv_length = static_cast(oss_length.str().size()); int addLeft = justify < 0 ? 0 : (justify - fv_length); if (addLeft < 0) addLeft = 0; int addRight = justify < 0 ? (-justify-fv_length) : 0; if (addRight < 0) addRight = 0; for (int i=addLeft; i--;) oss << " "; oss << std::setprecision(prec) << std::fixed << fv->v(); for (int i=addRight; i--;) oss << " "; } else { Printer p(oss,0,false); p.print(e); } return oss.str(); } std::string b_file_path(EnvI&, Call* call) { return FileUtils::file_path(call->loc().filename.str()); } std::string b_concat(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); std::ostringstream oss; for (unsigned int i=0; iv().size(); i++) { oss << eval_string(env,al->v()[i]); } return oss.str(); } std::string b_join(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==2); std::string sep = eval_string(env,args[0]); GCLock lock; ArrayLit* al = eval_array_lit(env,args[1]); std::ostringstream oss; for (unsigned int i=0; iv().size(); i++) { oss << eval_string(env,al->v()[i]); if (iv().size()-1) oss << sep; } return oss.str(); } IntSetVal* b_array_union(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); ArrayLit* al = eval_array_lit(env,args[0]); if (al->v().size()==0) return IntSetVal::a(); IntSetVal* isv = eval_intset(env,al->v()[0]); for (unsigned int i=0; iv().size(); i++) { IntSetRanges i0(isv); IntSetRanges i1(eval_intset(env,al->v()[i])); Ranges::Union u(i0,i1); isv = IntSetVal::ai(u); } return isv; } IntSetVal* b_array_intersect(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); ArrayLit* al = eval_array_lit(env,args[0]); std::vector ranges; if (al->v().size() > 0) { IntSetVal* i0 = eval_intset(env,al->v()[0]); if (i0->size() > 0) { IntSetRanges i0r(i0); IntVal min = i0r.min(); while (i0r()) { // Initialize with last interval IntVal max = i0r.max(); // Intersect with all other intervals restart: for (int j=al->v().size(); j--;) { IntSetRanges ij(eval_intset(env,al->v()[j])); // Skip intervals that are too small while (ij() && (ij.max() < min)) ++ij; if (!ij()) goto done; if (ij.min() > max) { min=ij.min(); max=ij.max(); goto restart; } // Now the intervals overlap if (min < ij.min()) min = ij.min(); if (max > ij.max()) max = ij.max(); } ranges.push_back(IntSetVal::Range(min,max)); // The next interval must be at least two elements away min = max + 2; } done: return IntSetVal::a(ranges); } else { return IntSetVal::a(); } } else { return IntSetVal::a(); } } Expression* b_sort_by_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==2); ArrayLit* al = eval_array_lit(env,args[0]); ArrayLit* order_e = eval_array_lit(env,args[1]); std::vector order(order_e->v().size()); std::vector a(order_e->v().size()); for (unsigned int i=0; iv()[i]); } struct Ord { std::vector& order; Ord(std::vector& order0) : order(order0) {} bool operator()(int i, int j) { return order[i] < order[j]; } } _ord(order); std::stable_sort(a.begin(), a.end(), _ord); std::vector sorted(a.size()); for (unsigned int i=sorted.size(); i--;) sorted[i] = al->v()[a[i]]; ArrayLit* al_sorted = new ArrayLit(al->loc(), sorted); al_sorted->type(al->type()); return al_sorted; } Expression* b_sort_by_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==2); ArrayLit* al = eval_array_lit(env,args[0]); ArrayLit* order_e = eval_array_lit(env,args[1]); std::vector order(order_e->v().size()); std::vector a(order_e->v().size()); for (unsigned int i=0; iv()[i]); } struct Ord { std::vector& order; Ord(std::vector& order0) : order(order0) {} bool operator()(int i, int j) { return order[i] < order[j]; } } _ord(order); std::stable_sort(a.begin(), a.end(), _ord); std::vector sorted(a.size()); for (unsigned int i=sorted.size(); i--;) sorted[i] = al->v()[a[i]]; ArrayLit* al_sorted = new ArrayLit(al->loc(), sorted); al_sorted->type(al->type()); return al_sorted; } Expression* b_sort(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); ArrayLit* al = eval_array_lit(env,args[0]); std::vector sorted(al->v().size()); for (unsigned int i=sorted.size(); i--;) sorted[i] = al->v()[i]; struct Ord { EnvI& env; Ord(EnvI& env0) : env(env0) {} bool operator()(Expression* e0, Expression* e1) { switch (e0->type().bt()) { case Type::BT_INT: return eval_int(env,e0) < eval_int(env,e1); case Type::BT_BOOL: return eval_bool(env,e0) < eval_bool(env,e1); case Type::BT_FLOAT: return eval_float(env,e0) < eval_float(env,e1); default: throw EvalError(env, e0->loc(), "unsupported type for sorting"); } } } _ord(env); std::sort(sorted.begin(),sorted.end(),_ord); ArrayLit* al_sorted = new ArrayLit(al->loc(), sorted); al_sorted->type(al->type()); return al_sorted; } std::default_random_engine& rnd_generator(void) { // TODO: initiate with seed if given as annotation/in command line static std::default_random_engine g; return g; } FloatVal b_normal_float_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() ==2); const double mean = eval_float(env,args[0]); const double stdv = eval_float(env,args[1]); std::normal_distribution distribution(mean,stdv); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_normal_int_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() ==2); const double mean = eval_float(env,args[0]); const double stdv = double(eval_int(env,args[1]).toInt()); std::normal_distribution distribution(mean,stdv); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_uniform_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 2); const double lb = eval_float(env,args[0]); const double ub = eval_float(env,args[1]); if(lb > ub) { std::stringstream ssm; ssm << "lowerbound of uniform distribution \"" << lb << "\" is higher than its upperbound: " << ub; throw EvalError(env, args[0]->loc(),ssm.str()); } std::uniform_real_distribution distribution(lb,ub); // return a sample from the distribution return distribution(rnd_generator()); } IntVal b_uniform_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 2); const long long int lb = eval_int(env,args[0]).toInt(); const long long int ub = eval_int(env,args[1]).toInt(); if(lb > ub) { std::stringstream ssm; ssm << "lowerbound of uniform distribution \"" << lb << "\" is higher than its upperbound: " << ub; throw EvalError(env, args[0]->loc(),ssm.str()); } std::uniform_int_distribution distribution(lb,ub); // return a sample from the distribution return IntVal(distribution(rnd_generator())); } IntVal b_poisson_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); long long int mean = eval_int(env,args[0]).toInt(); std::poisson_distribution distribution(mean); // return a sample from the distribution return IntVal(distribution(rnd_generator())); } IntVal b_poisson_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); double mean = eval_float(env,args[0]); std::poisson_distribution distribution(mean); // return a sample from the distribution return IntVal(distribution(rnd_generator())); } FloatVal b_gamma_float_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 2); const double alpha = eval_float(env,args[0]); const double beta = eval_float(env,args[1]); std::gamma_distribution distribution(alpha,beta); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_gamma_int_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 2); const double alpha = eval_float(env,args[0]); const double beta = eval_float(env,args[1]); std::gamma_distribution distribution(alpha,beta); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_weibull_int_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 2); const double shape = double(eval_int(env,args[0]).toInt()); if(shape < 0) { std::stringstream ssm; ssm << "The shape factor for the weibull distribution \"" << shape << "\" has to be greater than zero."; throw EvalError(env, args[0]->loc(),ssm.str()); } const double scale = eval_float(env,args[1]); if(scale < 0) { std::stringstream ssm; ssm << "The scale factor for the weibull distribution \"" << scale << "\" has to be greater than zero."; throw EvalError(env, args[1]->loc(),ssm.str()); } std::weibull_distribution distribution(shape, scale); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_weibull_float_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 2); const double shape = eval_float(env,args[0]); if(shape < 0) { std::stringstream ssm; ssm << "The shape factor for the weibull distribution \"" << shape << "\" has to be greater than zero."; throw EvalError(env, args[0]->loc(),ssm.str()); } const double scale = eval_float(env,args[1]); if(scale < 0) { std::stringstream ssm; ssm << "The scale factor for the weibull distribution \"" << scale << "\" has to be greater than zero."; throw EvalError(env, args[1]->loc(),ssm.str()); } std::weibull_distribution distribution(shape, scale); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_exponential_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); const double lambda = eval_float(env,args[0]); if(lambda < 0) { std::stringstream ssm; ssm << "The lambda-parameter for the exponential distribution function \"" << lambda << "\" has to be greater than zero."; throw EvalError(env, args[0]->loc(),ssm.str()); } std::exponential_distribution distribution(lambda); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_exponential_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); const double lambda = double(eval_int(env,args[0]).toInt()); if(lambda < 0) { std::stringstream ssm; ssm << "The lambda-parameter for the exponential distribution function \"" << lambda << "\" has to be greater than zero."; throw EvalError(env, args[0]->loc(),ssm.str()); } std::exponential_distribution distribution(lambda); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_lognormal_float_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() ==2); const double mean = eval_float(env,args[0]); const double stdv = eval_float(env,args[1]); std::lognormal_distribution distribution(mean,stdv); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_lognormal_int_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() ==2); const double mean = double(eval_int(env,args[0]).toInt()); const double stdv = eval_float(env,args[1]); std::lognormal_distribution distribution(mean,stdv); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_chisquared_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); const double lambda = eval_float(env,args[0]); std::exponential_distribution distribution(lambda); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_chisquared_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); const double lambda = double(eval_int(env,args[0]).toInt()); std::exponential_distribution distribution(lambda); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_cauchy_float_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() ==2); const double mean = eval_float(env,args[0]); const double scale = eval_float(env,args[1]); std::cauchy_distribution distribution(mean,scale); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_cauchy_int_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() ==2); const double mean = double(eval_int(env,args[0]).toInt()); const double scale = eval_float(env,args[1]); std::cauchy_distribution distribution(mean,scale); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_fdistribution_float_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() ==2); const double d1 = eval_float(env,args[0]); const double d2 = eval_float(env,args[1]); std::fisher_f_distribution distribution(d1,d2); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_fdistribution_int_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() ==2); const double d1 = double(eval_int(env,args[0]).toInt()); const double d2 = double(eval_int(env,args[1]).toInt()); std::fisher_f_distribution distribution(d1,d2); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_tdistribution_float(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); const double sampleSize = eval_float(env,args[0]); std::student_t_distribution distribution(sampleSize); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_tdistribution_int(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); const double sampleSize = double(eval_int(env,args[0]).toInt()); std::student_t_distribution distribution(sampleSize); // return a sample from the distribution return distribution(rnd_generator()); } IntVal b_discrete_distribution(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); GCLock lock; ArrayLit* al = eval_array_lit(env,args[0]); if(al->dims() != 1) { std::stringstream ssm; ssm << "expecting 1-dimensional array of weights for discrete distribution instead of: " << *al << std::endl; throw EvalError(env, al->loc(), ssm.str()); } std::vector weights(al->v().size()); for(unsigned int i = 0; i < al->v().size(); i++) { weights[i] = eval_int(env,al->v()[i]).toInt(); } #ifdef _MSC_VER std::size_t i(0); std::discrete_distribution distribution(weights.size(), 0.0,1.0, [&weights,&i](double){ return weights[i++]; }); #else std::discrete_distribution distribution(weights.begin(), weights.end()); #endif // return a sample from the distribution IntVal iv = IntVal(distribution(rnd_generator())); return iv; } bool b_bernoulli(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 1); const double p = eval_float(env,args[0]); std::bernoulli_distribution distribution(p); // return a sample from the distribution return distribution(rnd_generator()); } IntVal b_binomial(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size() == 2); double t = double(eval_int(env,args[0]).toInt()); double p = eval_float(env,args[1]); std::binomial_distribution distribution(t,p); // return a sample from the distribution return IntVal(distribution(rnd_generator())); } FloatVal b_atan(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; FloatVal f = eval_float(env,args[0]); return std::atan(f); } FloatVal b_cos(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; FloatVal f = eval_float(env,args[0]); return std::cos(f); } FloatVal b_sin(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; FloatVal f = eval_float(env,args[0]); return std::sin(f); } FloatVal b_asin(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; FloatVal f = eval_float(env,args[0]); return std::asin(f); } FloatVal b_acos(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; FloatVal f = eval_float(env,args[0]); return std::acos(f); } FloatVal b_tan(EnvI& env, Call* call) { ASTExprVec args = call->args(); assert(args.size()==1); GCLock lock; FloatVal f = eval_float(env,args[0]); return std::tan(f); } void registerBuiltins(Env& e, Model* m) { EnvI& env = e.envi(); std::vector t_intint(2); t_intint[0] = Type::parint(); t_intint[1] = Type::parint(); std::vector t_intarray(1); t_intarray[0] = Type::parint(-1); GCLock lock; rb(env, m, ASTString("min"), t_intint, b_int_min); rb(env, m, ASTString("min"), t_intarray, b_int_min); rb(env, m, ASTString("max"), t_intint, b_int_max); rb(env, m, ASTString("max"), t_intarray, b_int_max); rb(env, m, constants().ids.sum, t_intarray, b_sum_int); rb(env, m, ASTString("product"), t_intarray, b_product_int); rb(env, m, ASTString("pow"), t_intint, b_pow_int); { std::vector t(2); t[0] = Type::top(-1); t[1] = Type::top(-1); rb(env, m, ASTString("index_sets_agree"), t, b_index_sets_agree); } { std::vector t_anyarray1(1); t_anyarray1[0] = Type::optvartop(1); rb(env, m, ASTString("index_set"), t_anyarray1, b_index_set1); } { std::vector t_anyarray2(1); t_anyarray2[0] = Type::optvartop(2); rb(env, m, ASTString("index_set_1of2"), t_anyarray2, b_index_set1); rb(env, m, ASTString("index_set_2of2"), t_anyarray2, b_index_set2); } { std::vector t_anyarray3(1); t_anyarray3[0] = Type::optvartop(3); rb(env, m, ASTString("index_set_1of3"), t_anyarray3, b_index_set1); rb(env, m, ASTString("index_set_2of3"), t_anyarray3, b_index_set2); rb(env, m, ASTString("index_set_3of3"), t_anyarray3, b_index_set3); } { std::vector t_anyarray4(1); t_anyarray4[0] = Type::optvartop(4); rb(env, m, ASTString("index_set_1of4"), t_anyarray4, b_index_set1); rb(env, m, ASTString("index_set_2of4"), t_anyarray4, b_index_set2); rb(env, m, ASTString("index_set_3of4"), t_anyarray4, b_index_set3); rb(env, m, ASTString("index_set_4of4"), t_anyarray4, b_index_set4); } { std::vector t_anyarray5(1); t_anyarray5[0] = Type::optvartop(5); rb(env, m, ASTString("index_set_1of5"), t_anyarray5, b_index_set1); rb(env, m, ASTString("index_set_2of5"), t_anyarray5, b_index_set2); rb(env, m, ASTString("index_set_3of5"), t_anyarray5, b_index_set3); rb(env, m, ASTString("index_set_4of5"), t_anyarray5, b_index_set4); rb(env, m, ASTString("index_set_5of5"), t_anyarray5, b_index_set5); } { std::vector t_anyarray6(1); t_anyarray6[0] = Type::optvartop(6); rb(env, m, ASTString("index_set_1of6"), t_anyarray6, b_index_set1); rb(env, m, ASTString("index_set_2of6"), t_anyarray6, b_index_set2); rb(env, m, ASTString("index_set_3of6"), t_anyarray6, b_index_set3); rb(env, m, ASTString("index_set_4of6"), t_anyarray6, b_index_set4); rb(env, m, ASTString("index_set_5of6"), t_anyarray6, b_index_set5); rb(env, m, ASTString("index_set_6of6"), t_anyarray6, b_index_set6); } { std::vector t_arrayXd(1); t_arrayXd[0] = Type::top(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d_list); t_arrayXd[0] = Type::vartop(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d_list); t_arrayXd[0] = Type::optvartop(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d_list); } { std::vector t_arrayXd(2); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::top(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d); t_arrayXd[1] = Type::vartop(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d); t_arrayXd[1] = Type::optvartop(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d); } { std::vector t_arrayXd(2); t_arrayXd[0] = Type::top(-1); t_arrayXd[1] = Type::top(-1); rb(env, m, ASTString("arrayXd"), t_arrayXd, b_arrayXd); t_arrayXd[1] = Type::vartop(-1); rb(env, m, ASTString("arrayXd"), t_arrayXd, b_arrayXd); t_arrayXd[1] = Type::optvartop(-1); rb(env, m, ASTString("arrayXd"), t_arrayXd, b_arrayXd); } { std::vector t_arrayXd(3); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::top(-1); rb(env, m, ASTString("array2d"), t_arrayXd, b_array2d); t_arrayXd[2] = Type::vartop(-1); rb(env, m, ASTString("array2d"), t_arrayXd, b_array2d); t_arrayXd[2] = Type::optvartop(-1); rb(env, m, ASTString("array2d"), t_arrayXd, b_array2d); } { std::vector t_arrayXd(4); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::parsetint(); t_arrayXd[3] = Type::top(-1); rb(env, m, ASTString("array3d"), t_arrayXd, b_array3d); t_arrayXd[3] = Type::vartop(-1); rb(env, m, ASTString("array3d"), t_arrayXd, b_array3d); t_arrayXd[3] = Type::optvartop(-1); rb(env, m, ASTString("array3d"), t_arrayXd, b_array3d); } { std::vector t_arrayXd(5); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::parsetint(); t_arrayXd[3] = Type::parsetint(); t_arrayXd[4] = Type::top(-1); rb(env, m, ASTString("array4d"), t_arrayXd, b_array4d); t_arrayXd[4] = Type::vartop(-1); rb(env, m, ASTString("array4d"), t_arrayXd, b_array4d); t_arrayXd[4] = Type::optvartop(-1); rb(env, m, ASTString("array4d"), t_arrayXd, b_array4d); } { std::vector t_arrayXd(6); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::parsetint(); t_arrayXd[3] = Type::parsetint(); t_arrayXd[4] = Type::parsetint(); t_arrayXd[5] = Type::top(-1); rb(env, m, ASTString("array5d"), t_arrayXd, b_array5d); t_arrayXd[5] = Type::vartop(-1); rb(env, m, ASTString("array5d"), t_arrayXd, b_array5d); t_arrayXd[5] = Type::optvartop(-1); rb(env, m, ASTString("array5d"), t_arrayXd, b_array5d); } { std::vector t_arrayXd(7); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::parsetint(); t_arrayXd[3] = Type::parsetint(); t_arrayXd[4] = Type::parsetint(); t_arrayXd[5] = Type::parsetint(); t_arrayXd[6] = Type::top(-1); rb(env, m, ASTString("array6d"), t_arrayXd, b_array6d); t_arrayXd[6] = Type::vartop(-1); rb(env, m, ASTString("array6d"), t_arrayXd, b_array6d); t_arrayXd[6] = Type::optvartop(-1); rb(env, m, ASTString("array6d"), t_arrayXd, b_array6d); } { std::vector t(2); t[0] = Type::parbool(); t[1] = Type::parstring(); rb(env, m, constants().ids.assert, t, b_assert_bool); } { std::vector t(3); t[0] = Type::parbool(); t[1] = Type::parstring(); t[2] = Type::top(); rb(env, m, constants().ids.assert, t, b_assert); t[2] = Type::vartop(); rb(env, m, constants().ids.assert, t, b_assert); t[2] = Type::optvartop(); rb(env, m, constants().ids.assert, t, b_assert); } { std::vector t(1); t[0] = Type::parstring(); rb(env, m, ASTString("abort"), t, b_abort); rb(env, m, constants().ids.trace, t, b_trace); } { std::vector t(2); t[0] = Type::parstring(); t[1] = Type::top(); rb(env, m, constants().ids.trace, t, b_trace); t[1] = Type::vartop(); rb(env, m, constants().ids.trace, t, b_trace); t[1] = Type::optvartop(); rb(env, m, constants().ids.trace, t, b_trace); } { rb(env, m, ASTString("mzn_in_redundant_constraint"), std::vector(), b_in_redundant_constraint); } { std::vector t_length(1); t_length[0] = Type::optvartop(-1); rb(env, m, ASTString("length"), t_length, b_length); } { std::vector t(1); t[0] = Type::parbool(); rb(env, m, constants().ids.bool2int, t, b_bool2int); } { std::vector t(1); t[0] = Type::parbool(-1); rb(env, m, constants().ids.forall, t, b_forall_par); rb(env, m, constants().ids.exists, t, b_exists_par); rb(env, m, ASTString("xorall"), t, b_xorall_par); rb(env, m, ASTString("iffall"), t, b_iffall_par); } { std::vector t(2); t[0] = Type::parbool(-1); t[1] = Type::parbool(-1); rb(env, m, constants().ids.clause, t, b_clause_par); } { std::vector t(1); t[0] = Type::varsetint(); rb(env, m, ASTString("ub"), t, b_ub_set); rb(env, m, ASTString("lb"), t, b_lb_set); } { std::vector t(1); t[0] = Type::varsetint(1); rb(env, m, ASTString("ub_array"), t, b_array_ub_set); } { std::vector t(1); t[0] = Type::varint(); rb(env, m, ASTString("dom"), t, b_dom_varint); } { std::vector t(1); t[0] = Type::varint(-1); rb(env, m, ASTString("dom_array"), t, b_dom_array); rb(env, m, ASTString("dom_bounds_array"), t, b_dom_bounds_array); } { std::vector t(1); t[0] = Type::parsetint(); rb(env, m, ASTString("min"), t, b_min_parsetint); } { std::vector t(1); t[0] = Type::parsetint(); rb(env, m, ASTString("max"), t, b_max_parsetint); } { std::vector t(1); t[0] = Type::varint(); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("lb"), t, b_lb_varoptint); } { std::vector t(1); t[0] = Type::varint(); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("ub"), t, b_ub_varoptint); } { std::vector t(1); t[0] = Type::varint(); rb(env, m, ASTString("lb"), t, b_lb_varoptint); } { std::vector t(1); t[0] = Type::varint(); rb(env, m, ASTString("ub"), t, b_ub_varoptint); } { std::vector t(1); t[0] = Type::varint(-1); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("lb_array"), t, b_array_lb_int); } { std::vector t(1); t[0] = Type::varint(-1); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("ub_array"), t, b_array_ub_int); } { std::vector t(1); t[0] = Type::varfloat(); rb(env, m, ASTString("lb"), t, b_lb_varoptfloat); } { std::vector t(1); t[0] = Type::varfloat(); rb(env, m, ASTString("ub"), t, b_ub_varoptfloat); } { std::vector t(1); t[0] = Type::varfloat(-1); rb(env, m, ASTString("lb_array"), t, b_array_lb_float); } { std::vector t(1); t[0] = Type::varfloat(-1); rb(env, m, ASTString("ub_array"), t, b_array_ub_float); } { std::vector t(1); t[0] = Type::parsetint(); rb(env, m, ASTString("card"), t, b_card); } { std::vector t(1); t[0] = Type::parint(); rb(env, m, ASTString("abs"), t, b_abs_int); t[0] = Type::parfloat(); rb(env, m, ASTString("abs"), t, b_abs_float); } { std::vector t(1); t[0] = Type::varint(); rb(env, m, ASTString("has_bounds"), t, b_has_bounds_int); } { std::vector t(1); t[0] = Type::varfloat(); rb(env, m, ASTString("has_bounds"), t, b_has_bounds_float); } { std::vector t(1); t[0] = Type::varsetint(); rb(env, m, ASTString("has_ub_set"), t, b_has_ub_set); } { std::vector t(1); t[0] = Type::optvartop(); rb(env, m, ASTString("is_fixed"), t, b_is_fixed); } { std::vector t(1); t[0] = Type::optvartop(-1); rb(env, m, ASTString("is_fixed"), t, b_is_fixed_array); } { std::vector t(1); t[0] = Type::optvartop(); rb(env, m, ASTString("fix"), t, b_fix_bool); rb(env, m, ASTString("fix"), t, b_fix_int); rb(env, m, ASTString("fix"), t, b_fix_set); rb(env, m, ASTString("fix"), t, b_fix_float); } { std::vector t(1); t[0] = Type::optvartop(1); rb(env, m, ASTString("fix"), t, b_fix_array); } { std::vector t(1); t[0] = Type::parint(); rb(env, m, ASTString("int2float"), t, b_int2float); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("ceil"), t, b_ceil); rb(env, m, ASTString("floor"), t, b_floor); rb(env, m, ASTString("round"), t, b_round); rb(env, m, ASTString("log10"), t, b_log10); rb(env, m, ASTString("log2"), t, b_log2); rb(env, m, ASTString("ln"), t, b_ln); rb(env, m, ASTString("exp"), t, b_exp); rb(env, m, ASTString("sqrt"), t, b_sqrt); t.push_back(Type::parfloat()); rb(env, m, ASTString("log"), t, b_log); rb(env, m, ASTString("pow"), t, b_pow); } { std::vector t(1); t[0] = Type::parfloat(1); rb(env, m, constants().ids.sum, t, b_sum_float); rb(env, m, ASTString("product"), t, b_product_float); } { std::vector t(1); t[0] = Type::parfloat(1); rb(env, m, ASTString("min"), t, b_float_min); rb(env, m, ASTString("max"), t, b_float_max); t[0] = Type::parfloat(); t.push_back(Type::parfloat()); rb(env, m, ASTString("min"), t, b_float_min); rb(env, m, ASTString("max"), t, b_float_max); } { std::vector t(1); t[0] = Type::parsetint(); rb(env, m, ASTString("set2array"), t, b_set2array); } { std::vector t(1); t[0] = Type::parstring(); rb(env, m, ASTString("string_length"), t, b_string_length); } { rb(env, m, ASTString("file_path"), std::vector(), b_file_path); } { std::vector t(1); t[0] = Type::vartop(); rb(env, m, ASTString("show"), t, b_show); t[0] = Type::vartop(); t[0].st(Type::ST_SET); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("show"), t, b_show); t[0] = Type::vartop(-1); rb(env, m, ASTString("show"), t, b_show); } { std::vector t(3); t[0] = t[1] = Type::parint(); t[2] = Type::vartop(); rb(env, m, ASTString("format"), t, b_format); t[2] = Type::vartop(); t[2].st(Type::ST_SET); t[2].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("format"), t, b_format); t[2] = Type::vartop(-1); rb(env, m, ASTString("format"), t, b_format); } { std::vector t(2); t[0] = Type::parint(); t[1] = Type::vartop(); rb(env, m, ASTString("format"), t, b_format); t[1] = Type::vartop(); t[1].st(Type::ST_SET); t[1].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("format"), t, b_format); t[1] = Type::vartop(-1); rb(env, m, ASTString("format"), t, b_format); } { std::vector t(2); t[0] = Type::parint(); t[1] = Type::varint(); rb(env, m, ASTString("show_int"), t, b_show_int); } { std::vector t(3); t[0] = Type::parint(); t[1] = Type::parint(); t[2] = Type::varfloat(); rb(env, m, ASTString("show_float"), t, b_show_float); } { std::vector t(1); t[0] = Type::parstring(1); rb(env, m, ASTString("concat"), t, b_concat); } { std::vector t(2); t[0] = Type::parstring(); t[1] = Type::parstring(1); rb(env, m, ASTString("join"), t, b_join); } { std::vector t(2); t[0] = Type::varint(); t[1] = Type::varint(); rb(env, m, ASTString("compute_div_bounds"), t, b_compute_div_bounds); } { std::vector t(1); t[0] = Type::parsetint(1); rb(env, m, ASTString("array_intersect"), t, b_array_intersect); rb(env, m, ASTString("array_union"), t, b_array_union); } { std::vector t(1); t[0] = Type::parint(); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("occurs"), t, b_occurs); rb(env, m, ASTString("deopt"), t, b_deopt_int); t[0].bt(Type::BT_BOOL); rb(env, m, ASTString("occurs"), t, b_occurs); rb(env, m, ASTString("deopt"), t, b_deopt_bool); } { std::vector t(2); t[0] = Type::varbot(1); t[1] = Type::parint(1); rb(env, m, ASTString("sort_by"), t, b_sort_by_int); t[0] = Type::bot(1); rb(env, m, ASTString("sort_by"), t, b_sort_by_int); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("sort_by"), t, b_sort_by_int); } { std::vector t(2); t[0] = Type::varbot(1); t[1] = Type::parfloat(1); rb(env, m, ASTString("sort_by"), t, b_sort_by_float); t[0] = Type::bot(1); rb(env, m, ASTString("sort_by"), t, b_sort_by_float); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("sort_by"), t, b_sort_by_float); } { std::vector t(1); t[0] = Type::parint(1); rb(env, m, ASTString("sort"), t, b_sort); rb(env, m, ASTString("arg_min"), t, b_arg_min_int); rb(env, m, ASTString("arg_max"), t, b_arg_max_int); t[0] = Type::parbool(1); rb(env, m, ASTString("sort"), t, b_sort); t[0] = Type::parfloat(1); rb(env, m, ASTString("sort"), t, b_sort); rb(env, m, ASTString("arg_min"), t, b_arg_min_float); rb(env, m, ASTString("arg_max"), t, b_arg_max_float); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("atan"), t, b_atan); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("cos"), t, b_cos); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("sin"), t, b_sin); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("asin"), t, b_asin); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("acos"), t, b_acos); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("tan"), t, b_tan); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("normal"),t,b_normal_float_float); t[0] = Type::parint(); rb(env, m, ASTString("normal"),t,b_normal_int_float); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("uniform"),t,b_uniform_float); t[0] = Type::parint(); t[1] = Type::parint(); rb(env, m, ASTString("uniform"),t,b_uniform_int); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("poisson"),t,b_poisson_float); t[0] = Type::parint(); rb(env, m, ASTString("poisson"),t,b_poisson_int); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("gamma"),t,b_gamma_float_float); t[0] = Type::parint(); rb(env, m, ASTString("gamma"),t,b_gamma_int_float); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("weibull"),t,b_weibull_float_float); t[0] = Type::parint(); rb(env, m, ASTString("weibull"),t,b_weibull_int_float); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("exponential"),t,b_exponential_float); t[0] = Type::parint(); rb(env, m, ASTString("exponential"),t,b_exponential_int); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("lognormal"),t,b_lognormal_float_float); t[0] = Type::parint(); rb(env, m, ASTString("lognormal"),t,b_lognormal_int_float); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("chisquared"),t,b_chisquared_float); t[0] = Type::parint(); rb(env, m, ASTString("chisquared"),t,b_chisquared_int); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("cauchy"),t,b_cauchy_float_float); t[0] = Type::parint(); rb(env, m, ASTString("cauchy"),t,b_cauchy_int_float); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("fdistribution"),t,b_fdistribution_float_float); t[0] = Type::parint(); t[1] = Type::parint(); rb(env, m, ASTString("fdistribution"),t,b_fdistribution_int_int); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("tdistribution"),t,b_tdistribution_float); t[0] = Type::parint(); rb(env, m, ASTString("tdistribution"),t,b_tdistribution_int); } { std::vector t(1); t[0] = Type::parint(1); rb(env, m, ASTString("discrete_distribution"),t,b_discrete_distribution); } { std::vector t(1); t[0] = Type::parint(); rb(env, m, ASTString("bernoulli"),t,b_bernoulli); } { std::vector t(2); t[0] = Type::parint(); t[1] = Type::parfloat(); rb(env, m, ASTString("binomial"),t,b_binomial); } } } libminizinc-2.0.11/lib/ast.cpp0000644000175000017500000012622212646030173014610 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include #include #include #include namespace MiniZinc { Location::Location(void) : first_line(0), first_column(0), last_line(0), last_column(0), is_introduced(0) {} std::string Location::toString(void) const { std::ostringstream oss; oss << filename << ":" << first_line << "." << first_column; return oss.str(); } void Location::mark(void) const { filename.mark(); } Location Location::introduce() const { Location l = *this; l.is_introduced = 1; return l; } void Expression::addAnnotation(Expression* ann) { _ann.add(ann); } void Expression::addAnnotations(std::vector ann) { for (unsigned int i=0; i stack; stack.push_back(e); while (!stack.empty()) { const Expression* cur = stack.back(); stack.pop_back(); if (cur->_gc_mark==0) { cur->_gc_mark = 1; cur->loc().mark(); pushann(cur->ann()); switch (cur->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_ANON: break; case Expression::E_SETLIT: if (cur->cast()->isv()) cur->cast()->isv()->mark(); else pushall(cur->cast()->v()); break; case Expression::E_STRINGLIT: cur->cast()->v().mark(); break; case Expression::E_ID: if (cur->cast()->idn()==-1) cur->cast()->v().mark(); pushstack(cur->cast()->decl()); break; case Expression::E_ARRAYLIT: pushall(cur->cast()->v()); cur->cast()->_dims.mark(); break; case Expression::E_ARRAYACCESS: pushstack(cur->cast()->v()); pushall(cur->cast()->idx()); break; case Expression::E_COMP: pushstack(cur->cast()->_e); pushstack(cur->cast()->_where); pushall(cur->cast()->_g); cur->cast()->_g_idx.mark(); break; case Expression::E_ITE: pushstack(cur->cast()->e_else()); pushall(cur->cast()->_e_if_then); break; case Expression::E_BINOP: pushstack(cur->cast()->lhs()); pushstack(cur->cast()->rhs()); break; case Expression::E_UNOP: pushstack(cur->cast()->e()); break; case Expression::E_CALL: cur->cast()->id().mark(); pushall(cur->cast()->_args); if (FunctionI* fi = cur->cast()->_decl) { fi->mark(); fi->id().mark(); pushstack(fi->ti()); pushann(fi->ann()); pushstack(fi->e()); pushall(fi->params()); } break; case Expression::E_VARDECL: pushstack(cur->cast()->ti()); pushstack(cur->cast()->e()); pushstack(cur->cast()->id()); break; case Expression::E_LET: pushall(cur->cast()->let()); pushall(cur->cast()->_let_orig); pushstack(cur->cast()->in()); break; case Expression::E_TI: pushstack(cur->cast()->domain()); pushall(cur->cast()->ranges()); break; case Expression::E_TIID: cur->cast()->v().mark(); break; } } } } #undef pushstack #undef pushall void IntLit::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; cmb_hash(h(_v)); } void FloatLit::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; cmb_hash(h(_v)); } void SetLit::rehash(void) { init_hash(); if (isv()) { HASH_NAMESPACE::hash h; for (IntSetRanges r0(isv()); r0(); ++r0) { cmb_hash(h(r0.min())); cmb_hash(h(r0.max())); } } else { for (unsigned int i=v().size(); i--;) cmb_hash(Expression::hash(_v[i])); } } void BoolLit::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; cmb_hash(h(_v)); } void StringLit::rehash(void) { init_hash(); cmb_hash(_v.hash()); } void Id::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; if (idn()==-1) cmb_hash(v().hash()); else cmb_hash(h(idn())); } ASTString Id::str() const { if (idn()==-1) return v(); std::ostringstream oss; oss << "X_INTRODUCED_" << idn(); return oss.str(); } void TIId::rehash(void) { init_hash(); cmb_hash(_v.hash()); } void AnonVar::rehash(void) { init_hash(); } void ArrayLit::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; for (unsigned int i=0; i<_dims.size(); i+=2) { cmb_hash(h(_dims[i])); cmb_hash(h(_dims[i+1])); } for (unsigned int i=_v.size(); i--;) { cmb_hash(h(i)); cmb_hash(Expression::hash(_v[i])); } } int ArrayLit::dims(void) const { return _dims.size()/2; } int ArrayLit::min(int i) const { return _dims[2*i]; } int ArrayLit::max(int i) const { return _dims[2*i+1]; } int ArrayLit::length(void) const { if(dims() == 0) return 0; int l = max(0) - min(0) + 1; for(int i=1; i h; cmb_hash(h(_idx.size())); for (unsigned int i=_idx.size(); i--;) cmb_hash(Expression::hash(_idx[i])); } Generator::Generator(const std::vector& v, Expression* in) { std::vector vd; for (unsigned int i=0; iloc(), new TypeInst(in->loc(),Type::parint()),v[i]); nvd->toplevel(false); vd.push_back(nvd); } _v = vd; _in = in; } Generator::Generator(const std::vector& v, Expression* in) { std::vector vd; for (unsigned int i=0; iloc(), new TypeInst(in->loc(),Type::parint()),ASTString(v[i])); nvd->toplevel(false); vd.push_back(nvd); } _v = vd; _in = in; } Generator::Generator(const std::vector& v, Expression* in) { _v = v; _in = in; } bool Comprehension::set(void) const { return _flag_1; } void Comprehension::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; cmb_hash(h(set())); cmb_hash(Expression::hash(_e)); cmb_hash(Expression::hash(_where)); cmb_hash(h(_g_idx.size())); for (unsigned int i=_g_idx.size(); i--;) { cmb_hash(h(_g_idx[i])); } cmb_hash(h(_g.size())); for (unsigned int i=_g.size(); i--;) { cmb_hash(Expression::hash(_g[i])); } } int Comprehension::n_generators(void) const { return _g_idx.size()-1; } Expression* Comprehension::in(int i) { return _g[_g_idx[i]]; } const Expression* Comprehension::in(int i) const { return _g[_g_idx[i]]; } int Comprehension::n_decls(int i) const { return _g_idx[i+1]-_g_idx[i]-1; } VarDecl* Comprehension::decl(int gen, int i) { return _g[_g_idx[gen]+1+i]->cast(); } const VarDecl* Comprehension::decl(int gen, int i) const { return _g[_g_idx[gen]+1+i]->cast(); } void ITE::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; cmb_hash(h(_e_if_then.size())); for (unsigned int i=_e_if_then.size(); i--; ) { cmb_hash(Expression::hash(_e_if_then[i])); } cmb_hash(Expression::hash(e_else())); } BinOpType BinOp::op(void) const { return static_cast(_sec_id); } void BinOp::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; cmb_hash(h(static_cast(op()))); cmb_hash(Expression::hash(_e0)); cmb_hash(Expression::hash(_e1)); } namespace { class OpToString { protected: Model* rootSetModel; public: Id* sBOT_PLUS; Id* sBOT_MINUS; Id* sBOT_MULT; Id* sBOT_DIV; Id* sBOT_IDIV; Id* sBOT_MOD; Id* sBOT_LE; Id* sBOT_LQ; Id* sBOT_GR; Id* sBOT_GQ; Id* sBOT_EQ; Id* sBOT_NQ; Id* sBOT_IN; Id* sBOT_SUBSET; Id* sBOT_SUPERSET; Id* sBOT_UNION; Id* sBOT_DIFF; Id* sBOT_SYMDIFF; Id* sBOT_INTERSECT; Id* sBOT_PLUSPLUS; Id* sBOT_EQUIV; Id* sBOT_IMPL; Id* sBOT_RIMPL; Id* sBOT_OR; Id* sBOT_AND; Id* sBOT_XOR; Id* sBOT_DOTDOT; Id* sBOT_NOT; OpToString(void) { GCLock lock; rootSetModel = new Model(); std::vector rootSet; sBOT_PLUS = new Id(Location(),"'+'",NULL); rootSet.push_back(sBOT_PLUS); sBOT_MINUS = new Id(Location(),"'-'",NULL); rootSet.push_back(sBOT_MINUS); sBOT_MULT = new Id(Location(),"'*'",NULL); rootSet.push_back(sBOT_MULT); sBOT_DIV = new Id(Location(),"'/'",NULL); rootSet.push_back(sBOT_DIV); sBOT_IDIV = new Id(Location(),"'div'",NULL); rootSet.push_back(sBOT_IDIV); sBOT_MOD = new Id(Location(),"'mod'",NULL); rootSet.push_back(sBOT_MOD); sBOT_LE = new Id(Location(),"'<'",NULL); rootSet.push_back(sBOT_LE); sBOT_LQ = new Id(Location(),"'<='",NULL); rootSet.push_back(sBOT_LQ); sBOT_GR = new Id(Location(),"'>'",NULL); rootSet.push_back(sBOT_GR); sBOT_GQ = new Id(Location(),"'>='",NULL); rootSet.push_back(sBOT_GQ); sBOT_EQ = new Id(Location(),"'='",NULL); rootSet.push_back(sBOT_EQ); sBOT_NQ = new Id(Location(),"'!='",NULL); rootSet.push_back(sBOT_NQ); sBOT_IN = new Id(Location(),"'in'",NULL); rootSet.push_back(sBOT_IN); sBOT_SUBSET = new Id(Location(),"'subset'",NULL); rootSet.push_back(sBOT_SUBSET); sBOT_SUPERSET = new Id(Location(),"'superset'",NULL); rootSet.push_back(sBOT_SUPERSET); sBOT_UNION = new Id(Location(),"'union'",NULL); rootSet.push_back(sBOT_UNION); sBOT_DIFF = new Id(Location(),"'diff'",NULL); rootSet.push_back(sBOT_DIFF); sBOT_SYMDIFF = new Id(Location(),"'symdiff'",NULL); rootSet.push_back(sBOT_SYMDIFF); sBOT_INTERSECT = new Id(Location(),"'intersect'",NULL); rootSet.push_back(sBOT_INTERSECT); sBOT_PLUSPLUS = new Id(Location(),"'++'",NULL); rootSet.push_back(sBOT_PLUSPLUS); sBOT_EQUIV = new Id(Location(),"'<->'",NULL); rootSet.push_back(sBOT_EQUIV); sBOT_IMPL = new Id(Location(),"'->'",NULL); rootSet.push_back(sBOT_IMPL); sBOT_RIMPL = new Id(Location(),"'<-'",NULL); rootSet.push_back(sBOT_RIMPL); sBOT_OR = new Id(Location(),"'\\/'",NULL); rootSet.push_back(sBOT_OR); sBOT_AND = new Id(Location(),"'/\\'",NULL); rootSet.push_back(sBOT_AND); sBOT_XOR = new Id(Location(),"'xor'",NULL); rootSet.push_back(sBOT_XOR); sBOT_DOTDOT = new Id(Location(),"'..'",NULL); rootSet.push_back(sBOT_DOTDOT); sBOT_NOT = new Id(Location(),"'not'",NULL); rootSet.push_back(sBOT_NOT); rootSetModel->addItem(new ConstraintI(Location(), new ArrayLit(Location(),rootSet))); } static OpToString& o(void) { static OpToString _o; return _o; } }; } ASTString BinOp::opToString(void) const { switch (op()) { case BOT_PLUS: return OpToString::o().sBOT_PLUS->v(); case BOT_MINUS: return OpToString::o().sBOT_MINUS->v(); case BOT_MULT: return OpToString::o().sBOT_MULT->v(); case BOT_DIV: return OpToString::o().sBOT_DIV->v(); case BOT_IDIV: return OpToString::o().sBOT_IDIV->v(); case BOT_MOD: return OpToString::o().sBOT_MOD->v(); case BOT_LE: return OpToString::o().sBOT_LE->v(); case BOT_LQ: return OpToString::o().sBOT_LQ->v(); case BOT_GR: return OpToString::o().sBOT_GR->v(); case BOT_GQ: return OpToString::o().sBOT_GQ->v(); case BOT_EQ: return OpToString::o().sBOT_EQ->v(); case BOT_NQ: return OpToString::o().sBOT_NQ->v(); case BOT_IN: return OpToString::o().sBOT_IN->v(); case BOT_SUBSET: return OpToString::o().sBOT_SUBSET->v(); case BOT_SUPERSET: return OpToString::o().sBOT_SUPERSET->v(); case BOT_UNION: return OpToString::o().sBOT_UNION->v(); case BOT_DIFF: return OpToString::o().sBOT_DIFF->v(); case BOT_SYMDIFF: return OpToString::o().sBOT_SYMDIFF->v(); case BOT_INTERSECT: return OpToString::o().sBOT_INTERSECT->v(); case BOT_PLUSPLUS: return OpToString::o().sBOT_PLUSPLUS->v(); case BOT_EQUIV: return OpToString::o().sBOT_EQUIV->v(); case BOT_IMPL: return OpToString::o().sBOT_IMPL->v(); case BOT_RIMPL: return OpToString::o().sBOT_RIMPL->v(); case BOT_OR: return OpToString::o().sBOT_OR->v(); case BOT_AND: return OpToString::o().sBOT_AND->v(); case BOT_XOR: return OpToString::o().sBOT_XOR->v(); case BOT_DOTDOT: return OpToString::o().sBOT_DOTDOT->v(); default: assert(false); return ASTString(""); } } UnOpType UnOp::op(void) const { return static_cast(_sec_id); } void UnOp::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; cmb_hash(h(static_cast(_sec_id))); cmb_hash(Expression::hash(_e0)); } ASTString UnOp::opToString(void) const { switch (op()) { case UOT_PLUS: return OpToString::o().sBOT_PLUS->v(); case UOT_MINUS: return OpToString::o().sBOT_MINUS->v(); case UOT_NOT: return OpToString::o().sBOT_NOT->v(); default: assert(false); return ASTString(""); } } void Call::rehash(void) { init_hash(); cmb_hash(_id.hash()); HASH_NAMESPACE::hash hf; cmb_hash(hf(_decl)); HASH_NAMESPACE::hash hu; cmb_hash(hu(_args.size())); for (unsigned int i=_args.size(); i--;) cmb_hash(Expression::hash(_args[i])); } void VarDecl::rehash(void) { init_hash(); cmb_hash(Expression::hash(_ti)); cmb_hash(_id->hash()); cmb_hash(Expression::hash(_e)); } void Let::rehash(void) { init_hash(); cmb_hash(Expression::hash(_in)); HASH_NAMESPACE::hash h; cmb_hash(h(_let.size())); for (unsigned int i=_let.size(); i--;) cmb_hash(Expression::hash(_let[i])); } Let::Let(const Location& loc, const std::vector& let, Expression* in) : Expression(loc,E_LET,Type()) { _let = ASTExprVec(let); std::vector vde(let.size()); for (unsigned int i=0; i(let[i])) { vde[i] = vd->e(); } else { vde[i] = NULL; } } _let_orig = ASTExprVec(vde); _in = in; rehash(); } void Let::pushbindings(void) { GC::mark(); for (unsigned int i=_let.size(); i--;) { if (VarDecl* vd = _let[i]->dyn_cast()) { GC::trail(&vd->_e,vd->e()); if (vd->ti()->ranges().size() > 0) { GC::trail(reinterpret_cast(&vd->_ti),vd->ti()); } vd->e(_let_orig[i]); } } } void Let::popbindings(void) { GC::untrail(); } void TypeInst::rehash(void) { init_hash(); HASH_NAMESPACE::hash h; unsigned int rsize = _ranges.size(); cmb_hash(h(rsize)); for (unsigned int i=rsize; i--;) cmb_hash(Expression::hash(_ranges[i])); cmb_hash(Expression::hash(domain())); } void TypeInst::setRanges(const std::vector& ranges) { _ranges = ASTExprVec(ranges); if (ranges.size()==1 && ranges[0] && ranges[0]->isa() && ranges[0]->cast()->domain() && ranges[0]->cast()->domain()->isa()) _type.dim(-1); else _type.dim(ranges.size()); rehash(); } bool TypeInst::hasTiVariable(void) const { if (domain() && domain()->isa()) return true; for (unsigned int i=_ranges.size(); i--;) if (_ranges[i]->isa()) return true; return false; } namespace { Type getType(Expression* e) { return e->type(); } Type getType(const Type& t) { return t; } const Location& getLoc(Expression* e, FunctionI*) { return e->loc(); } const Location& getLoc(const Type&, FunctionI* fi) { return fi->loc(); } template Type return_type(EnvI& env, FunctionI* fi, const std::vector& ta) { if (fi->id()==constants().var_redef->id()) return Type::varbool(); Type ret = fi->ti()->type(); ASTString dh; if (fi->ti()->domain() && fi->ti()->domain()->isa()) dh = fi->ti()->domain()->cast()->v(); ASTString rh; if (fi->ti()->ranges().size()==1 && fi->ti()->ranges()[0]->domain() && fi->ti()->ranges()[0]->domain()->isa()) rh = fi->ti()->ranges()[0]->domain()->cast()->v(); ASTStringMap::t tmap; for (unsigned int i=0; iparams()[i]->ti(); if (tii->domain() && tii->domain()->isa()) { ASTString tiid = tii->domain()->cast()->v(); Type tiit = getType(ta[i]); tiit.dim(0); if (tii->type().st()==Type::ST_SET) tiit.st(Type::ST_PLAIN); ASTStringMap::t::iterator it = tmap.find(tiid); if (it==tmap.end()) { tmap.insert(std::pair(tiid,tiit)); } else { if (it->second.dim() > 0) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" used in both array and non-array position"); } else { Type tiit_par = tiit; tiit_par.ti(Type::TI_PAR); tiit_par.ot(Type::OT_PRESENT); Type its_par = it->second; its_par.ti(Type::TI_PAR); its_par.ot(Type::OT_PRESENT); if (tiit_par.bt()==Type::BT_TOP || tiit_par.bt()==Type::BT_BOT) { tiit_par.bt(its_par.bt()); } if (its_par.bt()==Type::BT_TOP || its_par.bt()==Type::BT_BOT) { its_par.bt(tiit_par.bt()); } if (tiit_par.isSubtypeOf(its_par)) { if (it->second.bt() == Type::BT_TOP) it->second.bt(tiit.bt()); } else if (its_par.isSubtypeOf(tiit_par)) { it->second = tiit_par; } else { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" instantiated with different types ("+ tiit.toString()+" vs "+ it->second.toString()+")"); } } } } if (tii->ranges().size()==1 && tii->ranges()[0]->domain() && tii->ranges()[0]->domain()->isa()) { ASTString tiid = tii->ranges()[0]->domain()->cast()->v(); if (getType(ta[i]).dim()==0) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+tiid.str()+ " must be an array index"); } Type tiit = Type::top(getType(ta[i]).dim()); ASTStringMap::t::iterator it = tmap.find(tiid); if (it==tmap.end()) { tmap.insert(std::pair(tiid,tiit)); } else { if (it->second.dim() == 0) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" used in both array and non-array position"); } else if (it->second!=tiit) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" instantiated with different types ("+ tiit.toString()+" vs "+ it->second.toString()+")"); } } } } if (dh.size() != 0) { ASTStringMap::t::iterator it = tmap.find(dh); if (it==tmap.end()) throw TypeError(env, fi->loc(),"type-inst variable $"+dh.str()+" used but not defined"); ret.bt(it->second.bt()); if (ret.st()==Type::ST_PLAIN) ret.st(it->second.st()); } if (rh.size() != 0) { ASTStringMap::t::iterator it = tmap.find(rh); if (it==tmap.end()) throw TypeError(env, fi->loc(),"type-inst variable $"+rh.str()+" used but not defined"); ret.dim(it->second.dim()); } return ret; } } Type FunctionI::rtype(EnvI& env, const std::vector& ta) { return return_type(env, this, ta); } Type FunctionI::rtype(EnvI& env, const std::vector& ta) { return return_type(env, this, ta); } Type FunctionI::argtype(const std::vector& ta, int n) { TypeInst* tii = params()[n]->ti(); if (tii->domain() && tii->domain()->isa()) { Type ty = ta[n]->type(); ty.st(tii->type().st()); ty.dim(tii->type().dim()); ASTString tv = tii->domain()->cast()->v(); for (unsigned int i=0; iti()->domain() && params()[i]->ti()->domain()->isa() && params()[i]->ti()->domain()->cast()->v() == tv) { Type toCheck = ta[i]->type(); toCheck.st(tii->type().st()); toCheck.dim(tii->type().dim()); if (toCheck != ty) { if (ty.isSubtypeOf(toCheck)) { ty = toCheck; } else { Type ty_par = ty; ty_par.ti(Type::TI_PAR); Type toCheck_par = toCheck; toCheck_par.ti(Type::TI_PAR); if (ty_par.isSubtypeOf(toCheck_par)) { ty.bt(toCheck.bt()); } } } } } return ty; } else { return tii->type(); } } bool Expression::equal_internal(const Expression* e0, const Expression* e1) { switch (e0->eid()) { case Expression::E_INTLIT: return e0->cast()->v() == e1->cast()->v(); case Expression::E_FLOATLIT: return e0->cast()->v() == e1->cast()->v(); case Expression::E_SETLIT: { const SetLit* s0 = e0->cast(); const SetLit* s1 = e1->cast(); if (s0->isv()) { if (s1->isv()) { IntSetRanges r0(s0->isv()); IntSetRanges r1(s1->isv()); return Ranges::equal(r0,r1); } else { return false; } } else { if (s1->isv()) return false; if (s0->v().size() != s1->v().size()) return false; for (unsigned int i=0; iv().size(); i++) if (!Expression::equal( s0->v()[i], s1->v()[i] )) return false; return true; } } case Expression::E_BOOLLIT: return e0->cast()->v() == e1->cast()->v(); case Expression::E_STRINGLIT: return e0->cast()->v() == e1->cast()->v(); case Expression::E_ID: { const Id* id0 = e0->cast(); const Id* id1 = e1->cast(); if (id0->decl()==NULL || id1->decl()==NULL) { return id0->v()==id1->v() && id0->idn()==id1->idn(); } return id0->decl()==id1->decl() || ( id0->decl()->flat() != NULL && id0->decl()->flat() == id1->decl()->flat() ); } case Expression::E_ANON: return false; case Expression::E_ARRAYLIT: { const ArrayLit* a0 = e0->cast(); const ArrayLit* a1 = e1->cast(); if (a0->v().size() != a1->v().size()) return false; if (a0->_dims.size() != a1->_dims.size()) return false; for (unsigned int i=0; i_dims.size(); i++) { if ( a0->_dims[i] != a1->_dims[i] ) { return false; } } for (unsigned int i=0; iv().size(); i++) { if (!Expression::equal( a0->v()[i], a1->v()[i] )) { return false; } } return true; } case Expression::E_ARRAYACCESS: { const ArrayAccess* a0 = e0->cast(); const ArrayAccess* a1 = e1->cast(); if (!Expression::equal( a0->v(), a1->v() )) return false; if (a0->idx().size() != a1->idx().size()) return false; for (unsigned int i=0; iidx().size(); i++) if (!Expression::equal( a0->idx()[i], a1->idx()[i] )) return false; return true; } case Expression::E_COMP: { const Comprehension* c0 = e0->cast(); const Comprehension* c1 = e1->cast(); if (c0->set() != c1->set()) return false; if (!Expression::equal ( c0->_e, c1->_e )) return false; if (!Expression::equal ( c0->_where, c1->_where )) return false; if (c0->_g.size() != c1->_g.size()) return false; for (unsigned int i=0; i_g.size(); i++) { if (!Expression::equal( c0->_g[i], c1->_g[i] )) return false; } for (unsigned int i=0; i_g_idx.size(); i++) { if (c0->_g_idx[i] != c1->_g_idx[i]) return false; } return true; } case Expression::E_ITE: { const ITE* i0 = e0->cast(); const ITE* i1 = e1->cast(); if (i0->_e_if_then.size() != i1->_e_if_then.size()) return false; for (unsigned int i=i0->_e_if_then.size(); i--; ) { if (!Expression::equal ( i0->_e_if_then[i], i1->_e_if_then[i])) return false; } if (!Expression::equal (i0->e_else(), i1->e_else())) return false; return true; } case Expression::E_BINOP: { const BinOp* b0 = e0->cast(); const BinOp* b1 = e1->cast(); if (b0->op() != b1->op()) return false; if (!Expression::equal (b0->lhs(), b1->lhs())) return false; if (!Expression::equal (b0->rhs(), b1->rhs())) return false; return true; } case Expression::E_UNOP: { const UnOp* b0 = e0->cast(); const UnOp* b1 = e1->cast(); if (b0->op() != b1->op()) return false; if (!Expression::equal (b0->e(), b1->e())) return false; return true; } case Expression::E_CALL: { const Call* c0 = e0->cast(); const Call* c1 = e1->cast(); if (c0->id() != c1->id()) return false; if (c0->_decl != c1->_decl) return false; if (c0->args().size() != c1->args().size()) return false; for (unsigned int i=0; iargs().size(); i++) if (!Expression::equal ( c0->args()[i], c1->args()[i] )) return false; return true; } case Expression::E_VARDECL: { const VarDecl* v0 = e0->cast(); const VarDecl* v1 = e1->cast(); if (!Expression::equal ( v0->ti(), v1->ti() )) return false; if (!Expression::equal ( v0->id(), v1->id())) return false; if (!Expression::equal ( v0->e(), v1->e() )) return false; return true; } case Expression::E_LET: { const Let* l0 = e0->cast(); const Let* l1 = e1->cast(); if (!Expression::equal ( l0->in(), l1->in() )) return false; if (l0->let().size() != l1->let().size()) return false; for (unsigned int i=l0->let().size(); i--;) if (!Expression::equal ( l0->let()[i], l1->let()[i])) return false; return true; } case Expression::E_TI: { const TypeInst* t0 = e0->cast(); const TypeInst* t1 = e1->cast(); if (t0->ranges().size() != t1->ranges().size()) return false; for (unsigned int i=t0->ranges().size(); i--;) if (!Expression::equal ( t0->ranges()[i], t1->ranges()[i])) return false; if (!Expression::equal (t0->domain(), t1->domain())) return false; return true; } case Expression::E_TIID: return false; default: assert(false); return false; } } Constants::Constants(void) { GCLock lock; TypeInst* ti = new TypeInst(Location(), Type::parbool()); lit_true = new BoolLit(Location(), true); var_true = new VarDecl(Location(), ti, "_bool_true", lit_true); lit_false = new BoolLit(Location(), false); var_false = new VarDecl(Location(), ti, "_bool_false", lit_false); absent = new Id(Location(),"_absent",NULL); Type absent_t; absent_t.bt(Type::BT_BOT); absent_t.dim(0); absent_t.st(Type::ST_PLAIN); absent_t.ot(Type::OT_OPTIONAL); absent->type(absent_t); IntSetVal* isv_infty = IntSetVal::a(-IntVal::infinity(), IntVal::infinity()); infinity = new SetLit(Location(), isv_infty); ids.forall = ASTString("forall"); ids.forall_reif = ASTString("forall_reif"); ids.exists = ASTString("exists"); ids.clause = ASTString("clause"); ids.bool2int = ASTString("bool2int"); ids.int2float = ASTString("int2float"); ids.bool2float = ASTString("bool2float"); ids.assert = ASTString("assert"); ids.trace = ASTString("trace"); ids.sum = ASTString("sum"); ids.lin_exp = ASTString("lin_exp"); ids.element = ASTString("element"); ids.show = ASTString("show"); ids.output = ASTString("output"); ids.fix = ASTString("fix"); ids.int_.lin_eq = ASTString("int_lin_eq"); ids.int_.lin_le = ASTString("int_lin_le"); ids.int_.lin_ne = ASTString("int_lin_ne"); ids.int_.plus = ASTString("int_plus"); ids.int_.minus = ASTString("int_minus"); ids.int_.times = ASTString("int_times"); ids.int_.div = ASTString("int_div"); ids.int_.mod = ASTString("int_mod"); ids.int_.lt = ASTString("int_lt"); ids.int_.le = ASTString("int_le"); ids.int_.gt = ASTString("int_gt"); ids.int_.ge = ASTString("int_ge"); ids.int_.eq = ASTString("int_eq"); ids.int_.ne = ASTString("int_ne"); ids.int_reif.lin_eq = ASTString("int_lin_eq_reif"); ids.int_reif.lin_le = ASTString("int_lin_le_reif"); ids.int_reif.lin_ne = ASTString("int_lin_ne_reif"); ids.int_reif.plus = ASTString("int_plus_reif"); ids.int_reif.minus = ASTString("int_minus_reif"); ids.int_reif.times = ASTString("int_times_reif"); ids.int_reif.div = ASTString("int_div_reif"); ids.int_reif.mod = ASTString("int_mod_reif"); ids.int_reif.lt = ASTString("int_lt_reif"); ids.int_reif.le = ASTString("int_le_reif"); ids.int_reif.gt = ASTString("int_gt_reif"); ids.int_reif.ge = ASTString("int_ge_reif"); ids.int_reif.eq = ASTString("int_eq_reif"); ids.int_reif.ne = ASTString("int_ne_reif"); ids.float_.lin_eq = ASTString("float_lin_eq"); ids.float_.lin_le = ASTString("float_lin_le"); ids.float_.lin_lt = ASTString("float_lin_lt"); ids.float_.lin_ne = ASTString("float_lin_ne"); ids.float_.plus = ASTString("float_plus"); ids.float_.minus = ASTString("float_minus"); ids.float_.times = ASTString("float_times"); ids.float_.div = ASTString("float_div"); ids.float_.mod = ASTString("float_mod"); ids.float_.lt = ASTString("float_lt"); ids.float_.le = ASTString("float_le"); ids.float_.gt = ASTString("float_gt"); ids.float_.ge = ASTString("float_ge"); ids.float_.eq = ASTString("float_eq"); ids.float_.ne = ASTString("float_ne"); ids.float_reif.lin_eq = ASTString("float_lin_eq_reif"); ids.float_reif.lin_le = ASTString("float_lin_le_reif"); ids.float_reif.lin_lt = ASTString("float_lin_lt_reif"); ids.float_reif.lin_ne = ASTString("float_lin_ne_reif"); ids.float_reif.plus = ASTString("float_plus_reif"); ids.float_reif.minus = ASTString("float_minus_reif"); ids.float_reif.times = ASTString("float_times_reif"); ids.float_reif.div = ASTString("float_div_reif"); ids.float_reif.mod = ASTString("float_mod_reif"); ids.float_reif.lt = ASTString("float_lt_reif"); ids.float_reif.le = ASTString("float_le_reif"); ids.float_reif.gt = ASTString("float_gt_reif"); ids.float_reif.ge = ASTString("float_ge_reif"); ids.float_reif.eq = ASTString("float_eq_reif"); ids.float_reif.ne = ASTString("float_ne_reif"); ids.bool_eq = ASTString("bool_eq"); ids.bool_eq_reif = ASTString("bool_eq_reif"); ids.bool_clause = ASTString("bool_clause"); ids.bool_clause_reif = ASTString("bool_clause_reif"); ids.bool_xor = ASTString("bool_xor"); ids.array_bool_or = ASTString("array_bool_or"); ids.array_bool_and = ASTString("array_bool_and"); ids.set_eq = ASTString("set_eq"); ids.set_in = ASTString("set_in"); ids.set_card = ASTString("set_card"); ids.introduced_var = ASTString("__INTRODUCED"); ctx.root = new Id(Location(),ASTString("ctx_root"),NULL); ctx.root->type(Type::ann()); ctx.pos = new Id(Location(),ASTString("ctx_pos"),NULL); ctx.pos->type(Type::ann()); ctx.neg = new Id(Location(),ASTString("ctx_neg"),NULL); ctx.neg->type(Type::ann()); ctx.mix = new Id(Location(),ASTString("ctx_mix"),NULL); ctx.mix->type(Type::ann()); ann.output_var = new Id(Location(), ASTString("output_var"), NULL); ann.output_var->type(Type::ann()); ann.output_array = ASTString("output_array"); ann.is_defined_var = new Id(Location(), ASTString("is_defined_var"), NULL); ann.is_defined_var->type(Type::ann()); ann.defines_var = ASTString("defines_var"); ann.is_reverse_map = new Id(Location(), ASTString("is_reverse_map"), NULL); ann.is_reverse_map->type(Type::ann()); ann.promise_total = new Id(Location(), ASTString("promise_total"), NULL); ann.promise_total->type(Type::ann()); ann.doc_comment = ASTString("doc_comment"); ann.is_introduced = ASTString("is_introduced"); var_redef = new FunctionI(Location(),"__internal_var_redef",new TypeInst(Location(),Type::varbool()), std::vector()); std::vector v; v.push_back(ti); v.push_back(lit_true); v.push_back(var_true); v.push_back(lit_false); v.push_back(var_false); v.push_back(absent); v.push_back(infinity); v.push_back(new StringLit(Location(),ids.forall)); v.push_back(new StringLit(Location(),ids.exists)); v.push_back(new StringLit(Location(),ids.clause)); v.push_back(new StringLit(Location(),ids.bool2int)); v.push_back(new StringLit(Location(),ids.int2float)); v.push_back(new StringLit(Location(),ids.bool2float)); v.push_back(new StringLit(Location(),ids.sum)); v.push_back(new StringLit(Location(),ids.lin_exp)); v.push_back(new StringLit(Location(),ids.element)); v.push_back(new StringLit(Location(),ids.show)); v.push_back(new StringLit(Location(),ids.output)); v.push_back(new StringLit(Location(),ids.fix)); v.push_back(new StringLit(Location(),ids.int_.lin_eq)); v.push_back(new StringLit(Location(),ids.int_.lin_le)); v.push_back(new StringLit(Location(),ids.int_.lin_ne)); v.push_back(new StringLit(Location(),ids.int_.plus)); v.push_back(new StringLit(Location(),ids.int_.minus)); v.push_back(new StringLit(Location(),ids.int_.times)); v.push_back(new StringLit(Location(),ids.int_.div)); v.push_back(new StringLit(Location(),ids.int_.mod)); v.push_back(new StringLit(Location(),ids.int_.lt)); v.push_back(new StringLit(Location(),ids.int_.le)); v.push_back(new StringLit(Location(),ids.int_.gt)); v.push_back(new StringLit(Location(),ids.int_.ge)); v.push_back(new StringLit(Location(),ids.int_.eq)); v.push_back(new StringLit(Location(),ids.int_.ne)); v.push_back(new StringLit(Location(),ids.int_reif.lin_eq)); v.push_back(new StringLit(Location(),ids.int_reif.lin_le)); v.push_back(new StringLit(Location(),ids.int_reif.lin_ne)); v.push_back(new StringLit(Location(),ids.int_reif.plus)); v.push_back(new StringLit(Location(),ids.int_reif.minus)); v.push_back(new StringLit(Location(),ids.int_reif.times)); v.push_back(new StringLit(Location(),ids.int_reif.div)); v.push_back(new StringLit(Location(),ids.int_reif.mod)); v.push_back(new StringLit(Location(),ids.int_reif.lt)); v.push_back(new StringLit(Location(),ids.int_reif.le)); v.push_back(new StringLit(Location(),ids.int_reif.gt)); v.push_back(new StringLit(Location(),ids.int_reif.ge)); v.push_back(new StringLit(Location(),ids.int_reif.eq)); v.push_back(new StringLit(Location(),ids.int_reif.ne)); v.push_back(new StringLit(Location(),ids.float_.lin_eq)); v.push_back(new StringLit(Location(),ids.float_.lin_le)); v.push_back(new StringLit(Location(),ids.float_.lin_lt)); v.push_back(new StringLit(Location(),ids.float_.lin_ne)); v.push_back(new StringLit(Location(),ids.float_.plus)); v.push_back(new StringLit(Location(),ids.float_.minus)); v.push_back(new StringLit(Location(),ids.float_.times)); v.push_back(new StringLit(Location(),ids.float_.div)); v.push_back(new StringLit(Location(),ids.float_.mod)); v.push_back(new StringLit(Location(),ids.float_.lt)); v.push_back(new StringLit(Location(),ids.float_.le)); v.push_back(new StringLit(Location(),ids.float_.gt)); v.push_back(new StringLit(Location(),ids.float_.ge)); v.push_back(new StringLit(Location(),ids.float_.eq)); v.push_back(new StringLit(Location(),ids.float_.ne)); v.push_back(new StringLit(Location(),ids.float_reif.lin_eq)); v.push_back(new StringLit(Location(),ids.float_reif.lin_le)); v.push_back(new StringLit(Location(),ids.float_reif.lin_lt)); v.push_back(new StringLit(Location(),ids.float_reif.lin_ne)); v.push_back(new StringLit(Location(),ids.float_reif.plus)); v.push_back(new StringLit(Location(),ids.float_reif.minus)); v.push_back(new StringLit(Location(),ids.float_reif.times)); v.push_back(new StringLit(Location(),ids.float_reif.div)); v.push_back(new StringLit(Location(),ids.float_reif.mod)); v.push_back(new StringLit(Location(),ids.float_reif.lt)); v.push_back(new StringLit(Location(),ids.float_reif.le)); v.push_back(new StringLit(Location(),ids.float_reif.gt)); v.push_back(new StringLit(Location(),ids.float_reif.ge)); v.push_back(new StringLit(Location(),ids.float_reif.eq)); v.push_back(new StringLit(Location(),ids.float_reif.ne)); v.push_back(new StringLit(Location(),ids.bool_eq)); v.push_back(new StringLit(Location(),ids.bool_eq_reif)); v.push_back(new StringLit(Location(),ids.bool_clause)); v.push_back(new StringLit(Location(),ids.bool_clause_reif)); v.push_back(new StringLit(Location(),ids.bool_xor)); v.push_back(new StringLit(Location(),ids.array_bool_or)); v.push_back(new StringLit(Location(),ids.array_bool_and)); v.push_back(new StringLit(Location(),ids.set_eq)); v.push_back(new StringLit(Location(),ids.set_in)); v.push_back(new StringLit(Location(),ids.set_card)); v.push_back(new StringLit(Location(),ids.assert)); v.push_back(new StringLit(Location(),ids.trace)); v.push_back(new StringLit(Location(),ids.introduced_var)); v.push_back(ctx.root); v.push_back(ctx.pos); v.push_back(ctx.neg); v.push_back(ctx.mix); v.push_back(ann.output_var); v.push_back(new StringLit(Location(),ann.output_array)); v.push_back(ann.is_defined_var); v.push_back(new StringLit(Location(),ann.defines_var)); v.push_back(ann.is_reverse_map); v.push_back(ann.promise_total); v.push_back(new StringLit(Location(),ann.doc_comment)); v.push_back(new StringLit(Location(), ann.is_introduced)); m = new Model(); m->addItem(new ConstraintI(Location(),new ArrayLit(Location(),v))); m->addItem(var_redef); } const int Constants::max_array_size; Constants& constants(void) { static Constants _c; return _c; } Annotation::~Annotation(void) { delete _s; } bool Annotation::contains(Expression* e) const { return _s && _s->contains(e); } bool Annotation::isEmpty(void) const { return _s == NULL || _s->isEmpty(); } ExpressionSetIter Annotation::begin(void) const { return _s == NULL ? ExpressionSetIter(true) : _s->begin(); } ExpressionSetIter Annotation::end(void) const { return _s == NULL ? ExpressionSetIter(true) : _s->end(); } void Annotation::add(Expression* e) { if (_s == NULL) _s = new ExpressionSet; if (e) _s->insert(e); } void Annotation::add(std::vector e) { if (_s == NULL) _s = new ExpressionSet; for (unsigned int i=e.size(); i--;) if (e[i]) _s->insert(e[i]); } void Annotation::remove(Expression* e) { if (_s && e) { _s->remove(e); } } void Annotation::removeCall(const ASTString& id) { if (_s==NULL) return; std::vector toRemove; for (ExpressionSetIter it=_s->begin(); it != _s->end(); ++it) { if (Call* c = (*it)->dyn_cast()) { if (c->id() == id) toRemove.push_back(*it); } } for (unsigned int i=toRemove.size(); i--;) _s->remove(toRemove[i]); } void Annotation::clear(void) { if (_s) { _s->clear(); } } void Annotation::merge(const Annotation& ann) { if (ann._s == NULL) return; if (_s == NULL) { _s = new ExpressionSet; } for (ExpressionSetIter it=ann.begin(); it != ann.end(); ++it) { _s->insert(*it); } } Expression* getAnnotation(const Annotation& ann, std::string str) { for(ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) { Expression* e = *i; if((e->isa() && e->cast()->str().str() == str) || (e->isa() && e->cast()->id().str() == str)) return e; } return NULL; } Expression* getAnnotation(const Annotation& ann, const ASTString& str) { for(ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) { Expression* e = *i; if((e->isa() && e->cast()->str() == str) || (e->isa() && e->cast()->id() == str)) return e; } return NULL; } } libminizinc-2.0.11/lib/eval_par.cpp0000644000175000017500000022144512646030173015615 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include #include #include #include #include namespace MiniZinc { template typename E::Val eval_id(EnvI& env, Expression* e) { Id* id = e->cast(); if (id->decl() == NULL) throw EvalError(env, e->loc(), "undeclared identifier", id->str().str()); VarDecl* vd = id->decl(); while (vd->flat() && vd->flat() != vd) vd = vd->flat(); if (vd->e() == NULL) throw EvalError(env, vd->loc(), "cannot evaluate expression", id->str().str()); typename E::Val r = E::e(env,vd->e()); if (!vd->evaluated() && (vd->toplevel() || vd->type().dim() > 0) ) { Expression* ne = E::exp(r); vd->e(ne); vd->evaluated(true); } return r; } class EvalIntLit { public: typedef IntLit* Val; typedef Expression* ArrayVal; static IntLit* e(EnvI& env, Expression* e) { return IntLit::a(eval_int(env, e)); } static Expression* exp(IntLit* e) { return e; } }; class EvalIntVal { public: typedef IntVal Val; typedef IntVal ArrayVal; static IntVal e(EnvI& env, Expression* e) { return eval_int(env, e); } static Expression* exp(IntVal e) { return IntLit::a(e); } }; class EvalFloatVal { public: typedef FloatVal Val; static FloatVal e(EnvI& env, Expression* e) { return eval_float(env, e); } static Expression* exp(FloatVal e) { return FloatLit::a(e); } }; class EvalFloatLit { public: typedef FloatLit* Val; typedef Expression* ArrayVal; static FloatLit* e(EnvI& env, Expression* e) { return FloatLit::a(eval_float(env, e)); } static Expression* exp(Expression* e) { return e; } }; class EvalString { public: typedef std::string Val; typedef std::string ArrayVal; static std::string e(EnvI& env, Expression* e) { return eval_string(env, e); } static Expression* exp(const std::string& e) { return new StringLit(Location(),e); } }; class EvalStringLit { public: typedef StringLit* Val; typedef Expression* ArrayVal; static StringLit* e(EnvI& env, Expression* e) { return new StringLit(Location(),eval_string(env, e)); } static Expression* exp(Expression* e) { return e; } }; class EvalBoolLit { public: typedef BoolLit* Val; typedef Expression* ArrayVal; static BoolLit* e(EnvI& env, Expression* e) { return constants().boollit(eval_bool(env, e)); } static Expression* exp(Expression* e) { return e; } }; class EvalBoolVal { public: typedef bool Val; static bool e(EnvI& env, Expression* e) { return eval_bool(env, e); } static Expression* exp(bool e) { return constants().boollit(e); } }; class EvalArrayLit { public: typedef ArrayLit* Val; typedef Expression* ArrayVal; static ArrayLit* e(EnvI& env, Expression* e) { return eval_array_lit(env, e); } static Expression* exp(Expression* e) { return e; } }; class EvalArrayLitCopy { public: typedef ArrayLit* Val; typedef Expression* ArrayVal; static ArrayLit* e(EnvI& env, Expression* e) { return copy(env,eval_array_lit(env, e),true)->cast(); } static Expression* exp(Expression* e) { return e; } }; class EvalIntSet { public: typedef IntSetVal* Val; static IntSetVal* e(EnvI& env, Expression* e) { return eval_intset(env, e); } static Expression* exp(IntSetVal* e) { return new SetLit(Location(),e); } }; class EvalBoolSet { public: typedef IntSetVal* Val; static IntSetVal* e(EnvI& env, Expression* e) { return eval_boolset(env, e); } static Expression* exp(IntSetVal* e) { return new SetLit(Location(),e); } }; class EvalSetLit { public: typedef SetLit* Val; typedef Expression* ArrayVal; static SetLit* e(EnvI& env, Expression* e) { return new SetLit(e->loc(),eval_intset(env, e)); } static Expression* exp(Expression* e) { return e; } }; class EvalBoolSetLit { public: typedef SetLit* Val; typedef Expression* ArrayVal; static SetLit* e(EnvI& env, Expression* e) { return new SetLit(e->loc(),eval_boolset(env, e)); } static Expression* exp(Expression* e) { return e; } }; class EvalNone { public: typedef Expression* Val; typedef Expression* ArrayVal; static Expression* e(EnvI&, Expression* e) { return e; } static Expression* exp(Expression* e) { return e; } }; class EvalCopy { public: typedef Expression* Val; typedef Expression* ArrayVal; static Expression* e(EnvI& env, Expression* e) { return copy(env,e,true); } static Expression* exp(Expression* e) { return e; } }; class EvalPar { public: typedef Expression* Val; typedef Expression* ArrayVal; static Expression* e(EnvI& env, Expression* e) { return eval_par(env, e); } static Expression* exp(Expression* e) { return e; } }; void checkDom(EnvI& env, Id* arg, IntSetVal* dom, Expression* e) { bool oob = false; if (e->type().isintset()) { IntSetVal* ev = eval_intset(env, e); IntSetRanges ev_r(ev); IntSetRanges dom_r(dom); oob = !Ranges::subset(ev_r, dom_r); } else { oob = !dom->contains(eval_int(env,e)); } if (oob) { std::ostringstream oss; oss << "value for argument `" << *arg << "' out of bounds"; throw EvalError(env, e->loc(), oss.str()); } } void checkDom(EnvI& env, Id* arg, FloatVal dom_min, FloatVal dom_max, Expression* e) { FloatVal ev = eval_float(env, e); if (ev < dom_min || ev > dom_max) { std::ostringstream oss; oss << "value for argument `" << *arg << "' out of bounds"; throw EvalError(env, e->loc(), oss.str()); } } template typename Eval::Val eval_call(EnvI& env, Call* ce) { std::vector previousParameters(ce->decl()->params().size()); for (unsigned int i=ce->decl()->params().size(); i--;) { VarDecl* vd = ce->decl()->params()[i]; previousParameters[i] = vd->e(); vd->flat(vd); vd->e(eval_par(env, ce->args()[i])); if (vd->e()->type().ispar()) { if (Expression* dom = vd->ti()->domain()) { if (!dom->isa()) { if (vd->e()->type().bt()==Type::BT_INT) { IntSetVal* isv = eval_intset(env, dom); if (vd->e()->type().dim() > 0) { ArrayLit* al = eval_array_lit(env, vd->e()); for (unsigned int i=0; iv().size(); i++) { checkDom(env, vd->id(), isv, al->v()[i]); } } else { checkDom(env, vd->id(),isv, vd->e()); } } else if (vd->e()->type().bt()==Type::BT_FLOAT) { GCLock lock; BinOp* bo = dom->cast(); FloatVal dom_min = eval_float(env,bo->lhs()); FloatVal dom_max = eval_float(env,bo->rhs()); checkDom(env, vd->id(), dom_min, dom_max, vd->e()); } } } } } typename Eval::Val ret = Eval::e(env,ce->decl()->e()); for (unsigned int i=ce->decl()->params().size(); i--;) { VarDecl* vd = ce->decl()->params()[i]; vd->e(previousParameters[i]); vd->flat(vd->e() ? vd : NULL); } return ret; } ArrayLit* eval_array_comp(EnvI& env, Comprehension* e) { ArrayLit* ret; if (e->type() == Type::parint(1)) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else if (e->type() == Type::parbool(1)) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else if (e->type() == Type::parfloat(1)) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else if (e->type() == Type::parsetint(1)) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else if (e->type() == Type::parstring(1)) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } ret->type(e->type()); return ret; } ArrayLit* eval_array_lit(EnvI& env, Expression* e) { switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_SETLIT: case Expression::E_ANON: case Expression::E_TI: case Expression::E_TIID: case Expression::E_VARDECL: throw EvalError(env, e->loc(), "not an array expression"); case Expression::E_ID: return eval_id(env,e); case Expression::E_ARRAYLIT: return e->cast(); case Expression::E_ARRAYACCESS: throw EvalError(env, e->loc(),"arrays of arrays not supported"); case Expression::E_COMP: return eval_array_comp(env,e->cast()); case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_array_lit(env,ite->e_then(i)); } return eval_array_lit(env,ite->e_else()); } case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->op()==BOT_PLUSPLUS) { ArrayLit* al0 = eval_array_lit(env,bo->lhs()); ArrayLit* al1 = eval_array_lit(env,bo->rhs()); std::vector v(al0->v().size()+al1->v().size()); for (unsigned int i=al0->v().size(); i--;) v[i] = al0->v()[i]; for (unsigned int i=al1->v().size(); i--;) v[al0->v().size()+i] = al1->v()[i]; ArrayLit* ret = new ArrayLit(e->loc(),v); ret->flat(al0->flat() && al1->flat()); ret->type(e->type()); return ret; } else { throw EvalError(env, e->loc(), "not an array expression", bo->opToString()); } } break; case Expression::E_UNOP: throw EvalError(env, e->loc(), "not an array expression"); case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.e) return eval_array_lit(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); ArrayLit* l_in = eval_array_lit(env,l->in()); ArrayLit* ret = copy(env,l_in,true)->cast(); ret->flat(l_in->flat()); l->popbindings(); return ret; } } assert(false); return NULL; } Expression* eval_arrayaccess(EnvI& env, ArrayLit* al, const std::vector& dims, bool& success) { success = true; assert(al->dims() == dims.size()); IntVal realidx = 0; int realdim = 1; for (int i=0; idims(); i++) realdim *= al->max(i)-al->min(i)+1; for (int i=0; idims(); i++) { IntVal ix = dims[i]; if (ix < al->min(i) || ix > al->max(i)) { success = false; Type t = al->type(); t.dim(0); if (t.isint()) return IntLit::a(0); if (t.isbool()) return constants().lit_false; if (t.isfloat()) return FloatLit::a(0.0); if (t.st() == Type::ST_SET || t.isbot()) { SetLit* ret = new SetLit(Location(),std::vector()); ret->type(t); return ret; } if (t.isstring()) return new StringLit(Location(),""); throw EvalError(env, al->loc(), "Internal error: unexpected type in array access expression"); } realdim /= al->max(i)-al->min(i)+1; realidx += (ix-al->min(i))*realdim; } assert(realidx >= 0 && realidx <= al->v().size()); return al->v()[static_cast(realidx.toInt())]; } Expression* eval_arrayaccess(EnvI& env, ArrayAccess* e, bool& success) { ArrayLit* al = eval_array_lit(env,e->v()); std::vector dims(e->idx().size()); for (unsigned int i=e->idx().size(); i--;) { dims[i] = eval_int(env,e->idx()[i]); } return eval_arrayaccess(env,al,dims,success); } Expression* eval_arrayaccess(EnvI& env, ArrayAccess* e) { bool success; Expression* ret = eval_arrayaccess(env,e,success); if (success) return ret; else throw EvalError(env, e->loc(), "array access out of bounds"); } IntSetVal* eval_intset(EnvI& env, Expression* e) { if (SetLit* sl = e->dyn_cast()) { if (sl->isv()) return sl->isv(); } CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_SETLIT: { SetLit* sl = e->cast(); std::vector vals(sl->v().size()); for (unsigned int i=0; iv().size(); i++) vals[i] = eval_int(env,sl->v()[i]); return IntSetVal::a(vals); } case Expression::E_BOOLLIT: case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_VARDECL: case Expression::E_TI: case Expression::E_UNOP: throw EvalError(env, e->loc(),"not a set of int expression"); break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); std::vector vals(al->v().size()); for (unsigned int i=0; iv().size(); i++) vals[i] = eval_int(env,al->v()[i]); return IntSetVal::a(vals); } break; case Expression::E_COMP: { Comprehension* c = e->cast(); std::vector a = eval_comp(env,c); return IntSetVal::a(a); } case Expression::E_ID: { GCLock lock; return eval_id(env,e)->isv(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_intset(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_intset(env,ite->e_then(i)); } return eval_intset(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); Expression* lhs = eval_par(env, bo->lhs()); Expression* rhs = eval_par(env, bo->rhs()); if (lhs->type().isintset() && rhs->type().isintset()) { IntSetVal* v0 = eval_intset(env,lhs); IntSetVal* v1 = eval_intset(env,rhs); IntSetRanges ir0(v0); IntSetRanges ir1(v1); switch (bo->op()) { case BOT_UNION: { Ranges::Union u(ir0,ir1); return IntSetVal::ai(u); } case BOT_DIFF: { Ranges::Diff u(ir0,ir1); return IntSetVal::ai(u); } case BOT_SYMDIFF: { Ranges::Union u(ir0,ir1); Ranges::Inter i(ir0,ir1); Ranges::Diff, Ranges::Inter> sd(u,i); return IntSetVal::ai(sd); } case BOT_INTERSECT: { Ranges::Inter u(ir0,ir1); return IntSetVal::ai(u); } default: throw EvalError(env, e->loc(),"not a set of int expression", bo->opToString()); } } else if (lhs->type().isint() && rhs->type().isint()) { if (bo->op() != BOT_DOTDOT) throw EvalError(env, e->loc(), "not a set of int expression", bo->opToString()); return IntSetVal::a(eval_int(env,lhs), eval_int(env,rhs)); } else { throw EvalError(env, e->loc(), "not a set of int expression", bo->opToString()); } } break; case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.s) return ce->decl()->_builtins.s(env,ce); if (ce->decl()->_builtins.e) return eval_intset(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); IntSetVal* ret = eval_intset(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return NULL; } } bool eval_bool(EnvI& env, Expression* e) { if (BoolLit* bl = e->dyn_cast()) { return bl->v(); } CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_ARRAYLIT: case Expression::E_COMP: case Expression::E_VARDECL: case Expression::E_TI: assert(false); throw EvalError(env, e->loc(),"not a bool expression"); break; case Expression::E_ID: { GCLock lock; return eval_id(env,e)->v(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_bool(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_bool(env,ite->e_then(i)); } return eval_bool(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); Expression* lhs = eval_par(env, bo->lhs()); Expression* rhs = eval_par(env, bo->rhs()); if ( bo->op()==BOT_EQ && (lhs->type().isopt() || rhs->type().isopt()) ) { if (lhs == constants().absent || rhs==constants().absent) return lhs==rhs; } if (lhs->type().isbool() && rhs->type().isbool()) { switch (bo->op()) { case BOT_LE: return eval_bool(env,lhs)eval_bool(env,rhs); case BOT_GQ: return eval_bool(env,lhs)>=eval_bool(env,rhs); case BOT_EQ: return eval_bool(env,lhs)==eval_bool(env,rhs); case BOT_NQ: return eval_bool(env,lhs)!=eval_bool(env,rhs); case BOT_EQUIV: return eval_bool(env,lhs)==eval_bool(env,rhs); case BOT_IMPL: return (!eval_bool(env,lhs))||eval_bool(env,rhs); case BOT_RIMPL: return (!eval_bool(env,rhs))||eval_bool(env,lhs); case BOT_OR: return eval_bool(env,lhs)||eval_bool(env,rhs); case BOT_AND: return eval_bool(env,lhs)&&eval_bool(env,rhs); case BOT_XOR: return eval_bool(env,lhs)^eval_bool(env,rhs); default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } else if (lhs->type().isint() && rhs->type().isint()) { IntVal v0 = eval_int(env,lhs); IntVal v1 = eval_int(env,rhs); switch (bo->op()) { case BOT_LE: return v0v1; case BOT_GQ: return v0>=v1; case BOT_EQ: return v0==v1; case BOT_NQ: return v0!=v1; default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } else if (lhs->type().isfloat() && rhs->type().isfloat()) { FloatVal v0 = eval_float(env,lhs); FloatVal v1 = eval_float(env,rhs); switch (bo->op()) { case BOT_LE: return v0v1; case BOT_GQ: return v0>=v1; case BOT_EQ: return v0==v1; case BOT_NQ: return v0!=v1; default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } else if (lhs->type().isint() && rhs->type().isintset()) { IntVal v0 = eval_int(env,lhs); GCLock lock; IntSetVal* v1 = eval_intset(env,rhs); switch (bo->op()) { case BOT_IN: return v1->contains(v0); default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } else if (lhs->type().is_set() && rhs->type().is_set()) { GCLock lock; IntSetVal* v0 = eval_intset(env,lhs); IntSetVal* v1 = eval_intset(env,rhs); IntSetRanges ir0(v0); IntSetRanges ir1(v1); switch (bo->op()) { case BOT_LE: return Ranges::less(ir0,ir1); case BOT_LQ: return Ranges::lessEq(ir0,ir1); case BOT_GR: return Ranges::less(ir1,ir0); case BOT_GQ: return Ranges::lessEq(ir1,ir0); case BOT_EQ: return Ranges::equal(ir0,ir1); case BOT_NQ: return !Ranges::equal(ir0,ir1); case BOT_SUBSET: return Ranges::subset(ir0,ir1); case BOT_SUPERSET: return Ranges::subset(ir1,ir0); default: throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } else if (lhs->type().isstring() && rhs->type().isstring()) { GCLock lock; std::string s0 = eval_string(env,lhs); std::string s1 = eval_string(env,rhs); switch (bo->op()) { case BOT_EQ: return s0==s1; case BOT_NQ: return s0!=s1; case BOT_LE: return s0s1; case BOT_GQ: return s0>=s1; default: throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } else if (bo->op()==BOT_EQ && lhs->type().isann()) { return Expression::equal(lhs, rhs); } else if (bo->op()==BOT_EQ && lhs->type().dim() > 0 && rhs->type().dim() > 0) { ArrayLit* al0 = eval_array_lit(env,lhs); ArrayLit* al1 = eval_array_lit(env,rhs); if (al0->v().size() != al1->v().size()) return false; for (unsigned int i=0; iv().size(); i++) { if (!Expression::equal(eval_par(env,al0->v()[i]), eval_par(env,al1->v()[i]))) { return false; } } return true; } else { throw EvalError(env, e->loc(), "not a bool expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); bool v0 = eval_bool(env,uo->e()); switch (uo->op()) { case UOT_NOT: return !v0; default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", uo->opToString()); } } break; case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.b) return ce->decl()->_builtins.b(env,ce); if (ce->decl()->_builtins.e) return eval_bool(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); bool ret = eval_bool(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return false; } } IntSetVal* eval_boolset(EnvI& env, Expression* e) { switch (e->eid()) { case Expression::E_SETLIT: { SetLit* sl = e->cast(); if (sl->isv()) return sl->isv(); std::vector vals(sl->v().size()); for (unsigned int i=0; iv().size(); i++) vals[i] = eval_bool(env,sl->v()[i]); return IntSetVal::a(vals); } case Expression::E_BOOLLIT: case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_VARDECL: case Expression::E_TI: case Expression::E_UNOP: throw EvalError(env, e->loc(),"not a set of bool expression"); break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); std::vector vals(al->v().size()); for (unsigned int i=0; iv().size(); i++) vals[i] = eval_bool(env,al->v()[i]); return IntSetVal::a(vals); } break; case Expression::E_COMP: { Comprehension* c = e->cast(); std::vector a = eval_comp(env,c); return IntSetVal::a(a); } case Expression::E_ID: { GCLock lock; return eval_id(env,e)->isv(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_boolset(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_boolset(env,ite->e_then(i)); } return eval_boolset(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); Expression* lhs = eval_par(env, bo->lhs()); Expression* rhs = eval_par(env, bo->rhs()); if (lhs->type().isintset() && rhs->type().isintset()) { IntSetVal* v0 = eval_boolset(env,lhs); IntSetVal* v1 = eval_boolset(env,rhs); IntSetRanges ir0(v0); IntSetRanges ir1(v1); switch (bo->op()) { case BOT_UNION: { Ranges::Union u(ir0,ir1); return IntSetVal::ai(u); } case BOT_DIFF: { Ranges::Diff u(ir0,ir1); return IntSetVal::ai(u); } case BOT_SYMDIFF: { Ranges::Union u(ir0,ir1); Ranges::Inter i(ir0,ir1); Ranges::Diff, Ranges::Inter> sd(u,i); return IntSetVal::ai(sd); } case BOT_INTERSECT: { Ranges::Inter u(ir0,ir1); return IntSetVal::ai(u); } default: throw EvalError(env, e->loc(),"not a set of bool expression", bo->opToString()); } } else if (lhs->type().isbool() && rhs->type().isbool()) { if (bo->op() != BOT_DOTDOT) throw EvalError(env, e->loc(), "not a set of bool expression", bo->opToString()); return IntSetVal::a(eval_bool(env,lhs), eval_bool(env,rhs)); } else { throw EvalError(env, e->loc(), "not a set of bool expression", bo->opToString()); } } break; case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.s) return ce->decl()->_builtins.s(env,ce); if (ce->decl()->_builtins.e) return eval_boolset(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); IntSetVal* ret = eval_boolset(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return NULL; } } IntVal eval_int(EnvI& env,Expression* e) { if (e->type().isbool()) { return eval_bool(env,e); } if (IntLit* il = e->dyn_cast()) { return il->v(); } CallStackItem csi(env,e); try { switch (e->eid()) { case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_ARRAYLIT: case Expression::E_COMP: case Expression::E_VARDECL: case Expression::E_TI: throw EvalError(env, e->loc(),"not an integer expression"); break; case Expression::E_ID: { GCLock lock; return eval_id(env,e)->v(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_int(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_int(env,ite->e_then(i)); } return eval_int(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); IntVal v0 = eval_int(env,bo->lhs()); IntVal v1 = eval_int(env,bo->rhs()); switch (bo->op()) { case BOT_PLUS: return v0+v1; case BOT_MINUS: return v0-v1; case BOT_MULT: return v0*v1; case BOT_IDIV: if (v1==0) throw EvalError(env, e->loc(),"division by zero"); return v0 / v1; case BOT_MOD: if (v1==0) throw EvalError(env, e->loc(),"division by zero"); return v0 % v1; default: throw EvalError(env, e->loc(),"not an integer expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); IntVal v0 = eval_int(env,uo->e()); switch (uo->op()) { case UOT_PLUS: return v0; case UOT_MINUS: return -v0; default: throw EvalError(env, e->loc(),"not an integer expression", uo->opToString()); } } break; case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.i) return ce->decl()->_builtins.i(env,ce); if (ce->decl()->_builtins.e) return eval_int(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); IntVal ret = eval_int(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return 0; } } catch (ArithmeticError& err) { throw EvalError(env, e->loc(), err.msg()); } } FloatVal eval_float(EnvI& env, Expression* e) { if (e->type().isint()) { return eval_int(env,e).toInt(); } else if (e->type().isbool()) { return eval_bool(env,e); } if (FloatLit* fl = e->dyn_cast()) { return fl->v(); } CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_ARRAYLIT: case Expression::E_COMP: case Expression::E_VARDECL: case Expression::E_TI: throw EvalError(env, e->loc(),"not a float expression"); break; case Expression::E_ID: { GCLock lock; return eval_id(env,e)->v(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_float(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_float(env,ite->e_then(i)); } return eval_float(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); FloatVal v0 = eval_float(env,bo->lhs()); FloatVal v1 = eval_float(env,bo->rhs()); switch (bo->op()) { case BOT_PLUS: return v0+v1; case BOT_MINUS: return v0-v1; case BOT_MULT: return v0*v1; case BOT_DIV: if (v1==0.0) throw EvalError(env, e->loc(),"division by zero"); return v0 / v1; default: throw EvalError(env, e->loc(),"not a float expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); FloatVal v0 = eval_float(env,uo->e()); switch (uo->op()) { case UOT_PLUS: return v0; case UOT_MINUS: return -v0; default: throw EvalError(env, e->loc(),"not a float expression", uo->opToString()); } } break; case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.f) return ce->decl()->_builtins.f(env,ce); if (ce->decl()->_builtins.e) return eval_float(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); FloatVal ret = eval_float(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return 0.0; } } std::string eval_string(EnvI& env, Expression* e) { switch (e->eid()) { case Expression::E_STRINGLIT: return e->cast()->v().str(); case Expression::E_FLOATLIT: case Expression::E_INTLIT: case Expression::E_BOOLLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_ARRAYLIT: case Expression::E_COMP: case Expression::E_VARDECL: case Expression::E_TI: throw EvalError(env, e->loc(),"not a string expression"); break; case Expression::E_ID: { GCLock lock; return eval_id(env,e)->v().str(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_string(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_string(env,ite->e_then(i)); } return eval_string(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); std::string v0 = eval_string(env,bo->lhs()); std::string v1 = eval_string(env,bo->rhs()); switch (bo->op()) { case BOT_PLUSPLUS: return v0+v1; default: throw EvalError(env, e->loc(),"not a string expression", bo->opToString()); } } break; case Expression::E_UNOP: throw EvalError(env, e->loc(),"not a string expression"); break; case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.str) return ce->decl()->_builtins.str(env,ce); if (ce->decl()->_builtins.e) return eval_string(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); std::string ret = eval_string(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return NULL; } } Expression* eval_par(EnvI& env, Expression* e) { if (e==NULL) return NULL; switch (e->eid()) { case Expression::E_ANON: case Expression::E_TIID: { return e; } case Expression::E_COMP: if (e->cast()->set()) return EvalSetLit::e(env,e); // fall through case Expression::E_ARRAYLIT: { ArrayLit* al = eval_array_lit(env,e); std::vector args(al->v().size()); for (unsigned int i=al->v().size(); i--;) args[i] = eval_par(env,al->v()[i]); std::vector > dims(al->dims()); for (unsigned int i=al->dims(); i--;) { dims[i].first = al->min(i); dims[i].second = al->max(i); } ArrayLit* ret = new ArrayLit(al->loc(),args,dims); Type t = al->type(); if (t.isbot() && ret->v().size() > 0) { t.bt(ret->v()[0]->type().bt()); } ret->type(t); return ret; } case Expression::E_VARDECL: { VarDecl* vd = e->cast(); throw EvalError(env, vd->loc(),"cannot evaluate variable declaration", vd->id()->v()); } case Expression::E_TI: { TypeInst* t = e->cast(); ASTExprVec r; if (t->ranges().size() > 0) { std::vector rv(t->ranges().size()); for (unsigned int i=t->ranges().size(); i--;) rv[i] = static_cast(eval_par(env,t->ranges()[i])); r = ASTExprVec(rv); } return new TypeInst(Location(),t->type(),r,eval_par(env,t->domain())); } case Expression::E_ID: { if (e == constants().absent) return e; Id* id = e->cast(); if (id->decl()==NULL) throw EvalError(env, e->loc(),"undefined identifier", id->v()); if (id->decl()->ti()->domain()) { if (BoolLit* bl = id->decl()->ti()->domain()->dyn_cast()) return bl; if (id->decl()->ti()->type().isint()) { if (SetLit* sl = id->decl()->ti()->domain()->dyn_cast()) { if (sl->isv() && sl->isv()->min()==sl->isv()->max()) { return IntLit::a(sl->isv()->min()); } } } else if (id->decl()->ti()->type().isfloat()) { if (BinOp* bo = id->decl()->ti()->domain()->dyn_cast()) { if (bo->op()==BOT_DOTDOT && bo->lhs()->isa() && bo->rhs()->isa()) { if (bo->lhs()->cast()->v() == bo->rhs()->cast()->v()) { return bo->lhs(); } } } } } if (id->decl()->e()==NULL) { return id; } else { return eval_par(env,id->decl()->e()); } } case Expression::E_STRINGLIT: return e; default: { if (e->type().dim() != 0) { ArrayLit* al = eval_array_lit(env,e); std::vector args(al->v().size()); for (unsigned int i=al->v().size(); i--;) args[i] = eval_par(env,al->v()[i]); std::vector > dims(al->dims()); for (unsigned int i=al->dims(); i--;) { dims[i].first = al->min(i); dims[i].second = al->max(i); } ArrayLit* ret = new ArrayLit(al->loc(),args,dims); Type t = al->type(); if ( (t.bt()==Type::BT_BOT || t.bt()==Type::BT_TOP) && ret->v().size() > 0) { t.bt(ret->v()[0]->type().bt()); } ret->type(t); return ret; } if (e->type().isintset()) { return EvalSetLit::e(env,e); } if (e->type().isboolset()) { return EvalBoolSetLit::e(env,e); } if (e->type()==Type::parint()) { return EvalIntLit::e(env,e); } if (e->type()==Type::parbool()) { return EvalBoolLit::e(env,e); } if (e->type()==Type::parfloat()) { return EvalFloatLit::e(env,e); } if (e->type()==Type::parstring()) { return EvalStringLit::e(env,e); } switch (e->eid()) { case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (ite->e_if(i)->type()==Type::parbool()) { if (eval_bool(env,ite->e_if(i))) return eval_par(env,ite->e_then(i)); } else { std::vector e_ifthen(ite->size()*2); for (int i=0; isize(); i++) { e_ifthen[2*i] = eval_par(env,ite->e_if(i)); e_ifthen[2*i+1] = eval_par(env,ite->e_then(i)); } ITE* n_ite = new ITE(ite->loc(),e_ifthen,eval_par(env,ite->e_else())); n_ite->type(ite->type()); return n_ite; } } return eval_par(env,ite->e_else()); } case Expression::E_CALL: { Call* c = e->cast(); if (c->decl()) { if (c->decl()->_builtins.e) { return eval_par(env,c->decl()->_builtins.e(env,c)); } else { if (c->decl()->e()==NULL) return c; return eval_call(env,c); } } else { std::vector args(c->args().size()); for (unsigned int i=0; iargs()[i]); } Call* nc = new Call(c->loc(),c->id(),args,c->decl()); nc->type(c->type()); return nc; } } case Expression::E_BINOP: { BinOp* bo = e->cast(); BinOp* nbo = new BinOp(e->loc(),eval_par(env,bo->lhs()),bo->op(),eval_par(env,bo->rhs())); nbo->type(bo->type()); return nbo; } case Expression::E_UNOP: { UnOp* uo = e->cast(); UnOp* nuo = new UnOp(e->loc(),uo->op(),eval_par(env,uo->e())); nuo->type(uo->type()); return nuo; } case Expression::E_ARRAYACCESS: { ArrayAccess* aa = e->cast(); for (unsigned int i=0; iidx().size(); i++) { if (!aa->idx()[i]->type().ispar()) { std::vector idx(aa->idx().size()); for (unsigned int j=0; jidx().size(); j++) { idx[j] = eval_par(env, aa->idx()[j]); } ArrayAccess* aa_new = new ArrayAccess(e->loc(), eval_par(env, aa->v()),idx); aa_new->type(aa->type()); return aa_new; } } return eval_par(env,eval_arrayaccess(env,aa)); } default: return e; } } } } class ComputeIntBounds : public EVisitor { public: typedef std::pair Bounds; std::vector _bounds; bool valid; EnvI& env; ComputeIntBounds(EnvI& env0) : valid(true), env(env0) {} bool enter(Expression* e) { if (e->type().isann()) return false; if (e->isa()) return false; if (e->type().dim() > 0) return false; if (e->type().ispar()) { if (e->type().isint()) { IntVal v = eval_int(env,e); _bounds.push_back(Bounds(v,v)); } else { valid = false; } return false; } if (ITE* ite = e->dyn_cast()) { Bounds itebounds(IntVal::infinity(), -IntVal::infinity()); for (unsigned int i=0; isize(); i++) { if (ite->e_if(i)->type().ispar() && ite->e_if(i)->type().cv()==Type::CV_NO) { if (eval_bool(env, ite->e_if(i))) { BottomUpIterator cbi(*this); cbi.run(ite->e_then(i)); Bounds& back = _bounds.back(); back.first = std::min(itebounds.first, back.first); back.second = std::max(itebounds.second, back.second); return false; } } else { BottomUpIterator cbi(*this); cbi.run(ite->e_then(i)); Bounds back = _bounds.back(); _bounds.pop_back(); itebounds.first = std::min(itebounds.first, back.first); itebounds.second = std::max(itebounds.second, back.second); } } BottomUpIterator cbi(*this); cbi.run(ite->e_else()); Bounds& back = _bounds.back(); back.first = std::min(itebounds.first, back.first); back.second = std::max(itebounds.second, back.second); return false; } return e->type().isint(); } /// Visit integer literal void vIntLit(const IntLit& i) { _bounds.push_back(Bounds(i.v(),i.v())); } /// Visit floating point literal void vFloatLit(const FloatLit&) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit Boolean literal void vBoolLit(const BoolLit&) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit set literal void vSetLit(const SetLit&) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit string literal void vStringLit(const StringLit&) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit identifier void vId(const Id& id) { VarDecl* vd = id.decl(); while (vd->flat() && vd->flat() != vd) vd = vd->flat(); if (vd->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,vd->ti()->domain()); if (isv->size()==0) { valid = false; _bounds.push_back(Bounds(0,0)); } else { _bounds.push_back(Bounds(isv->min(0),isv->max(isv->size()-1))); } } else { if (vd->e()) { BottomUpIterator cbi(*this); cbi.run(vd->e()); } else { _bounds.push_back(Bounds(-IntVal::infinity(),IntVal::infinity())); } } } /// Visit anonymous variable void vAnonVar(const AnonVar& v) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit array literal void vArrayLit(const ArrayLit& al) { } /// Visit array access void vArrayAccess(ArrayAccess& aa) { bool parAccess = true; for (unsigned int i=aa.idx().size(); i--;) { _bounds.pop_back(); if (!aa.idx()[i]->type().ispar()) { parAccess = false; } } if (Id* id = aa.v()->dyn_cast()) { while (id->decl()->e() && id->decl()->e()->isa()) { id = id->decl()->e()->cast(); } if (parAccess && id->decl()->e() && id->decl()->e()->isa()) { bool success; Expression* e = eval_arrayaccess(env,&aa, success); if (success) { BottomUpIterator cbi(*this); cbi.run(e); return; } } if (id->decl()->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,id->decl()->ti()->domain()); if (isv->size()>0) { _bounds.push_back(Bounds(isv->min(0),isv->max(isv->size()-1))); return; } } } valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit array comprehension void vComprehension(const Comprehension& c) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit if-then-else void vITE(const ITE& ite) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit binary operator void vBinOp(const BinOp& bo) { Bounds b1 = _bounds.back(); _bounds.pop_back(); Bounds b0 = _bounds.back(); _bounds.pop_back(); if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() || !b0.second.isFinite()) { valid = false; _bounds.push_back(Bounds(0,0)); } else { switch (bo.op()) { case BOT_PLUS: _bounds.push_back(Bounds(b0.first+b1.first,b0.second+b1.second)); break; case BOT_MINUS: _bounds.push_back(Bounds(b0.first-b1.second,b0.second-b1.first)); break; case BOT_MULT: { IntVal x0 = b0.first*b1.first; IntVal x1 = b0.first*b1.second; IntVal x2 = b0.second*b1.first; IntVal x3 = b0.second*b1.second; IntVal m = std::min(x0,std::min(x1,std::min(x2,x3))); IntVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(Bounds(m,n)); } break; case BOT_IDIV: { IntVal b0f = b0.first==0 ? 1 : b0.first; IntVal b0s = b0.second==0 ? -1 : b0.second; IntVal b1f = b1.first==0 ? 1 : b1.first; IntVal b1s = b1.second==0 ? -1 : b1.second; IntVal x0 = b0f / b1f; IntVal x1 = b0f / b1s; IntVal x2 = b0s / b1f; IntVal x3 = b0s / b1s; IntVal m = std::min(x0,std::min(x1,std::min(x2,x3))); IntVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(Bounds(m,n)); } break; case BOT_MOD: { IntVal b0f = b0.first==0 ? 1 : b0.first; IntVal b0s = b0.second==0 ? -1 : b0.second; IntVal b1f = b1.first==0 ? 1 : b1.first; IntVal b1s = b1.second==0 ? -1 : b1.second; IntVal x0 = b0f % b1f; IntVal x1 = b0f % b1s; IntVal x2 = b0s % b1f; IntVal x3 = b0s % b1s; IntVal m = std::min(x0,std::min(x1,std::min(x2,x3))); IntVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(Bounds(m,n)); } break; case BOT_DIV: case BOT_LE: case BOT_LQ: case BOT_GR: case BOT_GQ: case BOT_EQ: case BOT_NQ: case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: case BOT_UNION: case BOT_DIFF: case BOT_SYMDIFF: case BOT_INTERSECT: case BOT_PLUSPLUS: case BOT_EQUIV: case BOT_IMPL: case BOT_RIMPL: case BOT_OR: case BOT_AND: case BOT_XOR: case BOT_DOTDOT: valid = false; _bounds.push_back(Bounds(0,0)); } } } /// Visit unary operator void vUnOp(const UnOp& uo) { switch (uo.op()) { case UOT_PLUS: break; case UOT_MINUS: _bounds.back().first = -_bounds.back().first; _bounds.back().second = -_bounds.back().second; std::swap(_bounds.back().first, _bounds.back().second); break; case UOT_NOT: valid = false; } } /// Visit call void vCall(Call& c) { if (c.id() == constants().ids.lin_exp || c.id() == constants().ids.sum) { bool le = c.id() == constants().ids.lin_exp; ArrayLit* coeff = le ? eval_array_lit(env,c.args()[0]): NULL; if (c.args()[le ? 1 : 0]->type().isopt()) { valid = false; _bounds.push_back(Bounds(0,0)); return; } ArrayLit* al = eval_array_lit(env,c.args()[le ? 1 : 0]); IntVal d = le ? c.args()[2]->cast()->v() : 0; int stacktop = _bounds.size(); for (unsigned int i=al->v().size(); i--;) { BottomUpIterator cbi(*this); cbi.run(al->v()[i]); if (!valid) { for (unsigned int j=al->v().size()-1; j>i; j--) _bounds.pop_back(); return; } } assert(stacktop+al->v().size()==_bounds.size()); IntVal lb = d; IntVal ub = d; for (unsigned int i=0; iv().size(); i++) { Bounds b = _bounds.back(); _bounds.pop_back(); IntVal cv = le ? eval_int(env,coeff->v()[i]) : 1; if (cv > 0) { if (b.first.isFinite()) { if (lb.isFinite()) { lb += cv*b.first; } } else { lb = b.first; } if (b.second.isFinite()) { if (ub.isFinite()) { ub += cv*b.second; } } else { ub = b.second; } } else { if (b.second.isFinite()) { if (lb.isFinite()) { lb += cv*b.second; } } else { lb = -b.second; } if (b.first.isFinite()) { if (ub.isFinite()) { ub += cv*b.first; } } else { ub = -b.first; } } } _bounds.push_back(Bounds(lb,ub)); } else if (c.id() == "card") { if (IntSetVal* isv = compute_intset_bounds(env,c.args()[0])) { IntSetRanges isr(isv); _bounds.push_back(Bounds(0,Ranges::size(isr))); } else { valid = false; _bounds.push_back(Bounds(0,0)); } } else if (c.id() == "int_times") { Bounds b1 = _bounds.back(); _bounds.pop_back(); Bounds b0 = _bounds.back(); _bounds.pop_back(); if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() || !b0.second.isFinite()) { valid = false; _bounds.push_back(Bounds(0,0)); } else { IntVal x0 = b0.first*b1.first; IntVal x1 = b0.first*b1.second; IntVal x2 = b0.second*b1.first; IntVal x3 = b0.second*b1.second; IntVal m = std::min(x0,std::min(x1,std::min(x2,x3))); IntVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(Bounds(m,n)); } } else if (c.id() == constants().ids.bool2int) { _bounds.push_back(Bounds(0,1)); } else if (c.id() == "abs") { Bounds b0 = _bounds.back(); if (b0.first < 0) { _bounds.pop_back(); if (b0.second < 0) _bounds.push_back(Bounds(-b0.second,-b0.first)); else _bounds.push_back(Bounds(0,std::max(-b0.first,b0.second))); } } else { valid = false; _bounds.push_back(Bounds(0,0)); } } /// Visit let void vLet(const Let& l) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit variable declaration void vVarDecl(const VarDecl& vd) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit annotation void vAnnotation(const Annotation& e) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit type inst void vTypeInst(const TypeInst& e) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit TIId void vTIId(const TIId& e) { valid = false; _bounds.push_back(Bounds(0,0)); } }; IntBounds compute_int_bounds(EnvI& env, Expression* e) { ComputeIntBounds cb(env); BottomUpIterator cbi(cb); cbi.run(e); if (cb.valid) { assert(cb._bounds.size() > 0); return IntBounds(cb._bounds.back().first,cb._bounds.back().second,true); } else { return IntBounds(0,0,false); } } class ComputeFloatBounds : public EVisitor { protected: typedef std::pair FBounds; public: std::vector _bounds; bool valid; EnvI& env; ComputeFloatBounds(EnvI& env0) : valid(true), env(env0) {} bool enter(Expression* e) { if (e->type().isann()) return false; if (e->isa()) return false; if (e->type().dim() > 0) return false; if (e->type().ispar()) { if (e->type().isfloat()) { FloatVal v = eval_float(env,e); _bounds.push_back(FBounds(v,v)); } return false; } else { return e->type().isfloat(); } } /// Visit integer literal void vIntLit(const IntLit& i) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit floating point literal void vFloatLit(const FloatLit& f) { _bounds.push_back(FBounds(f.v(),f.v())); } /// Visit Boolean literal void vBoolLit(const BoolLit&) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit set literal void vSetLit(const SetLit&) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit string literal void vStringLit(const StringLit&) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit identifier void vId(const Id& id) { VarDecl* vd = id.decl(); while (vd->flat() && vd->flat() != vd) vd = vd->flat(); if (vd->ti()->domain()) { BinOp* bo = vd->ti()->domain()->cast(); assert(bo->op() == BOT_DOTDOT); _bounds.push_back(FBounds(eval_float(env,bo->lhs()),eval_float(env,bo->rhs()))); } else { if (vd->e()) { BottomUpIterator cbi(*this); cbi.run(vd->e()); } else { valid = false; _bounds.push_back(FBounds(0,0)); } } } /// Visit anonymous variable void vAnonVar(const AnonVar& v) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit array literal void vArrayLit(const ArrayLit& al) { } /// Visit array access void vArrayAccess(ArrayAccess& aa) { bool parAccess = true; for (unsigned int i=aa.idx().size(); i--;) { if (!aa.idx()[i]->type().ispar()) { parAccess = false; } } if (Id* id = aa.v()->dyn_cast()) { while (id->decl()->e() && id->decl()->e()->isa()) { id = id->decl()->e()->cast(); } if (parAccess && id->decl()->e() && id->decl()->e()->isa()) { bool success; Expression* e = eval_arrayaccess(env,&aa, success); if (success) { BottomUpIterator cbi(*this); cbi.run(e); return; } } if (id->decl()->ti()->domain()) { BinOp* bo = id->decl()->ti()->domain()->cast(); assert(bo->op() == BOT_DOTDOT); FBounds b(eval_float(env,bo->lhs()),eval_float(env,bo->rhs())); _bounds.push_back(b); return; } } valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit array comprehension void vComprehension(const Comprehension& c) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit if-then-else void vITE(const ITE& ite) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit binary operator void vBinOp(const BinOp& bo) { FBounds b1 = _bounds.back(); _bounds.pop_back(); FBounds b0 = _bounds.back(); _bounds.pop_back(); switch (bo.op()) { case BOT_PLUS: _bounds.push_back(FBounds(b0.first+b1.first,b0.second+b1.second)); break; case BOT_MINUS: _bounds.push_back(FBounds(b0.first-b1.second,b0.second-b1.first)); break; case BOT_MULT: { FloatVal x0 = b0.first*b1.first; FloatVal x1 = b0.first*b1.second; FloatVal x2 = b0.second*b1.first; FloatVal x3 = b0.second*b1.second; FloatVal m = std::min(x0,std::min(x1,std::min(x2,x3))); FloatVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(FBounds(m,n)); } break; case BOT_DIV: case BOT_IDIV: case BOT_MOD: case BOT_LE: case BOT_LQ: case BOT_GR: case BOT_GQ: case BOT_EQ: case BOT_NQ: case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: case BOT_UNION: case BOT_DIFF: case BOT_SYMDIFF: case BOT_INTERSECT: case BOT_PLUSPLUS: case BOT_EQUIV: case BOT_IMPL: case BOT_RIMPL: case BOT_OR: case BOT_AND: case BOT_XOR: case BOT_DOTDOT: valid = false; _bounds.push_back(FBounds(0,0)); } } /// Visit unary operator void vUnOp(const UnOp& uo) { switch (uo.op()) { case UOT_PLUS: break; case UOT_MINUS: _bounds.back().first = -_bounds.back().first; _bounds.back().second = -_bounds.back().second; break; case UOT_NOT: valid = false; _bounds.push_back(FBounds(0.0,0.0)); } } /// Visit call void vCall(Call& c) { if (c.id() == constants().ids.lin_exp || c.id() == constants().ids.sum) { bool le = c.id() == constants().ids.lin_exp; ArrayLit* coeff = le ? eval_array_lit(env,c.args()[0]): NULL; if (c.args()[le ? 1 : 0]->type().isopt()) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); return; } ArrayLit* al = eval_array_lit(env,c.args()[le ? 1 : 0]); FloatVal d = le ? c.args()[2]->cast()->v() : 0.0; int stacktop = _bounds.size(); for (unsigned int i=al->v().size(); i--;) { BottomUpIterator cbi(*this); cbi.run(al->v()[i]); if (!valid) return; } assert(stacktop+al->v().size()==_bounds.size()); FloatVal lb = d; FloatVal ub = d; for (unsigned int i=0; iv().size(); i++) { FBounds b = _bounds.back(); _bounds.pop_back(); FloatVal cv = le ? eval_float(env,coeff->v()[i]) : 1.0; if (cv > 0) { lb += cv*b.first; ub += cv*b.second; } else { lb += cv*b.second; ub += cv*b.first; } } _bounds.push_back(FBounds(lb,ub)); } else if (c.id() == "float_times") { BottomUpIterator cbi(*this); cbi.run(c.args()[0]); cbi.run(c.args()[1]); FBounds b1 = _bounds.back(); _bounds.pop_back(); FBounds b0 = _bounds.back(); _bounds.pop_back(); FloatVal x0 = b0.first*b1.first; FloatVal x1 = b0.first*b1.second; FloatVal x2 = b0.second*b1.first; FloatVal x3 = b0.second*b1.second; FloatVal m = std::min(x0,std::min(x1,std::min(x2,x3))); FloatVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(FBounds(m,n)); } else if (c.id() == "int2float") { ComputeIntBounds ib(env); BottomUpIterator cbi(ib); cbi.run(c.args()[0]); if (!ib.valid) valid = false; ComputeIntBounds::Bounds result = ib._bounds.back(); if (!result.first.isFinite() || !result.second.isFinite()) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } else { _bounds.push_back(FBounds(result.first.toInt(),result.second.toInt())); } } else if (c.id() == "abs") { BottomUpIterator cbi(*this); cbi.run(c.args()[0]); FBounds b0 = _bounds.back(); if (b0.first < 0) { _bounds.pop_back(); if (b0.second < 0) _bounds.push_back(FBounds(-b0.second,-b0.first)); else _bounds.push_back(FBounds(0.0,std::max(-b0.first,b0.second))); } } else { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } } /// Visit let void vLet(const Let& l) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit variable declaration void vVarDecl(const VarDecl& vd) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit annotation void vAnnotation(const Annotation& e) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit type inst void vTypeInst(const TypeInst& e) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit TIId void vTIId(const TIId& e) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } }; FloatBounds compute_float_bounds(EnvI& env, Expression* e) { ComputeFloatBounds cb(env); BottomUpIterator cbi(cb); cbi.run(e); if (cb.valid) { assert(cb._bounds.size() > 0); return FloatBounds(cb._bounds.back().first,cb._bounds.back().second,true); } else { return FloatBounds(0.0,0.0,false); } } class ComputeIntSetBounds : public EVisitor { public: std::vector _bounds; bool valid; EnvI& env; ComputeIntSetBounds(EnvI& env0) : valid(true), env(env0) {} bool enter(Expression* e) { if (e->type().isann()) return false; if (e->isa()) return false; if (e->type().dim() > 0) return false; if (!e->type().isintset()) return false; if (e->type().ispar()) { _bounds.push_back(eval_intset(env,e)); return false; } else { return true; } } /// Visit set literal void vSetLit(const SetLit& sl) { assert(sl.type().isvar()); assert(sl.isv()==NULL); IntSetVal* isv = IntSetVal::a(); for (unsigned int i=0; i u(i0,cr); isv = IntSetVal::ai(u); } _bounds.push_back(isv); } /// Visit identifier void vId(const Id& id) { if (id.decl()->ti()->domain()) { _bounds.push_back(eval_intset(env,id.decl()->ti()->domain())); } else { if (id.decl()->e()) { BottomUpIterator cbi(*this); cbi.run(id.decl()->e()); } else { valid = false; _bounds.push_back(NULL); } } } /// Visit anonymous variable void vAnonVar(const AnonVar& v) { valid = false; _bounds.push_back(NULL); } /// Visit array access void vArrayAccess(ArrayAccess& aa) { bool parAccess = true; for (unsigned int i=aa.idx().size(); i--;) { if (!aa.idx()[i]->type().ispar()) { parAccess = false; break; } } if (Id* id = aa.v()->dyn_cast()) { while (id->decl()->e() && id->decl()->e()->isa()) { id = id->decl()->e()->cast(); } if (parAccess && id->decl()->e() && id->decl()->e()->isa()) { bool success; Expression* e = eval_arrayaccess(env,&aa, success); if (success) { BottomUpIterator cbi(*this); cbi.run(e); return; } } if (id->decl()->ti()->domain()) { _bounds.push_back(eval_intset(env,id->decl()->ti()->domain())); return; } } valid = false; _bounds.push_back(NULL); } /// Visit array comprehension void vComprehension(const Comprehension& c) { valid = false; _bounds.push_back(NULL); } /// Visit if-then-else void vITE(const ITE& ite) { valid = false; _bounds.push_back(NULL); } /// Visit binary operator void vBinOp(const BinOp& bo) { if (bo.op()==BOT_DOTDOT) { IntBounds lb = compute_int_bounds(env, bo.lhs()); IntBounds ub = compute_int_bounds(env, bo.rhs()); valid = valid && lb.valid && ub.valid; _bounds.push_back(IntSetVal::a(lb.l, ub.u)); } else { IntSetVal* b1 = _bounds.back(); _bounds.pop_back(); IntSetVal* b0 = _bounds.back(); _bounds.pop_back(); switch (bo.op()) { case BOT_INTERSECT: case BOT_UNION: { IntSetRanges b0r(b0); IntSetRanges b1r(b1); Ranges::Union u(b0r,b1r); _bounds.push_back(IntSetVal::ai(u)); } break; case BOT_DIFF: { _bounds.push_back(b0); } break; case BOT_SYMDIFF: valid = false; _bounds.push_back(NULL); break; case BOT_PLUS: case BOT_MINUS: case BOT_MULT: case BOT_DIV: case BOT_IDIV: case BOT_MOD: case BOT_LE: case BOT_LQ: case BOT_GR: case BOT_GQ: case BOT_EQ: case BOT_NQ: case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: case BOT_PLUSPLUS: case BOT_EQUIV: case BOT_IMPL: case BOT_RIMPL: case BOT_OR: case BOT_AND: case BOT_XOR: case BOT_DOTDOT: valid = false; _bounds.push_back(NULL); } } } /// Visit unary operator void vUnOp(const UnOp& uo) { valid = false; _bounds.push_back(NULL); } /// Visit call void vCall(Call& c) { if (valid && (c.id() == "set_intersect" || c.id() == "set_union")) { IntSetVal* b0 = _bounds.back(); _bounds.pop_back(); IntSetVal* b1 = _bounds.back(); _bounds.pop_back(); IntSetRanges b0r(b0); IntSetRanges b1r(b1); Ranges::Union u(b0r,b1r); _bounds.push_back(IntSetVal::ai(u)); } else if (valid && c.id() == "set_diff") { IntSetVal* b0 = _bounds.back(); _bounds.pop_back(); _bounds.pop_back(); // don't need bounds of right hand side _bounds.push_back(b0); } else { valid = false; _bounds.push_back(NULL); } } /// Visit let void vLet(const Let& l) { valid = false; _bounds.push_back(NULL); } /// Visit variable declaration void vVarDecl(const VarDecl& vd) { valid = false; _bounds.push_back(NULL); } /// Visit annotation void vAnnotation(const Annotation& e) { valid = false; _bounds.push_back(NULL); } /// Visit type inst void vTypeInst(const TypeInst& e) { valid = false; _bounds.push_back(NULL); } /// Visit TIId void vTIId(const TIId& e) { valid = false; _bounds.push_back(NULL); } }; IntSetVal* compute_intset_bounds(EnvI& env, Expression* e) { ComputeIntSetBounds cb(env); BottomUpIterator cbi(cb); cbi.run(e); if (cb.valid) return cb._bounds.back(); else return NULL; } } libminizinc-2.0.11/lib/parser.yxx0000644000175000017500000014724712646030173015375 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ %pure-parser %parse-param {void *parm} %lex-param {void* SCANNER} %{ #define SCANNER static_cast(parm)->yyscanner #include #include #include #include namespace MiniZinc{ class Location; } #define YYLTYPE MiniZinc::Location #define YYLTYPE_IS_DECLARED 1 #define YYLTYPE_IS_TRIVIAL 0 #include #include using namespace std; using namespace MiniZinc; #define YYLLOC_DEFAULT(Current, Rhs, N) \ Current.filename = Rhs[1].filename; \ Current.first_line = Rhs[1].first_line; \ Current.first_column = Rhs[1].first_column; \ Current.last_line = Rhs[N].last_line; \ Current.last_column = Rhs[N].last_column; int yyparse(void*); int yylex(YYSTYPE*, YYLTYPE*, void* scanner); int yylex_init (void** scanner); int yylex_destroy (void* scanner); int yyget_lineno (void* scanner); void yyset_extra (void* user_defined ,void* yyscanner ); extern int yydebug; void yyerror(YYLTYPE* location, void* parm, const string& str) { ParserState* pp = static_cast(parm); Model* m = pp->model; while (m->parent() != NULL) { m = m->parent(); pp->err << "(included from file '" << m->filename() << "')" << endl; } pp->err << location->filename << ":" << location->first_line << ":" << endl; pp->printCurrentLine(); for (int i=0; i(location->first_column)-1; i++) pp->err << " "; for (unsigned int i=location->first_column; i<=location->last_column; i++) pp->err << "^"; pp->err << std::endl << "Error: " << str << std::endl << std::endl; pp->hadError = true; } bool notInDatafile(YYLTYPE* location, void* parm, const string& item) { ParserState* pp = static_cast(parm); if (pp->isDatafile) { yyerror(location,parm,item+" item not allowed in data file"); return false; } return true; } void filepath(const string& f, string& dirname, string& basename) { dirname = ""; basename = f; for (size_t p=basename.find_first_of('/'); p!=string::npos; dirname+=basename.substr(0,p+1), basename=basename.substr(p+1), p=basename.find_first_of('/') ) {} } // fastest way to read a file into a string (especially big files) // see: http://insanecoding.blogspot.be/2011/11/how-to-read-in-file-in-c.html std::string get_file_contents(std::ifstream &in) { if (in) { std::string contents; in.seekg(0, std::ios::end); contents.resize(static_cast(in.tellg())); in.seekg(0, std::ios::beg); in.read(&contents[0], contents.size()); in.close(); return(contents); } throw(errno); } Expression* createDocComment(const Location& loc, const std::string& s) { std::vector args(1); args[0] = new StringLit(loc, s); Call* c = new Call(loc, constants().ann.doc_comment, args); c->type(Type::ann()); return c; } Expression* createArrayAccess(const Location& loc, Expression* e, std::vector >& idx) { Expression* ret = e; for (unsigned int i=0; i& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { GCLock lock; vector includePaths; for (unsigned int i=0; i > files; map seenModels; Model* model = new Model(); model->setFilename(filename); if (!ignoreStdlib) { Model* stdlib = new Model; stdlib->setFilename("stdlib.mzn"); files.push_back(pair("./",stdlib)); seenModels.insert(pair("stdlib.mzn",stdlib)); IncludeI* stdlibinc = new IncludeI(Location(),stdlib->filename()); stdlibinc->m(stdlib,true); model->addItem(stdlibinc); } model->setFilepath(filename); bool isFzn; if (filename=="") { isFzn = false; } else { isFzn = (filename.compare(filename.length()-4,4,".fzn")==0); isFzn |= (filename.compare(filename.length()-4,4,".ozn")==0); isFzn |= (filename.compare(filename.length()-4,4,".szn")==0); } ParserState pp(filename,text, err, files, seenModels, model, false, isFzn, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } while (!files.empty()) { pair& np = files.back(); string parentPath = np.first; Model* m = np.second; files.pop_back(); string f(m->filename().str()); for (Model* p=m->parent(); p; p=p->parent()) { if (f == p->filename().c_str()) { err << "Error: cyclic includes: " << std::endl; for (Model* pe=m; pe; pe=pe->parent()) { err << " " << pe->filename() << std::endl; } goto error; } } ifstream file; string fullname; if (parentPath=="") { fullname = filename; if (FileUtils::file_exists(fullname)) { file.open(fullname.c_str(), std::ios::binary); } } else { includePaths.push_back(parentPath); for (unsigned int i=0; isetFilepath(fullname); bool isFzn = (fullname.compare(fullname.length()-4,4,".fzn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".ozn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".szn")==0); ParserState pp(fullname,s, err, files, seenModels, m, false, isFzn, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } return model; error: for (unsigned int i=0; i& datafiles, const vector& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { GCLock lock; string fileDirname; string fileBasename; filepath(filename, fileDirname, fileBasename); vector includePaths; for (unsigned int i=0; i > files; map seenModels; Model* model = new Model(); model->setFilename(fileBasename); if (!ignoreStdlib) { Model* stdlib = new Model; stdlib->setFilename("stdlib.mzn"); files.push_back(pair("./",stdlib)); seenModels.insert(pair("stdlib.mzn",stdlib)); Location stdlibloc; stdlibloc.filename=ASTString(filename); IncludeI* stdlibinc = new IncludeI(stdlibloc,stdlib->filename()); stdlibinc->m(stdlib,true); model->addItem(stdlibinc); } files.push_back(pair("",model)); while (!files.empty()) { pair& np = files.back(); string parentPath = np.first; Model* m = np.second; files.pop_back(); string f(m->filename().str()); for (Model* p=m->parent(); p; p=p->parent()) { if (f == p->filename().c_str()) { err << "Error: cyclic includes: " << std::endl; for (Model* pe=m; pe; pe=pe->parent()) { err << " " << pe->filename() << std::endl; } goto error; } } ifstream file; string fullname; if (parentPath=="") { fullname = filename; if (FileUtils::file_exists(fullname)) { file.open(fullname.c_str(), std::ios::binary); } } else { includePaths.push_back(parentPath); for (unsigned int i=0; isetFilepath(fullname); bool isFzn = (fullname.compare(fullname.length()-4,4,".fzn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".ozn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".szn")==0); ParserState pp(fullname,s, err, files, seenModels, m, false, isFzn, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } for (unsigned int i=0; i 5 && f.substr(0,5)=="cmd:/") { s = f.substr(5); } else { std::ifstream file; file.open(f.c_str(), std::ios::binary); if (!FileUtils::file_exists(f) || !file.is_open()) { err << "Error: cannot open data file '" << f << "'." << endl; goto error; } if (verbose) std::cerr << "processing data file '" << f << "'" << endl; s = get_file_contents(file); } ParserState pp(f, s, err, files, seenModels, model, true, false, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } return model; error: for (unsigned int i=0; i& datafiles, const vector& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { GCLock lock; vector > files; map seenModels; if (!ignoreStdlib) { Model* stdlib = new Model; stdlib->setFilename("stdlib.mzn"); files.push_back(pair("./",stdlib)); seenModels.insert(pair("stdlib.mzn",stdlib)); IncludeI* stdlibinc = new IncludeI(Location(),stdlib->filename()); stdlibinc->m(stdlib,true); model->addItem(stdlibinc); } while (!files.empty()) { pair& np = files.back(); string parentPath = np.first; Model* m = np.second; files.pop_back(); string f(m->filename().str()); for (Model* p=m->parent(); p; p=p->parent()) { if (f == p->filename().c_str()) { err << "Error: cyclic includes: " << std::endl; for (Model* pe=m; pe; pe=pe->parent()) { err << " " << pe->filename() << std::endl; } goto error; } } ifstream file; string fullname; if (parentPath=="") { err << "Internal error." << std::endl; goto error; } else { for (unsigned int i=0; isetFilepath(fullname); bool isFzn = (fullname.compare(fullname.length()-4,4,".fzn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".ozn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".szn")==0); ParserState pp(fullname,s, err, files, seenModels, m, false, isFzn, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } for (unsigned int i=0; i 5 && f.substr(0,5)=="cmd:/") { s = f.substr(5); } else { std::ifstream file; file.open(f.c_str(), std::ios::binary); if (!FileUtils::file_exists(f) || !file.is_open()) { err << "Error: cannot open data file '" << f << "'." << endl; goto error; } if (verbose) std::cerr << "processing data file '" << f << "'" << endl; s = get_file_contents(file); } ParserState pp(f, s, err, files, seenModels, model, true, false, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } return model; error: for (unsigned int i=0; i* vardeclexpr_v; MiniZinc::TypeInst* tiexpr; std::vector* tiexpr_v; MiniZinc::Expression* expression; std::vector* expression_v; std::vector >* expression_vv; std::vector > >* expression_vvv; MiniZinc::Generator* generator; std::vector* generator_v; std::vector* string_v; std::pair, MiniZinc::Expression*>* expression_p; MiniZinc::Generators* generators; } %locations %error-verbose %initial-action { GCLock lock; @$.filename = ASTString(static_cast(parm)->filename); } %token MZN_INTEGER_LITERAL "integer literal" MZN_BOOL_LITERAL "bool literal" %token MZN_FLOAT_LITERAL "float literal" %token MZN_IDENTIFIER "identifier" MZN_QUOTED_IDENTIFIER "quoted identifier" MZN_STRING_LITERAL "string literal" %token MZN_STRING_QUOTE_START "interpolated string start" MZN_STRING_QUOTE_MID "interpolated string middle" MZN_STRING_QUOTE_END "interpolated string end" %token MZN_TI_IDENTIFIER "type-inst identifier" MZN_DOC_COMMENT "documentation comment" MZN_DOC_FILE_COMMENT "file-level documentation comment" %token MZN_VAR "var" MZN_PAR "par" %token MZN_ABSENT "<>" %token MZN_ANN "ann" %token MZN_ANNOTATION "annotation" %token MZN_ANY "any" %token MZN_ARRAY "array" %token MZN_BOOL "bool" %token MZN_CASE "case" %token MZN_CONSTRAINT "constraint" %token MZN_DEFAULT "default" %token MZN_ELSE "else" %token MZN_ELSEIF "elseif" %token MZN_ENDIF "endif" %token MZN_ENUM "enum" %token MZN_FLOAT "float" %token MZN_FUNCTION "function" %token MZN_IF "if" %token MZN_INCLUDE "include" %token MZN_INFINITY "infinity" %token MZN_INT "int" %token MZN_LET "let" %token MZN_LIST "list" %token MZN_MAXIMIZE "maximize" %token MZN_MINIMIZE "minimize" %token MZN_OF "of" %token MZN_OPT "opt" %token MZN_SATISFY "satisfy" %token MZN_OUTPUT "output" %token MZN_PREDICATE "predicate" %token MZN_RECORD "record" %token MZN_SET "set" %token MZN_SOLVE "solve" %token MZN_STRING "string" %token MZN_TEST "test" %token MZN_THEN "then" %token MZN_TUPLE "tuple" %token MZN_TYPE "type" %token MZN_UNDERSCORE "_" %token MZN_VARIANT_RECORD "variant_record" %token MZN_WHERE "where" %token MZN_LEFT_BRACKET "[" %token MZN_LEFT_2D_BRACKET "[|" %token MZN_RIGHT_BRACKET "]" %token MZN_RIGHT_2D_BRACKET "|]" // Used to signal an error when parsing a MiniZinc file // that contains identifiers starting with _ %token FLATZINC_IDENTIFIER %token MZN_INVALID_INTEGER_LITERAL "invalid integer literal" %token MZN_INVALID_FLOAT_LITERAL "invalid float literal" %token MZN_UNTERMINATED_STRING "unterminated string" %token MZN_INVALID_NULL "null character" %token END 0 "end of file" %token MZN_EQUIV "<->" %token MZN_IMPL "->" MZN_RIMPL "<-" %token MZN_OR "\\/" MZN_XOR "xor" %token MZN_AND "/\\" %token MZN_LE "<" MZN_GR ">" MZN_LQ "<=" MZN_GQ ">=" MZN_EQ "=" MZN_NQ "!=" %token MZN_IN "in" MZN_SUBSET "subset" MZN_SUPERSET "superset" %token MZN_UNION "union" MZN_DIFF "diff" MZN_SYMDIFF "symdiff" %token MZN_DOTDOT ".." %token MZN_PLUS "+" MZN_MINUS "-" %token MZN_MULT "*" MZN_DIV "/" MZN_IDIV "div" MZN_MOD "mod" MZN_INTERSECT "intersect" %token MZN_NOT "not" %token MZN_PLUSPLUS "++" %token MZN_COLONCOLON "::" %right PREC_ANNO %left MZN_EQUIV %left MZN_IMPL MZN_RIMPL %left MZN_OR MZN_XOR %left MZN_AND %nonassoc MZN_LE MZN_GR MZN_LQ MZN_GQ MZN_EQ MZN_NQ %nonassoc MZN_IN MZN_SUBSET MZN_SUPERSET %left MZN_UNION MZN_DIFF MZN_SYMDIFF MZN_INTERSECT %nonassoc MZN_DOTDOT %left MZN_PLUS MZN_MINUS %left MZN_MULT MZN_DIV MZN_IDIV MZN_MOD %nonassoc MZN_NOT %left MZN_PLUSPLUS %left MZN_QUOTED_IDENTIFIER %left MZN_COLONCOLON %token MZN_EQUIV_QUOTED "'<->'" %token MZN_IMPL_QUOTED "'->'" MZN_RIMPL_QUOTED "'<-'" %token MZN_OR_QUOTED "'\\/'" MZN_XOR_QUOTED "'xor'" %token MZN_AND_QUOTED "'/\\'" %token MZN_LE_QUOTED "'<'" MZN_GR_QUOTED "'>'" MZN_LQ_QUOTED "'<='" MZN_GQ_QUOTED "'>='" MZN_EQ_QUOTED "'='" MZN_NQ_QUOTED "'!='" %token MZN_IN_QUOTED "'in'" MZN_SUBSET_QUOTED "'subset'" MZN_SUPERSET_QUOTED "'superset'" %token MZN_UNION_QUOTED "'union'" MZN_DIFF_QUOTED "'diff'" MZN_SYMDIFF_QUOTED "'symdiff'" %token MZN_DOTDOT_QUOTED "'..'" %token MZN_PLUS_QUOTED "'+'" MZN_MINUS_QUOTED "'-'" %token MZN_MULT_QUOTED "'*'" MZN_DIV_QUOTED "'/'" MZN_IDIV_QUOTED "'div'" MZN_MOD_QUOTED "'mod'" MZN_INTERSECT_QUOTED "'intersect'" %token MZN_NOT_QUOTED "'not'" %token MZN_COLONCOLON_QUOTED "'::'" %token MZN_PLUSPLUS_QUOTED "'++'" %type item item_tail include_item vardecl_item assign_item constraint_item solve_item output_item predicate_item annotation_item function_item %type ti_expr_and_id ti_expr_and_id_or_anon let_vardecl_item %type params params_list params_list_head %type ti_expr base_ti_expr base_ti_expr_tail %type ti_expr_list ti_expr_list_head %type expr expr_atom_head %type set_expr string_expr string_quote_rest %type simple_array_literal simple_array_literal_2d simple_array_comp if_then_else_expr call_expr quoted_op_call let_expr operation_item_tail set_literal set_comp %type expr_list expr_list_head elseif_list let_vardecl_item_list %type simple_array_literal_2d_list array_access_tail %type simple_array_literal_3d_list %type comp_tail %type generator %type generator_list generator_list_head %type id_list id_list_head %type comp_or_expr %type annotations ne_annotations %type quoted_op %type id_or_quoted_op %type opt_opt %% /********************************/ /* main goal and item lists */ /********************************/ model : item_list item_list : /* empty */ | item_list_head semi_or_none item_list_head: item { ParserState* pp = static_cast(parm); if ($1) pp->model->addItem($1); } | doc_file_comments item { ParserState* pp = static_cast(parm); if ($2) pp->model->addItem($2); } | item_list_head ';' item { ParserState* pp = static_cast(parm); if ($3) pp->model->addItem($3); } | item_list_head ';' doc_file_comments item { ParserState* pp = static_cast(parm); if ($4) pp->model->addItem($4); } | error ';' item doc_file_comments: MZN_DOC_FILE_COMMENT { ParserState* pp = static_cast(parm); if (pp->parseDocComments && $1) { pp->model->addDocComment($1); } free($1); } | doc_file_comments MZN_DOC_FILE_COMMENT { ParserState* pp = static_cast(parm); if (pp->parseDocComments && $2) { pp->model->addDocComment($2); } free($2); } semi_or_none : | ';' item : MZN_DOC_COMMENT item_tail { $$ = $2; ParserState* pp = static_cast(parm); if (FunctionI* fi = Item::dyn_cast($$)) { if (pp->parseDocComments) { fi->ann().add(createDocComment(@1,$1)); } } else if (VarDeclI* vdi = Item::dyn_cast($$)) { if (pp->parseDocComments) { vdi->e()->addAnnotation(createDocComment(@1,$1)); } } else { yyerror(&@2, parm, "documentation comments are only supported for function, predicate and variable declarations"); } free($1); } | item_tail { $$ = $1; } item_tail : include_item { $$=notInDatafile(&@$,parm,"include") ? $1 : NULL; } | vardecl_item { $$=notInDatafile(&@$,parm,"variable declaration") ? $1 : NULL; } | assign_item | constraint_item { $$=notInDatafile(&@$,parm,"constraint") ? $1 : NULL; } | solve_item { $$=notInDatafile(&@$,parm,"solve") ? $1 : NULL; } | output_item { $$=notInDatafile(&@$,parm,"output") ? $1 : NULL; } | predicate_item { $$=notInDatafile(&@$,parm,"predicate") ? $1 : NULL; } | function_item { $$=notInDatafile(&@$,parm,"predicate") ? $1 : NULL; } | annotation_item { $$=notInDatafile(&@$,parm,"annotation") ? $1 : NULL; } include_item : MZN_INCLUDE MZN_STRING_LITERAL { ParserState* pp = static_cast(parm); map::iterator ret = pp->seenModels.find($2); IncludeI* ii = new IncludeI(@$,ASTString($2)); $$ = ii; if (ret == pp->seenModels.end()) { Model* im = new Model; im->setParent(pp->model); im->setFilename($2); string fpath, fbase; filepath(pp->filename, fpath, fbase); if (fpath=="") fpath="./"; pair pm(fpath, im); pp->files.push_back(pm); ii->m(im); pp->seenModels.insert(pair($2,im)); } else { ii->m(ret->second, false); } free($2); } vardecl_item : ti_expr_and_id annotations { if ($1 && $2) $1->addAnnotations(*$2); if ($1) $$ = new VarDeclI(@$,$1); delete $2; } | ti_expr_and_id annotations MZN_EQ expr { if ($1) $1->e($4); if ($1 && $2) $1->addAnnotations(*$2); if ($1) $$ = new VarDeclI(@$,$1); delete $2; } assign_item : MZN_IDENTIFIER MZN_EQ expr { $$ = new AssignI(@$,$1,$3); free($1); } constraint_item : MZN_CONSTRAINT expr { $$ = new ConstraintI(@$,$2);} solve_item : MZN_SOLVE annotations MZN_SATISFY { $$ = SolveI::sat(@$); if ($$ && $2) $$->cast()->ann().add(*$2); delete $2; } | MZN_SOLVE annotations MZN_MINIMIZE expr { $$ = SolveI::min(@$,$4); if ($$ && $2) $$->cast()->ann().add(*$2); delete $2; } | MZN_SOLVE annotations MZN_MAXIMIZE expr { $$ = SolveI::max(@$,$4); if ($$ && $2) $$->cast()->ann().add(*$2); delete $2; } output_item : MZN_OUTPUT expr { $$ = new OutputI(@$,$2);} predicate_item : MZN_PREDICATE MZN_IDENTIFIER params annotations operation_item_tail { if ($3) $$ = new FunctionI(@$,$2,new TypeInst(@$, Type::varbool()),*$3,$5); if ($$ && $4) $$->cast()->ann().add(*$4); free($2); delete $3; delete $4; } | MZN_TEST MZN_IDENTIFIER params annotations operation_item_tail { if ($3) $$ = new FunctionI(@$,$2,new TypeInst(@$, Type::parbool()),*$3,$5); if ($$ && $4) $$->cast()->ann().add(*$4); free($2); delete $3; delete $4; } function_item : MZN_FUNCTION ti_expr ':' id_or_quoted_op params annotations operation_item_tail { if ($5) $$ = new FunctionI(@$,$4,$2,*$5,$7); if ($$ && $6) $$->cast()->ann().add(*$6); free($4); delete $5; delete $6; } | ti_expr ':' MZN_IDENTIFIER '(' params_list ')' annotations operation_item_tail { if ($5) $$ = new FunctionI(@$,$3,$1,*$5,$8); if ($$ && $7) $$->cast()->ann().add(*$7); free($3); delete $5; delete $7; } annotation_item : MZN_ANNOTATION MZN_IDENTIFIER params { TypeInst* ti=new TypeInst(@1,Type::ann()); if ($3==NULL || $3->empty()) { VarDecl* vd = new VarDecl(@$,ti,$2); $$ = new VarDeclI(@$,vd); } else { $$ = new FunctionI(@$,$2,ti,*$3,NULL); } free($2); delete $3; } | MZN_ANNOTATION MZN_IDENTIFIER params MZN_EQ expr { TypeInst* ti=new TypeInst(@1,Type::ann()); if ($3) $$ = new FunctionI(@$,$2,ti,*$3,$5); delete $3; } operation_item_tail : /*empty*/ { $$=NULL; } | MZN_EQ expr { $$=$2; } params : /* empty */ { $$=new vector(); } | '(' params_list ')' { $$=$2; } | '(' error ')' { $$=new vector(); } params_list : /* empty */ { $$=new vector(); } | params_list_head comma_or_none { $$=$1; } params_list_head : ti_expr_and_id_or_anon { $$=new vector(); if ($1) $1->toplevel(false); if ($1) $$->push_back($1); } | params_list_head ',' ti_expr_and_id_or_anon { $$=$1; if ($3) $3->toplevel(false); if ($1 && $3) $1->push_back($3); } comma_or_none : | ',' ti_expr_and_id_or_anon : ti_expr_and_id { $$=$1; } | ti_expr { if ($1) $$=new VarDecl(@$, $1, ""); } ti_expr_and_id : ti_expr ':' MZN_IDENTIFIER { if ($1 && $3) $$ = new VarDecl(@$, $1, $3); free($3); } ti_expr_list : ti_expr_list_head comma_or_none { $$=$1; } ti_expr_list_head : ti_expr { $$=new vector(); $$->push_back($1); } | ti_expr_list_head ',' ti_expr { $$=$1; if ($1 && $3) $1->push_back($3); } ti_expr : base_ti_expr | MZN_ARRAY MZN_LEFT_BRACKET ti_expr_list MZN_RIGHT_BRACKET MZN_OF base_ti_expr { $$ = $6; if ($$ && $3) $$->setRanges(*$3); delete $3; } | MZN_LIST MZN_OF base_ti_expr { $$ = $3; std::vector ti(1); ti[0] = new TypeInst(@$,Type::parint()); if ($$) $$->setRanges(ti); } base_ti_expr : base_ti_expr_tail { $$ = $1; } | MZN_OPT base_ti_expr_tail { $$ = $2; if ($$) { Type tt = $$->type(); tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | MZN_PAR opt_opt base_ti_expr_tail { $$ = $3; if ($$ && $2) { Type tt = $$->type(); tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | MZN_VAR opt_opt base_ti_expr_tail { $$ = $3; if ($$) { Type tt = $$->type(); tt.ti(Type::TI_VAR); if ($2) tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | opt_opt MZN_SET MZN_OF base_ti_expr_tail { $$ = $4; if ($$) { Type tt = $$->type(); tt.st(Type::ST_SET); if ($1) tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | MZN_PAR opt_opt MZN_SET MZN_OF base_ti_expr_tail { $$ = $5; if ($$) { Type tt = $$->type(); tt.st(Type::ST_SET); if ($2) tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | MZN_VAR opt_opt MZN_SET MZN_OF base_ti_expr_tail { $$ = $5; if ($$) { Type tt = $$->type(); tt.ti(Type::TI_VAR); tt.st(Type::ST_SET); if ($2) tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } opt_opt: /* nothing */ { $$ = false; } | MZN_OPT { $$ = true; } base_ti_expr_tail : MZN_INT { $$ = new TypeInst(@$,Type::parint()); } | MZN_BOOL { $$ = new TypeInst(@$,Type::parbool()); } | MZN_FLOAT { $$ = new TypeInst(@$,Type::parfloat()); } | MZN_STRING { $$ = new TypeInst(@$,Type::parstring()); } | MZN_ANN { $$ = new TypeInst(@$,Type::ann()); } | set_expr { if ($1) $$ = new TypeInst(@$,Type(),$1); } | MZN_TI_IDENTIFIER { $$ = new TypeInst(@$,Type::top(), new TIId(@$, $1)); free($1); } expr_list : expr_list_head comma_or_none expr_list_head : expr { $$=new std::vector; $$->push_back($1); } | expr_list_head ',' expr { $$=$1; if ($$ && $3) $$->push_back($3); } /// set_expr : expr_atom_head | set_expr MZN_COLONCOLON expr_atom_head { if ($1 && $3) $1->addAnnotation($3); $$=$1; } | set_expr MZN_UNION set_expr { $$=new BinOp(@$, $1, BOT_UNION, $3); } | set_expr MZN_DIFF set_expr { $$=new BinOp(@$, $1, BOT_DIFF, $3); } | set_expr MZN_SYMDIFF set_expr { $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); } | set_expr MZN_DOTDOT set_expr { if ($1==NULL || $3==NULL) { $$ = NULL; } else if ($1->isa() && $3->isa()) { $$=new SetLit(@$, IntSetVal::a($1->cast()->v(),$3->cast()->v())); } else { $$=new BinOp(@$, $1, BOT_DOTDOT, $3); } } | MZN_DOTDOT_QUOTED '(' expr ',' expr ')' { if ($3==NULL || $5==NULL) { $$ = NULL; } else if ($3->isa() && $5->isa()) { $$=new SetLit(@$, IntSetVal::a($3->cast()->v(),$5->cast()->v())); } else { $$=new BinOp(@$, $3, BOT_DOTDOT, $5); } } | set_expr MZN_INTERSECT set_expr { $$=new BinOp(@$, $1, BOT_INTERSECT, $3); } | set_expr MZN_PLUSPLUS set_expr { $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); } | set_expr MZN_PLUS set_expr { $$=new BinOp(@$, $1, BOT_PLUS, $3); } | set_expr MZN_MINUS set_expr { $$=new BinOp(@$, $1, BOT_MINUS, $3); } | set_expr MZN_MULT set_expr { $$=new BinOp(@$, $1, BOT_MULT, $3); } | set_expr MZN_DIV set_expr { $$=new BinOp(@$, $1, BOT_DIV, $3); } | set_expr MZN_IDIV set_expr { $$=new BinOp(@$, $1, BOT_IDIV, $3); } | set_expr MZN_MOD set_expr { $$=new BinOp(@$, $1, BOT_MOD, $3); } | set_expr MZN_QUOTED_IDENTIFIER set_expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, $2, args); free($2); } | MZN_PLUS set_expr %prec MZN_NOT { $$=new UnOp(@$, UOT_PLUS, $2); } | MZN_MINUS set_expr %prec MZN_NOT { if ($2 && $2->isa()) { $2->cast()->v(-$2->cast()->v()); $$ = $2; } else if ($2 && $2->isa()) { $2->cast()->v(-$2->cast()->v()); $$ = $2; } else { $$=new UnOp(@$, UOT_MINUS, $2); } } /// expr : expr_atom_head | expr MZN_COLONCOLON expr_atom_head { if ($1 && $3) $1->addAnnotation($3); $$=$1; } | expr MZN_EQUIV expr { $$=new BinOp(@$, $1, BOT_EQUIV, $3); } | expr MZN_IMPL expr { $$=new BinOp(@$, $1, BOT_IMPL, $3); } | expr MZN_RIMPL expr { $$=new BinOp(@$, $1, BOT_RIMPL, $3); } | expr MZN_OR expr { $$=new BinOp(@$, $1, BOT_OR, $3); } | expr MZN_XOR expr { $$=new BinOp(@$, $1, BOT_XOR, $3); } | expr MZN_AND expr { $$=new BinOp(@$, $1, BOT_AND, $3); } | expr MZN_LE expr { $$=new BinOp(@$, $1, BOT_LE, $3); } | expr MZN_GR expr { $$=new BinOp(@$, $1, BOT_GR, $3); } | expr MZN_LQ expr { $$=new BinOp(@$, $1, BOT_LQ, $3); } | expr MZN_GQ expr { $$=new BinOp(@$, $1, BOT_GQ, $3); } | expr MZN_EQ expr { $$=new BinOp(@$, $1, BOT_EQ, $3); } | expr MZN_NQ expr { $$=new BinOp(@$, $1, BOT_NQ, $3); } | expr MZN_IN expr { $$=new BinOp(@$, $1, BOT_IN, $3); } | expr MZN_SUBSET expr { $$=new BinOp(@$, $1, BOT_SUBSET, $3); } | expr MZN_SUPERSET expr { $$=new BinOp(@$, $1, BOT_SUPERSET, $3); } | expr MZN_UNION expr { $$=new BinOp(@$, $1, BOT_UNION, $3); } | expr MZN_DIFF expr { $$=new BinOp(@$, $1, BOT_DIFF, $3); } | expr MZN_SYMDIFF expr { $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); } | expr MZN_DOTDOT expr { if ($1==NULL || $3==NULL) { $$ = NULL; } else if ($1->isa() && $3->isa()) { $$=new SetLit(@$, IntSetVal::a($1->cast()->v(),$3->cast()->v())); } else { $$=new BinOp(@$, $1, BOT_DOTDOT, $3); } } | MZN_DOTDOT_QUOTED '(' expr ',' expr ')' { if ($3==NULL || $5==NULL) { $$ = NULL; } else if ($3->isa() && $5->isa()) { $$=new SetLit(@$, IntSetVal::a($3->cast()->v(),$5->cast()->v())); } else { $$=new BinOp(@$, $3, BOT_DOTDOT, $5); } } | expr MZN_INTERSECT expr { $$=new BinOp(@$, $1, BOT_INTERSECT, $3); } | expr MZN_PLUSPLUS expr { $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); } | expr MZN_PLUS expr { $$=new BinOp(@$, $1, BOT_PLUS, $3); } | expr MZN_MINUS expr { $$=new BinOp(@$, $1, BOT_MINUS, $3); } | expr MZN_MULT expr { $$=new BinOp(@$, $1, BOT_MULT, $3); } | expr MZN_DIV expr { $$=new BinOp(@$, $1, BOT_DIV, $3); } | expr MZN_IDIV expr { $$=new BinOp(@$, $1, BOT_IDIV, $3); } | expr MZN_MOD expr { $$=new BinOp(@$, $1, BOT_MOD, $3); } | expr MZN_QUOTED_IDENTIFIER expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, $2, args); free($2); } | MZN_NOT expr %prec MZN_NOT { $$=new UnOp(@$, UOT_NOT, $2); } | MZN_PLUS expr %prec MZN_NOT { if (($2 && $2->isa()) || ($2 && $2->isa())) { $$ = $2; } else { $$=new UnOp(@$, UOT_PLUS, $2); } } | MZN_MINUS expr %prec MZN_NOT { if ($2 && $2->isa()) { $2->cast()->v(-$2->cast()->v()); $$ = $2; } else if ($2 && $2->isa()) { $2->cast()->v(-$2->cast()->v()); $$ = $2; } else { $$=new UnOp(@$, UOT_MINUS, $2); } } expr_atom_head : '(' expr ')' { $$=$2; } | '(' expr ')' array_access_tail { if ($4) $$=createArrayAccess(@$, $2, *$4); delete $4; } | MZN_IDENTIFIER { $$=new Id(@$, $1, NULL); free($1); } | MZN_IDENTIFIER array_access_tail { if ($2) $$=createArrayAccess(@$, new Id(@1,$1,NULL), *$2); free($1); delete $2; } | MZN_UNDERSCORE { $$=new AnonVar(@$); } | MZN_UNDERSCORE array_access_tail { if ($2) $$=createArrayAccess(@$, new AnonVar(@$), *$2); delete $2; } | MZN_BOOL_LITERAL { $$=constants().boollit(($1!=0)); } | MZN_INTEGER_LITERAL { $$=new IntLit(@$, $1); } | MZN_INFINITY { $$=new IntLit(@$, IntVal::infinity()); } | MZN_FLOAT_LITERAL { $$=new FloatLit(@$, $1); } | string_expr | MZN_ABSENT { $$=constants().absent; } | set_literal | set_literal array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | set_comp | set_comp array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | simple_array_literal | simple_array_literal array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | simple_array_literal_2d | simple_array_literal_2d array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | simple_array_comp | simple_array_comp array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | if_then_else_expr | if_then_else_expr array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | let_expr | call_expr | call_expr array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } string_expr: MZN_STRING_LITERAL { $$=new StringLit(@$, $1); free($1); } | MZN_STRING_QUOTE_START string_quote_rest { $$=new BinOp(@$, new StringLit(@$, $1), BOT_PLUSPLUS, $2); free($1); } string_quote_rest: expr_list_head MZN_STRING_QUOTE_END { if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS, new StringLit(@$,$2)); free($2); delete $1; } | expr_list_head MZN_STRING_QUOTE_MID string_quote_rest { if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS, new BinOp(@$, new StringLit(@$,$2), BOT_PLUSPLUS, $3)); free($2); delete $1; } array_access_tail : MZN_LEFT_BRACKET expr_list MZN_RIGHT_BRACKET { $$=new std::vector >(); if ($2) { $$->push_back(*$2); delete $2; } } | array_access_tail MZN_LEFT_BRACKET expr_list MZN_RIGHT_BRACKET { $$=$1; if ($$ && $3) { $$->push_back(*$3); delete $3; } } set_literal : '{' '}' { $$ = new SetLit(@$, std::vector()); } | '{' expr_list '}' { if ($2) $$ = new SetLit(@$, *$2); delete $2; } set_comp : '{' expr '|' comp_tail '}' { if ($4) $$ = new Comprehension(@$, $2, *$4, true); delete $4; } comp_tail : generator_list { if ($1) $$=new Generators; $$->_g = *$1; $$->_w = NULL; delete $1; } | generator_list MZN_WHERE expr { if ($1) $$=new Generators; $$->_g = *$1; $$->_w = $3; delete $1; } generator_list : generator_list_head comma_or_none generator_list_head : generator { $$=new std::vector; if ($1) $$->push_back(*$1); delete $1; } | generator_list_head ',' generator { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; } generator : id_list MZN_IN expr { if ($1 && $3) $$=new Generator(*$1,$3); else $$=NULL; delete $1; } id_list : id_list_head comma_or_none id_list_head : MZN_IDENTIFIER { $$=new std::vector; $$->push_back($1); free($1); } | id_list_head ',' MZN_IDENTIFIER { $$=$1; if ($$ && $3) $$->push_back($3); free($3); } simple_array_literal : MZN_LEFT_BRACKET MZN_RIGHT_BRACKET { $$=new ArrayLit(@$, std::vector()); } | MZN_LEFT_BRACKET expr_list MZN_RIGHT_BRACKET { if ($2) $$=new ArrayLit(@$, *$2); delete $2; } simple_array_literal_2d : MZN_LEFT_2D_BRACKET MZN_RIGHT_2D_BRACKET { $$=new ArrayLit(@$, std::vector >()); } | MZN_LEFT_2D_BRACKET simple_array_literal_2d_list MZN_RIGHT_2D_BRACKET { if ($2) { $$=new ArrayLit(@$, *$2); for (unsigned int i=1; i<$2->size(); i++) if ((*$2)[i].size() != (*$2)[i-1].size()) yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length"); delete $2; } else { $$ = NULL; } } | MZN_LEFT_2D_BRACKET simple_array_literal_2d_list '|' MZN_RIGHT_2D_BRACKET { if ($2) { $$=new ArrayLit(@$, *$2); for (unsigned int i=1; i<$2->size(); i++) if ((*$2)[i].size() != (*$2)[i-1].size()) yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length"); delete $2; } else { $$ = NULL; } } | MZN_LEFT_2D_BRACKET simple_array_literal_3d_list MZN_RIGHT_2D_BRACKET { if ($2) { std::vector > dims(3); dims[0] = std::pair(1,$2->size()); if ($2->size()==0) { dims[1] = std::pair(1,0); dims[2] = std::pair(1,0); } else { dims[1] = std::pair(1,(*$2)[0].size()); if ((*$2)[0].size()==0) { dims[2] = std::pair(1,0); } else { dims[2] = std::pair(1,(*$2)[0][0].size()); } } std::vector a; for (unsigned int i=0; i > >; } | '|' simple_array_literal_2d_list '|' { $$=new std::vector > >; if ($2) $$->push_back(*$2); delete $2; } | simple_array_literal_3d_list ',' '|' simple_array_literal_2d_list '|' { $$=$1; if ($$ && $4) $$->push_back(*$4); delete $4; } simple_array_literal_2d_list : expr_list { $$=new std::vector >; if ($1) $$->push_back(*$1); delete $1; } | simple_array_literal_2d_list '|' expr_list { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; } simple_array_comp : MZN_LEFT_BRACKET expr '|' comp_tail MZN_RIGHT_BRACKET { if ($4) $$=new Comprehension(@$, $2, *$4, false); delete $4; } if_then_else_expr : MZN_IF expr MZN_THEN expr elseif_list MZN_ELSE expr MZN_ENDIF { std::vector iexps; iexps.push_back($2); iexps.push_back($4); if ($5) { for (unsigned int i=0; i<$5->size(); i+=2) { iexps.push_back((*$5)[i]); iexps.push_back((*$5)[i+1]); } } $$=new ITE(@$, iexps,$7); delete $5; } elseif_list : { $$=new std::vector; } | elseif_list MZN_ELSEIF expr MZN_THEN expr { $$=$1; if ($$ && $3 && $5) { $$->push_back($3); $$->push_back($5); } } quoted_op : MZN_EQUIV_QUOTED { $$=BOT_EQUIV; } | MZN_IMPL_QUOTED { $$=BOT_IMPL; } | MZN_RIMPL_QUOTED { $$=BOT_RIMPL; } | MZN_OR_QUOTED { $$=BOT_OR; } | MZN_XOR_QUOTED { $$=BOT_XOR; } | MZN_AND_QUOTED { $$=BOT_AND; } | MZN_LE_QUOTED { $$=BOT_LE; } | MZN_GR_QUOTED { $$=BOT_GR; } | MZN_LQ_QUOTED { $$=BOT_LQ; } | MZN_GQ_QUOTED { $$=BOT_GQ; } | MZN_EQ_QUOTED { $$=BOT_EQ; } | MZN_NQ_QUOTED { $$=BOT_NQ; } | MZN_IN_QUOTED { $$=BOT_IN; } | MZN_SUBSET_QUOTED { $$=BOT_SUBSET; } | MZN_SUPERSET_QUOTED { $$=BOT_SUPERSET; } | MZN_UNION_QUOTED { $$=BOT_UNION; } | MZN_DIFF_QUOTED { $$=BOT_DIFF; } | MZN_SYMDIFF_QUOTED { $$=BOT_SYMDIFF; } | MZN_PLUS_QUOTED { $$=BOT_PLUS; } | MZN_MINUS_QUOTED { $$=BOT_MINUS; } | MZN_MULT_QUOTED { $$=BOT_MULT; } | MZN_DIV_QUOTED { $$=BOT_DIV; } | MZN_IDIV_QUOTED { $$=BOT_IDIV; } | MZN_MOD_QUOTED { $$=BOT_MOD; } | MZN_INTERSECT_QUOTED { $$=BOT_INTERSECT; } | MZN_PLUSPLUS_QUOTED { $$=BOT_PLUSPLUS; } | MZN_NOT_QUOTED { $$=-1; } quoted_op_call : quoted_op '(' expr ',' expr ')' { if ($1==-1) { $$=NULL; yyerror(&@3, parm, "syntax error, unary operator with two arguments"); } else { $$=new BinOp(@$, $3,static_cast($1),$5); } } | quoted_op '(' expr ')' { int uot=-1; switch ($1) { case -1: uot = UOT_NOT; break; case BOT_MINUS: uot = UOT_MINUS; break; case BOT_PLUS: uot = UOT_PLUS; break; default: yyerror(&@3, parm, "syntax error, binary operator with unary argument list"); break; } if (uot==-1) $$=NULL; else { if (uot==UOT_PLUS && $3 && ($3->isa() || $3->isa())) { $$ = $3; } else if (uot==UOT_MINUS && $3 && $3->isa()) { $3->cast()->v(-$3->cast()->v()); $$ = $3; } else if (uot==UOT_MINUS && $3 && $3->isa()) { $3->cast()->v(-$3->cast()->v()); $$ = $3; } else { $$=new UnOp(@$, static_cast(uot),$3); } } } call_expr : MZN_IDENTIFIER '(' ')' { $$=new Call(@$, $1, std::vector()); free($1); } | quoted_op_call | MZN_IDENTIFIER '(' comp_or_expr ')' { if ($3==NULL || $3->second) { yyerror(&@3, parm, "syntax error, 'where' expression outside generator call"); $$=NULL; } else { $$=new Call(@$, $1, $3->first); } free($1); delete $3; } | MZN_IDENTIFIER '(' comp_or_expr ')' '(' expr ')' { vector gens; vector ids; if ($3) { for (unsigned int i=0; i<$3->first.size(); i++) { if (Id* id = Expression::dyn_cast($3->first[i])) { ids.push_back(id->v()); } else { if (BinOp* boe = Expression::dyn_cast($3->first[i])) { if (boe->lhs() && boe->rhs()) { Id* id = Expression::dyn_cast(boe->lhs()); if (id && boe->op() == BOT_IN) { ids.push_back(id->v()); gens.push_back(Generator(ids,boe->rhs())); ids = vector(); } else { yyerror(&@3, parm, "illegal expression in generator call"); } } } else { yyerror(&@3, parm, "illegal expression in generator call"); } } } } if (ids.size() != 0) { yyerror(&@3, parm, "illegal expression in generator call"); } ParserState* pp = static_cast(parm); if (pp->hadError) { $$=NULL; } else { Generators g; g._g = gens; g._w = $3->second; Comprehension* ac = new Comprehension(@$, $6,g,false); vector args; args.push_back(ac); $$=new Call(@$, $1, args); } free($1); delete $3; } comp_or_expr : expr_list { $$=new pair,Expression*>; if ($1) $$->first=*$1; $$->second=NULL; delete $1; } | expr_list MZN_WHERE expr { $$=new pair,Expression*>; if ($1) $$->first=*$1; $$->second=$3; delete $1; } let_expr : MZN_LET '{' let_vardecl_item_list '}' MZN_IN expr %prec PREC_ANNO { if ($3 && $6) { $$=new Let(@$, *$3, $6); delete $3; } else { $$=NULL; } } | MZN_LET '{' let_vardecl_item_list comma_or_semi '}' MZN_IN expr %prec PREC_ANNO { if ($3 && $7) { $$=new Let(@$, *$3, $7); delete $3; } else { $$=NULL; } } let_vardecl_item_list : let_vardecl_item { $$=new vector; $$->push_back($1); } | constraint_item { $$=new vector; if ($1) { ConstraintI* ce = $1->cast(); $$->push_back(ce->e()); ce->e(NULL); } } | let_vardecl_item_list comma_or_semi let_vardecl_item { $$=$1; if ($$ && $3) $$->push_back($3); } | let_vardecl_item_list comma_or_semi constraint_item { $$=$1; if ($$ && $3) { ConstraintI* ce = $3->cast(); $$->push_back(ce->e()); ce->e(NULL); } } comma_or_semi : ',' | ';' let_vardecl_item : ti_expr_and_id annotations { $$ = $1; if ($$) $$->toplevel(false); if ($$ && $2) $$->addAnnotations(*$2); delete $2; } | ti_expr_and_id annotations MZN_EQ expr { if ($1) $1->e($4); $$ = $1; if ($$) $$->loc(@$); if ($$) $$->toplevel(false); if ($$ && $2) $$->addAnnotations(*$2); delete $2; } annotations : /* empty */ { $$=NULL; } | ne_annotations ne_annotations : MZN_COLONCOLON expr_atom_head { $$=new std::vector(1); (*$$)[0] = $2; } | ne_annotations MZN_COLONCOLON expr_atom_head { $$=$1; if ($$) $$->push_back($3); } id_or_quoted_op : MZN_IDENTIFIER { $$=$1; } | MZN_EQUIV_QUOTED { $$=strdup("'<->'"); } | MZN_IMPL_QUOTED { $$=strdup("'->'"); } | MZN_RIMPL_QUOTED { $$=strdup("'<-'"); } | MZN_OR_QUOTED { $$=strdup("'\\/'"); } | MZN_XOR_QUOTED { $$=strdup("'xor'"); } | MZN_AND_QUOTED { $$=strdup("'/\\'"); } | MZN_LE_QUOTED { $$=strdup("'<'"); } | MZN_GR_QUOTED { $$=strdup("'>'"); } | MZN_LQ_QUOTED { $$=strdup("'<='"); } | MZN_GQ_QUOTED { $$=strdup("'>='"); } | MZN_EQ_QUOTED { $$=strdup("'='"); } | MZN_NQ_QUOTED { $$=strdup("'!='"); } | MZN_IN_QUOTED { $$=strdup("'in'"); } | MZN_SUBSET_QUOTED { $$=strdup("'subset'"); } | MZN_SUPERSET_QUOTED { $$=strdup("'superset'"); } | MZN_UNION_QUOTED { $$=strdup("'union'"); } | MZN_DIFF_QUOTED { $$=strdup("'diff'"); } | MZN_SYMDIFF_QUOTED { $$=strdup("'symdiff'"); } | MZN_DOTDOT_QUOTED { $$=strdup("'..'"); } | MZN_PLUS_QUOTED { $$=strdup("'+'"); } | MZN_MINUS_QUOTED { $$=strdup("'-'"); } | MZN_MULT_QUOTED { $$=strdup("'*'"); } | MZN_DIV_QUOTED { $$=strdup("'/'"); } | MZN_IDIV_QUOTED { $$=strdup("'div'"); } | MZN_MOD_QUOTED { $$=strdup("'mod'"); } | MZN_INTERSECT_QUOTED { $$=strdup("'intersect'"); } | MZN_NOT_QUOTED { $$=strdup("'not'"); } | MZN_PLUSPLUS_QUOTED { $$=strdup("'++'"); } libminizinc-2.0.11/lib/values.cpp0000644000175000017500000000132712646030173015316 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include namespace MiniZinc { const IntVal IntVal::minint(void) { return IntVal(INT_MIN); } const IntVal IntVal::maxint(void) { return IntVal(INT_MAX); } const IntVal IntVal::infinity(void) { return IntVal(1,true); } IntSetVal::IntSetVal(IntVal m, IntVal n) : ASTChunk(sizeof(Range)) { get(0).min = m; get(0).max = n; } }libminizinc-2.0.11/lib/typecheck.cpp0000644000175000017500000011537712646030173016011 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include #include #include #include namespace MiniZinc { struct VarDeclCmp { UNORDERED_NAMESPACE::unordered_map& _pos; VarDeclCmp(UNORDERED_NAMESPACE::unordered_map& pos) : _pos(pos) {} bool operator()(Expression* e0, Expression* e1) { if (VarDecl* vd0 = Expression::dyn_cast(e0)) { if (VarDecl* vd1 = Expression::dyn_cast(e1)) { return _pos[vd0] < _pos[vd1]; } else { return true; } } else { return false; } } }; struct ItemCmp { UNORDERED_NAMESPACE::unordered_map& _pos; ItemCmp(UNORDERED_NAMESPACE::unordered_map& pos) : _pos(pos) {} bool operator()(Item* i0, Item* i1) { if (VarDeclI* vd0 = i0->cast()) { if (VarDeclI* vd1 = i1->cast()) { return _pos[vd0->e()] < _pos[vd1->e()]; } else { return true; } } else { return false; } } }; void TopoSorter::add(EnvI& env, VarDecl* vd, bool unique) { DeclMap::iterator vdi = idmap.find(vd->id()); if (vdi == idmap.end()) { Decls nd; nd.push_back(vd); idmap.insert(vd->id(),nd); } else { if (unique) { GCLock lock; throw TypeError(env, vd->loc(),"identifier `"+vd->id()->str().str()+ "' already defined"); } vdi->second.push_back(vd); } } void TopoSorter::remove(EnvI& env, VarDecl* vd) { DeclMap::iterator vdi = idmap.find(vd->id()); assert(vdi != idmap.end()); vdi->second.pop_back(); if (vdi->second.empty()) idmap.remove(vd->id()); } VarDecl* TopoSorter::get(EnvI& env, const ASTString& id_v, const Location& loc) { GCLock lock; Id* id = new Id(Location(), id_v, NULL); DeclMap::iterator decl = idmap.find(id); if (decl==idmap.end()) { GCLock lock; throw TypeError(env,loc,"undefined identifier `"+id->str().str()+"'"); } return decl->second.back(); } VarDecl* TopoSorter::checkId(EnvI& env, Id* id, const Location& loc) { DeclMap::iterator decl = idmap.find(id); if (decl==idmap.end()) { GCLock lock; throw TypeError(env,loc,"undefined identifier `"+id->str().str()+"'"); } PosMap::iterator pi = pos.find(decl->second.back()); if (pi==pos.end()) { // new id run(env, decl->second.back()); } else { // previously seen, check if circular if (pi->second==-1) { GCLock lock; throw TypeError(env,loc,"circular definition of `"+id->str().str()+"'"); } } return decl->second.back(); } VarDecl* TopoSorter::checkId(EnvI& env, const ASTString& id_v, const Location& loc) { GCLock lock; Id* id = new Id(loc,id_v,NULL); return checkId(env, id, loc); } void TopoSorter::run(EnvI& env, Expression* e) { if (e==NULL) return; switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: break; case Expression::E_SETLIT: { SetLit* sl = e->cast(); if(sl->isv()==NULL) for (unsigned int i=0; iv().size(); i++) run(env,sl->v()[i]); } break; case Expression::E_ID: { if (e != constants().absent) e->cast()->decl(checkId(env, e->cast(),e->loc())); } break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); for (unsigned int i=0; iv().size(); i++) run(env, al->v()[i]); } break; case Expression::E_ARRAYACCESS: { ArrayAccess* ae = e->cast(); run(env, ae->v()); for (unsigned int i=0; iidx().size(); i++) run(env, ae->idx()[i]); } break; case Expression::E_COMP: { Comprehension* ce = e->cast(); for (int i=0; in_generators(); i++) { run(env, ce->in(i)); for (int j=0; jn_decls(i); j++) { add(env, ce->decl(i,j), false); } } if (ce->where()) run(env, ce->where()); run(env, ce->e()); for (int i=0; in_generators(); i++) { for (int j=0; jn_decls(i); j++) { remove(env, ce->decl(i,j)); } } } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { run(env, ite->e_if(i)); run(env, ite->e_then(i)); } run(env, ite->e_else()); } break; case Expression::E_BINOP: { BinOp* be = e->cast(); std::vector todo; todo.push_back(be->lhs()); todo.push_back(be->rhs()); while (!todo.empty()) { Expression* e = todo.back(); todo.pop_back(); if (BinOp* e_bo = e->dyn_cast()) { todo.push_back(e_bo->lhs()); todo.push_back(e_bo->rhs()); for (ExpressionSetIter it = e_bo->ann().begin(); it != e_bo->ann().end(); ++it) run(env, *it); } else { run(env, e); } } } break; case Expression::E_UNOP: { UnOp* ue = e->cast(); run(env, ue->e()); } break; case Expression::E_CALL: { Call* ce = e->cast(); for (unsigned int i=0; iargs().size(); i++) run(env, ce->args()[i]); } break; case Expression::E_VARDECL: { VarDecl* ve = e->cast(); PosMap::iterator pi = pos.find(ve); if (pi==pos.end()) { pos.insert(std::pair(ve,-1)); run(env, ve->ti()); run(env, ve->e()); ve->payload(decls.size()); decls.push_back(ve); pi = pos.find(ve); pi->second = decls.size()-1; } else { assert(pi->second != -1); } } break; case Expression::E_TI: { TypeInst* ti = e->cast(); for (unsigned int i=0; iranges().size(); i++) run(env, ti->ranges()[i]); run(env, ti->domain()); } break; case Expression::E_TIID: break; case Expression::E_LET: { Let* let = e->cast(); for (unsigned int i=0; ilet().size(); i++) { run(env, let->let()[i]); if (VarDecl* vd = let->let()[i]->dyn_cast()) { add(env, vd,false); } } run(env, let->in()); VarDeclCmp poscmp(pos); std::stable_sort(let->let().begin(), let->let().end(), poscmp); for (unsigned int i=0; ilet().size(); i++) { if (VarDecl* vd = let->let()[i]->dyn_cast()) { let->let_orig()[i] = vd->e(); } else { let->let_orig()[i] = NULL; } } for (unsigned int i=0; ilet().size(); i++) { if (VarDecl* vd = let->let()[i]->dyn_cast()) { remove(env, vd); } } } break; } for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) run(env, *it); } KeepAlive addCoercion(EnvI& env, Model* m, Expression* e, const Type& funarg_t) { if (e->type().dim()==funarg_t.dim() && (funarg_t.bt()==Type::BT_BOT || funarg_t.bt()==Type::BT_TOP || e->type().bt()==funarg_t.bt() || e->type().bt()==Type::BT_BOT)) return e; std::vector args(1); args[0] = e; GCLock lock; Call* c = NULL; if (e->type().dim()==0 && funarg_t.dim()!=0) { if (e->type().isvar()) { throw TypeError(env, e->loc(),"cannot coerce var set into array"); } std::vector set2a_args(1); set2a_args[0] = e; Call* set2a = new Call(e->loc(), ASTString("set2array"), set2a_args); FunctionI* fi = m->matchFn(env, set2a); assert(fi); set2a->type(fi->rtype(env, args)); set2a->decl(fi); e = set2a; } if (funarg_t.bt()==Type::BT_TOP || e->type().bt()==funarg_t.bt() || e->type().bt()==Type::BT_BOT) { KeepAlive ka(e); return ka; } if (e->type().bt()==Type::BT_BOOL) { if (funarg_t.bt()==Type::BT_INT) { c = new Call(e->loc(), constants().ids.bool2int, args); } else if (funarg_t.bt()==Type::BT_FLOAT) { c = new Call(e->loc(), constants().ids.bool2float, args); } } else if (e->type().bt()==Type::BT_INT) { if (funarg_t.bt()==Type::BT_FLOAT) { c = new Call(e->loc(), constants().ids.int2float, args); } } if (c) { FunctionI* fi = m->matchFn(env, c); assert(fi); c->type(fi->rtype(env, args)); c->decl(fi); KeepAlive ka(c); return ka; } throw TypeError(env, e->loc(),"cannot determine coercion from type "+e->type().toString()+" to type "+funarg_t.toString()); } KeepAlive addCoercion(EnvI& env, Model* m, Expression* e, Expression* funarg) { return addCoercion(env, m, e, funarg->type()); } template class Typer { public: EnvI& _env; Model* _model; std::vector& _typeErrors; Typer(EnvI& env, Model* model, std::vector& typeErrors) : _env(env), _model(model), _typeErrors(typeErrors) {} /// Check annotations when expression is finished void exit(Expression* e) { for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) if (!(*it)->type().isann()) throw TypeError(_env,(*it)->loc(),"expected annotation, got `"+(*it)->type().toString()+"'"); } bool enter(Expression*) { return true; } /// Visit integer literal void vIntLit(const IntLit&) {} /// Visit floating point literal void vFloatLit(const FloatLit&) {} /// Visit Boolean literal void vBoolLit(const BoolLit&) {} /// Visit set literal void vSetLit(SetLit& sl) { Type ty; ty.st(Type::ST_SET); if (sl.isv()) { ty.bt(Type::BT_INT); sl.type(ty); return; } for (unsigned int i=0; itype().dim() > 0) throw TypeError(_env,sl.v()[i]->loc(),"set literals cannot contain arrays"); if (sl.v()[i]->type().isvar()) ty.ti(Type::TI_VAR); if (sl.v()[i]->type().cv()) ty.cv(true); if (!Type::bt_subtype(sl.v()[i]->type().bt(), ty.bt())) { if (ty.bt() == Type::BT_UNKNOWN || Type::bt_subtype(ty.bt(), sl.v()[i]->type().bt())) { ty.bt(sl.v()[i]->type().bt()); } else { throw TypeError(_env,sl.loc(),"non-uniform set literal"); } } } if (ty.bt() == Type::BT_UNKNOWN) { ty.bt(Type::BT_BOT); } else { if (ty.isvar() && ty.bt()!=Type::BT_INT) { if (ty.bt()==Type::BT_BOOL) ty.bt(Type::BT_INT); else throw TypeError(_env,sl.loc(),"cannot coerce set literal element to var int"); } for (unsigned int i=0; itype().isunknown()); id.type(id.decl()->type()); } } /// Visit anonymous variable void vAnonVar(const AnonVar&) {} /// Visit array literal void vArrayLit(ArrayLit& al) { Type ty; ty.dim(al.dims()); std::vector anons; bool haveInferredType = false; for (unsigned int i=0; itype().dim() > 0) throw TypeError(_env,vi->loc(),"arrays cannot be elements of arrays"); AnonVar* av = vi->dyn_cast(); if (av) { ty.ti(Type::TI_VAR); anons.push_back(av); } else if (vi->type().isvar()) { ty.ti(Type::TI_VAR); } if (vi->type().cv()) ty.cv(true); if (vi->type().isopt()) { ty.ot(Type::OT_OPTIONAL); } if (ty.bt()==Type::BT_UNKNOWN) { if (av == NULL) { if (haveInferredType) { if (ty.st() != vi->type().st()) { throw TypeError(_env,al.loc(),"non-uniform array literal"); } } else { haveInferredType = true; ty.st(vi->type().st()); } if (vi->type().bt() != Type::BT_BOT) { ty.bt(vi->type().bt()); } } } else { if (av == NULL) { if (vi->type().bt() == Type::BT_BOT) { if (vi->type().st() != ty.st()) { throw TypeError(_env,al.loc(),"non-uniform array literal"); } } else { if (Type::bt_subtype(ty.bt(), vi->type().bt())) { ty.bt(vi->type().bt()); } if (!Type::bt_subtype(vi->type().bt(),ty.bt()) || ty.st() != vi->type().st()) { throw TypeError(_env,al.loc(),"non-uniform array literal"); } } } } } if (ty.bt() == Type::BT_UNKNOWN) { ty.bt(Type::BT_BOT); if (!anons.empty()) throw TypeError(_env,al.loc(),"array literal must contain at least one non-anonymous variable"); } else { Type at = ty; at.dim(0); if (at.ti()==Type::TI_VAR && at.st()==Type::ST_SET && at.bt()!=Type::BT_INT) { if (at.bt()==Type::BT_BOOL) { ty.bt(Type::BT_INT); at.bt(Type::BT_INT); } else { throw TypeError(_env,al.loc(),"cannot coerce array element to var set of int"); } } for (unsigned int i=0; itype(at); } for (unsigned int i=0; itype().dim()==0) { if (aa.v()->type().st() == Type::ST_SET) { Type tv = aa.v()->type(); tv.st(Type::ST_PLAIN); tv.dim(1); aa.v(addCoercion(_env, _model, aa.v(), tv)()); } else { throw TypeError(_env,aa.v()->loc(),"not an array in array access"); } } if (aa.v()->type().dim() != aa.idx().size()) throw TypeError(_env,aa.v()->loc(),"array dimensions do not match"); Type tt = aa.v()->type(); tt.dim(0); for (unsigned int i=0; iisa()) { aai->type(Type::varint()); } if (aai->type().is_set() || (aai->type().bt() != Type::BT_INT && aai->type().bt() != Type::BT_BOOL) || aai->type().dim() != 0) { throw TypeError(_env,aai->loc(),"array index must be `int', but is `"+aai->type().toString()+"'"); } aa.idx()[i] = addCoercion(_env, _model, aai, Type::varint())(); if (aai->type().isopt()) { tt.ot(Type::OT_OPTIONAL); } if (aai->type().isvar()) { tt.ti(Type::TI_VAR); } if (aai->type().cv()) tt.cv(true); } aa.type(tt); } /// Visit array comprehension void vComprehension(Comprehension& c) { Type tt = c.e()->type(); for (int i=0; itype(); if (ty_in == Type::varsetint()) { tt.ot(Type::OT_OPTIONAL); tt.ti(Type::TI_VAR); } if (ty_in.cv()) tt.cv(true); } if (c.where()) { if (c.where()->type() == Type::varbool()) { tt.ot(Type::OT_OPTIONAL); tt.ti(Type::TI_VAR); } else if (c.where()->type() != Type::parbool()) { throw TypeError(_env,c.where()->loc(), "where clause must be bool, but is `"+ c.where()->type().toString()+"'"); } if (c.where()->type().cv()) tt.cv(true); } if (c.set()) { if (c.e()->type().dim() != 0 || c.e()->type().st() == Type::ST_SET) throw TypeError(_env,c.e()->loc(), "set comprehension expression must be scalar, but is `" +c.e()->type().toString()+"'"); tt.st(Type::ST_SET); } else { if (c.e()->type().dim() != 0) throw TypeError(_env,c.e()->loc(), "array comprehension expression cannot be an array"); tt.dim(1); } c.type(tt); } /// Visit array comprehension generator void vComprehensionGenerator(Comprehension& c, int gen_i) { Expression* g_in = c.in(gen_i); const Type& ty_in = g_in->type(); if (ty_in != Type::varsetint() && ty_in != Type::parsetint() && ty_in.dim() != 1) { throw TypeError(_env,g_in->loc(), "generator expression must be (par or var) set of int or one-dimensional array, but is `"+ty_in.toString()+"'"); } Type ty_id; bool needIntLit = false; if (ty_in.dim()==0) { ty_id = Type::parint(); needIntLit = true; } else { ty_id = ty_in; ty_id.dim(0); } for (int j=0; je(new IntLit(Location(),0)); } c.decl(gen_i,j)->type(ty_id); c.decl(gen_i,j)->ti()->type(ty_id); } } /// Visit if-then-else void vITE(ITE& ite) { Type tret = ite.e_else()->type(); std::vector anons; bool allpar = !(tret.isvar()); if (tret.isunknown()) { if (AnonVar* av = ite.e_else()->dyn_cast()) { allpar = false; anons.push_back(av); } else { throw TypeError(_env,ite.e_else()->loc(), "cannot infer type of expression in else branch of conditional"); } } bool allpresent = !(tret.isopt()); bool varcond = false; for (int i=0; itype() == Type::varbool()); if (eif->type() != Type::parbool() && eif->type() != Type::varbool()) throw TypeError(_env,eif->loc(), "expected bool conditional expression, got `"+ eif->type().toString()+"'"); if (eif->type().cv()) tret.cv(true); if (ethen->type().isunknown()) { if (AnonVar* av = ethen->dyn_cast()) { allpar = false; anons.push_back(av); } else { throw TypeError(_env,ethen->loc(), "cannot infer type of expression in then branch of conditional"); } } else { if (tret.isbot() || tret.isunknown()) tret.bt(ethen->type().bt()); if ( (!ethen->type().isbot() && !Type::bt_subtype(ethen->type().bt(), tret.bt()) && !Type::bt_subtype(tret.bt(), ethen->type().bt())) || ethen->type().st() != tret.st() || ethen->type().dim() != tret.dim()) { throw TypeError(_env,ethen->loc(), "type mismatch in branches of conditional. Then-branch has type `"+ ethen->type().toString()+"', but else branch has type `"+ tret.toString()+"'"); } if (Type::bt_subtype(tret.bt(), ethen->type().bt())) { tret.bt(ethen->type().bt()); } if (ethen->type().isvar()) allpar=false; if (ethen->type().isopt()) allpresent=false; if (ethen->type().cv()) tret.cv(true); } } Type tret_var(tret); tret_var.ti(Type::TI_VAR); for (unsigned int i=0; itype(tret_var); } for (int i=0; i 0) throw TypeError(_env,ite.loc(), "conditional with var condition cannot have array type"); if (varcond || !allpar) tret.ti(Type::TI_VAR); if (!allpresent) tret.ot(Type::OT_OPTIONAL); ite.type(tret); } /// Visit binary operator void vBinOp(BinOp& bop) { std::vector args(2); args[0] = bop.lhs(); args[1] = bop.rhs(); if (FunctionI* fi = _model->matchFn(_env,bop.opToString(),args)) { bop.lhs(addCoercion(_env, _model,bop.lhs(),fi->argtype(args, 0))()); bop.rhs(addCoercion(_env, _model,bop.rhs(),fi->argtype(args, 1))()); args[0] = bop.lhs(); args[1] = bop.rhs(); Type ty = fi->rtype(_env,args); ty.cv(bop.lhs()->type().cv() || bop.rhs()->type().cv()); bop.type(ty); if (fi->e()) bop.decl(fi); else bop.decl(NULL); } else { throw TypeError(_env,bop.loc(), std::string("type error in operator application for `")+ bop.opToString().str()+"'. No matching operator found with left-hand side type `"+bop.lhs()->type().toString()+ "' and right-hand side type `"+bop.rhs()->type().toString()+"'"); } } /// Visit unary operator void vUnOp(UnOp& uop) { std::vector args(1); args[0] = uop.e(); if (FunctionI* fi = _model->matchFn(_env,uop.opToString(),args)) { uop.e(addCoercion(_env, _model,uop.e(),fi->argtype(args,0))()); args[0] = uop.e(); Type ty = fi->rtype(_env,args); ty.cv(uop.e()->type().cv()); uop.type(ty); if (fi->e()) uop.decl(fi); } else { throw TypeError(_env,uop.loc(), std::string("type error in operator application for `")+ uop.opToString().str()+"'. No matching operator found with type `"+uop.e()->type().toString()+"'"); } } /// Visit call void vCall(Call& call) { std::vector args(call.args().size()); std::copy(call.args().begin(),call.args().end(),args.begin()); if (FunctionI* fi = _model->matchFn(_env,call.id(),args)) { bool cv = false; for (unsigned int i=0; iargtype(args,i))(); call.args()[i] = args[i]; cv = cv || args[i]->type().cv(); } Type ty = fi->rtype(_env,args); ty.cv(cv); call.type(ty); call.decl(fi); } else { std::ostringstream oss; oss << "no function or predicate with this signature found: `"; oss << call.id() << "("; for (unsigned int i=0; itype().toString(); if (itype().cv(); if (VarDecl* vdi = li->dyn_cast()) { if (vdi->e()==NULL && vdi->type().is_set() && vdi->type().isvar() && vdi->ti()->domain()==NULL) { _typeErrors.push_back(TypeError(_env,vdi->loc(), "set element type for `"+vdi->id()->str().str()+"' is not finite")); } if (vdi->type().ispar() && vdi->e() == NULL) throw TypeError(_env,vdi->loc(), "let variable `"+vdi->id()->v().str()+"' must be initialised"); if (vdi->ti()->hasTiVariable()) { _typeErrors.push_back(TypeError(_env,vdi->loc(), "type-inst variables not allowed in type-inst for let variable `"+vdi->id()->str().str()+"'")); } let.let_orig()[i] = vdi->e(); } } Type ty = let.in()->type(); ty.cv(cv); let.type(ty); } /// Visit variable declaration void vVarDecl(VarDecl& vd) { if (ignoreVarDecl) { assert(!vd.type().isunknown()); if (vd.e()) { if (! vd.e()->type().isSubtypeOf(vd.ti()->type())) { _typeErrors.push_back(TypeError(_env,vd.e()->loc(), "initialisation value for `"+vd.id()->str().str()+"' has invalid type-inst: expected `"+ vd.ti()->type().toString()+"', actual `"+vd.e()->type().toString()+"'")); } else { vd.e(addCoercion(_env, _model, vd.e(), vd.ti()->type())()); } } } else { vd.type(vd.ti()->type()); vd.id()->type(vd.type()); } } /// Visit type inst void vTypeInst(TypeInst& ti) { Type tt = ti.type(); if (ti.ranges().size()>0) { bool foundTIId=false; for (unsigned int i=0; itype().cv()) tt.cv(true); if (ri->type() == Type::top()) { if (foundTIId) { throw TypeError(_env,ri->loc(), "only one type-inst variable allowed in array index"); } else { foundTIId = true; } } else if (ri->type() != Type::parint()) { assert(ri->isa()); throw TypeError(_env,ri->loc(), "invalid type in array index, expected `set of int', actual `"+ ri->type().toString()+"'"); } } tt.dim(foundTIId ? -1 : ti.ranges().size()); } if (ti.domain() && ti.domain()->type().cv()) tt.cv(true); if (ti.domain() && !ti.domain()->isa()) { if (ti.domain()->type().ti() != Type::TI_PAR || ti.domain()->type().st() != Type::ST_SET) throw TypeError(_env,ti.domain()->loc(), "type-inst must be par set"); if (ti.domain()->type().dim() != 0) throw TypeError(_env,ti.domain()->loc(), "type-inst cannot be an array"); } if (tt.isunknown()) { assert(ti.domain()); switch (ti.domain()->type().bt()) { case Type::BT_INT: case Type::BT_FLOAT: break; case Type::BT_BOT: { Type tidt = ti.domain()->type(); tidt.bt(Type::BT_INT); ti.domain()->type(tidt); } break; default: throw TypeError(_env,ti.domain()->loc(), "type-inst must be int or float"); } tt.bt(ti.domain()->type().bt()); } else { // assert(ti.domain()==NULL || ti.domain()->isa()); } if (tt.st()==Type::ST_SET && tt.ti()==Type::TI_VAR && tt.bt() != Type::BT_INT && tt.bt() != Type::BT_TOP) throw TypeError(_env,ti.loc(), "var set element types other than `int' not allowed"); ti.type(tt); } void vTIId(TIId& id) {} }; void typecheck(Env& env, Model* m, std::vector& typeErrors, bool ignoreUndefinedParameters) { TopoSorter ts; std::vector functionItems; std::vector assignItems; class TSV0 : public ItemVisitor { public: EnvI& env; TopoSorter& ts; Model* model; bool hadSolveItem; bool hadOutputItem; std::vector& fis; std::vector& ais; TSV0(EnvI& env0, TopoSorter& ts0, Model* model0, std::vector& fis0, std::vector& ais0) : env(env0), ts(ts0), model(model0), hadSolveItem(false), hadOutputItem(false), fis(fis0), ais(ais0) {} void vAssignI(AssignI* i) { ais.push_back(i); } void vVarDeclI(VarDeclI* i) { ts.add(env, i->e(), true); } void vFunctionI(FunctionI* i) { model->registerFn(env, i); fis.push_back(i); } void vSolveI(SolveI* si) { if (hadSolveItem) throw TypeError(env,si->loc(),"Only one solve item allowed"); hadSolveItem = true; } void vOutputI(OutputI* oi) { if (hadOutputItem) throw TypeError(env,oi->loc(),"Only one output item allowed"); hadOutputItem = true; } } _tsv0(env.envi(),ts,m,functionItems,assignItems); iterItems(_tsv0,m); for (unsigned int i=0; iid(),ai->loc()); if (vd->e()) throw TypeError(env.envi(),ai->loc(),"multiple assignment to the same variable"); ai->remove(); vd->e(ai->e()); } class TSV1 : public ItemVisitor { public: EnvI& env; TopoSorter& ts; TSV1(EnvI& env0, TopoSorter& ts0) : env(env0), ts(ts0) {} void vVarDeclI(VarDeclI* i) { ts.run(env,i->e()); } void vAssignI(AssignI* i) {} void vConstraintI(ConstraintI* i) { ts.run(env,i->e()); } void vSolveI(SolveI* i) { for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) ts.run(env,*it); ts.run(env,i->e()); } void vOutputI(OutputI* i) { ts.run(env,i->e()); } void vFunctionI(FunctionI* fi) { ts.run(env,fi->ti()); for (unsigned int i=0; iparams().size(); i++) ts.run(env,fi->params()[i]); for (ExpressionSetIter it = fi->ann().begin(); it != fi->ann().end(); ++it) ts.run(env,*it); for (unsigned int i=0; iparams().size(); i++) ts.add(env,fi->params()[i],false); ts.run(env,fi->e()); for (unsigned int i=0; iparams().size(); i++) ts.remove(env,fi->params()[i]); } } _tsv1(env.envi(),ts); iterItems(_tsv1,m); m->sortFn(); { struct SortByPayload { bool operator ()(Item* i0, Item* i1) { if (i0->isa()) return !i1->isa(); if (VarDeclI* vdi0 = i0->dyn_cast()) { if (VarDeclI* vdi1 = i1->dyn_cast()) { return vdi0->e()->payload() < vdi1->e()->payload(); } else { return !i1->isa(); } } return false; } } _sbp; std::stable_sort(m->begin(), m->end(), _sbp); } { Typer ty(env.envi(), m, typeErrors); BottomUpIterator > bu_ty(ty); for (unsigned int i=0; ipayload(0); bu_ty.run(ts.decls[i]->ti()); ty.vVarDecl(*ts.decls[i]); } for (unsigned int i=0; iti()); for (unsigned int j=0; jparams().size(); j++) bu_ty.run(functionItems[i]->params()[j]); } } { Typer ty(env.envi(), m, typeErrors); BottomUpIterator > bu_ty(ty); class TSV2 : public ItemVisitor { public: EnvI& env; Model* m; BottomUpIterator >& bu_ty; std::vector& _typeErrors; TSV2(EnvI& env0, Model* m0, BottomUpIterator >& b, std::vector& typeErrors) : env(env0), m(m0), bu_ty(b), _typeErrors(typeErrors) {} void vVarDeclI(VarDeclI* i) { bu_ty.run(i->e()); if (i->e()->ti()->hasTiVariable()) { _typeErrors.push_back(TypeError(env, i->e()->loc(), "type-inst variables not allowed in type-inst for `"+i->e()->id()->str().str()+"'")); } VarDecl* vdi = i->e(); if (vdi->e()==NULL && vdi->type().is_set() && vdi->type().isvar() && vdi->ti()->domain()==NULL) { _typeErrors.push_back(TypeError(env,vdi->loc(), "set element type for `"+vdi->id()->str().str()+"' is not finite")); } } void vAssignI(AssignI* i) { bu_ty.run(i->e()); if (!i->e()->type().isSubtypeOf(i->decl()->ti()->type())) { _typeErrors.push_back(TypeError(env, i->e()->loc(), "assignment value for `"+i->decl()->id()->str().str()+"' has invalid type-inst: expected `"+ i->decl()->ti()->type().toString()+"', actual `"+i->e()->type().toString()+"'")); // Assign to "true" constant to avoid generating further errors that the parameter // is undefined i->decl()->e(constants().lit_true); } } void vConstraintI(ConstraintI* i) { bu_ty.run(i->e()); if (!i->e()->type().isSubtypeOf(Type::varbool())) throw TypeError(env, i->e()->loc(), "invalid type of constraint, expected `"+Type::varbool().toString()+"', actual `"+i->e()->type().toString()+"'"); } void vSolveI(SolveI* i) { for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) { bu_ty.run(*it); if (!(*it)->type().isann()) throw TypeError(env, (*it)->loc(), "expected annotation, got `"+(*it)->type().toString()+"'"); } bu_ty.run(i->e()); if (i->e()) { Type et = i->e()->type(); if (! (et.isSubtypeOf(Type::varint()) || et.isSubtypeOf(Type::varfloat()))) throw TypeError(env, i->e()->loc(), "objective has invalid type, expected int or float, actual `"+et.toString()+"'"); } } void vOutputI(OutputI* i) { bu_ty.run(i->e()); if (i->e()->type() != Type::parstring(1) && i->e()->type() != Type::bot(1)) throw TypeError(env, i->e()->loc(), "invalid type in output item, expected `"+Type::parstring(1).toString()+"', actual `"+i->e()->type().toString()+"'"); } void vFunctionI(FunctionI* i) { for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) { bu_ty.run(*it); if (!(*it)->type().isann()) throw TypeError(env, (*it)->loc(), "expected annotation, got `"+(*it)->type().toString()+"'"); } bu_ty.run(i->ti()); bu_ty.run(i->e()); if (i->e() && !i->e()->type().isSubtypeOf(i->ti()->type())) throw TypeError(env, i->e()->loc(), "return type of function does not match body, declared type is `"+i->ti()->type().toString()+ "', body type is `"+i->e()->type().toString()+"'"); if (i->e()) i->e(addCoercion(env, m, i->e(), i->ti()->type())()); } } _tsv2(env.envi(), m, bu_ty, typeErrors); iterItems(_tsv2,m); } class TSV3 : public ItemVisitor { public: EnvI& env; Model* m; TSV3(EnvI& env0, Model* m0) : env(env0), m(m0) {} void vAssignI(AssignI* i) { i->decl()->e(addCoercion(env, m, i->e(), i->decl()->type())()); } } _tsv3(env.envi(),m); if (typeErrors.empty()) { iterItems(_tsv3,m); } for (unsigned int i=0; itoplevel() && ts.decls[i]->type().ispar() && !ts.decls[i]->type().isann() && ts.decls[i]->e()==NULL) { if (ts.decls[i]->type().isopt()) { ts.decls[i]->e(constants().absent); } else if (!ignoreUndefinedParameters) { typeErrors.push_back(TypeError(env.envi(), ts.decls[i]->loc(), " symbol error: variable `" + ts.decls[i]->id()->str().str() + "' must be defined (did you forget to specify a data file?)")); } } } } void typecheck(Env& env, Model* m, AssignI* ai) { std::vector typeErrors; Typer ty(env.envi(), m, typeErrors); BottomUpIterator > bu_ty(ty); bu_ty.run(ai->e()); if (!typeErrors.empty()) { throw typeErrors[0]; } if (!ai->e()->type().isSubtypeOf(ai->decl()->ti()->type())) { throw TypeError(env.envi(), ai->e()->loc(), "assignment value for `"+ai->decl()->id()->str().str()+"' has invalid type-inst: expected `"+ ai->decl()->ti()->type().toString()+"', actual `"+ai->e()->type().toString()+"'"); } } void typecheck_fzn(Env& env, Model* m) { ASTStringMap::t declMap; for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*m)[i]->dyn_cast()) { Type t = vdi->e()->type(); declMap.insert(std::pair(vdi->e()->id()->v(), i)); if (t.isunknown()) { if (vdi->e()->ti()->domain()) { switch (vdi->e()->ti()->domain()->eid()) { case Expression::E_BINOP: { BinOp* bo = vdi->e()->ti()->domain()->cast(); if (bo->op()==BOT_DOTDOT) { t.bt(bo->lhs()->type().bt()); if (t.isunknown()) { throw TypeError(env.envi(), vdi->e()->loc(), "Cannot determine type of variable declaration"); } vdi->e()->type(t); } else { throw TypeError(env.envi(), vdi->e()->loc(), "Only ranges allowed in FlatZinc type inst"); } } case Expression::E_ID: { ASTStringMap::t::iterator it = declMap.find(vdi->e()->ti()->domain()->cast()->v()); if (it == declMap.end()) { throw TypeError(env.envi(), vdi->e()->loc(), "Cannot determine type of variable declaration"); } t.bt((*m)[it->second]->cast()->e()->type().bt()); if (t.isunknown()) { throw TypeError(env.envi(), vdi->e()->loc(), "Cannot determine type of variable declaration"); } vdi->e()->type(t); } default: throw TypeError(env.envi(), vdi->e()->loc(), "Cannot determine type of variable declaration"); } } else { throw TypeError(env.envi(), vdi->e()->loc(), "Cannot determine type of variable declaration"); } } } } } } libminizinc-2.0.11/lib/optimize_constraints.cpp0000644000175000017500000002620712646030173020312 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include namespace MiniZinc { void OptimizeRegistry::reg(const MiniZinc::ASTString& call, optimizer opt) { _m.insert(std::make_pair(call, opt)); } OptimizeRegistry::ConstraintStatus OptimizeRegistry::process(EnvI& env, MiniZinc::Item* i, MiniZinc::Call* c, Expression*& rewrite) { ASTStringMap::t::iterator it = _m.find(c->id()); if (it != _m.end()) { return it->second(env,i,c,rewrite); } return CS_NONE; } OptimizeRegistry& OptimizeRegistry::registry(void) { static OptimizeRegistry reg; return reg; } namespace Optimizers { OptimizeRegistry::ConstraintStatus o_linear(EnvI& env, Item* ii, Call* c, Expression*& rewrite) { ArrayLit* al_c = eval_array_lit(env,c->args()[0]); std::vector coeffs(al_c->v().size()); for (unsigned int i=0; iv().size(); i++) { coeffs[i] = eval_int(env,al_c->v()[i]); } ArrayLit* al_x = eval_array_lit(env,c->args()[1]); std::vector x(al_x->v().size()); for (unsigned int i=0; iv().size(); i++) { x[i] = al_x->v()[i]; } IntVal d = 0; simplify_lin(coeffs, x, d); if (coeffs.size()==0) { bool failed; if (c->id()==constants().ids.int_.lin_le) { failed = (d > eval_int(env,c->args()[2])); } else if (c->id()==constants().ids.int_.lin_eq) { failed = (d != eval_int(env,c->args()[2])); } else { failed = (d == eval_int(env,c->args()[2])); } if (failed) { return OptimizeRegistry::CS_FAILED; } else { return OptimizeRegistry::CS_ENTAILED; } } else if (coeffs.size()==1 && (ii->isa() || ii->cast()->e()->ti()->domain()==constants().lit_true)) { VarDecl* vd = x[0]()->cast()->decl(); IntSetVal* domain = vd->ti()->domain() ? eval_intset(env,vd->ti()->domain()) : NULL; if (c->id()==constants().ids.int_.lin_eq) { IntVal rd = eval_int(env,c->args()[2])-d; if (rd % coeffs[0] == 0) { IntVal nd = rd / coeffs[0]; if (domain && !domain->contains(nd)) return OptimizeRegistry::CS_FAILED; std::vector args(2); args[0] = x[0](); args[1] = IntLit::a(nd); Call* c = new Call(Location(), constants().ids.int_.eq, args); c->type(Type::varbool()); rewrite = c; return OptimizeRegistry::CS_REWRITE; } else { return OptimizeRegistry::CS_FAILED; } } else if (c->id()==constants().ids.int_.lin_le) { IntVal ac = std::abs(coeffs[0]); IntVal rd = eval_int(env,c->args()[2])-d; IntVal ad = std::abs(rd); IntVal nd; if (ad % ac == 0) { nd = rd / coeffs[0]; } else { double nd_d = static_cast(ad.toInt()) / static_cast(ac.toInt()); if (coeffs[0] >= 0 && rd >= 0) { nd = static_cast(std::floor(nd_d)); } else if (rd >= 0) { nd = -static_cast(std::floor(nd_d)); } else if (coeffs[0] >= 0) { nd = -static_cast(std::ceil(nd_d)); } else { nd = static_cast(std::ceil(nd_d)); } } bool swapSign = coeffs[0] < 0; if (domain) { if (swapSign) { if (domain->max() < nd) { return OptimizeRegistry::CS_FAILED; } else if (domain->min() >= nd) return OptimizeRegistry::CS_ENTAILED; } else { if (domain->min() > nd) { return OptimizeRegistry::CS_FAILED; } else if (domain->max() <= nd) return OptimizeRegistry::CS_ENTAILED; } std::vector args(2); args[0] = x[0](); args[1] = IntLit::a(nd); if (swapSign) std::swap(args[0], args[1]); Call* nc = new Call(Location(), constants().ids.int_.le, args); nc->type(Type::varbool()); rewrite = nc; return OptimizeRegistry::CS_REWRITE; } } } else if (c->id()==constants().ids.int_.lin_eq && coeffs.size()==2 && ((coeffs[0]==1 && coeffs[1]==-1) || (coeffs[1]==1 && coeffs[0]==-1)) && eval_int(env,c->args()[2])-d==0) { std::vector args(2); args[0] = x[0](); args[1] = x[1](); Call* c = new Call(Location(), constants().ids.int_.eq, args); rewrite = c; return OptimizeRegistry::CS_REWRITE; } if (coeffs.size() < al_c->v().size()) { std::vector coeffs_e(coeffs.size()); std::vector x_e(coeffs.size()); for (unsigned int i=0; iloc(),coeffs_e); al_c_new->type(Type::parint(1)); ArrayLit* al_x_new = new ArrayLit(al_x->loc(),x_e); al_x_new->type(al_x->type()); std::vector args(3); args[0] = al_c_new; args[1] = al_x_new; args[2] = IntLit::a(eval_int(env,c->args()[2])-d); Call* nc = new Call(Location(), c->id(), args); nc->type(Type::varbool()); for (ExpressionSetIter it = c->ann().begin(); it != c->ann().end(); ++it) { nc->addAnnotation(*it); } rewrite = nc; return OptimizeRegistry::CS_REWRITE; } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_lin_exp(EnvI& env, Item* i, Call* c, Expression*& rewrite) { if (c->type().isint()) { ArrayLit* al_c = eval_array_lit(env,c->args()[0]); std::vector coeffs(al_c->v().size()); for (unsigned int i=0; iv().size(); i++) { coeffs[i] = eval_int(env,al_c->v()[i]); } ArrayLit* al_x = eval_array_lit(env,c->args()[1]); std::vector x(al_x->v().size()); for (unsigned int i=0; iv().size(); i++) { x[i] = al_x->v()[i]; } IntVal d = eval_int(env,c->args()[2]); simplify_lin(coeffs, x, d); if (coeffs.size()==0) { rewrite = IntLit::a(d); return OptimizeRegistry::CS_REWRITE; } else if (coeffs.size() < al_c->v().size()) { if (coeffs.size()==1 && coeffs[0]==1 && d==0) { rewrite = x[0](); return OptimizeRegistry::CS_REWRITE; } std::vector coeffs_e(coeffs.size()); std::vector x_e(coeffs.size()); for (unsigned int i=0; iloc(),coeffs_e); al_c_new->type(Type::parint(1)); ArrayLit* al_x_new = new ArrayLit(al_x->loc(),x_e); al_x_new->type(al_x->type()); std::vector args(3); args[0] = al_c_new; args[1] = al_x_new; args[2] = IntLit::a(d); Call* nc = new Call(Location(),c->id(),args); nc->type(c->type()); for (ExpressionSetIter it = c->ann().begin(); it != c->ann().end(); ++it) { nc->addAnnotation(*it); } rewrite = nc; return OptimizeRegistry::CS_REWRITE; } } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_element(EnvI& env, Item* i, Call* c, Expression*& rewrite) { if (c->args()[0]->isa()) { IntVal idx = eval_int(env,c->args()[0]); ArrayLit* al = eval_array_lit(env,c->args()[1]); if (idx < 1 || idx > al->v().size()) { return OptimizeRegistry::CS_FAILED; } Expression* result = al->v()[idx.toInt()-1]; std::vector args(2); args[0] = result; args[1] = c->args()[2]; Call* eq = new Call(Location(),constants().ids.int_.eq,args); rewrite = eq; return OptimizeRegistry::CS_REWRITE; } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_clause(EnvI& env, Item* i, Call* c, Expression*& rewrite) { std::vector pos; std::vector neg; ArrayLit* al_pos = eval_array_lit(env, c->args()[0]); for (unsigned int i=0; iv().size(); i++) { if (Id* ident = al_pos->v()[i]->dyn_cast()) { if (ident->decl()->ti()->domain()==NULL) pos.push_back(ident->decl()); } } ArrayLit* al_neg = eval_array_lit(env, c->args()[1]); for (unsigned int i=0; iv().size(); i++) { if (Id* ident = al_neg->v()[i]->dyn_cast()) { if (ident->decl()->ti()->domain()==NULL) neg.push_back(ident->decl()); } } bool subsumed = false; if (pos.size() > 0 && neg.size() > 0) { std::sort(pos.begin(),pos.end()); std::sort(neg.begin(), neg.end()); unsigned int ix=0; unsigned int iy=0; for (;;) { if (pos[ix]==neg[iy]) { subsumed = true; break; } if (pos[ix] < neg[iy]) { ix++; } else { iy++; } if (ix==pos.size() || iy==neg.size()) break; } } if (subsumed) { return OptimizeRegistry::CS_ENTAILED; } else { return OptimizeRegistry::CS_OK; } } class Register { public: Register(void) { GCLock lock; Model* m = new Model; ASTString id_element("array_int_element"); ASTString id_var_element("array_var_int_element"); std::vector e; e.push_back(new StringLit(Location(),id_element)); e.push_back(new StringLit(Location(),id_var_element)); m->addItem(new ConstraintI(Location(),new ArrayLit(Location(),e))); OptimizeRegistry::registry().reg(constants().ids.int_.lin_eq, o_linear); OptimizeRegistry::registry().reg(constants().ids.int_.lin_le, o_linear); OptimizeRegistry::registry().reg(constants().ids.int_.lin_ne, o_linear); OptimizeRegistry::registry().reg(id_element, o_element); OptimizeRegistry::registry().reg(constants().ids.lin_exp, o_lin_exp); OptimizeRegistry::registry().reg(id_var_element, o_element); OptimizeRegistry::registry().reg(constants().ids.clause, o_clause); OptimizeRegistry::registry().reg(constants().ids.bool_clause, o_clause); } } _r; } }libminizinc-2.0.11/lib/htmlprinter.cpp0000644000175000017500000005501512646030173016372 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include #include #include #include namespace MiniZinc { namespace HtmlDocOutput { class DocItem { public: enum DocType { T_PAR=0, T_VAR=1, T_FUN=2 }; DocItem(const DocType& t0, std::string id0, std::string doc0) : t(t0), id(id0), doc(doc0) {} DocType t; std::string id; std::string doc; }; typedef UNORDERED_NAMESPACE::unordered_map FunMap; class Group; class GroupMap { public: typedef std::vector Map; Map m; ~GroupMap(); Map::iterator find(const std::string& n); }; class Group { public: Group(const std::string& name0, const std::string& fullPath0) : name(name0), fullPath(fullPath0) {} std::string name; std::string fullPath; std::string desc; std::string htmlName; GroupMap subgroups; std::vector items; std::string getAnchor(int level, int indivFileLevel) { if (level < indivFileLevel) { return fullPath + ".html"; } else { return "#" + fullPath; } } std::string toHTML(int level, int indivFileLevel, Group* parent, int idx, const std::string& basename) { std::ostringstream oss; int realLevel = (level < indivFileLevel) ? 0 : level - indivFileLevel; oss << "
\n"; if (parent) { oss << "
"; if (idx > 0) { oss << " "; } oss << " "; if (idx < parent->subgroups.m.size()-1) { oss << " "; } if (items.size() > 0) { oss << "reveal all\n"; oss << "hide all\n"; } oss << "
"; } if (!htmlName.empty()) { oss << "\n"; oss << "
\n" << desc << "
\n"; } if (subgroups.m.size() != 0) { oss << "

Sections:

\n"; oss << "
    \n"; for (GroupMap::Map::iterator it = subgroups.m.begin(); it != subgroups.m.end(); ++it) { oss << "
  • " << (*it)->htmlName << "\n"; if ((*it)->htmlName.empty()) { std::cerr << "Warning: undocumented group " << (*it)->fullPath << "\n"; } } oss << "
\n"; if (items.size() > 0) oss << "

Declarations in this section:

\n"; } struct SortById { bool operator ()(const DocItem& i0, const DocItem& i1) { return i0.t < i1.t || (i0.t==i1.t && i0.id < i1.id); } } _cmp; std::stable_sort(items.begin(), items.end(), _cmp); int cur_t = -1; const char* dt[] = {"par","var","fun"}; const char* dt_desc[] = {"Parameters","Variables","Functions and Predicates"}; for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (it->t != cur_t) { if (cur_t != -1) oss << "
\n"; cur_t = it->t; oss << "
\n"; oss << "
" << dt_desc[cur_t] << "
\n"; } oss << it->doc; } if (cur_t != -1) oss << "
\n"; if (level >= indivFileLevel) { for (unsigned int i=0; itoHTML(level+1, indivFileLevel, this, i, basename); } } oss << ""; return oss.str(); } }; GroupMap::~GroupMap() { for (Map::iterator it = m.begin(); it != m.end(); ++it) { delete *it; } } GroupMap::Map::iterator GroupMap::find(const std::string& n) { for (Map::iterator it = m.begin(); it != m.end(); ++it) if ((*it)->name == n) return it; return m.end(); } void addToGroup(Group& gm, const std::string& group, DocItem& di) { std::vector subgroups; size_t lastpos = 0; size_t pos = group.find("."); while (pos != std::string::npos) { subgroups.push_back(group.substr(lastpos, pos-lastpos)); lastpos = pos+1; pos = group.find(".", lastpos); } subgroups.push_back(group.substr(lastpos, std::string::npos)); GroupMap* cgm = &gm.subgroups; std::string gpath(gm.fullPath); for (unsigned int i=0; ifind(subgroups[i]) == cgm->m.end()) { cgm->m.push_back(new Group(subgroups[i], gpath)); } Group& g = **cgm->find(subgroups[i]); if (i==subgroups.size()-1) { g.items.push_back(di); } else { cgm = &g.subgroups; } } } void setGroupDesc(Group& maingroup, const std::string& group, std::string htmlName, std::string s) { if (group == "MAIN") { if (!maingroup.htmlName.empty()) { std::cerr << "Warning: two descriptions for group `" << group << "'\n"; } maingroup.htmlName = htmlName; maingroup.desc = s; return; } std::vector subgroups; size_t lastpos = 0; size_t pos = group.find("."); while (pos != std::string::npos) { subgroups.push_back(group.substr(lastpos, pos-lastpos)); lastpos = pos+1; pos = group.find(".", lastpos); } subgroups.push_back(group.substr(lastpos, std::string::npos)); GroupMap* cgm = &maingroup.subgroups; std::string gpath(maingroup.fullPath); for (unsigned int i=0; ifind(subgroups[i]) == cgm->m.end()) { cgm->m.push_back(new Group(subgroups[i], gpath)); } Group& g = **cgm->find(subgroups[i]); if (i==subgroups.size()-1) { if (!g.htmlName.empty()) { std::cerr << "Warning: two descriptions for group `" << group << "'\n"; } g.htmlName = htmlName; g.desc = s; } else { cgm = &g.subgroups; } } } std::string extractArgWord(std::string& s, size_t n) { size_t start = n; while (start < s.size() && s[start]!=' ' && s[start]!='\t') start++; while (start < s.size() && (s[start]==' ' || s[start]=='\t')) start++; int end = start+1; while (end < s.size() && (isalnum(s[end]) || s[end]=='_' || s[end]=='.')) end++; std::string ret = s.substr(start,end-start); s = s.substr(0,n)+s.substr(end,std::string::npos); return ret; } } class CollectFunctionsVisitor : public ItemVisitor { protected: EnvI& env; HtmlDocOutput::FunMap& _funmap; bool _includeStdLib; public: CollectFunctionsVisitor(EnvI& env0, HtmlDocOutput::FunMap& funmap, bool includeStdLib) : env(env0), _funmap(funmap), _includeStdLib(includeStdLib) {} bool enterModel(Model* m) { return _includeStdLib || m->filename()!="stdlib.mzn"; } void vFunctionI(FunctionI* fi) { if (Call* docstring = Expression::dyn_cast(getAnnotation(fi->ann(), constants().ann.doc_comment))) { std::string ds = eval_string(env,docstring->args()[0]); std::string group("main"); size_t group_idx = ds.find("@group"); if (group_idx!=std::string::npos) { group = HtmlDocOutput::extractArgWord(ds, group_idx); } _funmap.insert(std::make_pair(fi, group)); } } }; class PrintHtmlVisitor : public ItemVisitor { protected: EnvI& env; HtmlDocOutput::Group& _maingroup; HtmlDocOutput::FunMap& _funmap; bool _includeStdLib; std::vector replaceArgs(std::string& s) { std::vector replacements; std::ostringstream oss; size_t lastpos = 0; size_t pos = std::min(s.find("\\a"), s.find("\\p")); size_t mathjax_open = s.find("\\("); size_t mathjax_close = s.rfind("\\)"); if (pos == std::string::npos) return replacements; while (pos != std::string::npos) { oss << s.substr(lastpos, pos-lastpos); size_t start = pos; while (start < s.size() && s[start]!=' ' && s[start]!='\t') start++; while (start < s.size() && (s[start]==' ' || s[start]=='\t')) start++; int end = start+1; while (end < s.size() && (isalnum(s[end]) || s[end]=='_')) end++; if (s[pos+1]=='a') { replacements.push_back(s.substr(start,end-start)); if (pos >= mathjax_open && pos <= mathjax_close) { oss << "{\\bf " << replacements.back() << "}"; } else { oss << "" << replacements.back() << ""; } } else { if (pos >= mathjax_open && pos <= mathjax_close) { oss << "{\\bf " << s.substr(start,end-start) << "}"; } else { oss << "" << s.substr(start,end-start) << ""; } } lastpos = end; pos = std::min(s.find("\\a", lastpos), s.find("\\p", lastpos)); } oss << s.substr(lastpos, std::string::npos); s = oss.str(); return replacements; } std::pair extractArgLine(std::string& s, size_t n) { size_t start = n; while (start < s.size() && s[start]!=' ' && s[start]!='\t') start++; while (start < s.size() && (s[start]==' ' || s[start]=='\t')) start++; int end = start+1; while (end < s.size() && s[end]!=':') end++; std::string arg = s.substr(start,end-start); size_t doc_start = end+1; while (end < s.size() && s[end]!='\n') end++; std::string ret = s.substr(doc_start,end-doc_start); replaceArgs(ret); s = s.substr(0,n)+s.substr(end,std::string::npos); return make_pair(arg,ret); } std::string addHTML(const std::string& s) { std::ostringstream oss; size_t lastpos = 0; size_t pos = s.find('\n'); bool inUl = false; oss << "

\n"; while (pos != std::string::npos) { oss << s.substr(lastpos, pos-lastpos); size_t next = std::min(s.find('\n', pos+1),s.find('-', pos+1)); if (next==std::string::npos) { lastpos = pos+1; break; } bool allwhite = true; for (size_t cur = pos+1; cur < next; cur++) { if (s[cur]!=' ' && s[cur]!='\t') { allwhite = false; break; } } if (allwhite) { if (s[next]=='-') { if (!inUl) { oss << "

    \n"; inUl = true; } oss << "
  • "; } else { if (inUl) { oss << "
\n"; inUl = false; } else { oss << "

\n"; } } lastpos = next+1; pos = s.find('\n', lastpos); } else { lastpos = pos+1; if (s[pos]=='\n') { oss << " "; } if (s[next]=='-') { pos = s.find('\n', next+1); } else { pos = next; } } } oss << s.substr(lastpos, std::string::npos); if (inUl) oss << "\n"; oss << "

\n"; return oss.str(); } public: PrintHtmlVisitor(EnvI& env0, HtmlDocOutput::Group& mg, HtmlDocOutput::FunMap& fm, bool includeStdLib) : env(env0), _maingroup(mg), _funmap(fm), _includeStdLib(includeStdLib) {} bool enterModel(Model* m) { if (!_includeStdLib && m->filename()=="stdlib.mzn") return false; const std::string& dc = m->docComment(); if (!dc.empty()) { size_t gpos = dc.find("@groupdef"); while (gpos != std::string::npos) { size_t start = gpos; while (start < dc.size() && dc[start]!=' ' && dc[start]!='\t') start++; while (start < dc.size() && (dc[start]==' ' || dc[start]=='\t')) start++; size_t end = start+1; while (end < dc.size() && (isalnum(dc[end]) || dc[end]=='_' || dc[end]=='.')) end++; std::string groupName = dc.substr(start,end-start); size_t doc_start = end+1; while (end < dc.size() && dc[end]!='\n') end++; std::string groupHTMLName = dc.substr(doc_start,end-doc_start); size_t next = dc.find("@groupdef", gpos+1); HtmlDocOutput::setGroupDesc(_maingroup, groupName, groupHTMLName, addHTML(dc.substr(end, next == std::string::npos ? next : next-end))); gpos = next; } } return true; } /// Visit variable declaration void vVarDeclI(VarDeclI* vdi) { if (Call* docstring = Expression::dyn_cast(getAnnotation(vdi->e()->ann(), constants().ann.doc_comment))) { std::string ds = eval_string(env,docstring->args()[0]); std::string group("main"); size_t group_idx = ds.find("@group"); if (group_idx!=std::string::npos) { group = HtmlDocOutput::extractArgWord(ds, group_idx); } std::ostringstream os; os << "
\n"; os << "
\n"; if (vdi->e()->ti()->type() == Type::ann()) { os << "annotation "; os << "" << *vdi->e()->id() << ""; } else { os << *vdi->e()->ti() << ": " << *vdi->e()->id(); } os << "
\n"; os << addHTML(ds); os << "
"; GCLock lock; HtmlDocOutput::DocItem di(vdi->e()->type().ispar() ? HtmlDocOutput::DocItem::T_PAR: HtmlDocOutput::DocItem::T_VAR, vdi->e()->type().toString()+" "+vdi->e()->id()->str().str(), os.str()); HtmlDocOutput::addToGroup(_maingroup, group, di); } } /// Visit function item void vFunctionI(FunctionI* fi) { if (Call* docstring = Expression::dyn_cast(getAnnotation(fi->ann(), constants().ann.doc_comment))) { std::string ds = eval_string(env,docstring->args()[0]); std::string group("main"); size_t group_idx = ds.find("@group"); if (group_idx!=std::string::npos) { group = HtmlDocOutput::extractArgWord(ds, group_idx); } size_t param_idx = ds.find("@param"); std::vector > params; while (param_idx != std::string::npos) { params.push_back(extractArgLine(ds, param_idx)); param_idx = ds.find("@param"); } std::vector args = replaceArgs(ds); UNORDERED_NAMESPACE::unordered_set allArgs; for (unsigned int i=0; iparams().size(); i++) { if (allArgs.find(fi->params()[i]->id()->str().str()) == allArgs.end()) { std::cerr << "Warning: parameter " << *fi->params()[i]->id() << " not documented for function " << fi->id() << " at location " << fi->loc() << "\n"; } } std::ostringstream os; os << "
\n"; os << "
"; os << ""; std::ostringstream fs; if (fi->ti()->type() == Type::ann()) { fs << "annotation "; os << "annotation "; } else if (fi->ti()->type() == Type::parbool()) { fs << "test "; os << "test "; } else if (fi->ti()->type() == Type::varbool()) { fs << "predicate "; os << "predicate "; } else { fs << "function " << *fi->ti() << ": "; os << "function " << *fi->ti() << ": "; } fs << fi->id() << "("; os << "" << fi->id() << "("; size_t align = fs.str().size(); for (unsigned int i=0; iparams().size(); i++) { fs << *fi->params()[i]->ti() << ": " << *fi->params()[i]->id(); if (i < fi->params().size()-1) { fs << ", "; } } bool splitArgs = (fs.str().size() > 70); for (unsigned int i=0; iparams().size(); i++) { os << "" << *fi->params()[i]->ti() << ": " << "" << *fi->params()[i]->id() << ""; if (i < fi->params().size()-1) { os << ","; if (splitArgs) { os << "\n"; for (unsigned int j=align; j--;) os << " "; } else { os << " "; } } } os << ")"; if (fi->e()) { FunctionI* f_body = fi; bool alias; do { alias = false; Call* c = Expression::dyn_cast(f_body->e()); if (c && c->args().size()==f_body->params().size()) { bool sameParams = true; for (unsigned int i=0; iparams().size(); i++) { Id* ident = c->args()[i]->dyn_cast(); if (ident == NULL || ident->decl() != f_body->params()[i] || ident->str() != c->decl()->params()[i]->id()->str()) { sameParams = false; break; } } if (sameParams) { alias = true; f_body = c->decl(); } } } while (alias); if (f_body->e()) { std::ostringstream body_os; Printer p(body_os, 70); p.print(f_body->e()); std::string filename = f_body->loc().filename.str(); size_t lastSlash = filename.find_last_of("/"); if (lastSlash != std::string::npos) { filename = filename.substr(lastSlash+1, std::string::npos); } os << " ="; os << "\n
"; os << "
"; os << body_os.str(); os << "
\n"; os << "(standard decomposition from "<loc().first_line<<")"; os << "
"; } } os << "
\n
\n"; if (fi->id().c_str()[0]=='\'') { std::string op = fi->id().str(); op = op.substr(1,op.length()-2); const char* space = (op[0]>='a' ? " " : ""); if (fi->params().size()==2) { os << "

Usage: " << *fi->params()[0]->id() << space << op << space << *fi->params()[1]->id() << "

"; } else if (fi->params().size()==1) { os << "

Usage: " << op << space << *fi->params()[0]->id() << "

"; } } std::string dshtml = addHTML(ds); os << dshtml; if (params.size() > 0) { os << "
Parameters
\n"; os << "
    \n"; for (unsigned int i=0; i" << params[i].first << ": " << params[i].second << "\n"; } os << "
\n"; } os << "
"; os << "
"; HtmlDocOutput::DocItem di(HtmlDocOutput::DocItem::T_FUN, fi->id().str(), os.str()); HtmlDocOutput::addToGroup(_maingroup, group, di); } } }; std::vector HtmlPrinter::printHtml(EnvI& env, MiniZinc::Model* m, const std::string& basename, int splitLevel, bool includeStdLib) { using namespace HtmlDocOutput; Group g(basename,basename); FunMap funMap; CollectFunctionsVisitor fv(env,funMap,includeStdLib); iterItems(fv, m); PrintHtmlVisitor phv(env,g,funMap,includeStdLib); iterItems(phv, m); std::vector ret; struct SI { Group* g; Group* p; int level; int idx; SI(Group* g0, Group* p0, int level0, int idx0) : g(g0), p(p0), level(level0), idx(idx0) {} }; std::vector stack; stack.push_back(SI(&g,NULL,0,0)); while (!stack.empty()) { Group& g = *stack.back().g; int curLevel = stack.back().level; int curIdx = stack.back().idx; Group* p = stack.back().p; stack.pop_back(); ret.push_back(HtmlDocument(g.fullPath, g.htmlName, g.toHTML(curLevel, splitLevel, p, curIdx, basename))); if (curLevel < splitLevel) { for (unsigned int i=0; i */ /* 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/. */ #include #include namespace MiniZinc { LocationException::LocationException(EnvI& env, const Location& loc, const std::string& msg) : Exception(msg), _loc(loc) { env.createErrorStack(); } } libminizinc-2.0.11/lib/flatten.cpp0000644000175000017500000076035612646030173015472 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include #include #include #include #include #include #include namespace MiniZinc { /// Output operator for contexts template std::basic_ostream& operator <<(std::basic_ostream& os, Ctx& ctx) { switch (ctx.b) { case C_ROOT: os << "R"; break; case C_POS: os << "+"; break; case C_NEG: os << "-"; break; case C_MIX: os << "M"; break; default: assert(false); break; } switch (ctx.i) { case C_ROOT: os << "R"; break; case C_POS: os << "+"; break; case C_NEG: os << "-"; break; case C_MIX: os << "M"; break; default: assert(false); break; } if (ctx.neg) os << "!"; return os; } BCtx operator +(const BCtx& c) { switch (c) { case C_ROOT: return C_POS; case C_POS: return C_POS; case C_NEG: return C_NEG; case C_MIX: return C_MIX; default: assert(false); return C_ROOT; } } BCtx operator -(const BCtx& c) { switch (c) { case C_ROOT: return C_NEG; case C_POS: return C_NEG; case C_NEG: return C_POS; case C_MIX: return C_MIX; default: assert(false); return C_ROOT; } } /// Check if \a c is non-positive bool nonpos(const BCtx& c) { return c==C_NEG || c==C_MIX; } /// Check if \a c is non-negative bool nonneg(const BCtx& c) { return c==C_ROOT || c==C_POS; } void dumpEEb(const std::vector& ee) { for (unsigned int i=0; i& ee) { for (unsigned int i=0; i toExpVec(std::vector& v) { std::vector r(v.size()); for (unsigned int i=v.size(); i--;) r[i] = v[i](); return r; } void addCtxAnn(VarDecl* vd, BCtx& c) { if (vd) { Id* ctx_id = NULL; switch (c) { case C_ROOT: ctx_id=constants().ctx.root; break; case C_POS: ctx_id=constants().ctx.pos; break; case C_NEG: ctx_id=constants().ctx.neg; break; case C_MIX: ctx_id=constants().ctx.mix; break; default: assert(false);; } vd->addAnnotation(ctx_id); } } Expression* definesVarAnn(Id* id) { std::vector args(1); args[0] = id; Call* c = new Call(Location().introduce(),constants().ann.defines_var,args); c->type(Type::ann()); return c; } bool isDefinesVarAnn(Expression* e) { return e->isa() && e->cast()->id()==constants().ann.defines_var; } /// Check if \a e is NULL or true bool istrue(EnvI& env, Expression* e) { GCLock lock; return e==NULL || (e->type().ispar() && e->type().isbool() && eval_bool(env,e)); } /// Check if \a e is non-NULL and false bool isfalse(EnvI& env, Expression* e) { GCLock lock; return e!=NULL && e->type().ispar() && e->type().isbool() && !eval_bool(env,e); } EE flat_exp(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); KeepAlive bind(EnvI& env, Ctx ctx, VarDecl* vd, Expression* e); VarDecl* newVarDecl(EnvI& env, Ctx ctx, TypeInst* ti, Id* id, VarDecl* origVd, Expression* rhs) { VarDecl* vd; if (id == NULL) vd = new VarDecl(rhs ? rhs->loc().introduce() : Location().introduce(), ti, env.genId()); else vd = new VarDecl(rhs ? rhs->loc().introduce() : Location().introduce(), ti, id); if (vd->e()) { bind(env, ctx, vd, rhs); } else { vd->e(rhs); } assert(!vd->type().isbot()); if (origVd && (origVd->id()->idn()!=-1 || origVd->toplevel())) { vd->introduced(origVd->introduced()); } else { vd->introduced(true); } vd->flat(vd); if (origVd) { for (ExpressionSetIter it = origVd->ann().begin(); it != origVd->ann().end(); ++it) { EE ee_ann = flat_exp(env, Ctx(), *it, NULL, constants().var_true); vd->addAnnotation(ee_ann.r()); } } VarDeclI* ni = new VarDeclI(Location().introduce(),vd); env.flat_addItem(ni); EE ee(vd,NULL); env.map_insert(vd->id(),ee); return vd; } #define MZN_FILL_REIFY_MAP(T,ID) reifyMap.insert(std::pair(constants().ids.T.ID,constants().ids.T ## reif.ID)); EnvI::EnvI(Model* orig0) : orig(orig0), output(new Model), ignorePartial(false), maxCallStack(0), collect_vardecls(false), in_redundant_constraint(0), _flat(new Model), ids(0) { MZN_FILL_REIFY_MAP(int_,lin_eq); MZN_FILL_REIFY_MAP(int_,lin_le); MZN_FILL_REIFY_MAP(int_,lin_ne); MZN_FILL_REIFY_MAP(int_,plus); MZN_FILL_REIFY_MAP(int_,minus); MZN_FILL_REIFY_MAP(int_,times); MZN_FILL_REIFY_MAP(int_,div); MZN_FILL_REIFY_MAP(int_,mod); MZN_FILL_REIFY_MAP(int_,lt); MZN_FILL_REIFY_MAP(int_,le); MZN_FILL_REIFY_MAP(int_,gt); MZN_FILL_REIFY_MAP(int_,ge); MZN_FILL_REIFY_MAP(int_,eq); MZN_FILL_REIFY_MAP(int_,ne); MZN_FILL_REIFY_MAP(float_,lin_eq); MZN_FILL_REIFY_MAP(float_,lin_le); MZN_FILL_REIFY_MAP(float_,lin_lt); MZN_FILL_REIFY_MAP(float_,lin_ne); MZN_FILL_REIFY_MAP(float_,plus); MZN_FILL_REIFY_MAP(float_,minus); MZN_FILL_REIFY_MAP(float_,times); MZN_FILL_REIFY_MAP(float_,div); MZN_FILL_REIFY_MAP(float_,mod); MZN_FILL_REIFY_MAP(float_,lt); MZN_FILL_REIFY_MAP(float_,le); MZN_FILL_REIFY_MAP(float_,gt); MZN_FILL_REIFY_MAP(float_,ge); MZN_FILL_REIFY_MAP(float_,eq); MZN_FILL_REIFY_MAP(float_,ne); reifyMap.insert(std::pair(constants().ids.forall,constants().ids.forall_reif)); reifyMap.insert(std::pair(constants().ids.bool_eq,constants().ids.bool_eq_reif)); reifyMap.insert(std::pair(constants().ids.bool_clause,constants().ids.bool_clause_reif)); reifyMap.insert(std::pair(constants().ids.clause,constants().ids.bool_clause_reif)); } EnvI::~EnvI(void) { delete _flat; delete output; } long long int EnvI::genId(void) { return ids++; } void EnvI::map_insert(Expression* e, const EE& ee) { KeepAlive ka(e); map.insert(ka,WW(ee.r(),ee.b())); } EnvI::Map::iterator EnvI::map_find(Expression* e) { KeepAlive ka(e); Map::iterator it = map.find(ka); if (it != map.end()) { if (it->second.r()) { if (it->second.r()->isa()) { int idx = vo.find(it->second.r()->cast()); if (idx == -1 || (*_flat)[idx]->removed()) return map.end(); } } else { return map.end(); } } return it; } void EnvI::map_remove(Expression* e) { KeepAlive ka(e); map.remove(ka); } EnvI::Map::iterator EnvI::map_end(void) { return map.end(); } void EnvI::dump(void) { struct EED { static std::string d(const WW& ee) { std::ostringstream oss; oss << ee.r() << " " << ee.b(); return oss.str(); } }; map.dump(); } void EnvI::flat_addItem(Item* i) { _flat->addItem(i); Expression* toAnnotate = NULL; Expression* toAdd = NULL; switch (i->iid()) { case Item::II_VD: { VarDeclI* vd = i->cast(); toAnnotate = vd->e()->e(); vo.add(vd, _flat->size()-1); toAdd = vd->e(); break; } case Item::II_CON: { ConstraintI* ci = i->cast(); toAnnotate = ci->e(); if (ci->e()->isa() && !ci->e()->cast()->v()) { _flat->fail(*this); } toAdd = ci->e(); break; } case Item::II_SOL: { SolveI* si = i->cast(); CollectOccurrencesE ce(vo,si); topDown(ce,si->e()); for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) topDown(ce,*it); break; } case Item::II_OUT: { OutputI* si = i->cast(); toAdd = si->e(); break; } default: break; } if (toAnnotate && toAnnotate->isa()) { int prev = idStack.size() > 0 ? idStack.back() : 0; bool allCalls = true; for (int i = callStack.size()-1; i >= prev; i--) { Expression* ee = reinterpret_cast(reinterpret_cast(callStack[i]) & ~static_cast(1)); allCalls = allCalls && (i==callStack.size()-1 || ee->isa()); for (ExpressionSetIter it = ee->ann().begin(); it != ee->ann().end(); ++it) { EE ee_ann = flat_exp(*this, Ctx(), *it, NULL, constants().var_true); if (allCalls || !isDefinesVarAnn(ee_ann.r())) toAnnotate->addAnnotation(ee_ann.r()); } } } if (toAdd) { CollectOccurrencesE ce(vo,i); topDown(ce,toAdd); } } void EnvI::flat_removeItem(MiniZinc::Item* i) { i->remove(); } void EnvI::flat_removeItem(int i) { (*_flat)[i]->remove(); } void EnvI::collectVarDecls(bool b) { collect_vardecls = b; } void EnvI::vo_add_exp(VarDecl* vd) { if (vd->e() && vd->e()->isa()) { int prev = idStack.size() > 0 ? idStack.back() : 0; for (int i = callStack.size()-1; i >= prev; i--) { Expression* ee = reinterpret_cast(reinterpret_cast(callStack[i]) & ~static_cast(1)); for (ExpressionSetIter it = ee->ann().begin(); it != ee->ann().end(); ++it) { EE ee_ann = flat_exp(*this, Ctx(), *it, NULL, constants().var_true); vd->e()->addAnnotation(ee_ann.r()); } } } int idx = vo.find(vd); CollectOccurrencesE ce(vo,(*_flat)[idx]); topDown(ce, vd->e()); if (collect_vardecls) modifiedVarDecls.push_back(idx); } Model* EnvI::flat(void) { return _flat; } ASTString EnvI::reifyId(const ASTString& id) { ASTStringMap::t::iterator it = reifyMap.find(id); if (it == reifyMap.end()) { return id.str()+"_reif"; } else { return it->second; } } #undef MZN_FILL_REIFY_MAP void EnvI::addWarning(const std::string& msg) { if (warnings.size()>20) return; if (warnings.size()==20) { warnings.push_back("Further warnings have been suppressed.\n"); } else { std::ostringstream oss; dumpStack(oss, false); warnings.push_back(msg+"\n"+oss.str()); } } void EnvI::createErrorStack(void) { errorStack.clear(); for (unsigned int i=callStack.size(); i--;) { KeepAlive ka(callStack[i]); errorStack.push_back(ka); } } CallStackItem::CallStackItem(EnvI& env0, Expression* e) : env(env0) { if (e->isa()) env.idStack.push_back(env.callStack.size()); if (e->isa() && e->cast()->id()=="redundant_constraint") env.in_redundant_constraint++; env.callStack.push_back(e); env.maxCallStack = std::max(env.maxCallStack, static_cast(env.callStack.size())); } CallStackItem::CallStackItem(EnvI& env0, Id* ident, IntVal i) : env(env0) { Expression* ee = reinterpret_cast(reinterpret_cast(ident) | static_cast(1)); env.callStack.push_back(ee); env.maxCallStack = std::max(env.maxCallStack, static_cast(env.callStack.size())); } CallStackItem::~CallStackItem(void) { Expression* e = reinterpret_cast(reinterpret_cast(env.callStack.back()) & ~static_cast(1)); if (e->isa()) env.idStack.pop_back(); if (e->isa() && e->cast()->id()=="redundant_constraint") env.in_redundant_constraint--; env.callStack.pop_back(); } class CallArgItem { public: EnvI& env; CallArgItem(EnvI& env0) : env(env0) { env.idStack.push_back(env.callStack.size()); } ~CallArgItem(void) { env.idStack.pop_back(); } }; FlatteningError::FlatteningError(EnvI& env, const Location& loc, const std::string& msg) : LocationException(env,loc,msg) {} Env::Env(Model* m) : e(new EnvI(m)) {} Env::~Env(void) { delete e; } Model* Env::model(void) { return e->orig; } Model* Env::flat(void) { return e->flat(); } Model* Env::output(void) { return e->output; } EnvI& Env::envi(void) { return *e; } const EnvI& Env::envi(void) const { return *e; } std::ostream& Env::dumpErrorStack(std::ostream& os) { return e->dumpStack(os, true); } std::ostream& EnvI::dumpStack(std::ostream& os, bool errStack) { int lastError = 0; std::vector errStackCopy; if (errStack) { errStackCopy.resize(errorStack.size()); for (unsigned int i=0; i& stack = errStack ? errStackCopy : callStack; for (; lastError < stack.size(); lastError++) { Expression* e = reinterpret_cast(reinterpret_cast(stack[lastError]) & ~static_cast(1)); bool isCompIter = reinterpret_cast(stack[lastError]) & static_cast(1); if (e->loc().is_introduced) continue; if (!isCompIter && e->isa()) { break; } } ASTString curloc_f; int curloc_l = -1; for (int i=lastError-1; i>=0; i--) { Expression* e = reinterpret_cast(reinterpret_cast(stack[i]) & ~static_cast(1)); bool isCompIter = reinterpret_cast(stack[i]) & static_cast(1); ASTString newloc_f = e->loc().filename; if (e->loc().is_introduced) continue; int newloc_l = e->loc().first_line; if (newloc_f != curloc_f || newloc_l != curloc_l) { os << " " << newloc_f << ":" << newloc_l << ":" << std::endl; curloc_f = newloc_f; curloc_l = newloc_l; } if (isCompIter) os << " with "; else os << " in "; switch (e->eid()) { case Expression::E_INTLIT: os << "integer literal" << std::endl; break; case Expression::E_FLOATLIT: os << "float literal" << std::endl; break; case Expression::E_SETLIT: os << "set literal" << std::endl; break; case Expression::E_BOOLLIT: os << "bool literal" << std::endl; break; case Expression::E_STRINGLIT: os << "string literal" << std::endl; break; case Expression::E_ID: if (isCompIter) { if (e->cast()->decl()->e()->type().ispar()) os << *e << " = " << *e->cast()->decl()->e() << std::endl; else os << *e << " = " << std::endl; } else { os << "identifier" << *e << std::endl; } break; case Expression::E_ANON: os << "anonymous variable" << std::endl; break; case Expression::E_ARRAYLIT: os << "array literal" << std::endl; break; case Expression::E_ARRAYACCESS: os << "array access" << std::endl; break; case Expression::E_COMP: { const Comprehension* cmp = e->cast(); if (cmp->set()) os << "set "; else os << "array "; os << "comprehension expression" << std::endl; } break; case Expression::E_ITE: os << "if-then-else expression" << std::endl; break; case Expression::E_BINOP: os << "binary " << e->cast()->opToString() << " operator expression" << std::endl; break; case Expression::E_UNOP: os << "unary " << e->cast()->opToString() << " operator expression" << std::endl; break; case Expression::E_CALL: os << "call '" << e->cast()->id() << "'" << std::endl; break; case Expression::E_VARDECL: { GCLock lock; os << "variable declaration for '" << e->cast()->id()->str() << "'" << std::endl; } break; case Expression::E_LET: os << "let expression" << std::endl; break; case Expression::E_TI: os << "type-inst expression" << std::endl; break; case Expression::E_TIID: os << "type identifier" << std::endl; break; default: assert(false); os << "unknown expression (internal error)" << std::endl; break; } } return os; } const std::vector& Env::warnings(void) { return envi().warnings; } void Env::clearWarnings(void) { envi().warnings.clear(); } unsigned int Env::maxCallStack(void) const { return envi().maxCallStack; } bool isTotal(FunctionI* fi) { return fi->ann().contains(constants().ann.promise_total); } bool isReverseMap(BinOp* e) { return e->ann().contains(constants().ann.is_reverse_map); } Expression* follow_id(Expression* e) { for (;;) { if (e==NULL) return NULL; if (e->eid()==Expression::E_ID && e != constants().absent) { e = e->cast()->decl()->e(); } else { return e; } } } Expression* follow_id_to_decl(Expression* e) { for (;;) { if (e==NULL) return NULL; if (e==constants().absent) return e; switch (e->eid()) { case Expression::E_ID: e = e->cast()->decl(); break; case Expression::E_VARDECL: if (e->cast()->e() && e->cast()->e()->isa()) e = e->cast()->e(); else return e; break; default: return e; } } } Expression* follow_id_to_value(Expression* e) { Expression* decl = follow_id_to_decl(e); if (VarDecl* vd = decl->dyn_cast()) { if (vd->e() && vd->e()->type().ispar()) return vd->e(); return vd->id(); } else { return decl; } } void checkIndexSets(EnvI& env, VarDecl* vd, Expression* e) { ASTExprVec tis = vd->ti()->ranges(); std::vector newtis(tis.size()); bool needNewTypeInst = false; GCLock lock; switch (e->eid()) { case Expression::E_ID: { Id* id = e->cast(); ASTExprVec e_tis = id->decl()->ti()->ranges(); assert(tis.size()==e_tis.size()); for (unsigned int i=0; idomain()==NULL) { newtis[i] = e_tis[i]; needNewTypeInst = true; } else { if (!eval_intset(env,tis[i]->domain())->equal(eval_intset(env,e_tis[i]->domain()))) throw EvalError(env, vd->loc(), "Index set mismatch"); newtis[i] = tis[i]; } } } break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); for (unsigned int i=0; idomain()==NULL) { newtis[i] = new TypeInst(Location().introduce(),Type(),new SetLit(Location().introduce(),IntSetVal::a(al->min(i),al->max(i)))); needNewTypeInst = true; } else { IntSetVal* isv = eval_intset(env,tis[i]->domain()); assert(isv->size()<=1); if ( (isv->size()==0 && al->min(i) <= al->max(i)) || (isv->size()!=0 && (isv->min(0) != al->min(i) || isv->max(0) != al->max(i))) ) throw EvalError(env, vd->loc(), "Index set mismatch"); newtis[i] = tis[i]; } } } break; default: throw InternalError("not supported yet"); } if (needNewTypeInst) { TypeInst* tic = copy(env,vd->ti())->cast(); tic->setRanges(newtis); vd->ti(tic); } } /// Turn \a c into domain constraints if possible. /// Return whether \a c is still required in the model. bool checkDomainConstraints(EnvI& env, Call* c) { if (c->id()==constants().ids.int_.le) { Expression* e0 = c->args()[0]; Expression* e1 = c->args()[1]; if (e0->type().ispar() && e1->isa()) { // greater than Id* id = e1->cast(); IntVal lb = eval_int(env,e0); if (id->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,id->decl()->ti()->domain()); if (domain->min() >= lb) return false; IntSetRanges dr(domain); Ranges::Const cr(lb,IntVal::infinity()); Ranges::Inter i(dr,cr); IntSetVal* newibv = IntSetVal::ai(i); id->decl()->ti()->domain(new SetLit(Location().introduce(), newibv)); id->decl()->ti()->setComputedDomain(false); } else { id->decl()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(lb,IntVal::infinity()))); } return false; } else if (e1->type().ispar() && e0->isa()) { // less than Id* id = e0->cast(); IntVal ub = eval_int(env,e1); if (id->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,id->decl()->ti()->domain()); if (domain->max() <= ub) return false; IntSetRanges dr(domain); Ranges::Const cr(-IntVal::infinity(), ub); Ranges::Inter i(dr,cr); IntSetVal* newibv = IntSetVal::ai(i); id->decl()->ti()->domain(new SetLit(Location().introduce(), newibv)); id->decl()->ti()->setComputedDomain(false); } else { id->decl()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(-IntVal::infinity(), ub))); } } } else if (c->id()==constants().ids.int_.lin_le) { ArrayLit* al_c = follow_id(c->args()[0])->cast(); if (al_c->v().size()==1) { ArrayLit* al_x = follow_id(c->args()[1])->cast(); IntVal coeff = eval_int(env,al_c->v()[0]); IntVal y = eval_int(env,c->args()[2]); IntVal lb = -IntVal::infinity(); IntVal ub = IntVal::infinity(); IntVal r = y % coeff; if (coeff >= 0) { ub = y / coeff; if (r<0) --ub; } else { lb = y / coeff; if (r<0) ++lb; } if (Id* id = al_x->v()[0]->dyn_cast()) { if (id->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,id->decl()->ti()->domain()); if (domain->max() <= ub && domain->min() >= lb) return false; IntSetRanges dr(domain); Ranges::Const cr(lb, ub); Ranges::Inter i(dr,cr); IntSetVal* newibv = IntSetVal::ai(i); id->decl()->ti()->domain(new SetLit(Location().introduce(), newibv)); id->decl()->ti()->setComputedDomain(false); } else { id->decl()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(lb, ub))); } return false; } } } return true; } KeepAlive bind(EnvI& env, Ctx ctx, VarDecl* vd, Expression* e) { assert(e==NULL || !e->isa()); if (Id* ident = e->dyn_cast()) { if (ident->decl()) { VarDecl* e_vd = follow_id_to_decl(ident)->cast(); e = e_vd->id(); } } if (ctx.neg) { assert(e->type().bt() == Type::BT_BOOL); if (vd==constants().var_true) { if (!isfalse(env,e)) { if (Id* id = e->dyn_cast()) { while (id != NULL) { assert(id->decl() != NULL); if (id->decl()->ti()->domain() && istrue(env,id->decl()->ti()->domain())) { GCLock lock; env.flat_addItem(new ConstraintI(Location().introduce(),constants().lit_false)); } else { id->decl()->ti()->domain(constants().lit_false); GCLock lock; std::vector args(2); args[0] = id; args[1] = constants().lit_false; Call* c = new Call(Location().introduce(),constants().ids.bool_eq,args); c->decl(env.orig->matchFn(env,c)); c->type(c->decl()->rtype(env,args)); if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } return constants().lit_true; } else { GC::lock(); BinOp* bo = new BinOp(e->loc(),e,BOT_EQUIV,constants().lit_false); bo->type(e->type()); KeepAlive ka(bo); GC::unlock(); EE ee = flat_exp(env,Ctx(),bo,NULL,constants().var_true); return bind(env,Ctx(),vd,ee.r()); } } return constants().lit_true; } else { GC::lock(); BinOp* bo = new BinOp(e->loc(),e,BOT_EQUIV,constants().lit_false); bo->type(e->type()); KeepAlive ka(bo); GC::unlock(); EE ee = flat_exp(env,Ctx(),bo,NULL,constants().var_true); return bind(env,Ctx(),vd,ee.r()); } } else { if (vd==constants().var_true) { if (!istrue(env,e)) { if (Id* id = e->dyn_cast()) { assert(id->decl() != NULL); while (id != NULL) { if (id->decl()->ti()->domain() && isfalse(env,id->decl()->ti()->domain())) { GCLock lock; env.flat_addItem(new ConstraintI(Location().introduce(),constants().lit_false)); } else if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(constants().lit_true); GCLock lock; std::vector args(2); args[0] = id; args[1] = constants().lit_true; Call* c = new Call(Location().introduce(),constants().ids.bool_eq,args); c->decl(env.orig->matchFn(env,c)); c->type(c->decl()->rtype(env,args)); if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } } else { GCLock lock; // extract domain information from added constraint if possible if (!e->isa() || checkDomainConstraints(env,e->cast())) { env.flat_addItem(new ConstraintI(Location().introduce(),e)); } } } return constants().lit_true; } else if (vd==constants().var_false) { if (!isfalse(env,e)) { throw InternalError("not supported yet"); } return constants().lit_true; } else if (vd==NULL) { if (e==NULL) return NULL; switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_ID: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_VARDECL: return e; case Expression::E_BINOP: case Expression::E_UNOP: return e; /// TODO: should not happen once operators are evaluated case Expression::E_ARRAYACCESS: case Expression::E_COMP: case Expression::E_ITE: case Expression::E_LET: case Expression::E_TI: throw InternalError("unevaluated expression"); case Expression::E_ARRAYLIT: { GCLock lock; ArrayLit* al = e->cast(); /// TODO: review if limit of 10 is a sensible choice if (al->type().bt()==Type::BT_ANN || al->v().size() <= 10) return e; std::vector ranges(al->dims()); for (unsigned int i=0; iloc(), Type(), new SetLit(Location().introduce(),IntSetVal::a(al->min(i),al->max(i)))); } ASTExprVec ranges_v(ranges); assert(!al->type().isbot()); Expression* domain = NULL; if (al->v().size() > 0 && al->v()[0]->type().isint()) { IntVal min = IntVal::infinity(); IntVal max = -IntVal::infinity(); for (unsigned int i=0; iv().size(); i++) { IntBounds ib = compute_int_bounds(env,al->v()[i]); if (!ib.valid) { min = -IntVal::infinity(); max = IntVal::infinity(); break; } min = std::min(min, ib.l); max = std::max(max, ib.u); } if (min != -IntVal::infinity() && max != IntVal::infinity()) { domain = new SetLit(Location().introduce(), IntSetVal::a(min,max)); } } TypeInst* ti = new TypeInst(e->loc(),al->type(),ranges_v,domain); if (domain) ti->setComputedDomain(true); VarDecl* vd = newVarDecl(env, ctx, ti, NULL, NULL, al); EE ee(vd,NULL); env.map_insert(al,ee); env.map_insert(vd->e(),ee); return vd->id(); } case Expression::E_CALL: { if (e->type().isann()) return e; GCLock lock; /// TODO: handle array types TypeInst* ti = new TypeInst(Location().introduce(),e->type()); VarDecl* vd = newVarDecl(env, ctx, ti, NULL, NULL, e); if (vd->e()->type().bt()==Type::BT_INT && vd->e()->type().dim()==0) { IntSetVal* ibv = NULL; if (vd->e()->type().is_set()) { ibv = compute_intset_bounds(env,vd->e()); } else { IntBounds ib = compute_int_bounds(env,vd->e()); if (ib.valid) { ibv = IntSetVal::a(ib.l,ib.u); } } if (ibv) { Id* id = vd->id(); while (id != NULL) { if (id->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,id->decl()->ti()->domain()); IntSetRanges dr(domain); IntSetRanges ibr(ibv); Ranges::Inter i(dr,ibr); IntSetVal* newibv = IntSetVal::ai(i); if (ibv->card() == newibv->card()) { id->decl()->ti()->setComputedDomain(true); } else { ibv = newibv; } } else { id->decl()->ti()->setComputedDomain(true); } if (id->type().st()==Type::ST_PLAIN && ibv->size()==0) { env.flat()->fail(env); } else { id->decl()->ti()->domain(new SetLit(Location().introduce(),ibv)); } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } } } else if (vd->e()->type().isbool()) { addCtxAnn(vd, ctx.b); } else if (vd->e()->type().bt()==Type::BT_FLOAT && vd->e()->type().dim()==0) { FloatBounds fb = compute_float_bounds(env,vd->e()); BinOp* ibv = LinearTraits::intersect_domain(NULL, fb.l, fb.u); if (fb.valid) { Id* id = vd->id(); while (id != NULL) { if (id->decl()->ti()->domain()) { BinOp* domain = Expression::cast(id->decl()->ti()->domain()); BinOp* ndomain = LinearTraits::intersect_domain(domain, fb.l, fb.u); if (ibv && ndomain==domain) { id->decl()->ti()->setComputedDomain(true); } else { ibv = ndomain; } } else { id->decl()->ti()->setComputedDomain(true); } if (LinearTraits::domain_empty(ibv)) { env.flat()->fail(env); } else { id->decl()->ti()->domain(ibv); } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } } } return vd->id(); } default: assert(false); return NULL; } } else { if (vd->e()==NULL) { Expression* ret = e; if (e==NULL || (e->type().ispar() && e->type().isbool())) { GCLock lock; if (e==NULL || eval_bool(env,e)) { vd->e(constants().lit_true); } else { vd->e(constants().lit_false); } if (vd->ti()->domain()) { if (vd->ti()->domain() != vd->e()) { env.flat()->fail(env); return vd->id(); } } else { vd->ti()->domain(vd->e()); vd->ti()->setComputedDomain(true); } std::vector args(2); args[0] = vd->id(); args[1] = vd->e(); Call* c = new Call(Location().introduce(),constants().ids.bool_eq,args); c->decl(env.orig->matchFn(env,c)); c->type(c->decl()->rtype(env,args)); if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); return vd->id(); } } else { if (e->type().dim() > 0) { // Check that index sets match env.errorStack.clear(); checkIndexSets(env,vd,e); if (vd->ti()->domain() && e->isa()) { ArrayLit* al = e->cast(); if (e->type().bt()==Type::BT_INT) { IntSetVal* isv = eval_intset(env, vd->ti()->domain()); for (unsigned int i=0; iv().size(); i++) { if (Id* id = al->v()[i]->dyn_cast()) { VarDecl* vdi = id->decl(); if (vdi->ti()->domain()==NULL) { vdi->ti()->domain(vd->ti()->domain()); } else { IntSetVal* vdi_dom = eval_intset(env, vdi->ti()->domain()); IntSetRanges isvr(isv); IntSetRanges vdi_domr(vdi_dom); Ranges::Inter inter(isvr,vdi_domr); IntSetVal* newdom = IntSetVal::ai(inter); if (newdom->size()==0) { env.flat()->fail(env); } else { vdi->ti()->domain(new SetLit(Location().introduce(),newdom)); } } } } } else if (e->type().bt()==Type::BT_FLOAT) { FloatVal f_min = eval_float(env, vd->ti()->domain()->cast()->lhs()); FloatVal f_max = eval_float(env, vd->ti()->domain()->cast()->rhs()); for (unsigned int i=0; iv().size(); i++) { if (Id* id = al->v()[i]->dyn_cast()) { VarDecl* vdi = id->decl(); if (vdi->ti()->domain()==NULL) { vdi->ti()->domain(vd->ti()->domain()); } else { BinOp* ndomain = LinearTraits::intersect_domain(vdi->ti()->domain()->cast(), f_min, f_max); if (ndomain != vdi->ti()->domain()) { vdi->ti()->domain(ndomain); } } } } } } } else if (Id* e_id = e->dyn_cast()) { if (e_id == vd->id()) { ret = vd->id(); } else { ASTString cid; if (e->type().isint()) { cid = constants().ids.int_.eq; } else if (e->type().isbool()) { cid = constants().ids.bool_eq; } else if (e->type().is_set()) { cid = constants().ids.set_eq; } else if (e->type().isfloat()) { cid = constants().ids.float_.eq; } if (cid != "") { GCLock lock; std::vector args(2); args[0] = vd->id(); args[1] = e_id; Call* c = new Call(Location().introduce(),cid,args); c->decl(env.orig->matchFn(env,c)); c->type(c->decl()->rtype(env,args)); if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); ret = vd->id(); vd->e(e); env.vo_add_exp(vd); } } } } if (ret != vd->id()) { vd->e(ret); env.vo_add_exp(vd); ret = vd->id(); } if (vd->e() && vd->e()->type().bt()==Type::BT_INT && vd->e()->type().dim()==0) { GCLock lock; IntSetVal* ibv = NULL; if (vd->e()->type().is_set()) { ibv = compute_intset_bounds(env,vd->e()); } else { IntBounds ib = compute_int_bounds(env,vd->e()); if (ib.valid) { Call* call = vd->e()->dyn_cast(); if (call && call->id()==constants().ids.lin_exp) { ArrayLit* al = eval_array_lit(env, call->args()[1]); if (al->v().size()==1) { IntBounds check_zeroone = compute_int_bounds(env, al->v()[0]); if (check_zeroone.l==0 && check_zeroone.u==1) { ArrayLit* coeffs = eval_array_lit(env, call->args()[0]); std::vector newdom(2); newdom[0] = 0; newdom[1] = eval_int(env, coeffs->v()[0])+eval_int(env, call->args()[2]); ibv = IntSetVal::a(newdom); } } } if (ibv==NULL) { ibv = IntSetVal::a(ib.l,ib.u); } } } if (ibv) { if (vd->ti()->domain()) { IntSetVal* domain = eval_intset(env,vd->ti()->domain()); IntSetRanges dr(domain); IntSetRanges ibr(ibv); Ranges::Inter i(dr,ibr); IntSetVal* newibv = IntSetVal::ai(i); if (ibv->card() == newibv->card()) { vd->ti()->setComputedDomain(true); } else { ibv = newibv; } } else { vd->ti()->setComputedDomain(true); } vd->ti()->domain(new SetLit(Location().introduce(),ibv)); } } } return ret; } else if (vd == e) { return vd->id(); } else if (vd->e() != e) { e = follow_id_to_decl(e); if (vd == e) return vd->id(); switch (e->eid()) { case Expression::E_BOOLLIT: { Id* id = vd->id(); while (id != NULL) { if (id->decl()->ti()->domain() && eval_bool(env,id->decl()->ti()->domain()) == e->cast()->v()) { return constants().lit_true; } else if (id->decl()->ti()->domain() && eval_bool(env,id->decl()->ti()->domain()) != e->cast()->v()) { GCLock lock; env.flat_addItem(new ConstraintI(Location().introduce(),constants().lit_false)); } else { id->decl()->ti()->domain(e); GCLock lock; std::vector args(2); args[0] = id; args[1] = e; Call* c = new Call(Location().introduce(),constants().ids.bool_eq,args); c->decl(env.orig->matchFn(env,c)); c->type(c->decl()->rtype(env,args)); if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } return constants().lit_true; } case Expression::E_VARDECL: { VarDecl* e_vd = e->cast(); if (vd->e()==e_vd->id() || e_vd->e()==vd->id()) return vd->id(); if (e->type().dim() != 0) throw InternalError("not supported yet"); GCLock lock; ASTString cid; if (e->type().isint()) { cid = constants().ids.int_.eq; } else if (e->type().isbool()) { cid = constants().ids.bool_eq; } else if (e->type().is_set()) { cid = constants().ids.set_eq; } else if (e->type().isfloat()) { cid = constants().ids.float_.eq; } else { throw InternalError("not yet implemented"); } std::vector args(2); args[0] = vd->id(); args[1] = e_vd->id(); Call* c = new Call(Location().introduce(),cid,args); c->decl(env.orig->matchFn(env,c)); c->type(c->decl()->rtype(env,args)); flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); return vd->id(); } case Expression::E_CALL: { Call* c = e->cast(); GCLock lock; Call* nc; std::vector args; if (c->id() == constants().ids.lin_exp) { ArrayLit* le_c = follow_id(c->args()[0])->cast(); std::vector ncoeff(le_c->v().size()); std::copy(le_c->v().begin(),le_c->v().end(),ncoeff.begin()); ncoeff.push_back(IntLit::a(-1)); args.push_back(new ArrayLit(Location().introduce(),ncoeff)); args[0]->type(le_c->type()); ArrayLit* le_x = follow_id(c->args()[1])->cast(); std::vector nx(le_x->v().size()); std::copy(le_x->v().begin(),le_x->v().end(),nx.begin()); nx.push_back(vd->id()); args.push_back(new ArrayLit(Location().introduce(),nx)); args[1]->type(le_x->type()); if (c->type().bt()==Type::BT_INT) { IntVal d = c->args()[2]->cast()->v(); args.push_back(IntLit::a(-d)); nc = new Call(c->loc().introduce(), constants().ids.int_.lin_eq, args); } else { FloatVal d = c->args()[2]->cast()->v(); args.push_back(FloatLit::a(-d)); nc = new Call(c->loc().introduce(), constants().ids.float_.lin_eq, args); } } else { args.resize(c->args().size()); std::copy(c->args().begin(),c->args().end(),args.begin()); args.push_back(vd->id()); ASTString nid = c->id(); if (c->id() == constants().ids.exists) { nid = constants().ids.array_bool_or; } else if (c->id() == constants().ids.forall) { nid = constants().ids.array_bool_and; } else if (vd->type().isbool()) { nid = env.reifyId(c->id()); } nc = new Call(c->loc().introduce(), nid, args); } nc->decl(env.orig->matchFn(env,nc)); if (nc->decl() == NULL) { throw InternalError("undeclared function or predicate " +nc->id().str()); } nc->type(nc->decl()->rtype(env,args)); nc->addAnnotation(definesVarAnn(vd->id())); vd->addAnnotation(constants().ann.is_defined_var); flat_exp(env, Ctx(), nc, constants().var_true, constants().var_true); return vd->id(); } break; default: throw InternalError("not supported yet"); } } else { return e; } } } } KeepAlive conj(EnvI& env,VarDecl* b,Ctx ctx,const std::vector& e) { if (!ctx.neg) { std::vector nontrue; for (unsigned int i=0; i args; ArrayLit* al = new ArrayLit(Location().introduce(),nontrue); al->type(Type::varbool(1)); args.push_back(al); Call* ret = new Call(Location().introduce(),constants().ids.forall,args); ret->decl(env.orig->matchFn(env,ret)); ret->type(ret->decl()->rtype(env,args)); KeepAlive ka(ret); GC::unlock(); return flat_exp(env,ctx,ret,b,constants().var_true).r; } } } else { Ctx nctx = ctx; nctx.neg = false; // negated std::vector nonfalse; for (unsigned int i=0; iloc(),UOT_NOT,nonfalse[0]); uo->type(Type::varbool()); KeepAlive ka(uo); GC::unlock(); return flat_exp(env,nctx,uo,b,constants().var_true).r; } else { if (b==constants().var_false) { for (unsigned int i=0; i args; for (unsigned int i=0; iloc(),UOT_NOT,nonfalse[i]); uo->type(Type::varbool()); nonfalse[i] = uo; } ArrayLit* al = new ArrayLit(Location().introduce(),nonfalse); al->type(Type::varbool(1)); args.push_back(al); Call* ret = new Call(Location().introduce().introduce(),constants().ids.exists,args); ret->decl(env.orig->matchFn(env, ret)); ret->type(ret->decl()->rtype(env, args)); assert(ret->decl()); KeepAlive ka(ret); GC::unlock(); return flat_exp(env,nctx,ret,b,constants().var_true).r; } } } } TypeInst* eval_typeinst(EnvI& env, VarDecl* vd) { bool hasTiVars = vd->ti()->domain() && vd->ti()->domain()->isa(); for (unsigned int i=0; iti()->ranges().size(); i++) { hasTiVars = hasTiVars || (vd->ti()->ranges()[i]->domain() && vd->ti()->ranges()[i]->domain()->isa()); } if (hasTiVars) { assert(vd->e()); if (vd->e()->type().dim()==0) return new TypeInst(Location().introduce(),vd->e()->type()); ArrayLit* al = eval_array_lit(env,vd->e()); std::vector dims(al->dims()); for (unsigned int i=0; imin(i),al->max(i)))); } return new TypeInst(Location().introduce(), vd->e()->type(), dims, eval_par(env,vd->ti()->domain())); } else { std::vector dims(vd->ti()->ranges().size()); for (unsigned int i=0; iti()->ranges().size(); i++) { if (vd->ti()->ranges()[i]->domain()) { IntSetVal* isv = eval_intset(env,vd->ti()->ranges()[i]->domain()); if (isv->size() > 1) throw EvalError(env, vd->ti()->ranges()[i]->domain()->loc(), "array index set must be contiguous range"); SetLit* sl = new SetLit(vd->ti()->ranges()[i]->loc(),isv); sl->type(Type::parsetint()); dims[i] = new TypeInst(vd->ti()->ranges()[i]->loc(), Type(),sl); } else { dims[i] = new TypeInst(vd->ti()->ranges()[i]->loc(), Type(), NULL); } } Type t = (vd->e() && !vd->e()->type().isbot()) ? vd->e()->type() : vd->ti()->type(); return new TypeInst(vd->ti()->loc(), t, dims, eval_par(env,vd->ti()->domain())); } } ASTString opToBuiltin(BinOp* op, BinOpType bot) { std::string builtin; if (op->rhs()->type().isint()) { switch (bot) { case BOT_PLUS: return constants().ids.int_.plus; case BOT_MINUS: return constants().ids.int_.minus; case BOT_MULT: return constants().ids.int_.times; case BOT_IDIV: return constants().ids.int_.div; case BOT_MOD: return constants().ids.int_.mod; case BOT_LE: return constants().ids.int_.lt; case BOT_LQ: return constants().ids.int_.le; case BOT_GR: return constants().ids.int_.gt; case BOT_GQ: return constants().ids.int_.ge; case BOT_EQ: return constants().ids.int_.eq; case BOT_NQ: return constants().ids.int_.ne; default: throw InternalError("not yet implemented"); } } else if (op->rhs()->type().isbool()) { if (bot==BOT_EQ || bot==BOT_EQUIV) return constants().ids.bool_eq; builtin = "bool_"; } else if (op->rhs()->type().is_set()) { builtin = "set_"; } else if (op->rhs()->type().isfloat()) { switch (bot) { case BOT_PLUS: return constants().ids.float_.plus; case BOT_MINUS: return constants().ids.float_.minus; case BOT_MULT: return constants().ids.float_.times; case BOT_DIV: return constants().ids.float_.div; case BOT_MOD: return constants().ids.float_.mod; case BOT_LE: return constants().ids.float_.lt; case BOT_LQ: return constants().ids.float_.le; case BOT_GR: return constants().ids.float_.gt; case BOT_GQ: return constants().ids.float_.ge; case BOT_EQ: return constants().ids.float_.eq; case BOT_NQ: return constants().ids.float_.ne; default: throw InternalError("not yet implemented"); } } else if (op->rhs()->type().isopt() && (bot==BOT_EQUIV || bot==BOT_EQ)) { /// TODO: extend to all option type operators switch (op->lhs()->type().bt()) { case Type::BT_BOOL: return constants().ids.bool_eq; case Type::BT_FLOAT: return constants().ids.float_.eq; case Type::BT_INT: if (op->lhs()->type().st()==Type::ST_PLAIN) return constants().ids.int_.eq; else return constants().ids.set_eq; default: throw InternalError("not yet implemented"); } } else { throw InternalError(op->opToString().str()+" not yet implemented"); } switch (bot) { case BOT_PLUS: return builtin+"plus"; case BOT_MINUS: return builtin+"minus"; case BOT_MULT: return builtin+"times"; case BOT_DIV: return builtin+"div"; case BOT_IDIV: return builtin+"div"; case BOT_MOD: return builtin+"mod"; case BOT_LE: return builtin+"lt"; case BOT_LQ: return builtin+"le"; case BOT_GR: return builtin+"gt"; case BOT_GQ: return builtin+"ge"; case BOT_EQ: return builtin+"eq"; case BOT_NQ: return builtin+"ne"; case BOT_IN: return constants().ids.set_in; case BOT_SUBSET: return builtin+"subset"; case BOT_SUPERSET: return builtin+"superset"; case BOT_UNION: return builtin+"union"; case BOT_DIFF: return builtin+"diff"; case BOT_SYMDIFF: return builtin+"symdiff"; case BOT_INTERSECT: return builtin+"intersect"; case BOT_PLUSPLUS: case BOT_DOTDOT: throw InternalError("not yet implemented"); case BOT_EQUIV: return builtin+"eq"; case BOT_IMPL: return builtin+"le"; case BOT_RIMPL: return builtin+"ge"; case BOT_OR: return builtin+"or"; case BOT_AND: return builtin+"and"; case BOT_XOR: return constants().ids.bool_xor; default: assert(false); return ASTString(""); } } Call* same_call(Expression* e, const ASTString& id) { Expression* ce = follow_id(e); if (ce && ce->isa() && ce->cast()->id() == id) return ce->cast(); return NULL; } template void collectLinExps(EnvI& env, typename LinearTraits::Val c, Expression* exp, std::vector::Val>& coeffs, std::vector& vars, typename LinearTraits::Val& constval) { typedef typename LinearTraits::Val Val; struct StackItem { Expression* e; Val c; StackItem(Expression* e0, Val c0) : e(e0), c(c0) {} }; std::vector stack; stack.push_back(StackItem(exp,c)); while (!stack.empty()) { Expression* e = stack.back().e; Val c = stack.back().c; stack.pop_back(); if (e==NULL) continue; if (e->type().ispar()) { constval += c * LinearTraits::eval(env,e); } else if (Lit* l = e->dyn_cast()) { constval += c * l->v(); } else if (BinOp* bo = e->dyn_cast()) { switch (bo->op()) { case BOT_PLUS: stack.push_back(StackItem(bo->lhs(),c)); stack.push_back(StackItem(bo->rhs(),c)); break; case BOT_MINUS: stack.push_back(StackItem(bo->lhs(),c)); stack.push_back(StackItem(bo->rhs(),-c)); break; case BOT_MULT: if (bo->lhs()->type().ispar()) { stack.push_back(StackItem(bo->rhs(),c*LinearTraits::eval(env,bo->lhs()))); } else if (bo->rhs()->type().ispar()) { stack.push_back(StackItem(bo->lhs(),c*LinearTraits::eval(env,bo->rhs()))); } else { coeffs.push_back(c); vars.push_back(e); } break; case BOT_DIV: if (bo->rhs()->isa() && bo->rhs()->cast()->v()==1.0) { stack.push_back(StackItem(bo->lhs(),c)); } else { coeffs.push_back(c); vars.push_back(e); } break; case BOT_IDIV: if (bo->rhs()->isa() && bo->rhs()->cast()->v()==1) { stack.push_back(StackItem(bo->lhs(),c)); } else { coeffs.push_back(c); vars.push_back(e); } break; default: coeffs.push_back(c); vars.push_back(e); break; } // } else if (Call* call = e->dyn_cast()) { // /// TODO! Handle sum, lin_exp (maybe not that important?) } else { coeffs.push_back(c); vars.push_back(e); } } } template KeepAlive mklinexp(EnvI& env, typename LinearTraits::Val c0, typename LinearTraits::Val c1, Expression* e0, Expression* e1) { typedef typename LinearTraits::Val Val; GCLock lock; std::vector coeffs; std::vector vars; Val constval = 0; collectLinExps(env, c0, e0, coeffs, vars, constval); collectLinExps(env, c1, e1, coeffs, vars, constval); simplify_lin(coeffs, vars, constval); KeepAlive ka; if (coeffs.size()==0) { ka = LinearTraits::newLit(constval); } else if (coeffs.size()==1 && coeffs[0]==1 && constval==0) { ka = vars[0]; } else { std::vector coeffs_e(coeffs.size()); for (unsigned int i=coeffs.size(); i--;) { if (!LinearTraits::finite(coeffs[i])) { throw FlatteningError(env,e0->loc(), "unbounded coefficient in linear expression"); } coeffs_e[i] = LinearTraits::newLit(coeffs[i]); } std::vector vars_e(vars.size()); for (unsigned int i=vars.size(); i--;) vars_e[i] = vars[i](); std::vector args(3); args[0]=new ArrayLit(e0->loc(),coeffs_e); Type t = coeffs_e[0]->type(); t.dim(1); args[0]->type(t); args[1]=new ArrayLit(e0->loc(),vars_e); Type tt = vars_e[0]->type(); tt.dim(1); args[1]->type(tt); args[2] = LinearTraits::newLit(constval); Call* c = new Call(e0->loc().introduce(),constants().ids.lin_exp,args); tt = args[1]->type(); tt.dim(0); c->decl(env.orig->matchFn(env, c)); if (c->decl()==NULL) { throw FlatteningError(env,c->loc(), "cannot find matching declaration"); } c->type(c->decl()->rtype(env, args)); ka = c; } assert(ka()); return ka; } class CmpExp { public: bool operator ()(const KeepAlive& i, const KeepAlive& j) const { if (Expression::equal(i(),j())) return false; return i()& x, bool identity) { for (unsigned int i=0; iisa()) { if (x[i]()->cast()->v()==identity) { // skip } else { return true; } } else { x[ci++] = x[i]; } } } x.resize(ci); return false; } bool contains_dups(std::vector& x, std::vector& y) { if (x.size()==0 || y.size()==0) return false; unsigned int ix=0; unsigned int iy=0; for (;;) { if (x[ix]()==y[iy]()) return true; if (x[ix]() < y[iy]()) { ix++; } else { iy++; } if (ix==x.size() || iy==y.size()) return false; } } /// Return a lin_exp or id if \a e is a lin_exp or id template Expression* get_linexp(Expression* e) { for (;;) { if (e && e->eid()==Expression::E_ID && e != constants().absent) { if (e->cast()->decl()->e()) { e = e->cast()->decl()->e(); } else { break; } } else { break; } } if (e && (e->isa() || e->isa() || (e->isa() && e->cast()->id() == constants().ids.lin_exp))) return e; return NULL; } KeepAlive flat_cv_exp(EnvI& env, Ctx ctx, Expression* e); /// TODO: check if all expressions are total /// If yes, use element encoding /// If not, use implication encoding EE flat_ite(EnvI& env,Ctx ctx, ITE* ite, VarDecl* r, VarDecl* b) { // The conditions of each branch of the if-then-else std::vector conditions; // Whether the right hand side of each branch is defined std::vector defined; GC::lock(); // Compute bounds of result as union bounds of all branches IntBounds r_bounds(IntVal::infinity(),-IntVal::infinity(),true); std::vector r_bounds_int; bool r_bounds_valid_int = true; std::vector r_bounds_set; bool r_bounds_valid_set = true; std::vector r_bounds_float; bool r_bounds_valid_float = true; VarDecl* nr = r; if (b==NULL) { b = newVarDecl(env, Ctx(), new TypeInst(Location().introduce(),Type::varbool()), NULL, NULL, NULL); } Ctx cmix; cmix.b = C_MIX; cmix.i = C_MIX; for (int i=0; isize(); i++) { bool cond = true; if (ite->e_if(i)->type()==Type::parbool()) { // par bool case: evaluate condition statically if (ite->e_if(i)->type().cv()) { KeepAlive ka = flat_cv_exp(env, ctx, ite->e_if(i)); cond = eval_bool(env, ka()); } else { cond = eval_bool(env,ite->e_if(i)); } if (cond) { if (nr==NULL || conditions.size()==0) { // no var conditions before this one, so we can simply emit // the then branch GC::unlock(); return flat_exp(env,ctx,ite->e_then(i),r,b); } // had var conditions, so we have to take them into account // and emit new conditional clause Ctx cmix; cmix.b = C_MIX; cmix.i = C_MIX; EE ethen = flat_exp(env, cmix, ite->e_then(i), NULL, NULL); Expression* eq_then; if (nr == constants().var_true) { eq_then = ethen.r(); } else { eq_then = new BinOp(Location().introduce(),nr->id(),BOT_EQ,ethen.r()); eq_then->type(Type::varbool()); } { std::vector neg; std::vector clauseArgs(2); if (b != constants().var_true) neg.push_back(b->id()); // temporarily push the then part onto the conditions conditions.push_back(eq_then); clauseArgs[0] = new ArrayLit(Location().introduce(),conditions); clauseArgs[0]->type(Type::varbool(1)); clauseArgs[1] = new ArrayLit(Location().introduce(),neg); clauseArgs[1]->type(Type::varbool(1)); { // b -> r=r[i] Call* clause = new Call(Location().introduce(), constants().ids.clause, clauseArgs); clause->decl(env.orig->matchFn(env, clause)); clause->type(clause->decl()->rtype(env, clauseArgs)); (void) flat_exp(env, Ctx(), clause, constants().var_true, constants().var_true); } conditions.pop_back(); } // add another condition and definedness variable conditions.push_back(constants().lit_true); defined.push_back(ethen.b()); } } else { if (nr==NULL) { // need to introduce new result variable TypeInst* ti = new TypeInst(Location().introduce(),ite->type(),NULL); nr = newVarDecl(env, Ctx(), ti, NULL, NULL, NULL); } // flatten the then branch EE ethen = flat_exp(env, cmix, ite->e_then(i), NULL, NULL); Expression* eq_then; if (nr == constants().var_true) { eq_then = ethen.r(); } else { eq_then = new BinOp(Location().introduce(),nr->id(),BOT_EQ,ethen.r()); eq_then->type(Type::varbool()); } { // Create a clause with all the previous conditions negated, the // current condition, and the then branch. // Also take partiality into account. std::vector neg(1); std::vector clauseArgs(2); neg[0] = ite->e_if(i); if (b != constants().var_true) neg.push_back(b->id()); // temporarily push the then part onto the conditions conditions.push_back(eq_then); clauseArgs[0] = new ArrayLit(Location().introduce(),conditions); clauseArgs[0]->type(Type::varbool(1)); clauseArgs[1] = new ArrayLit(Location().introduce(),neg); clauseArgs[1]->type(Type::varbool(1)); { // b /\ c[i] -> r=r[i] Call* clause = new Call(Location().introduce(), constants().ids.clause, clauseArgs); clause->decl(env.orig->matchFn(env, clause)); clause->type(clause->decl()->rtype(env, clauseArgs)); (void) flat_exp(env, Ctx(), clause, constants().var_true, constants().var_true); } conditions.pop_back(); } // add current condition and definedness variable conditions.push_back(ite->e_if(i)); defined.push_back(ethen.b()); } // update bounds if (cond) { if (r_bounds_valid_int && ite->e_then(i)->type().isint()) { IntBounds ib_then = compute_int_bounds(env,ite->e_then(i)); if (ib_then.valid) r_bounds_int.push_back(ib_then); r_bounds_valid_int = r_bounds_valid_int && ib_then.valid; } else if (r_bounds_valid_set && ite->e_then(i)->type().isintset()) { IntSetVal* isv = compute_intset_bounds(env, ite->e_then(i)); if (isv) r_bounds_set.push_back(isv); r_bounds_valid_set = r_bounds_valid_set && isv; } else if (r_bounds_valid_float && ite->e_then(i)->type().isfloat()) { FloatBounds fb_then = compute_float_bounds(env, ite->e_then(i)); if (fb_then.valid) r_bounds_float.push_back(fb_then); r_bounds_valid_float = r_bounds_valid_float && fb_then.valid; } } } if (nr==NULL || conditions.size()==0) { // no var condition, and all par conditions were false, // so simply emit else branch GC::unlock(); return flat_exp(env,ctx,ite->e_else(),r,b); } // update bounds of result with bounds of else branch if (r_bounds_valid_int && ite->e_else()->type().isint()) { IntBounds ib_else = compute_int_bounds(env,ite->e_else()); if (ib_else.valid) { r_bounds_int.push_back(ib_else); IntVal lb = IntVal::infinity(); IntVal ub = -IntVal::infinity(); for (unsigned int i=0; iid()); if (orig_r_bounds.valid) { lb = std::max(lb,orig_r_bounds.l); ub = std::min(ub,orig_r_bounds.u); } } SetLit* r_dom = new SetLit(Location().introduce(), IntSetVal::a(lb,ub)); nr->ti()->domain(r_dom); } } else if (r_bounds_valid_set && ite->e_else()->type().isintset()) { IntSetVal* isv_else = compute_intset_bounds(env, ite->e_else()); if (isv_else) { IntSetVal* isv = isv_else; for (unsigned int i=0; i u(i0,i1); isv = IntSetVal::ai(u); } if (r) { IntSetVal* orig_r_bounds = compute_intset_bounds(env,r->id()); if (orig_r_bounds) { IntSetRanges i0(isv); IntSetRanges i1(orig_r_bounds); Ranges::Inter inter(i0,i1); isv = IntSetVal::ai(inter); } } SetLit* r_dom = new SetLit(Location().introduce(),isv); nr->ti()->domain(r_dom); } } else if (r_bounds_valid_float && ite->e_else()->type().isfloat()) { FloatBounds fb_else = compute_float_bounds(env, ite->e_else()); if (fb_else.valid) { FloatVal lb = fb_else.l; FloatVal ub = fb_else.u; for (unsigned int i=0; iid()); if (orig_r_bounds.valid) { lb = std::max(lb,orig_r_bounds.l); ub = std::min(ub,orig_r_bounds.u); } } BinOp* r_dom = new BinOp(Location().introduce(), FloatLit::a(lb), BOT_DOTDOT, FloatLit::a(ub)); r_dom->type(Type::parfloat(1)); nr->ti()->domain(r_dom); } } // flatten else branch EE eelse = flat_exp(env, cmix, ite->e_else(), NULL, NULL); Expression* eq_else; if (nr == constants().var_true) { eq_else = eelse.r(); } else { eq_else = new BinOp(Location().introduce(),nr->id(),BOT_EQ,eelse.r()); eq_else->type(Type::varbool()); } { // Create a clause with all the previous conditions negated, and // the else branch. // Also take partiality into account. std::vector neg; std::vector clauseArgs(2); if (b != constants().var_true) neg.push_back(b->id()); // temporarily push the then part onto the conditions conditions.push_back(eq_else); clauseArgs[0] = new ArrayLit(Location().introduce(),conditions); clauseArgs[0]->type(Type::varbool(1)); clauseArgs[1] = new ArrayLit(Location().introduce(),neg); clauseArgs[1]->type(Type::varbool(1)); { // b /\ c[i] -> r=r[i] Call* clause = new Call(Location().introduce(), constants().ids.clause, clauseArgs); clause->decl(env.orig->matchFn(env, clause)); clause->type(clause->decl()->rtype(env, clauseArgs)); (void) flat_exp(env, Ctx(), clause, constants().var_true, constants().var_true); } conditions.pop_back(); } conditions.push_back(constants().lit_true); defined.push_back(eelse.b()); // If all branches are defined, then the result is also defined bool allDefined = true; for (unsigned int i=0; itype().ispar() && defined[i]->type().isbool() && eval_bool(env,defined[i])) ) { allDefined = false; break; } } if (allDefined) { bind(env, ctx, b, constants().lit_true); } else { // Otherwise, generate clauses linking b and the definedness variables std::vector pos; std::vector neg(2); std::vector clauseArgs(2); for (unsigned int i=0; iid(); pos.push_back(defined[i]); clauseArgs[0] = new ArrayLit(Location().introduce(),pos); clauseArgs[0]->type(Type::varbool(1)); clauseArgs[1] = new ArrayLit(Location().introduce(),neg); clauseArgs[1]->type(Type::varbool(1)); { // b /\ c[i] -> b[i] Call* clause = new Call(Location().introduce(), constants().ids.clause, clauseArgs); clause->decl(env.orig->matchFn(env, clause)); clause->type(clause->decl()->rtype(env, clauseArgs)); clause->ann().add(constants().ann.promise_total); (void) flat_exp(env, Ctx(), clause, constants().var_true, constants().var_true); } pos.pop_back(); pos.push_back(b->id()); neg[1] = defined[i]; clauseArgs[0] = new ArrayLit(Location().introduce(),pos); clauseArgs[0]->type(Type::varbool(1)); clauseArgs[1] = new ArrayLit(Location().introduce(),neg); clauseArgs[1]->type(Type::varbool(1)); { // b[i] /\ c -> b Call* clause = new Call(Location().introduce(), constants().ids.clause, clauseArgs); clause->decl(env.orig->matchFn(env, clause)); clause->type(clause->decl()->rtype(env, clauseArgs)); clause->ann().add(constants().ann.promise_total); (void) flat_exp(env, Ctx(), clause, constants().var_true, constants().var_true); } pos.push_back(conditions[i]); } } EE ret; ret.r = nr->id(); ret.b = b->id(); GC::unlock(); return ret; } template void flatten_linexp_binop(EnvI& env, Ctx ctx, VarDecl* r, VarDecl* b, EE& ret, Expression* le0, Expression* le1, BinOpType& bot, bool doubleNeg, std::vector& ees, std::vector& args, ASTString& callid) { typedef typename LinearTraits::Val Val; std::vector coeffv; std::vector alv; Val d = 0; Expression* le[2] = {le0,le1}; Id* assignTo = NULL; if (bot==BOT_EQ && ctx.b == C_ROOT) { if (le0->isa()) { assignTo = le0->cast(); } else if (le1->isa()) { assignTo = le1->cast(); } } for (unsigned int i=0; i<2; i++) { Val sign = (i==0 ? 1 : -1); if (Lit* l = le[i]->dyn_cast()) { d += sign*l->v(); } else if (le[i]->isa()) { coeffv.push_back(sign); alv.push_back(le[i]); } else if (Call* sc = le[i]->dyn_cast()) { GCLock lock; ArrayLit* sc_coeff = eval_array_lit(env,sc->args()[0]); ArrayLit* sc_al = eval_array_lit(env,sc->args()[1]); d += sign*LinearTraits::eval(env,sc->args()[2]); for (unsigned int j=0; jv().size(); j++) { coeffv.push_back(sign*LinearTraits::eval(env,sc_coeff->v()[j])); alv.push_back(sc_al->v()[j]); } } else { throw EvalError(env, le[i]->loc(), "Internal error, unexpected expression inside linear expression"); } } simplify_lin(coeffv,alv,d); if (coeffv.size()==0) { bool result; switch (bot) { case BOT_LE: result = (0<-d); break; case BOT_LQ: result = (0<=-d); break; case BOT_GR: result = (0>-d); break; case BOT_GQ: result = (0>=-d); break; case BOT_EQ: result = (0==-d); break; case BOT_NQ: result = (0!=-d); break; default: assert(false); break; } if (doubleNeg) result = !result; ees[2].b = constants().boollit(result); ret.r = conj(env,r,ctx,ees); return; } else if (coeffv.size()==1 && std::abs(coeffv[0])==1) { if (coeffv[0]==-1) { switch (bot) { case BOT_LE: bot = BOT_GR; break; case BOT_LQ: bot = BOT_GQ; break; case BOT_GR: bot = BOT_LE; break; case BOT_GQ: bot = BOT_LQ; break; default: break; } } else { d = -d; } typename LinearTraits::Bounds ib = LinearTraits::compute_bounds(env,alv[0]()); if (ib.valid) { bool failed = false; bool subsumed = false; switch (bot) { case BOT_LE: subsumed = ib.u < d; failed = ib.l >= d; break; case BOT_LQ: subsumed = ib.u <= d; failed = ib.l > d; break; case BOT_GR: subsumed = ib.l > d; failed = ib.u <= d; break; case BOT_GQ: subsumed = ib.l >= d; failed = ib.u < d; break; case BOT_EQ: subsumed = ib.l==d && ib.u==d; failed = ib.u < d || ib.l > d; break; case BOT_NQ: subsumed = ib.u < d || ib.l > d; failed = ib.l==d && ib.u==d; break; default: break; } if (doubleNeg) { std::swap(subsumed, failed); } if (subsumed) { ees[2].b = constants().lit_true; ret.r = conj(env,r,ctx,ees); return; } else if (failed) { ees[2].b = constants().lit_false; ret.r = conj(env,r,ctx,ees); return; } } if (ctx.b == C_ROOT && alv[0]()->isa() && bot==BOT_EQ) { GCLock lock; VarDecl* vd = alv[0]()->cast()->decl(); if (vd->ti()->domain()) { typename LinearTraits::Domain domain = LinearTraits::eval_domain(env,vd->ti()->domain()); if (LinearTraits::domain_contains(domain,d)) { if (!LinearTraits::domain_equals(domain,d)) { vd->ti()->setComputedDomain(false); vd->ti()->domain(LinearTraits::new_domain(d)); } ret.r = bind(env,ctx,r,constants().lit_true); } else { ret.r = bind(env,ctx,r,constants().lit_false); } } else { vd->ti()->setComputedDomain(false); vd->ti()->domain(LinearTraits::new_domain(d)); ret.r = bind(env,ctx,r,constants().lit_true); } } else { GCLock lock; Expression* e0; Expression* e1; BinOpType old_bot = bot; Val old_d = d; switch (bot) { case BOT_LE: e0 = alv[0](); if (e0->type().isint()) { d--; bot = BOT_LQ; } e1 = LinearTraits::newLit(d); break; case BOT_GR: e1 = alv[0](); if (e1->type().isint()) { d++; bot = BOT_LQ; } else { bot = BOT_LE; } e0 = LinearTraits::newLit(d); break; case BOT_GQ: e0 = LinearTraits::newLit(d); e1 = alv[0](); bot = BOT_LQ; break; default: e0 = alv[0](); e1 = LinearTraits::newLit(d); } if (ctx.b == C_ROOT && alv[0]()->isa() && alv[0]()->cast()->decl()->ti()->domain()) { VarDecl* vd = alv[0]()->cast()->decl(); typename LinearTraits::Domain domain = LinearTraits::eval_domain(env,vd->ti()->domain()); typename LinearTraits::Domain ndomain = LinearTraits::limit_domain(old_bot,domain,old_d); if (domain && ndomain) { if (LinearTraits::domain_empty(ndomain)) { ret.r = bind(env,ctx,r,constants().lit_false); return; } else if (!LinearTraits::domain_equals(domain,ndomain)) { ret.r = bind(env,ctx,r,constants().lit_true); vd->ti()->setComputedDomain(false); vd->ti()->domain(LinearTraits::new_domain(ndomain)); if (r==constants().var_true) { BinOp* bo = new BinOp(Location().introduce(), e0, bot, e1); bo->type(Type::varbool()); std::vector boargs(2); boargs[0] = e0; boargs[1] = e1; Call* c = new Call(Location(), opToBuiltin(bo, bot), boargs); c->type(Type::varbool()); c->decl(env.orig->matchFn(env, c)); EnvI::Map::iterator it = env.map_find(c); if (it != env.map_end()) { if (Id* ident = it->second.r()->template dyn_cast()) { bind(env, Ctx(), ident->decl(), constants().lit_true); it->second.r = constants().lit_true; } if (Id* ident = it->second.b()->template dyn_cast()) { bind(env, Ctx(), ident->decl(), constants().lit_true); it->second.b = constants().lit_true; } } } } return; } } args.push_back(e0); args.push_back(e1); } } else if (bot==BOT_EQ && coeffv.size()==2 && coeffv[0]==-coeffv[1] && d==0) { Id* id0 = alv[0]()->cast(); Id* id1 = alv[1]()->cast(); if (ctx.b == C_ROOT && r==constants().var_true && (id0->decl()->e()==NULL || id1->decl()->e()==NULL)) { if (id0->decl()->e()) (void) bind(env,ctx,id1->decl(),id0); else (void) bind(env,ctx,id0->decl(),id1); } else { callid = LinearTraits::id_eq(); args.push_back(alv[0]()); args.push_back(alv[1]()); } } else { GCLock lock; if (assignTo != NULL) { Val resultCoeff; typename LinearTraits::Bounds bounds(d,d,true); for (unsigned int i=coeffv.size(); i--;) { if (alv[i]()==assignTo) { resultCoeff = coeffv[i]; continue; } typename LinearTraits::Bounds b = LinearTraits::compute_bounds(env,alv[i]()); if (b.valid && LinearTraits::finite(b)) { if (coeffv[i] > 0) { bounds.l += coeffv[i]*b.l; bounds.u += coeffv[i]*b.u; } else { bounds.l += coeffv[i]*b.u; bounds.u += coeffv[i]*b.l; } } else { bounds.valid = false; break; } } if (bounds.valid) { if (resultCoeff < 0) { bounds.l = LinearTraits::floor_div(bounds.l,-resultCoeff); bounds.u = LinearTraits::ceil_div(bounds.u,-resultCoeff); } else { Val bl = bounds.l; bounds.l = LinearTraits::ceil_div(bounds.u,-resultCoeff); bounds.u = LinearTraits::floor_div(bl,-resultCoeff); } VarDecl* vd = assignTo->decl(); if (vd->ti()->domain()) { typename LinearTraits::Domain domain = LinearTraits::eval_domain(env,vd->ti()->domain()); if (LinearTraits::domain_intersects(domain,bounds.l,bounds.u)) { typename LinearTraits::Domain new_domain = LinearTraits::intersect_domain(domain,bounds.l,bounds.u); if (!LinearTraits::domain_equals(domain,new_domain)) { vd->ti()->setComputedDomain(false); vd->ti()->domain(LinearTraits::new_domain(new_domain)); } } else { ret.r = bind(env,ctx,r,constants().lit_false); } } else { vd->ti()->setComputedDomain(true); vd->ti()->domain(LinearTraits::new_domain(bounds.l,bounds.u)); } } } int coeff_sign; LinearTraits::constructLinBuiltin(bot,callid,coeff_sign,d); std::vector coeff_ev(coeffv.size()); for (unsigned int i=coeff_ev.size(); i--;) coeff_ev[i] = LinearTraits::newLit(coeff_sign*coeffv[i]); ArrayLit* ncoeff = new ArrayLit(Location().introduce(),coeff_ev); Type t = coeff_ev[0]->type(); t.dim(1); ncoeff->type(t); args.push_back(ncoeff); std::vector alv_e(alv.size()); Type tt = alv[0]()->type(); tt.dim(1); for (unsigned int i=alv.size(); i--;) { if (alv[i]()->type().isvar()) tt.ti(Type::TI_VAR); alv_e[i] = alv[i](); } ArrayLit* nal = new ArrayLit(Location().introduce(),alv_e); nal->type(tt); args.push_back(nal); Lit* il = LinearTraits::newLit(-d); args.push_back(il); } } template void flatten_linexp_call(EnvI& env, Ctx ctx, Ctx nctx, ASTString& cid, Call* c, EE& ret, VarDecl* b, VarDecl* r, std::vector& args_ee, std::vector& args) { typedef typename LinearTraits::Val Val; Expression* al_arg = (cid==constants().ids.sum ? args_ee[0].r() : args_ee[1].r()); EE flat_al = flat_exp(env,nctx,al_arg,NULL,NULL); ArrayLit* al = follow_id(flat_al.r())->template cast(); KeepAlive al_ka = al; if (al->dims()>1) { Type alt = al->type(); alt.dim(1); GCLock lock; al = new ArrayLit(al->loc(),al->v()); al->type(alt); al_ka = al; } Val d = (cid == constants().ids.sum ? Val(0) : LinearTraits::eval(env,args_ee[2].r())); std::vector c_coeff(al->v().size()); if (cid==constants().ids.sum) { for (unsigned int i=al->v().size(); i--;) c_coeff[i] = 1; } else { EE flat_coeff = flat_exp(env,nctx,args_ee[0].r(),NULL,NULL); ArrayLit* coeff = follow_id(flat_coeff.r())->template cast(); for (unsigned int i=coeff->v().size(); i--;) c_coeff[i] = LinearTraits::eval(env,coeff->v()[i]); } cid = constants().ids.lin_exp; std::vector coeffv; std::vector alv; for (unsigned int i=0; iv().size(); i++) { if (Call* sc = same_call(al->v()[i],cid)) { Val cd = c_coeff[i]; GCLock lock; ArrayLit* sc_coeff = eval_array_lit(env,sc->args()[0]); ArrayLit* sc_al = eval_array_lit(env,sc->args()[1]); Val sc_d = LinearTraits::eval(env,sc->args()[2]); assert(sc_coeff->v().size() == sc_al->v().size()); for (unsigned int j=0; jv().size(); j++) { coeffv.push_back(cd*LinearTraits::eval(env,sc_coeff->v()[j])); alv.push_back(sc_al->v()[j]); } d += cd*sc_d; } else { coeffv.push_back(c_coeff[i]); alv.push_back(al->v()[i]); } } simplify_lin(coeffv,alv,d); if (coeffv.size()==0) { GCLock lock; ret.b = conj(env,b,Ctx(),args_ee); ret.r = bind(env,ctx,r,LinearTraits::newLit(d)); return; } else if (coeffv.size()==1 && coeffv[0]==1 && d==0) { ret.b = conj(env,b,Ctx(),args_ee); ret.r = bind(env,ctx,r,alv[0]()); return; } GCLock lock; std::vector coeff_ev(coeffv.size()); for (unsigned int i=coeff_ev.size(); i--;) coeff_ev[i] = LinearTraits::newLit(coeffv[i]); ArrayLit* ncoeff = new ArrayLit(Location().introduce(),coeff_ev); Type t = coeff_ev[0]->type(); t.dim(1); ncoeff->type(t); args.push_back(ncoeff); std::vector alv_e(alv.size()); bool al_same_as_before = alv.size()==al->v().size(); for (unsigned int i=alv.size(); i--;) { alv_e[i] = alv[i](); al_same_as_before = al_same_as_before && Expression::equal(alv_e[i],al->v()[i]); } if (al_same_as_before) { Expression* rd = follow_id_to_decl(flat_al.r()); if (rd->isa()) rd = rd->cast()->id(); if (rd->type().dim()>1) { ArrayLit* al = eval_array_lit(env,rd); std::vector > dims(1); dims[0].first = 1; dims[0].second = al->v().size(); rd = new ArrayLit(al->loc(),al->v(),dims); Type t = al->type(); t.dim(1); rd->type(t); } args.push_back(rd); } else { ArrayLit* nal = new ArrayLit(al->loc(),alv_e); nal->type(al->type()); args.push_back(nal); } Lit* il = LinearTraits::newLit(d); args.push_back(il); } Call* aggregateAndOrOps(EnvI& env, BinOp* bo, bool negateArgs, BinOpType bot) { assert(bot == BOT_AND || bot == BOT_OR); BinOpType negbot = (bot == BOT_AND ? BOT_OR : BOT_AND); typedef std::pair arg_literal; std::vector bo_args(2); bo_args[0] = arg_literal(bo->lhs(), !negateArgs); bo_args[1] = arg_literal(bo->rhs(), !negateArgs); std::vector output_pos; std::vector output_neg; unsigned int processed = 0; while (processed < bo_args.size()) { BinOp* bo_arg = bo_args[processed].first->dyn_cast(); UnOp* uo_arg = bo_args[processed].first->dyn_cast(); bool positive = bo_args[processed].second; if (bo_arg && positive && bo_arg->op() == bot) { bo_args[processed].first = bo_arg->lhs(); bo_args.push_back(arg_literal(bo_arg->rhs(),true)); } else if (bo_arg && !positive && bo_arg->op() == negbot) { bo_args[processed].first = bo_arg->lhs(); bo_args.push_back(arg_literal(bo_arg->rhs(),false)); } else if (uo_arg && !positive && uo_arg->op() == UOT_NOT) { bo_args[processed].first = uo_arg->e(); bo_args[processed].second = true; } else if (bot==BOT_OR && uo_arg && positive && uo_arg->op() == UOT_NOT) { output_neg.push_back(uo_arg->e()); processed++; } else { if (positive) { output_pos.push_back(bo_args[processed].first); } else { output_neg.push_back(bo_args[processed].first); } processed++; } } Call* c; std::vector c_args(1); if (bot == BOT_AND) { for (unsigned int i=0; iloc(),UOT_NOT,output_neg[i]); neg_arg->type(output_neg[i]->type()); output_pos.push_back(neg_arg); } ArrayLit* al = new ArrayLit(Location().introduce(), output_pos); Type al_t = bo->type(); al_t.dim(1); al->type(al_t); c_args[0] = al; c = new Call(bo->loc().introduce(), bot==BOT_AND ? constants().ids.forall : constants().ids.exists, c_args); } else { ArrayLit* al_pos = new ArrayLit(Location().introduce(), output_pos); Type al_t = bo->type(); al_t.dim(1); al_pos->type(al_t); c_args[0] = al_pos; if (output_neg.size() > 0) { ArrayLit* al_neg = new ArrayLit(Location().introduce(), output_neg); al_neg->type(al_t); c_args.push_back(al_neg); } c = new Call(bo->loc().introduce(), output_neg.empty() ? constants().ids.exists : constants().ids.clause, c_args); } c->decl(env.orig->matchFn(env, c)); assert(c->decl()); Type t = c->decl()->rtype(env, c_args); t.cv(bo->type().cv()); c->type(t); return c; } KeepAlive flat_cv_exp(EnvI& env, Ctx ctx, Expression* e) { GCLock lock; if (e->type().ispar() && !e->type().cv()) { return eval_par(env, e); } if (e->type().isvar()) { EE ee = flat_exp(env, ctx, e, NULL,NULL); if (isfalse(env, ee.b())) throw FlatteningError(env, e->loc(), "cannot flatten partial function in this position"); return ee.r(); } switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_TIID: case Expression::E_VARDECL: case Expression::E_TI: case Expression::E_ANON: assert(false); return NULL; case Expression::E_ID: { Id* id = e->cast(); return flat_cv_exp(env, ctx, id->decl()->e()); } case Expression::E_SETLIT: { SetLit* sl = e->cast(); if (sl->isv()) return sl; std::vector es(sl->v().size()); GCLock lock; for (unsigned int i=0; iv().size(); i++) { es[i] = flat_cv_exp(env, ctx, sl->v()[i])(); } SetLit* sl_ret = new SetLit(Location().introduce(),es); Type t = sl->type(); t.cv(false); sl_ret->type(t); return eval_par(env, sl_ret); } case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); std::vector es(al->v().size()); GCLock lock; for (unsigned int i=0; iv().size(); i++) { es[i] = flat_cv_exp(env, ctx, al->v()[i])(); } std::vector > dims(al->dims()); for (unsigned int i=0; idims(); i++) { dims[i] = std::make_pair(al->min(i), al->max(i)); } Expression* al_ret = eval_par(env, new ArrayLit(Location().introduce(),es,dims)); Type t = al->type(); t.cv(false); al_ret->type(t); return al_ret; } case Expression::E_ARRAYACCESS: { ArrayAccess* aa = e->cast(); GCLock lock; Expression* av = flat_cv_exp(env, ctx, aa->v())(); std::vector idx(aa->idx().size()); for (unsigned int i=0; iidx().size(); i++) { idx[i] = flat_cv_exp(env, ctx, aa->idx()[i])(); } ArrayAccess* aa_ret = new ArrayAccess(Location().introduce(),av,idx); Type t = aa->type(); t.cv(false); aa_ret->type(t); return eval_par(env, aa_ret); } case Expression::E_COMP: { Comprehension* c = e->cast(); GCLock lock; class EvalFlatCvExp { public: Ctx ctx; EvalFlatCvExp(Ctx& ctx0) : ctx(ctx0) {} typedef Expression* ArrayVal; Expression* e(EnvI& env, Expression* e) { return flat_cv_exp(env,ctx,e)(); } static Expression* exp(Expression* e) { return e; } } eval(ctx); std::vector a = eval_comp(env,eval,c); Type t = Type::bot(); bool allPar = true; for (unsigned int i=0; itype(); if (!a[i]->type().ispar()) allPar = false; } if (!allPar) t.ti(Type::TI_VAR); if (c->set()) t.st(Type::ST_SET); else t.dim(c->type().dim()); t.cv(false); if (c->set()) { if (c->type().ispar() && allPar) { SetLit* sl = new SetLit(c->loc().introduce(), a); sl->type(t); Expression* slr = eval_par(env,sl); slr->type(t); return slr; } else { throw InternalError("var set comprehensions not supported yet"); } } else { ArrayLit* alr = new ArrayLit(Location().introduce(),a); alr->type(t); alr->flat(true); return alr; } } case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { KeepAlive ka = flat_cv_exp(env,ctx,ite->e_if(i)); if (eval_bool(env,ka())) return flat_cv_exp(env,ctx,ite->e_then(i)); } return flat_cv_exp(env,ctx,ite->e_else()); } case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->op() == BOT_AND) { GCLock lock; Expression* lhs = flat_cv_exp(env, ctx, bo->lhs())(); if (!eval_bool(env, lhs)) { return constants().lit_false; } return eval_par(env, flat_cv_exp(env, ctx, bo->rhs())()); } else if (bo->op() == BOT_OR) { GCLock lock; Expression* lhs = flat_cv_exp(env, ctx, bo->lhs())(); if (eval_bool(env, lhs)) { return constants().lit_true; } return eval_par(env, flat_cv_exp(env, ctx, bo->rhs())()); } GCLock lock; BinOp* nbo = new BinOp(bo->loc().introduce(),flat_cv_exp(env, ctx, bo->lhs())(),bo->op(),flat_cv_exp(env, ctx, bo->rhs())()); nbo->type(bo->type()); return eval_par(env, nbo); } case Expression::E_UNOP: { UnOp* uo = e->cast(); GCLock lock; UnOp* nuo = new UnOp(uo->loc(), uo->op(), flat_cv_exp(env, ctx, uo->e())()); nuo->type(uo->type()); return eval_par(env, nuo); } case Expression::E_CALL: { Call* c = e->cast(); if (c->id()=="mzn_in_root_context") { return constants().boollit(ctx.b==C_ROOT); } std::vector args(c->args().size()); GCLock lock; for (unsigned int i=0; iargs().size(); i++) { args[i] = flat_cv_exp(env, ctx, c->args()[i])(); } Call* nc = new Call(c->loc(), c->id(), args); nc->decl(c->decl()); nc->type(c->type()); return eval_par(env, nc); } case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); KeepAlive ret = flat_cv_exp(env, ctx, l->in()); l->popbindings(); return ret; } } } EE flat_exp(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { if (e==NULL) return EE(); EE ret; assert(!e->type().isunknown()); if (e->type().ispar() && !e->isa() && !e->isa() && e->type().bt()!=Type::BT_ANN) { ret.b = bind(env,Ctx(),b,constants().lit_true); if (e->type().cv()) { KeepAlive ka = flat_cv_exp(env,ctx,e); ret.r = bind(env,ctx,r,ka()); return ret; } if (e->type().dim() > 0) { EnvI::Map::iterator it; Id* id = e->dyn_cast(); if (id && (id->decl()->flat()==NULL || id->decl()->toplevel())) { VarDecl* vd = id->decl()->flat(); if (vd==NULL) { vd = flat_exp(env,Ctx(),id->decl(),NULL,constants().var_true).r()->cast()->decl(); id->decl()->flat(vd); ArrayLit* al = follow_id(vd->id())->cast(); if (al->v().size()==0) { if (r==NULL) ret.r = al; else ret.r = bind(env,ctx,r,al); return ret; } } ret.r = bind(env,ctx,r,e->cast()->decl()->flat()->id()); return ret; } else if ( (it = env.map_find(e)) != env.map_end()) { ret.r = bind(env,ctx,r,it->second.r()->cast()->id()); return ret; } else { GCLock lock; ArrayLit* al = follow_id(eval_par(env,e))->cast(); if (al->v().size()==0 || (r && r->e()==NULL)) { if (r==NULL) ret.r = al; else ret.r = bind(env,ctx,r,al); return ret; } if ( (it = env.map_find(al)) != env.map_end()) { ret.r = bind(env,ctx,r,it->second.r()->cast()->id()); return ret; } std::vector ranges(al->dims()); for (unsigned int i=0; iloc(), Type(), new SetLit(Location().introduce(),IntSetVal::a(al->min(i),al->max(i)))); } ASTExprVec ranges_v(ranges); assert(!al->type().isbot()); TypeInst* ti = new TypeInst(e->loc(),al->type(),ranges_v,NULL); VarDecl* vd = newVarDecl(env, ctx, ti, NULL, NULL, al); EE ee(vd,NULL); env.map_insert(al,ee); env.map_insert(vd->e(),ee); ret.r = bind(env,ctx,r,vd->id()); return ret; } } GCLock lock; ret.r = bind(env,ctx,r,eval_par(env,e)); return ret; } switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_STRINGLIT: { CallStackItem _csi(env,e); GCLock lock; ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,Ctx(),r,e); return ret; } case Expression::E_SETLIT: { CallStackItem _csi(env,e); SetLit* sl = e->cast(); assert(sl->isv()==NULL); std::vector elems_ee(sl->v().size()); for (unsigned int i=sl->v().size(); i--;) elems_ee[i] = flat_exp(env,ctx,sl->v()[i],NULL,NULL); std::vector elems(elems_ee.size()); bool allPar = true; for (unsigned int i=elems.size(); i--;) { elems[i] = elems_ee[i].r(); allPar = allPar && elems[i]->type().ispar(); } ret.b = conj(env,b,Ctx(),elems_ee); if (allPar) { GCLock lock; Expression* ee = eval_par(env,e); ret.r = bind(env,Ctx(),r,ee); } else { GCLock lock; ArrayLit* al = new ArrayLit(sl->loc(),elems); al->type(Type::varint(1)); std::vector args(1); args[0] = al; Call* cc = new Call(sl->loc().introduce(), "array2set", args); cc->type(Type::varsetint()); FunctionI* fi = env.orig->matchFn(env, cc->id(),args); if (fi==NULL) { throw FlatteningError(env,cc->loc(), "cannot find matching declaration"); } assert(fi); assert(fi->rtype(env, args).isSubtypeOf(cc->type())); cc->decl(fi); EE ee = flat_exp(env, Ctx(), cc, NULL, constants().var_true); ret.r = bind(env,Ctx(),r,ee.r()); } } break; case Expression::E_BOOLLIT: { CallStackItem _csi(env,e); GCLock lock; ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,e); return ret; } break; case Expression::E_ID: { CallStackItem _csi(env,e); Id* id = e->cast(); if (id->decl()==NULL) { if (id->type().isann()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,e); return ret; } else { throw FlatteningError(env,e->loc(), "undefined identifier"); } } id = follow_id_to_decl(id)->cast()->id(); if (ctx.neg && id->type().dim() > 0) { if (id->type().dim() > 1) throw InternalError("multi-dim arrays in negative positions not supported yet"); KeepAlive ka; { GCLock lock; std::vector gen_id(1); gen_id[0] = new VarDecl(id->loc(), new TypeInst(id->loc(),Type::parint()),env.genId(), new IntLit(id->loc(),0)); /// TODO: support arbitrary dimensions std::vector idxsetargs(1); idxsetargs[0] = id; Call* idxset = new Call(id->loc().introduce(),"index_set",idxsetargs); idxset->decl(env.orig->matchFn(env, idxset)); idxset->type(idxset->decl()->rtype(env, idxsetargs)); Generator gen(gen_id,idxset); std::vector idx(1); Generators gens; gens._g.push_back(gen); gens._w = NULL; UnOp* aanot = new UnOp(id->loc(),UOT_NOT,NULL); Comprehension* cp = new Comprehension(id->loc(), aanot, gens, false); Id* bodyidx = cp->decl(0,0)->id(); idx[0] = bodyidx; ArrayAccess* aa = new ArrayAccess(id->loc(),id,idx); aanot->e(aa); Type tt = id->type(); tt.dim(0); aa->type(tt); aanot->type(aa->type()); cp->type(id->type()); ctx.neg = false; ka = cp; } ret = flat_exp(env,ctx,ka(),r,b); } else { GCLock lock; VarDecl* vd = id->decl()->flat(); Expression* rete = NULL; if (vd==NULL) { // New top-level id, need to copy into env.m vd = flat_exp(env,Ctx(),id->decl(),NULL,constants().var_true).r() ->cast()->decl(); } ret.b = bind(env,Ctx(),b,constants().lit_true); if (vd && vd->e()!=NULL) { switch (vd->e()->eid()) { case Expression::E_INTLIT: case Expression::E_BOOLLIT: case Expression::E_FLOATLIT: case Expression::E_ID: rete = vd->e(); break; default: break; } } else if (vd && vd->ti()->ranges().size() > 0) { // create fresh variables and array literal std::vector > dims; IntVal asize = 1; for (unsigned int i=0; iti()->ranges().size(); i++) { TypeInst* ti = vd->ti()->ranges()[i]; if (ti->domain()==NULL) throw FlatteningError(env,ti->loc(),"array dimensions unknown"); IntSetVal* isv = eval_intset(env,ti->domain()); if (isv->size() == 0) { dims.push_back(std::pair(1,0)); asize = 0; } else { if (isv->size() != 1) throw FlatteningError(env,ti->loc(),"invalid array index set"); asize *= (isv->max(0)-isv->min(0)+1); dims.push_back(std::pair(static_cast(isv->min(0).toInt()), static_cast(isv->max(0).toInt()))); } } Type tt = vd->ti()->type(); tt.dim(0); if (asize > Constants::max_array_size) { std::ostringstream oss; oss << "array size (" << asize << ") exceeds maximum allowed size (" << Constants::max_array_size << ")"; throw FlatteningError(env,vd->loc(),oss.str()); } std::vector elems(static_cast(asize.toInt())); for (int i=0; i(asize.toInt()); i++) { TypeInst* vti = new TypeInst(Location().introduce(),tt,vd->ti()->domain()); VarDecl* nvd = newVarDecl(env, Ctx(), vti, NULL, vd, NULL); elems[i] = nvd->id(); } // After introducing variables for each array element, the original domain can be // set to "computed" (since it is a consequence of the individual variable domains) vd->ti()->setComputedDomain(true); ArrayLit* al = new ArrayLit(Location().introduce(),elems,dims); al->type(vd->type()); vd->e(al); env.vo_add_exp(vd); EE ee; ee.r = vd; env.map_insert(vd->e(), ee); } if (rete==NULL) { if (!vd->toplevel()) { // create new VarDecl in toplevel, if decl doesnt exist yet EnvI::Map::iterator it = env.map_find(vd->e()); if (it==env.map_end()) { Expression* vde = follow_id(vd->e()); ArrayLit* vdea = vde ? vde->dyn_cast() : NULL; if (vdea && vdea->v().size()==0) { // Do not create names for empty arrays but return array literal directly rete = vdea; } else { VarDecl* nvd = newVarDecl(env, ctx, eval_typeinst(env,vd), NULL, vd, NULL); if (vd->e()) { (void) flat_exp(env, Ctx(), vd->e(), nvd, constants().var_true); } vd = nvd; EE ee(vd,NULL); if (vd->e()) env.map_insert(vd->e(),ee); } } else { if (it->second.r()->isa()) { vd = it->second.r()->cast(); } else { rete = it->second.r(); } } } if (rete==NULL) { if (id->type().bt() == Type::BT_ANN && vd->e()) { rete = vd->e(); } else { ArrayLit* vda = vd->dyn_cast(); if (vda && vda->v().size()==0) { // Do not create names for empty arrays but return array literal directly rete = vda; } else { rete = vd->id(); } } } } ret.r = bind(env,ctx,r,rete); } } break; case Expression::E_ANON: { CallStackItem _csi(env,e); AnonVar* av = e->cast(); if (av->type().isbot()) { throw InternalError("type of anonymous variable could not be inferred"); } GCLock lock; VarDecl* vd = new VarDecl(Location().introduce(), new TypeInst(Location().introduce(), av->type()), env.genId()); ret = flat_exp(env,Ctx(),vd,NULL,constants().var_true); } break; case Expression::E_ARRAYLIT: { CallStackItem _csi(env,e); ArrayLit* al = e->cast(); if (al->flat()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,Ctx(),r,al); } else { std::vector elems_ee(al->v().size()); for (unsigned int i=al->v().size(); i--;) elems_ee[i] = flat_exp(env,ctx,al->v()[i],NULL,NULL); std::vector elems(elems_ee.size()); for (unsigned int i=elems.size(); i--;) elems[i] = elems_ee[i].r(); std::vector > dims(al->dims()); for (unsigned int i=al->dims(); i--;) dims[i] = std::pair(al->min(i), al->max(i)); KeepAlive ka; { GCLock lock; ArrayLit* alr = new ArrayLit(Location().introduce(),elems,dims); alr->type(al->type()); alr->flat(true); ka = alr; } ret.b = conj(env,b,Ctx(),elems_ee); ret.r = bind(env,Ctx(),r,ka()); } } break; case Expression::E_ARRAYACCESS: { CallStackItem _csi(env,e); ArrayAccess* aa = e->cast(); KeepAlive aa_ka = aa; Ctx nctx = ctx; nctx.b = +nctx.b; nctx.neg = false; EE eev = flat_exp(env,nctx,aa->v(),NULL,NULL); std::vector ees; start_flatten_arrayaccess: for (unsigned int i=0; iidx().size(); i++) { Expression* tmp = follow_id_to_decl(aa->idx()[i]); if (VarDecl* vd = tmp->dyn_cast()) tmp = vd->id(); if (tmp->type().ispar()) { ArrayLit* al; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast(); } std::vector elems; std::vector idx(aa->idx().size()); std::vector > dims; std::vector newaccess; std::vector nonpar; std::vector stack; for (unsigned int j=0; jidx().size(); j++) { Expression* tmp = follow_id_to_decl(aa->idx()[j]); if (VarDecl* vd = tmp->dyn_cast()) tmp = vd->id(); if (tmp->type().ispar()) { GCLock lock; idx[j] = eval_int(env, tmp).toInt(); } else { idx[j] = al->min(j); stack.push_back(nonpar.size()); nonpar.push_back(j); dims.push_back(std::make_pair(al->min(j), al->max(j))); newaccess.push_back(aa->idx()[j]); } } if (stack.empty()) { bool success; KeepAlive ka; { GCLock lock; ka = eval_arrayaccess(env, al, idx, success); if (!success && ctx.b==C_ROOT && b==constants().var_true) { throw FlatteningError(env,e->loc(),"array access out of bounds"); } } ees.push_back(EE(NULL,constants().boollit(success))); ees.push_back(EE(NULL,eev.b())); if (aa->type().isbool() && !aa->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ees.push_back(EE(NULL,ka())); ret.r = conj(env,r,ctx,ees); } else { ret.b = conj(env,b,ctx,ees); ret.r = bind(env,ctx,r,ka()); } return ret; } while (!stack.empty()) { int cur = stack.back(); if (cur==nonpar.size()-1) { stack.pop_back(); for (int i = al->min(nonpar[cur]); i <= al->max(nonpar[cur]); i++) { idx[nonpar[cur]] = i; bool success; GCLock lock; Expression* al_idx = eval_arrayaccess(env, al, idx, success); if (!success) { if (ctx.b==C_ROOT && b==constants().var_true) { throw FlatteningError(env,e->loc(),"array access out of bounds"); } ees.push_back(EE(NULL,constants().lit_false)); ees.push_back(EE(NULL,eev.b())); if (aa->type().isbool() && !aa->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = conj(env,r,ctx,ees); } else { ret.b = conj(env,b,ctx,ees); ret.r = bind(env,ctx,r,al_idx); } return ret; } elems.push_back(al_idx); } } else { if (idx[nonpar[cur]].toInt()==al->max(nonpar[cur])) { idx[nonpar[cur]]=al->min(nonpar[cur]); stack.pop_back(); } else { idx[nonpar[cur]]++; for (unsigned int j=cur+1; j elems_e(elems.size()); for (unsigned int i=0; iloc(), elems_e, dims); Type t = al->type(); t.dim(dims.size()); newal->type(t); eev.r = newal; ArrayAccess* n_aa = new ArrayAccess(aa->loc(), newal, newaccess); n_aa->type(aa->type()); aa = n_aa; aa_ka = aa; } } } if (aa->idx().size()==1 && aa->idx()[0]->isa()) { ArrayAccess* aa_inner = aa->idx()[0]->cast(); ArrayLit* al; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast(); } if (aa_inner->v()->type().ispar()) { KeepAlive ka_al_inner = flat_cv_exp(env, ctx, aa_inner->v()); ArrayLit* al_inner = ka_al_inner()->cast(); std::vector composed_e(al_inner->v().size()); for (unsigned int i=0; iv().size(); i++) { GCLock lock; IntVal inner_idx = eval_int(env, al_inner->v()[i]); if (inner_idx < al->min(0) || inner_idx > al->max(0)) goto flatten_arrayaccess; composed_e[i] = al->v()[inner_idx.toInt()-al->min(0)]; } std::vector > dims(al_inner->dims()); for (unsigned int i=0; idims(); i++) { dims[i] = std::make_pair(al_inner->min(i), al_inner->max(i)); } { GCLock lock; Expression* newal = new ArrayLit(al->loc(), composed_e, dims); Type t = al->type(); t.dim(dims.size()); newal->type(t); eev.r = newal; ArrayAccess* n_aa = new ArrayAccess(aa->loc(), newal, aa_inner->idx()); n_aa->type(aa->type()); aa = n_aa; aa_ka = aa; goto start_flatten_arrayaccess; } } } flatten_arrayaccess: Ctx dimctx = ctx; dimctx.neg = false; for (unsigned int i=0; iidx().size(); i++) { Expression* tmp = follow_id_to_decl(aa->idx()[i]); if (VarDecl* vd = tmp->dyn_cast()) tmp = vd->id(); ees.push_back(flat_exp(env, dimctx, tmp, NULL, NULL)); } ees.push_back(EE(NULL,eev.b())); bool parAccess=true; for (unsigned int i=0; iidx().size(); i++) { if (!ees[i].r()->type().ispar()) { parAccess = false; break; } } if (parAccess) { ArrayLit* al; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast(); } KeepAlive ka; bool success; { GCLock lock; std::vector dims(aa->idx().size()); for (unsigned int i=aa->idx().size(); i--;) dims[i] = eval_int(env,ees[i].r()); ka = eval_arrayaccess(env,al,dims,success); } if (!success && ctx.b==C_ROOT && b==constants().var_true) { throw FlatteningError(env,e->loc(),"array access out of bounds"); } ees.push_back(EE(NULL,constants().boollit(success))); if (aa->type().isbool() && !aa->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ees.push_back(EE(NULL,ka())); ret.r = conj(env,r,ctx,ees); } else { ret.b = conj(env,b,ctx,ees); ret.r = bind(env,ctx,r,ka()); } } else { std::vector args(aa->idx().size()+1); for (unsigned int i=aa->idx().size(); i--;) args[i] = ees[i].r(); args[aa->idx().size()] = eev.r(); KeepAlive ka; { GCLock lock; Call* cc = new Call(e->loc().introduce(),constants().ids.element,args); cc->type(aa->type()); FunctionI* fi = env.orig->matchFn(env,cc->id(),args); if (fi==NULL) { throw FlatteningError(env,cc->loc(), "cannot find matching declaration"); } assert(fi); assert(fi->rtype(env,args).isSubtypeOf(cc->type())); cc->decl(fi); ka = cc; } Ctx elemctx = ctx; elemctx.neg = false; EE ee = flat_exp(env,elemctx,ka(),NULL,NULL); ees.push_back(ee); if (aa->type().isbool() && !aa->type().isopt()) { ee.b = ee.r; ees.push_back(ee); ret.r = conj(env,r,ctx,ees); ret.b = bind(env,ctx,b,constants().boollit(!ctx.neg)); } else { ret.r = bind(env,ctx,r,ee.r()); ret.b = conj(env,b,ctx,ees); } } } break; case Expression::E_COMP: { CallStackItem _csi(env,e); Comprehension* c = e->cast(); KeepAlive c_ka(c); if (c->type().isopt()) { std::vector in(c->n_generators()); std::vector where; GCLock lock; for (int i=0; in_generators(); i++) { if (c->in(i)->type().isvar() && c->in(i)->type().dim()==0) { std::vector args(1); args[0] = c->in(i); Call* ub = new Call(Location().introduce(),"ub",args); ub->type(Type::parsetint()); ub->decl(env.orig->matchFn(env, ub)); in[i] = ub; for (int j=0; jn_decls(i); j++) { BinOp* bo = new BinOp(Location().introduce(),c->decl(i,j)->id(), BOT_IN, c->in(i)); bo->type(Type::varbool()); where.push_back(bo); } } else { in[i] = c->in(i); } } if (where.size() > 0 || (c->where() && c->where()->type().isvar())) { Generators gs; if (c->where()==NULL || c->where()->type().ispar()) gs._w = c->where(); else where.push_back(c->where()); for (int i=0; in_generators(); i++) { std::vector vds(c->n_decls(i)); for (int j=0; jn_decls(i); j++) vds[j] = c->decl(i, j); gs._g.push_back(Generator(vds,in[i])); } Expression* cond; if (where.size() > 1) { ArrayLit* al = new ArrayLit(Location().introduce(), where); al->type(Type::varbool(1)); std::vector args(1); args[0] = al; Call* forall = new Call(Location().introduce(), constants().ids.forall, args); forall->type(Type::varbool()); forall->decl(env.orig->matchFn(env, forall)); cond = forall; } else { cond = where[0]; } Expression* r_bounds = NULL; if (c->e()->type().bt()==Type::BT_INT && c->e()->type().dim() == 0) { std::vector ubargs(1); ubargs[0] = c->e(); if (c->e()->type().st()==Type::ST_SET) { Call* bc = new Call(Location().introduce(),"ub",ubargs); bc->type(Type::parsetint()); bc->decl(env.orig->matchFn(env, bc)); r_bounds = bc; } else { Call* lbc = new Call(Location().introduce(),"lb",ubargs); lbc->type(Type::parint()); lbc->decl(env.orig->matchFn(env, lbc)); Call* ubc = new Call(Location().introduce(),"ub",ubargs); ubc->type(Type::parint()); ubc->decl(env.orig->matchFn(env, ubc)); r_bounds = new BinOp(Location().introduce(),lbc,BOT_DOTDOT,ubc); r_bounds->type(Type::parsetint()); } } Type tt; tt = c->e()->type(); tt.ti(Type::TI_VAR); tt.ot(Type::OT_OPTIONAL); TypeInst* ti = new TypeInst(Location().introduce(),tt,r_bounds); VarDecl* r = new VarDecl(c->loc(),ti,env.genId()); r->addAnnotation(constants().ann.promise_total); r->introduced(true); r->flat(r); std::vector let_exprs(3); let_exprs[0] = r; BinOp* r_eq_e = new BinOp(Location().introduce(),r->id(),BOT_EQ,c->e()); r_eq_e->type(Type::varbool()); let_exprs[1] = new BinOp(Location().introduce(),cond,BOT_IMPL,r_eq_e); let_exprs[1]->type(Type::varbool()); let_exprs[1]->addAnnotation(constants().ann.promise_total); std::vector absent_r_args(1); absent_r_args[0] = r->id(); Call* absent_r = new Call(Location().introduce(), "absent", absent_r_args); absent_r->type(Type::varbool()); absent_r->decl(env.orig->matchFn(env, absent_r)); let_exprs[2] = new BinOp(Location().introduce(),cond,BOT_OR,absent_r); let_exprs[2]->type(Type::varbool()); let_exprs[2]->addAnnotation(constants().ann.promise_total); Let* let = new Let(Location().introduce(), let_exprs, r->id()); let->type(r->type()); Comprehension* nc = new Comprehension(c->loc(),let,gs,c->set()); nc->type(c->type()); c = nc; c_ka = c; } } class EvalF { public: Ctx ctx; EvalF(Ctx ctx0) : ctx(ctx0) {} typedef EE ArrayVal; EE e(EnvI& env, Expression* e0) { VarDecl* b = ctx.b==C_ROOT ? constants().var_true : NULL; VarDecl* r = (ctx.b == C_ROOT && e0->type().isbool() && !e0->type().isopt()) ? constants().var_true : NULL; return flat_exp(env,ctx,e0,r,b); } } _evalf(ctx); std::vector elems_ee = eval_comp(env,_evalf,c); std::vector elems(elems_ee.size()); Type elemType = Type::bot(); bool allPar = true; for (unsigned int i=elems.size(); i--;) { elems[i] = elems_ee[i].r(); if (elemType==Type::bot()) elemType = elems[i]->type(); if (!elems[i]->type().ispar()) allPar = false; } if (elemType.isbot()) { elemType = c->type(); elemType.ti(Type::TI_PAR); } if (!allPar) elemType.ti(Type::TI_VAR); if (c->set()) elemType.st(Type::ST_SET); else elemType.dim(c->type().dim()); KeepAlive ka; { GCLock lock; if (c->set()) { if (c->type().ispar() && allPar) { SetLit* sl = new SetLit(c->loc(), elems); sl->type(elemType); Expression* slr = eval_par(env,sl); slr->type(elemType); ka = slr; } else { throw InternalError("var set comprehensions not supported yet"); } } else { ArrayLit* alr = new ArrayLit(Location().introduce(),elems); alr->type(elemType); alr->flat(true); ka = alr; } } assert(!ka()->type().isbot()); ret.b = conj(env,b,Ctx(),elems_ee); ret.r = bind(env,Ctx(),r,ka()); } break; case Expression::E_ITE: { CallStackItem _csi(env,e); ITE* ite = e->cast(); ret = flat_ite(env,ctx,ite,r,b); } break; case Expression::E_BINOP: { CallStackItem _csi(env,e); BinOp* bo = e->cast(); if (isReverseMap(bo)) { CallArgItem cai(env); Id* id = bo->lhs()->dyn_cast(); if (id==NULL) throw EvalError(env, bo->lhs()->loc(), "Reverse mappers are only defined for identifiers"); if (bo->op() != BOT_EQ && bo->op() != BOT_EQUIV) throw EvalError(env, bo->loc(), "Reverse mappers have to use `=` as the operator"); Call* c = bo->rhs()->dyn_cast(); if (c==NULL) throw EvalError(env, bo->rhs()->loc(), "Reverse mappers require call on right hand side"); std::vector args(c->args().size()); for (unsigned int i=0; iargs().size(); i++) { Id* idi = c->args()[i]->dyn_cast(); if (idi==NULL) throw EvalError(env, c->args()[i]->loc(), "Reverse mapper calls require identifiers as arguments"); EE ee = flat_exp(env, Ctx(), idi, NULL, constants().var_true); args[i] = ee.r(); } EE ee = flat_exp(env, Ctx(), id, NULL, constants().var_true); GCLock lock; Call* revMap = new Call(Location().introduce(),c->id(),args); args.push_back(ee.r()); Call* keepAlive = new Call(Location().introduce(),constants().var_redef->id(),args); keepAlive->type(Type::varbool()); keepAlive->decl(constants().var_redef); ret = flat_exp(env, Ctx(), keepAlive, constants().var_true, constants().var_true); if (ee.r()->isa()) { env.reverseMappers.insert(ee.r()->cast(),revMap); } break; } if ( (bo->op()==BOT_EQ || bo->op()==BOT_EQUIV) && (bo->lhs()==constants().absent || bo->rhs()==constants().absent) ) { GCLock lock; std::vector args(1); args[0] = bo->lhs()==constants().absent ? bo->rhs() : bo->lhs(); if (args[0] != constants().absent) { Call* cr = new Call(bo->loc().introduce(),"absent",args); cr->decl(env.orig->matchFn(env, cr)); cr->type(cr->decl()->rtype(env, args)); ret = flat_exp(env, ctx, cr, r, b); } else { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_true); } break; } Ctx ctx0 = ctx; ctx0.neg = false; Ctx ctx1 = ctx; ctx1.neg = false; BinOpType bot = bo->op(); if (bo->lhs()->type().isbool()) { switch (bot) { case BOT_EQ: bot = BOT_EQUIV; break; case BOT_NQ: bot = BOT_XOR; break; case BOT_LQ: bot = BOT_IMPL; break; case BOT_GQ: bot = BOT_RIMPL; break; default: break; } } bool negArgs = false; bool doubleNeg = false; if (ctx.neg) { switch (bot) { case BOT_AND: ctx.b = -ctx.b; ctx.neg = false; negArgs = true; bot = BOT_OR; break; case BOT_OR: ctx.b = -ctx.b; ctx.neg = false; negArgs = true; bot = BOT_AND; break; default: break; } } Expression* boe0 = bo->lhs(); Expression* boe1 = bo->rhs(); switch (bot) { case BOT_PLUS: { KeepAlive ka; if (boe0->type().isint()) { ka = mklinexp(env,1,1,boe0,boe1); } else { ka = mklinexp(env,1.0,1.0,boe0,boe1); } ret = flat_exp(env,ctx,ka(),r,b); } break; case BOT_MINUS: { KeepAlive ka; if (boe0->type().isint()) { ka = mklinexp(env,1,-1,boe0,boe1); } else { ka = mklinexp(env,1.0,-1.0,boe0,boe1); } ret = flat_exp(env,ctx,ka(),r,b); } break; case BOT_MULT: case BOT_IDIV: case BOT_MOD: case BOT_DIV: case BOT_UNION: case BOT_DIFF: case BOT_SYMDIFF: case BOT_INTERSECT: case BOT_DOTDOT: { assert(!ctx0.neg); assert(!ctx1.neg); EE e0 = flat_exp(env,ctx0,boe0,NULL,b); EE e1 = flat_exp(env,ctx1,boe1,NULL,b); if (e0.r()->type().ispar() && e1.r()->type().ispar()) { GCLock lock; BinOp* parbo = new BinOp(bo->loc(),e0.r(),bo->op(),e1.r()); Type tt = bo->type(); tt.ti(Type::TI_PAR); parbo->type(tt); Expression* res = eval_par(env,parbo); assert(!res->type().isunknown()); ret.r = bind(env,ctx,r,res); std::vector ees(2); ees[0].b = e0.b; ees[1].b = e1.b; ret.b = conj(env,b,Ctx(),ees); break; } if (bot==BOT_MULT) { Expression* e0r = e0.r(); Expression* e1r = e1.r(); if (e0r->type().ispar()) std::swap(e0r,e1r); if (e1r->type().ispar() && e1r->type().isint()) { IntVal coeff = eval_int(env,e1r); KeepAlive ka = mklinexp(env,coeff,0,e0r,NULL); ret = flat_exp(env,ctx,ka(),r,b); break; } else if (e1r->type().ispar() && e1r->type().isfloat()) { FloatVal coeff = eval_float(env,e1r); KeepAlive ka = mklinexp(env,coeff,0.0,e0r,NULL); ret = flat_exp(env,ctx,ka(),r,b); break; } } else if (bot==BOT_DIV || bot==BOT_IDIV) { Expression* e0r = e0.r(); Expression* e1r = e1.r(); if (e1r->type().ispar() && e1r->type().isint()) { IntVal coeff = eval_int(env,e1r); if (coeff==1) { ret = flat_exp(env,ctx,e0r,r,b); break; } } else if (e1r->type().ispar() && e1r->type().isfloat()) { FloatVal coeff = eval_float(env,e1r); if (coeff==1.0) { ret = flat_exp(env,ctx,e0r,r,b); break; } else { KeepAlive ka = mklinexp(env,1.0/coeff,0.0,e0r,NULL); ret = flat_exp(env,ctx,ka(),r,b); break; } } } GC::lock(); std::vector args(2); args[0] = e0.r(); args[1] = e1.r(); Call* cc; if (bo->decl()) { cc = new Call(bo->loc().introduce(),bo->opToString(),args); } else { cc = new Call(bo->loc().introduce(),opToBuiltin(bo,bot),args); } cc->type(bo->type()); EnvI::Map::iterator cit; if ( (cit = env.map_find(cc)) != env.map_end()) { ret.b = bind(env,Ctx(),b,env.ignorePartial ? constants().lit_true : cit->second.b()); ret.r = bind(env,ctx,r,cit->second.r()); } else { if (FunctionI* fi = env.orig->matchFn(env,cc->id(),args)) { assert(cc->type() == fi->rtype(env,args)); cc->decl(fi); cc->type(cc->decl()->rtype(env,args)); KeepAlive ka(cc); GC::unlock(); EE ee = flat_exp(env,ctx,cc,r,NULL); GC::lock(); ret.r = ee.r; std::vector ees(3); ees[0].b = e0.b; ees[1].b = e1.b; ees[2].b = ee.b; ret.b = conj(env,b,Ctx(),ees); } else { ret.r = bind(env,ctx,r,cc); std::vector ees(2); ees[0].b = e0.b; ees[1].b = e1.b; ret.b = conj(env,b,Ctx(),ees); if (!ctx.neg) env.map_insert(cc,ret); } } } GC::unlock(); break; case BOT_AND: { if (r==constants().var_true) { Ctx nctx; nctx.neg = negArgs; nctx.b = negArgs ? C_NEG : C_ROOT; std::vector todo; todo.push_back(boe0); todo.push_back(boe1); while (!todo.empty()) { Expression* e_todo = todo.back(); todo.pop_back(); BinOp* e_bo = e_todo->dyn_cast(); if (e_bo && e_bo->op()==BOT_AND) { todo.push_back(e_bo->lhs()); todo.push_back(e_bo->rhs()); } else { (void) flat_exp(env,nctx,e_todo,constants().var_true,constants().var_true); } } ret.r = bind(env,ctx,r,constants().lit_true); break; } else { GC::lock(); Call* c = aggregateAndOrOps(env, bo, negArgs, bot); KeepAlive ka(c); GC::unlock(); ret = flat_exp(env,ctx,c,r,b); if (Id* id = ret.r()->dyn_cast()) { addCtxAnn(id->decl(), ctx.b); } } break; } case BOT_OR: { GC::lock(); Call* c = aggregateAndOrOps(env, bo, negArgs, bot); KeepAlive ka(c); GC::unlock(); ret = flat_exp(env,ctx,c,r,b); if (Id* id = ret.r()->dyn_cast()) { addCtxAnn(id->decl(), ctx.b); } } break; case BOT_RIMPL: { std::swap(boe0,boe1); } // fall through case BOT_IMPL: { if (ctx.b==C_ROOT && r==constants().var_true && boe0->type().ispar()) { bool b; { GCLock lock; b = eval_bool(env,boe0); } if (b) { Ctx nctx = ctx; nctx.neg = negArgs; nctx.b = negArgs ? C_NEG : C_ROOT; ret = flat_exp(env,nctx,boe1,constants().var_true,constants().var_true); } else { Ctx nctx = ctx; nctx.neg = negArgs; nctx.b = negArgs ? C_NEG : C_ROOT; ret = flat_exp(env,nctx,constants().lit_true,constants().var_true,constants().var_true); } break; } if (ctx.b==C_ROOT && r==constants().var_true && boe1->type().ispar()) { bool b; { GCLock lock; b = eval_bool(env,boe1); } if (b) { Ctx nctx = ctx; nctx.neg = negArgs; nctx.b = negArgs ? C_NEG : C_ROOT; ret = flat_exp(env,nctx,constants().lit_true,constants().var_true,constants().var_true); break; } else { Ctx nctx = ctx; nctx.neg = !negArgs; nctx.b = !negArgs ? C_NEG : C_ROOT; ret = flat_exp(env,nctx,boe0,constants().var_true,constants().var_true); break; } } GC::lock(); std::vector args; ASTString id; if (ctx.neg) { std::vector bo_args(2); bo_args[0] = boe0; bo_args[1] = new UnOp(bo->loc(),UOT_NOT,boe1); bo_args[1]->type(boe1->type()); id = constants().ids.forall; args.push_back(new ArrayLit(bo->loc(),bo_args)); args[0]->type(Type::varbool(1)); } else { std::vector clause_pos(1); clause_pos[0] = boe1; std::vector clause_neg(1); clause_neg[0] = boe0; args.push_back(new ArrayLit(boe1->loc().introduce(), clause_pos)); Type t0 = boe1->type(); t0.dim(1); args[0]->type(t0); args.push_back(new ArrayLit(boe0->loc().introduce(), clause_neg)); Type t1 = boe0->type(); t1.dim(1); args[1]->type(t1); id = constants().ids.clause; } ctx.neg = false; Call* c = new Call(bo->loc().introduce(),id,args); c->decl(env.orig->matchFn(env,c)); if (c->decl()==NULL) { throw FlatteningError(env,c->loc(), "cannot find matching declaration"); } c->type(c->decl()->rtype(env,args)); KeepAlive ka(c); GC::unlock(); ret = flat_exp(env,ctx,c,r,b); if (Id* id = ret.r()->dyn_cast()) { addCtxAnn(id->decl(),ctx.b); } } break; case BOT_EQUIV: if (ctx.neg) { ctx.neg = false; ctx.b = -ctx.b; bot = BOT_XOR; ctx0.b = ctx1.b = C_MIX; goto flatten_bool_op; } else { if (istrue(env, boe0)) { return flat_exp(env, ctx, boe1, r, b); } if (istrue(env, boe1)) { return flat_exp(env, ctx, boe0, r, b); } if (r && r==constants().var_true) { if (boe1->type().ispar() || boe1->isa()) std::swap(boe0,boe1); if (istrue(env,boe0)) { return flat_exp(env,ctx1,boe1,r,b); } else if (isfalse(env,boe0)) { ctx1.neg = true; ctx1.b = -ctx1.b; return flat_exp(env,ctx1,boe1,r,b); } else { ctx0.b = C_MIX; EE e0 = flat_exp(env,ctx0,boe0,NULL,NULL); if (istrue(env,e0.r())) { return flat_exp(env,ctx1,boe1,r,b); } else if (isfalse(env,e0.r())) { ctx1.neg = true; ctx1.b = -ctx1.b; return flat_exp(env,ctx1,boe1,r,b); } else { Id* id = e0.r()->cast(); ctx1.b = C_MIX; (void) flat_exp(env,ctx1,boe1,id->decl(),constants().var_true); ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,Ctx(),r,constants().lit_true); } } break; } else { ctx0.b = ctx1.b = C_MIX; goto flatten_bool_op; } } case BOT_XOR: if (ctx.neg) { ctx.neg = false; ctx.b = -ctx.b; bot = BOT_EQUIV; } ctx0.b = ctx1.b = C_MIX; goto flatten_bool_op; case BOT_LE: if (ctx.neg) { doubleNeg = true; bot = BOT_GQ; if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = +ctx0.b; ctx1.b = -ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = +ctx0.i; ctx1.i = -ctx1.i; } } else { if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = -ctx0.b; ctx1.b = +ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = -ctx0.i; ctx1.i = +ctx1.i; } } goto flatten_bool_op; case BOT_LQ: if (ctx.neg) { doubleNeg = true; bot = BOT_GR; if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = +ctx0.b; ctx1.b = -ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = +ctx0.i; ctx1.i = -ctx1.i; } } else { if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = -ctx0.b; ctx1.b = +ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = -ctx0.i; ctx1.i = +ctx1.i; } } goto flatten_bool_op; case BOT_GR: if (ctx.neg) { doubleNeg = true; bot = BOT_LQ; if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = -ctx0.b; ctx1.b = +ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = -ctx0.i; ctx1.i = +ctx1.i; } } else { if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = +ctx0.b; ctx1.b = -ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = +ctx0.i; ctx1.i = -ctx1.i; } } goto flatten_bool_op; case BOT_GQ: if (ctx.neg) { doubleNeg = true; bot = BOT_LE; if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = -ctx0.b; ctx1.b = +ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = -ctx0.i; ctx1.i = +ctx1.i; } } else { if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = +ctx0.b; ctx1.b = -ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = +ctx0.i; ctx1.i = -ctx1.i; } } goto flatten_bool_op; case BOT_EQ: if (ctx.neg) { doubleNeg = true; bot = BOT_NQ; } if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = ctx1.b = C_MIX; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = ctx1.i = C_MIX; } goto flatten_bool_op; case BOT_NQ: if (ctx.neg) { doubleNeg = true; bot = BOT_EQ; } if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = ctx1.b = C_MIX; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = ctx1.i = C_MIX; } goto flatten_bool_op; case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: ctx0.i = ctx1.i = C_MIX; flatten_bool_op: { bool inRootCtx = (ctx0.b==ctx1.b && ctx0.b==C_ROOT && b==constants().var_true); EE e0 = flat_exp(env,ctx0,boe0,NULL,inRootCtx ? b : NULL); EE e1 = flat_exp(env,ctx1,boe1,NULL,inRootCtx ? b : NULL); ret.b = bind(env,Ctx(),b,constants().lit_true); std::vector ees(3); ees[0].b = e0.b; ees[1].b = e1.b; if (isfalse(env, e0.b()) || isfalse(env, e1.b())) { ees.resize(2); ret.r = conj(env,r,ctx,ees); break; } if (e0.r()->type().ispar() && e1.r()->type().ispar()) { GCLock lock; BinOp* bo_par = new BinOp(e->loc(),e0.r(),bot,e1.r()); bo_par->type(Type::parbool()); bool bo_val = eval_bool(env,bo_par); if (doubleNeg) bo_val = !bo_val; ees[2].b = constants().boollit(bo_val); ret.r = conj(env,r,ctx,ees); break; } if (ctx.b==C_ROOT && r==constants().var_true && e1.r()->type().ispar() && e0.r()->isa() && (bot==BOT_IN || bot==BOT_SUBSET) ) { VarDecl* vd = e0.r()->cast()->decl(); if (vd->ti()->domain()==NULL) { vd->ti()->domain(e1.r()); } else { GCLock lock; IntSetVal* newdom = eval_intset(env,e1.r()); Id* id = vd->id(); while (id != NULL) { bool changeDom = false; if (id->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,id->decl()->ti()->domain()); IntSetRanges dr(domain); IntSetRanges ibr(newdom); Ranges::Inter i(dr,ibr); IntSetVal* newibv = IntSetVal::ai(i); if (domain->card() != newibv->card()) { newdom = newibv; changeDom = true; } } else { changeDom = true; } if (id->type().st()==Type::ST_PLAIN && newdom->size()==0) { env.flat()->fail(env); } else if (changeDom) { id->decl()->ti()->setComputedDomain(false); id->decl()->ti()->domain(new SetLit(Location().introduce(),newdom)); } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } } ret.r = bind(env,ctx,r,constants().lit_true); break; } std::vector args; ASTString callid; Expression* le0 = NULL; Expression* le1 = NULL; if (boe0->type().isint() && !boe0->type().isopt() && bot != BOT_IN) { le0 = get_linexp(e0.r()); } else if (boe0->type().isfloat() && !boe0->type().isopt() && bot != BOT_IN) { le0 = get_linexp(e0.r()); } if (le0) { if (boe1->type().isint() && !boe1->type().isopt()) { le1 = get_linexp(e1.r()); } else if (boe1->type().isfloat() && !boe1->type().isopt()) { le1 = get_linexp(e1.r()); } } if (le1) { if (boe0->type().isint()) { flatten_linexp_binop(env,ctx,r,b,ret,le0,le1,bot,doubleNeg,ees,args,callid); } else { flatten_linexp_binop(env,ctx,r,b,ret,le0,le1,bot,doubleNeg,ees,args,callid); } } else { switch (bot) { case BOT_GR: std::swap(e0,e1); bot = BOT_LE; break; case BOT_GQ: std::swap(e0,e1); bot = BOT_LQ; break; default: break; } args.push_back(e0.r); args.push_back(e1.r); } if (args.size() > 0) { GC::lock(); if (callid=="") { if (bo->decl()) { callid = bo->decl()->id(); } else { callid = opToBuiltin(bo,bot); } } std::vector args_e(args.size()); for (unsigned int i=args.size(); i--;) args_e[i] = args[i](); Call* cc = new Call(e->loc().introduce(),callid,args_e); cc->decl(env.orig->matchFn(env,cc->id(),args_e)); if (cc->decl()==NULL) { throw FlatteningError(env,cc->loc(), "cannot find matching declaration"); } cc->type(cc->decl()->rtype(env,args_e)); // add defines_var annotation if applicable Id* assignTo = NULL; if (bot==BOT_EQ && ctx.b == C_ROOT) { if (le0 && le0->isa()) { assignTo = le0->cast(); } else if (le1 && le1->isa()) { assignTo = le1->cast(); } if (assignTo) { cc->addAnnotation(definesVarAnn(assignTo)); assignTo->decl()->flat()->addAnnotation(constants().ann.is_defined_var); } } EnvI::Map::iterator cit = env.map_find(cc); if (cit != env.map_end()) { ees[2].b = cit->second.r(); if (doubleNeg) { Type t = ees[2].b()->type(); ees[2].b = new UnOp(Location().introduce(),UOT_NOT,ees[2].b()); ees[2].b()->type(t); } if (Id* id = ees[2].b()->dyn_cast()) { addCtxAnn(id->decl(),ctx.b); } ret.r = conj(env,r,ctx,ees); GC::unlock(); } else { bool singleExp = true; for (unsigned int i=0; itype(); ees[2].b = new UnOp(Location().introduce(),UOT_NOT,ees[2].b()); ees[2].b()->type(t); } if (Id* id = ees[2].b()->dyn_cast()) { addCtxAnn(id->decl(),ctx.b); } ret.r = conj(env,r,ctx,ees); } if (!ctx.neg) env.map_insert(cc,ret); } } else { ret.r = conj(env,r,ctx,ees); } } break; case BOT_PLUSPLUS: { std::vector ee(2); EE eev = flat_exp(env,ctx,boe0,NULL,NULL); ee[0] = eev; ArrayLit* al; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast(); } ArrayLit* al0 = al; eev = flat_exp(env,ctx,boe1,NULL,NULL); ee[1] = eev; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast(); } ArrayLit* al1 = al; std::vector v(al0->v().size()+al1->v().size()); for (unsigned int i=al0->v().size(); i--;) v[i] = al0->v()[i]; for (unsigned int i=al1->v().size(); i--;) v[al0->v().size()+i] = al1->v()[i]; GCLock lock; ArrayLit* alret = new ArrayLit(e->loc(),v); alret->type(e->type()); ret.b = conj(env,b,Ctx(),ee); ret.r = bind(env,ctx,r,alret); } break; } } break; case Expression::E_UNOP: { CallStackItem _csi(env,e); UnOp* uo = e->cast(); switch (uo->op()) { case UOT_NOT: { Ctx nctx = ctx; nctx.b = -nctx.b; nctx.neg = !nctx.neg; ret = flat_exp(env,nctx,uo->e(),r,b); } break; case UOT_PLUS: ret = flat_exp(env,ctx,uo->e(),r,b); break; case UOT_MINUS: { GC::lock(); if (UnOp* uo_inner = uo->e()->dyn_cast()) { if (uo_inner->op()==UOT_MINUS) { ret = flat_exp(env,ctx,uo_inner->e(),r,b); break; } } Expression* zero; if (uo->e()->type().bt()==Type::BT_INT) zero = IntLit::a(0); else zero = FloatLit::a(0.0); BinOp* bo = new BinOp(Location().introduce(),zero,BOT_MINUS,uo->e()); bo->type(uo->type()); KeepAlive ka(bo); GC::unlock(); ret = flat_exp(env,ctx,ka(),r,b); } break; default: break; } } break; case Expression::E_CALL: { Call* c = e->cast(); FunctionI* decl = env.orig->matchFn(env,c); if (decl == NULL) { throw InternalError("undeclared function or predicate " +c->id().str()); } if (decl->params().size()==1) { if (Call* call_body = Expression::dyn_cast(decl->e())) { if (call_body->args().size()==1 && Expression::equal(call_body->args()[0],decl->params()[0]->id())) { c->id(call_body->id()); c->decl(call_body->decl()); } } } Ctx nctx = ctx; nctx.neg = false; ASTString cid = c->id(); CallStackItem _csi(env,e); if (decl->e()==NULL) { if (cid == constants().ids.forall) { nctx.b = +nctx.b; if (ctx.neg) { ctx.neg = false; nctx.neg = true; cid = constants().ids.exists; } } else if (cid == constants().ids.exists) { nctx.b = +nctx.b; if (ctx.neg) { ctx.neg = false; nctx.neg = true; cid = constants().ids.forall; } } else if (cid == constants().ids.bool2int) { if (ctx.neg) { ctx.neg = false; nctx.neg = true; nctx.b = -ctx.i; } else { nctx.b = ctx.i; } } else if (cid == constants().ids.assert || cid == constants().ids.trace) { if (cid == constants().ids.assert && c->args().size()==2) { (void) decl->_builtins.b(env,c); ret = flat_exp(env,ctx,constants().lit_true,r,b); } else { KeepAlive callres = decl->_builtins.e(env,c); ret = flat_exp(env,ctx,callres(),r,b); // This is all we need to do for assert, so break out of the E_CALL } break; } } else if (ctx.b==C_ROOT && decl->e()->isa() && eval_bool(env,decl->e())) { bool allBool = true; for (unsigned int i=0; iargs().size(); i++) { if (c->args()[i]->type().bt()!=Type::BT_BOOL) { allBool = false; break; } } if (allBool) { ret.r = bind(env,ctx,r,constants().lit_true); ret.b = bind(env,ctx,b,constants().lit_true); break; } } if (ctx.b==C_ROOT && decl->e()==NULL && cid == constants().ids.forall && r==constants().var_true) { ret.b = bind(env,ctx,b,constants().lit_true); EE flat_al = flat_exp(env,Ctx(),c->args()[0],NULL,constants().var_true); ArrayLit* al = follow_id(flat_al.r())->cast(); nctx.b = C_ROOT; for (unsigned int i=0; iv().size(); i++) (void) flat_exp(env,nctx,al->v()[i],r,b); ret.r = bind(env,ctx,r,constants().lit_true); } else { if (decl->e() && decl->params().size()==1 && decl->e()->isa() && decl->params()[0]->ti()->domain()==NULL && decl->e()->cast()->decl() == decl->params()[0]) { ret = flat_exp(env, ctx, c->args()[0], r, b); break; } std::vector args_ee(c->args().size()); bool mixContext = decl->e()!=NULL || (cid != constants().ids.forall && cid != constants().ids.exists && cid != constants().ids.bool2int && cid != constants().ids.sum && cid != constants().ids.lin_exp && cid != "assert"); bool isPartial = false; for (unsigned int i=c->args().size(); i--;) { Ctx argctx = nctx; if (mixContext) { if (cid==constants().ids.clause) { argctx.b = (i==0 ? +nctx.b : -nctx.b); } else if (c->args()[i]->type().bt()==Type::BT_BOOL) { argctx.b = C_MIX; } else if (c->args()[i]->type().bt()==Type::BT_INT) { argctx.i = C_MIX; } } Expression* tmp = follow_id_to_decl(c->args()[i]); if (VarDecl* vd = tmp->dyn_cast()) tmp = vd->id(); CallArgItem cai(env); args_ee[i] = flat_exp(env,argctx,tmp,NULL,NULL); isPartial |= isfalse(env, args_ee[i].b()); } if (isPartial && c->type().isbool() && !c->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); args_ee.resize(1); args_ee[0] = EE(NULL, constants().lit_false); ret.r = conj(env, r, ctx, args_ee); break; } std::vector args; if (decl->e()==NULL && (cid == constants().ids.exists || cid == constants().ids.clause)) { std::vector pos_alv; std::vector neg_alv; for (unsigned int i=0; i& local_pos = i==0 ? pos_alv : neg_alv; std::vector& local_neg = i==1 ? pos_alv : neg_alv; ArrayLit* al = follow_id(args_ee[i].r())->cast(); std::vector alv; for (unsigned int i=0; iv().size(); i++) { if (Call* sc = same_call(al->v()[i],cid)) { if (sc->id()==constants().ids.clause) { alv.push_back(sc); } else { GCLock lock; ArrayLit* sc_c = eval_array_lit(env,sc->args()[0]); for (unsigned int j=0; jv().size(); j++) { alv.push_back(sc_c->v()[j]); } } } else { alv.push_back(al->v()[i]); } } for (unsigned int j=0; jargs()[1],constants().lit_false)) { local_neg.push_back(neg_call->args()[0]); } else { Call* clause = same_call(alv[j](),constants().ids.clause); if (clause) { ArrayLit* clause_pos = eval_array_lit(env,clause->args()[0]); for (unsigned int k=0; kv().size(); k++) { local_pos.push_back(clause_pos->v()[k]); } ArrayLit* clause_neg = eval_array_lit(env,clause->args()[1]); for (unsigned int k=0; kv().size(); k++) { local_neg.push_back(clause_neg->v()[k]); } } else { local_pos.push_back(alv[j]); } } } } bool subsumed = remove_dups(pos_alv,false); subsumed = subsumed || remove_dups(neg_alv,true); subsumed = subsumed || contains_dups(pos_alv, neg_alv); if (subsumed) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_true); return ret; } if (neg_alv.empty()) { if (pos_alv.size()==0) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_false); return ret; } else if (pos_alv.size()==1) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,pos_alv[0]()); return ret; } GCLock lock; ArrayLit* nal = new ArrayLit(Location().introduce(),toExpVec(pos_alv)); nal->type(Type::varbool(1)); args.push_back(nal); cid = constants().ids.exists; } else { GCLock lock; ArrayLit* pos_al = new ArrayLit(Location().introduce(),toExpVec(pos_alv)); pos_al->type(Type::varbool(1)); ArrayLit* neg_al = new ArrayLit(Location().introduce(),toExpVec(neg_alv)); neg_al->type(Type::varbool(1)); cid = constants().ids.clause; args.push_back(pos_al); args.push_back(neg_al); } } else if (decl->e()==NULL && cid == constants().ids.forall) { ArrayLit* al = follow_id(args_ee[0].r())->cast(); std::vector alv; for (unsigned int i=0; iv().size(); i++) { if (Call* sc = same_call(al->v()[i],cid)) { GCLock lock; ArrayLit* sc_c = eval_array_lit(env,sc->args()[0]); for (unsigned int j=0; jv().size(); j++) { alv.push_back(sc_c->v()[j]); } } else { alv.push_back(al->v()[i]); } } bool subsumed = remove_dups(alv,true); if (subsumed) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_false); return ret; } if (alv.size()==0) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_true); return ret; } else if (alv.size()==1) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,alv[0]()); return ret; } GCLock lock; ArrayLit* nal = new ArrayLit(al->loc(),toExpVec(alv)); nal->type(al->type()); args.push_back(nal); } else if (decl->e()==NULL && (cid == constants().ids.lin_exp || cid==constants().ids.sum)) { if (e->type().isint()) { flatten_linexp_call(env,ctx,nctx,cid,c,ret,b,r,args_ee,args); } else { flatten_linexp_call(env,ctx,nctx,cid,c,ret,b,r,args_ee,args); } if (args.size()==0) break; } else { for (unsigned int i=0; i e_args = toExpVec(args); Call* cr_c = new Call(c->loc().introduce(),cid,e_args); decl = env.orig->matchFn(env,cr_c); if (decl==NULL) throw FlatteningError(env,cr_c->loc(), "cannot find matching declaration"); cr_c->type(decl->rtype(env,e_args)); assert(decl); cr_c->decl(decl); cr = cr_c; } EnvI::Map::iterator cit = env.map_find(cr()); if (cit != env.map_end()) { ret.b = bind(env,Ctx(),b,env.ignorePartial ? constants().lit_true : cit->second.b()); ret.r = bind(env,ctx,r,cit->second.r()); } else { for (unsigned int i=0; iparams().size(); i++) { if (Expression* dom = decl->params()[i]->ti()->domain()) { if (!dom->isa()) { // May have to constrain actual argument if (args[i]()->type().bt() == Type::BT_INT) { GCLock lock; IntSetVal* isv = eval_intset(env,dom); BinOpType bot; bool needToConstrain; if (args[i]()->type().st() == Type::ST_SET) { bot = BOT_SUBSET; needToConstrain = true; } else { bot = BOT_IN; if (args[i]()->type().dim() > 0) { needToConstrain = true; } else { IntBounds ib = compute_int_bounds(env,args[i]()); needToConstrain = !ib.valid || isv->size()==0 || ib.l < isv->min(0) || ib.u > isv->max(isv->size()-1); } } if (needToConstrain) { GCLock lock; Expression* domconstraint; if (args[i]()->type().dim() > 0) { std::vector domargs(2); domargs[0] = args[i](); domargs[1] = dom; Call* c = new Call(Location().introduce(),"var_dom",domargs); c->type(Type::varbool()); c->decl(env.orig->matchFn(env,c)); domconstraint = c; } else { domconstraint = new BinOp(Location().introduce(),args[i](),bot,dom); } domconstraint->type(args[i]()->type().ispar() ? Type::parbool() : Type::varbool()); if (ctx.b == C_ROOT) { (void) flat_exp(env, Ctx(), domconstraint, constants().var_true, constants().var_true); } else { EE ee = flat_exp(env, Ctx(), domconstraint, NULL, constants().var_true); ee.b = ee.r; args_ee.push_back(ee); } } } else if (args[i]()->type().bt() == Type::BT_FLOAT) { GCLock lock; BinOp* bo = dom->cast(); FloatVal dom_min = eval_float(env,bo->lhs()); FloatVal dom_max = eval_float(env,bo->rhs()); bool needToConstrain; if (args[i]()->type().dim() > 0) { needToConstrain = true; } else { FloatBounds fb = compute_float_bounds(env,args[i]()); needToConstrain = !fb.valid || dom_min > dom_max || fb.l < dom_min || fb.u > dom_max; } if (needToConstrain) { GCLock lock; Expression* domconstraint; std::vector domargs(3); domargs[0] = args[i](); domargs[1] = bo->lhs(); domargs[2] = bo->rhs(); Call* c = new Call(Location().introduce(),"var_dom",domargs); c->type(Type::varbool()); c->decl(env.orig->matchFn(env,c)); domconstraint = c; domconstraint->type(args[i]()->type().ispar() ? Type::parbool() : Type::varbool()); if (ctx.b == C_ROOT) { (void) flat_exp(env, Ctx(), domconstraint, constants().var_true, constants().var_true); } else { EE ee = flat_exp(env, Ctx(), domconstraint, NULL, constants().var_true); ee.b = ee.r; args_ee.push_back(ee); } } } else if (args[i]()->type().bt() == Type::BT_BOT) { // Nothing to be done for empty arrays/sets } else { throw EvalError(env,decl->params()[i]->loc(),"domain restrictions other than int and float not supported yet"); } } } } if (cr()->type().isbool() && !cr()->type().ispar() && !cr()->type().isopt() && (ctx.b != C_ROOT || r != constants().var_true)) { std::vector argtypes(args.size()); for (unsigned int i=0; itype(); argtypes.push_back(Type::varbool()); GCLock lock; ASTString r_cid = env.reifyId(cid); FunctionI* reif_decl = env.orig->matchFn(env, r_cid, argtypes); if (reif_decl && reif_decl->e()) { VarDecl* reif_b; if (r==NULL || (r != NULL && r->e() != NULL)) { reif_b = newVarDecl(env, Ctx(), new TypeInst(Location().introduce(),Type::varbool()), NULL, NULL, NULL); if (reif_b->ti()->domain()) { if (reif_b->ti()->domain() == constants().lit_true) { bind(env,ctx,r,constants().lit_true); r = constants().var_true; ctx.b = C_ROOT; goto call_nonreif; } else { std::vector args_e(args.size()+1); for (unsigned int i=0; itype(Type::varbool()); reif_call->decl(reif_decl); flat_exp(env, Ctx(), reif_call, constants().var_true, constants().var_true); args_ee.push_back(EE(NULL,constants().lit_false)); ret.r = conj(env,r,ctx,args_ee); ret.b = bind(env,ctx,b,constants().lit_true); return ret; } } } else { reif_b = r; } reif_b->e(cr()); if (r != NULL && r->e() != NULL) { bind(env,Ctx(),r,reif_b->id()); } env.vo_add_exp(reif_b); ret.b = bind(env,Ctx(),b,constants().lit_true); args_ee.push_back(EE(NULL,reif_b->id())); ret.r = conj(env,NULL,ctx,args_ee); return ret; } } call_nonreif: if ( (cr()->type().ispar() && !cr()->type().isann()) || decl->e()==NULL) { Call* cr_c = cr()->cast(); /// All builtins are total std::vector argt(cr_c->args().size()); for (unsigned int i=argt.size(); i--;) argt[i] = cr_c->args()[i]->type(); Type callt = decl->rtype(env,argt); if (callt.ispar() && callt.bt()!=Type::BT_ANN) { GCLock lock; ret.b = conj(env,b,Ctx(),args_ee); ret.r = bind(env,ctx,r,eval_par(env,cr_c)); // Do not insert into map, since par results will quickly become // garbage anyway and then disappear from the map } else if (decl->_builtins.e) { KeepAlive callres = decl->_builtins.e(env,cr_c); EE res = flat_exp(env,ctx,callres(),r,b); args_ee.push_back(res); ret.b = conj(env,b,Ctx(),args_ee); ret.r = bind(env,ctx,r,res.r()); if (!ctx.neg && !cr_c->type().isann()) env.map_insert(cr_c,ret); } else { ret.b = conj(env,b,Ctx(),args_ee); ret.r = bind(env,ctx,r,cr_c); if (!ctx.neg && !cr_c->type().isann()) env.map_insert(cr_c,ret); } } else { std::vector previousParameters(decl->params().size()); for (unsigned int i=decl->params().size(); i--;) { VarDecl* vd = decl->params()[i]; previousParameters[i] = vd->e(); vd->flat(vd); vd->e(args[i]()); } if (decl->e()->type().isbool() && !decl->e()->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); if (ctx.b==C_ROOT && r==constants().var_true) { (void) flat_exp(env,Ctx(),decl->e(),r,constants().var_true); } else { Ctx nctx; if (!isTotal(decl)) { nctx = ctx; nctx.neg = false; } EE ee = flat_exp(env,nctx,decl->e(),NULL,constants().var_true); ee.b = ee.r; args_ee.push_back(ee); } ret.r = conj(env,r,ctx,args_ee); } else { if (isTotal(decl)) { EE ee = flat_exp(env,Ctx(),decl->e(),r,constants().var_true); ret.r = bind(env,ctx,r,ee.r()); } else { ret = flat_exp(env,ctx,decl->e(),r,NULL); args_ee.push_back(ret); } ret.b = conj(env,b,Ctx(),args_ee); } if (!ctx.neg && !cr()->type().isann()) env.map_insert(cr(),ret); // Restore previous mapping for (unsigned int i=decl->params().size(); i--;) { VarDecl* vd = decl->params()[i]; vd->e(previousParameters[i]()); vd->flat(vd->e() ? vd : NULL); } } } } } break; case Expression::E_VARDECL: { CallStackItem _csi(env,e); GCLock lock; if (ctx.b != C_ROOT) throw FlatteningError(env,e->loc(), "not in root context"); VarDecl* v = e->cast(); VarDecl* it = v->flat(); if (it==NULL) { TypeInst* ti = eval_typeinst(env,v); VarDecl* vd = newVarDecl(env, ctx, ti, v->id()->idn()==-1 && !v->toplevel() ? NULL : v->id(), v, NULL); v->flat(vd); Ctx nctx; if (v->e() && v->e()->type().bt() == Type::BT_BOOL) nctx.b = C_MIX; if (v->e()) { (void) flat_exp(env,nctx,v->e(),vd,constants().var_true); if (v->e()->type().dim() > 0) { Expression* ee = follow_id_to_decl(vd->e()); if (ee->isa()) ee = ee->cast()->e(); assert(ee && ee->isa()); ArrayLit* al = ee->cast(); if (vd->ti()->domain()) { for (unsigned int i=0; iv().size(); i++) { if (Id* ali_id = al->v()[i]->dyn_cast()) { if (ali_id->decl()->ti()->domain()==NULL) { ali_id->decl()->ti()->domain(vd->ti()->domain()); } } } } } } ret.r = bind(env,Ctx(),r,vd->id()); } else { ret.r = bind(env,Ctx(),r,it); } ret.b = bind(env,Ctx(),b,constants().lit_true); } break; case Expression::E_LET: { CallStackItem _csi(env,e); Let* let = e->cast(); GC::mark(); std::vector cs; std::vector flatmap; let->pushbindings(); for (unsigned int i=0; ilet().size(); i++) { Expression* le = let->let()[i]; if (VarDecl* vd = le->dyn_cast()) { Expression* let_e = NULL; if (vd->e()) { Ctx nctx = ctx; nctx.neg = false; if (vd->e()->type().bt()==Type::BT_BOOL) nctx.b = C_MIX; EE ee = flat_exp(env,nctx,vd->e(),NULL,NULL); let_e = ee.r(); cs.push_back(ee); if (vd->ti()->domain() != NULL) { GCLock lock; std::vector domargs(2); domargs[0] = ee.r(); if (vd->ti()->type().isfloat()) { BinOp* bo_dom = vd->ti()->domain()->cast(); domargs[1] = bo_dom->lhs(); domargs.push_back(bo_dom->rhs()); } else { domargs[1] = vd->ti()->domain(); } Call* c = new Call(vd->ti()->loc().introduce(),"var_dom",domargs); c->type(Type::varbool()); c->decl(env.orig->matchFn(env,c)); VarDecl* b_b = (nctx.b==C_ROOT && b==constants().var_true) ? b : NULL; VarDecl* r_r = (nctx.b==C_ROOT && b==constants().var_true) ? b : NULL; ee = flat_exp(env, nctx, c, r_r, b_b); cs.push_back(ee); ee.b = ee.r; cs.push_back(ee); } if (vd->type().dim() > 0) { checkIndexSets(env, vd, let_e); } } else { if ((ctx.b==C_NEG || ctx.b==C_MIX) && !vd->ann().contains(constants().ann.promise_total)) { CallStackItem csi_vd(env, vd); throw FlatteningError(env,vd->loc(), "free variable in non-positive context"); } GCLock lock; TypeInst* ti = eval_typeinst(env,vd); VarDecl* nvd = newVarDecl(env, ctx, ti, NULL, vd, NULL); let_e = nvd->id(); } vd->e(let_e); flatmap.push_back(vd->flat()); if (Id* id = let_e->dyn_cast()) { vd->flat(id->decl()); } else { vd->flat(vd); } } else { if (ctx.b==C_ROOT || le->ann().contains(constants().ann.promise_total)) { (void) flat_exp(env,Ctx(),le,constants().var_true,constants().var_true); } else { EE ee = flat_exp(env,ctx,le,NULL,constants().var_true); ee.b = ee.r; cs.push_back(ee); } } } if (r==constants().var_true && ctx.b==C_ROOT && !ctx.neg) { ret.b = bind(env,Ctx(),b,constants().lit_true); (void) flat_exp(env,ctx,let->in(),r,b); ret.r = conj(env,r,Ctx(),cs); } else { Ctx nctx = ctx; nctx.neg = false; EE ee = flat_exp(env,nctx,let->in(),NULL,NULL); if (let->type().isbool() && !let->type().isopt()) { ee.b = ee.r; cs.push_back(ee); ret.r = conj(env,r,ctx,cs); ret.b = bind(env,Ctx(),b,constants().lit_true); } else { cs.push_back(ee); ret.r = bind(env,Ctx(),r,ee.r()); ret.b = conj(env,b,Ctx(),cs); } } let->popbindings(); // Restore previous mapping for (unsigned int i=0; ilet().size(); i++) { if (VarDecl* vd = let->let()[i]->dyn_cast()) { vd->flat(Expression::cast(flatmap.back()())); flatmap.pop_back(); } } } break; case Expression::E_TI: throw InternalError("not supported yet"); break; case Expression::E_TIID: throw InternalError("not supported yet"); break; } assert(ret.r()); return ret; } bool isBuiltin(FunctionI* decl) { return (decl->loc().filename == "builtins.mzn" || decl->loc().filename.endsWith("/builtins.mzn") || decl->loc().filename == "stdlib.mzn" || decl->loc().filename.endsWith("/stdlib.mzn") || decl->loc().filename == "flatzinc_builtins.mzn" || decl->loc().filename.endsWith("/flatzinc_builtins.mzn")); } void outputVarDecls(EnvI& env, Item* ci, Expression* e); bool cannotUseRHSForOutput(EnvI& env, Expression* e) { if (e==NULL) return true; class V : public EVisitor { public: EnvI& env; bool success; V(EnvI& env0) : env(env0), success(true) {} /// Visit anonymous variable void vAnonVar(const AnonVar&) { success = false; } /// Visit array literal void vArrayLit(const ArrayLit&) {} /// Visit array access void vArrayAccess(const ArrayAccess&) {} /// Visit array comprehension void vComprehension(const Comprehension&) {} /// Visit if-then-else void vITE(const ITE&) {} /// Visit binary operator void vBinOp(const BinOp&) {} /// Visit unary operator void vUnOp(const UnOp&) {} /// Visit call void vCall(Call& c) { std::vector tv(c.args().size()); for (unsigned int i=c.args().size(); i--;) { tv[i] = c.args()[i]->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env,c.id(), tv); Type t; if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, c.id(), tv); if (origdecl == NULL) { throw FlatteningError(env,c.loc(),"function is used in output, par version needed"); } if (origdecl->e() && cannotUseRHSForOutput(env, origdecl->e())) { success = false; } else { if (!isBuiltin(origdecl)) { decl = copy(env,env.cmap,origdecl)->cast(); CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); outputVarDecls(env,origdecl,decl->e()); outputVarDecls(env,origdecl,decl->ti()); } else { decl = origdecl; } c.decl(decl); } } if (success) { t = decl->rtype(env, tv); if (!t.ispar()) success = false; } } void vId(const Id& id) {} /// Visit let void vLet(const Let&) { success = false; } /// Visit variable declaration void vVarDecl(const VarDecl& vd) {} /// Visit type inst void vTypeInst(const TypeInst&) {} /// Visit TIId void vTIId(const TIId&) {} /// Determine whether to enter node bool enter(Expression* e) { return success; } } _v(env); topDown(_v, e); return !_v.success; } void removeIsOutput(VarDecl* vd) { if (vd==NULL) return; vd->ann().remove(constants().ann.output_var); vd->ann().removeCall(constants().ann.output_array); } void makePar(EnvI& env, Expression* e) { class Par : public EVisitor { public: /// Visit variable declaration void vVarDecl(VarDecl& vd) { vd.ti()->type(vd.type()); } /// Determine whether to enter node bool enter(Expression* e) { Type t = e->type(); t.ti(Type::TI_PAR); e->type(t); return true; } } _par; topDown(_par, e); class Decls : public EVisitor { public: EnvI& env; Decls(EnvI& env0) : env(env0) {} void vCall(Call& c) { c.decl(env.orig->matchFn(env,&c)); } } _decls(env); topDown(_decls, e); } void outputVarDecls(EnvI& env, Item* ci, Expression* e) { class O : public EVisitor { public: EnvI& env; Item* ci; O(EnvI& env0, Item* ci0) : env(env0), ci(ci0) {} void vId(Id& id) { if (&id==constants().absent) return; if (!id.decl()->toplevel()) return; VarDecl* vd = id.decl(); VarDecl* reallyFlat = vd->flat(); while (reallyFlat != NULL && reallyFlat != reallyFlat->flat()) reallyFlat = reallyFlat->flat(); IdMap::iterator idx = reallyFlat ? env.output_vo.idx.find(reallyFlat->id()) : env.output_vo.idx.end(); IdMap::iterator idx2 = env.output_vo.idx.find(vd->id()); if (idx==env.output_vo.idx.end() && idx2==env.output_vo.idx.end()) { VarDeclI* nvi = new VarDeclI(Location().introduce(), copy(env,env.cmap,vd)->cast()); Type t = nvi->e()->ti()->type(); if (t.ti() != Type::TI_PAR) { t.ti(Type::TI_PAR); } makePar(env,nvi->e()); nvi->e()->ti()->domain(NULL); nvi->e()->flat(vd->flat()); nvi->e()->ann().clear(); nvi->e()->introduced(false); if (reallyFlat) env.output_vo.add(reallyFlat, env.output->size()); env.output_vo.add(nvi, env.output->size()); env.output_vo.add(nvi->e(), ci); env.output->addItem(nvi); IdMap::iterator it; if ( (it = env.reverseMappers.find(nvi->e()->id())) != env.reverseMappers.end()) { Call* rhs = copy(env,env.cmap,it->second())->cast(); { std::vector tv(rhs->args().size()); for (unsigned int i=rhs->args().size(); i--;) { tv[i] = rhs->args()[i]->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, rhs->id(), tv); Type t; if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, rhs->id(), tv); if (origdecl == NULL) { throw FlatteningError(env,rhs->loc(),"function is used in output, par version needed"); } if (!isBuiltin(origdecl)) { decl = copy(env,env.cmap,origdecl)->cast(); CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); } outputVarDecls(env,nvi,it->second()); nvi->e()->e(rhs); } else if (reallyFlat && cannotUseRHSForOutput(env, reallyFlat->e())) { assert(nvi->e()->flat()); nvi->e()->e(NULL); if (nvi->e()->type().dim() == 0) { reallyFlat->addAnnotation(constants().ann.output_var); } else { std::vector args(reallyFlat->e()->type().dim()); for (unsigned int i=0; ie()->ti()->ranges()[i]->domain() == NULL) { args[i] = new SetLit(Location().introduce(), eval_intset(env,reallyFlat->ti()->ranges()[i]->domain())); } else { args[i] = new SetLit(Location().introduce(), eval_intset(env,nvi->e()->ti()->ranges()[i]->domain())); } } ArrayLit* al = new ArrayLit(Location().introduce(), args); args.resize(1); args[0] = al; reallyFlat->addAnnotation(new Call(Location().introduce(),constants().ann.output_array,args,NULL)); } } else { outputVarDecls(env, nvi, nvi->e()->e()); } CollectOccurrencesE ce(env.output_vo,nvi); topDown(ce, nvi->e()); } } } _o(env,ci); topDown(_o, e); } void copyOutput(EnvI& e) { struct CopyOutput : public EVisitor { EnvI& env; CopyOutput(EnvI& env0) : env(env0) {} void vId(Id& _id) { _id.decl(_id.decl()->flat()); } void vCall(Call& c) { std::vector tv(c.args().size()); for (unsigned int i=c.args().size(); i--;) { tv[i] = c.args()[i]->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = c.decl(); if (!isBuiltin(decl)) { env.flat_addItem(decl); } } }; for (unsigned int i=e.orig->size(); i--;) { if (OutputI* oi = (*e.orig)[i]->dyn_cast()) { GCLock lock; OutputI* noi = copy(e,oi)->cast(); CopyOutput co(e); topDown(co, noi->e()); e.flat_addItem(noi); break; } } } void createOutput(EnvI& e) { if (e.output->size() > 0) { // Adapt existing output model // (generated by repeated flattening) e.output_vo.clear(); for (unsigned int i=0; isize(); i++) { Item* item = (*e.output)[i]; if (item->removed()) continue; switch (item->iid()) { case Item::II_VD: { VarDecl* vd = item->cast()->e(); IdMap::iterator it; GCLock lock; VarDecl* reallyFlat = vd->flat(); while (reallyFlat && reallyFlat!=reallyFlat->flat()) reallyFlat=reallyFlat->flat(); if (vd->e()==NULL) { if (vd->flat()->e() && vd->flat()->e()->type().ispar()) { VarDecl* reallyFlat = vd->flat(); while (reallyFlat!=reallyFlat->flat()) reallyFlat=reallyFlat->flat(); removeIsOutput(reallyFlat); Expression* flate = copy(e,e.cmap,follow_id(reallyFlat->id())); outputVarDecls(e,item,flate); vd->e(flate); } else if ( (it = e.reverseMappers.find(vd->id())) != e.reverseMappers.end()) { Call* rhs = copy(e,e.cmap,it->second())->cast(); std::vector tv(rhs->args().size()); for (unsigned int i=rhs->args().size(); i--;) { tv[i] = rhs->args()[i]->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = e.output->matchFn(e, rhs->id(), tv); if (decl==NULL) { FunctionI* origdecl = e.orig->matchFn(e, rhs->id(), tv); if (origdecl == NULL) { throw FlatteningError(e,rhs->loc(),"function is used in output, par version needed"); } if (!isBuiltin(origdecl)) { decl = copy(e,e.cmap,origdecl)->cast(); CollectOccurrencesE ce(e.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); e.output->registerFn(e, decl); e.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); removeIsOutput(reallyFlat); if (e.vo.occurrences(reallyFlat)==0 && reallyFlat->e()==NULL) { IdMap::iterator cur_idx = e.vo.idx.find(reallyFlat->id()); if (cur_idx != e.vo.idx.end()) { VarDeclI* vdi = (*e.flat())[cur_idx->second]->cast(); vdi->remove(); } } outputVarDecls(e,item,it->second()->cast()); vd->e(rhs); } else { // If the VarDecl does not have a usable right hand side, it needs to be // marked as output in the FlatZinc assert(vd->flat()); bool needOutputAnn = true; if (reallyFlat->e() && reallyFlat->e()->isa()) { ArrayLit* al = reallyFlat->e()->cast(); for (unsigned int i=0; iv().size(); i++) { if (Id* id = al->v()[i]->dyn_cast()) { if (e.reverseMappers.find(id) != e.reverseMappers.end()) { needOutputAnn = false; break; } } } if (!needOutputAnn) { removeIsOutput(vd); outputVarDecls(e, item, al); vd->e(copy(e,e.cmap,al)); } } if (needOutputAnn) { if (!isOutput(vd->flat())) { GCLock lock; if (vd->type().dim() == 0) { vd->flat()->addAnnotation(constants().ann.output_var); } else { std::vector args(vd->type().dim()); for (unsigned int i=0; iti()->ranges()[i]->domain() == NULL) { args[i] = new SetLit(Location().introduce(), eval_intset(e,vd->flat()->ti()->ranges()[i]->domain())); } else { args[i] = new SetLit(Location().introduce(), eval_intset(e,vd->ti()->ranges()[i]->domain())); } } ArrayLit* al = new ArrayLit(Location().introduce(), args); args.resize(1); args[0] = al; vd->flat()->addAnnotation(new Call(Location().introduce(),constants().ann.output_array,args,NULL)); } } } } } e.output_vo.add(item->cast(), i); CollectOccurrencesE ce(e.output_vo,item); topDown(ce, vd); } break; case Item::II_OUT: { CollectOccurrencesE ce(e.output_vo,item); topDown(ce, item->cast()->e()); } break; case Item::II_FUN: { CollectOccurrencesE ce(e.output_vo,item); topDown(ce, item->cast()->e()); topDown(ce, item->cast()->ti()); for (unsigned int i = item->cast()->params().size(); i--;) topDown(ce, item->cast()->params()[i]); } break; default: throw FlatteningError(e,item->loc(), "invalid item in output model"); } } } else { // Create new output model OutputI* outputItem = NULL; class OV1 : public ItemVisitor { public: EnvI& env; VarOccurrences& vo; OutputI*& outputItem; OV1(EnvI& env0, VarOccurrences& vo0, OutputI*& outputItem0) : env(env0), vo(vo0), outputItem(outputItem0) {} void vOutputI(OutputI* oi) { GCLock lock; outputItem = copy(env,env.cmap, oi)->cast(); makePar(env,outputItem->e()); env.output->addItem(outputItem); } } _ov1(e,e.output_vo,outputItem); iterItems(_ov1,e.orig); if (outputItem==NULL) { // Create output item for all variables defined at toplevel in the MiniZinc source GCLock lock; std::vector outputVars; for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*e.orig)[i]->dyn_cast()) { VarDecl* vd = vdi->e(); if (vd->type().isvar() && vd->e()==NULL) { std::ostringstream s; s << vd->id()->str().str() << " = "; if (vd->type().dim() > 0) { s << "array" << vd->type().dim() << "d("; for (unsigned int i=0; itype().dim(); i++) { IntSetVal* idxset = eval_intset(e,vd->ti()->ranges()[i]->domain()); s << *idxset << ","; } } StringLit* sl = new StringLit(Location().introduce(),s.str()); outputVars.push_back(sl); std::vector showArgs(1); showArgs[0] = vd->id(); Call* show = new Call(Location().introduce(),constants().ids.show,showArgs); show->type(Type::parstring()); FunctionI* fi = e.orig->matchFn(e, show); assert(fi); show->decl(fi); outputVars.push_back(show); std::string ends = vd->type().dim() > 0 ? ")" : ""; ends += ";\n"; StringLit* eol = new StringLit(Location().introduce(),ends); outputVars.push_back(eol); } } } OutputI* newOutputItem = new OutputI(Location().introduce(),new ArrayLit(Location().introduce(),outputVars)); e.orig->addItem(newOutputItem); outputItem = copy(e,e.cmap, newOutputItem)->cast(); e.output->addItem(outputItem); } class CollectFunctions : public EVisitor { public: EnvI& env; CollectFunctions(EnvI& env0) : env(env0) {} bool enter(Expression* e) { if (e->type().isvar()) { Type t = e->type(); t.ti(Type::TI_PAR); e->type(t); } return true; } void vCall(Call& c) { std::vector tv(c.args().size()); for (unsigned int i=c.args().size(); i--;) { tv[i] = c.args()[i]->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, c.id(), tv); Type t; if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, c.id(), tv); if (origdecl == NULL || !origdecl->rtype(env, tv).ispar()) { throw FlatteningError(env,c.loc(),"function is used in output, par version needed"); } if (!isBuiltin(origdecl)) { GCLock lock; decl = copy(env,env.cmap,origdecl)->cast(); CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); topDown(*this, decl->e()); } else { decl = origdecl; } } c.decl(decl); } } _cf(e); topDown(_cf, outputItem->e()); class OV2 : public ItemVisitor { public: EnvI& env; OV2(EnvI& env0) : env(env0) {} void vVarDeclI(VarDeclI* vdi) { IdMap::iterator idx = env.output_vo.idx.find(vdi->e()->id()); if (idx!=env.output_vo.idx.end()) return; if (Expression* vd_e = env.cmap.find(vdi->e())) { VarDecl* vd = vd_e->cast(); GCLock lock; VarDeclI* vdi_copy = copy(env,env.cmap,vdi)->cast(); Type t = vdi_copy->e()->ti()->type(); t.ti(Type::TI_PAR); vdi_copy->e()->ti()->domain(NULL); vdi_copy->e()->flat(vdi->e()->flat()); vdi_copy->e()->ann().clear(); vdi_copy->e()->introduced(false); IdMap::iterator it; if (!vdi->e()->type().ispar()) { if (vd->flat() == NULL && vdi->e()->e()!=NULL && vdi->e()->e()->type().ispar()) { Expression* flate = eval_par(env, vdi->e()->e()); outputVarDecls(env,vdi_copy,flate); vd->e(flate); } else { vd = follow_id_to_decl(vd->id())->cast(); VarDecl* reallyFlat = vd->flat(); while (reallyFlat!=reallyFlat->flat()) reallyFlat=reallyFlat->flat(); if (vd->flat()->e() && vd->flat()->e()->type().ispar()) { Expression* flate = copy(env,env.cmap,follow_id(reallyFlat->id())); outputVarDecls(env,vdi_copy,flate); vd->e(flate); } else if ( (it = env.reverseMappers.find(vd->id())) != env.reverseMappers.end()) { Call* rhs = copy(env,env.cmap,it->second())->cast(); { std::vector tv(rhs->args().size()); for (unsigned int i=rhs->args().size(); i--;) { tv[i] = rhs->args()[i]->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, rhs->id(), tv); if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, rhs->id(), tv); if (origdecl == NULL) { throw FlatteningError(env,rhs->loc(),"function is used in output, par version needed"); } if (!isBuiltin(origdecl)) { decl = copy(env,env.cmap,origdecl)->cast(); CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); } outputVarDecls(env,vdi_copy,rhs); vd->e(rhs); } else if (cannotUseRHSForOutput(env,vd->e())) { // If the VarDecl does not have a usable right hand side, it needs to be // marked as output in the FlatZinc vd->e(NULL); assert(vd->flat()); if (vd->type().dim() == 0) { vd->flat()->addAnnotation(constants().ann.output_var); } else { bool needOutputAnn = true; if (reallyFlat->e() && reallyFlat->e()->isa()) { ArrayLit* al = reallyFlat->e()->cast(); for (unsigned int i=0; iv().size(); i++) { if (Id* id = al->v()[i]->dyn_cast()) { if (env.reverseMappers.find(id) != env.reverseMappers.end()) { needOutputAnn = false; break; } } } if (!needOutputAnn) { outputVarDecls(env, vdi_copy, al); vd->e(copy(env,env.cmap,al)); } } if (needOutputAnn) { std::vector args(vdi->e()->type().dim()); for (unsigned int i=0; ie()->ti()->ranges()[i]->domain() == NULL) { args[i] = new SetLit(Location().introduce(), eval_intset(env,vd->flat()->ti()->ranges()[i]->domain())); } else { args[i] = new SetLit(Location().introduce(), eval_intset(env,vd->ti()->ranges()[i]->domain())); } } ArrayLit* al = new ArrayLit(Location().introduce(), args); args.resize(1); args[0] = al; vd->flat()->addAnnotation(new Call(Location().introduce(),constants().ann.output_array,args,NULL)); } } } if (env.output_vo.find(reallyFlat) == -1) env.output_vo.add(reallyFlat, env.output->size()); } } makePar(env,vdi_copy->e()); env.output_vo.add(vdi_copy, env.output->size()); CollectOccurrencesE ce(env.output_vo,vdi_copy); topDown(ce, vdi_copy->e()); env.output->addItem(vdi_copy); } } } _ov2(e); iterItems(_ov2,e.orig); CollectOccurrencesE ce(e.output_vo,outputItem); topDown(ce, outputItem->e()); } std::vector deletedVarDecls; for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*e.output)[i]->dyn_cast()) { if (!vdi->removed() && e.output_vo.occurrences(vdi->e())==0) { CollectDecls cd(e.output_vo,deletedVarDecls,vdi); topDown(cd, vdi->e()->e()); removeIsOutput(vdi->e()->flat()); if (e.output_vo.find(vdi->e())!=-1) e.output_vo.remove(vdi->e()); vdi->remove(); } } } while (!deletedVarDecls.empty()) { VarDecl* cur = deletedVarDecls.back(); deletedVarDecls.pop_back(); if (e.output_vo.occurrences(cur) == 0) { IdMap::iterator cur_idx = e.output_vo.idx.find(cur->id()); if (cur_idx != e.output_vo.idx.end()) { VarDeclI* vdi = (*e.output)[cur_idx->second]->cast(); if (!vdi->removed()) { CollectDecls cd(e.output_vo,deletedVarDecls,vdi); topDown(cd,cur->e()); removeIsOutput(vdi->e()->flat()); if (e.output_vo.find(vdi->e())!=-1) e.output_vo.remove(vdi->e()); vdi->remove(); } } } } for (IdMap::iterator it = e.output_vo._m.begin(); it != e.output_vo._m.end(); ++it) { std::vector toRemove; for (VarOccurrences::Items::iterator iit = it->second.begin(); iit != it->second.end(); ++iit) { if ((*iit)->removed()) { toRemove.push_back(*iit); } } for (unsigned int i=0; isecond.erase(toRemove[i]); } } } void cleanupOutput(EnvI& env) { for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*env.output)[i]->dyn_cast()) { vdi->e()->flat(NULL); } } } bool checkParDomain(EnvI& env, Expression* e, Expression* domain) { if (e->type()==Type::parint()) { IntSetVal* isv = eval_intset(env,domain); if (!isv->contains(eval_int(env,e))) return false; } else if (e->type()==Type::parfloat()) { BinOp* bo = domain->cast(); assert(bo->op()==BOT_DOTDOT); FloatVal d_min = eval_float(env,bo->lhs()); FloatVal d_max = eval_float(env,bo->rhs()); FloatVal de = eval_float(env,e); if (de < d_min || de > d_max) return false; } else if (e->type()==Type::parsetint()) { IntSetVal* isv = eval_intset(env,domain); IntSetRanges ir(isv); IntSetVal* rsv = eval_intset(env,e); IntSetRanges rr(rsv); if (!Ranges::subset(rr, ir)) return false; } return true; } void flatten(Env& e, FlatteningOptions opt) { EnvI& env = e.envi(); bool onlyRangeDomains; { GCLock lock; Call* check_only_range = new Call(Location(),"mzn_check_only_range_domains", std::vector()); check_only_range->type(Type::parbool()); check_only_range->decl(env.orig->matchFn(e.envi(), check_only_range)); onlyRangeDomains = eval_bool(e.envi(), check_only_range); } class ExpandArrayDecls : public ItemVisitor { public: EnvI& env; ExpandArrayDecls(EnvI& env0) : env(env0) {} void vVarDeclI(VarDeclI* v) { if (v->e()->type().isvar() && v->e()->type().dim() > 0 && v->e()->e() == NULL) { (void) flat_exp(env,Ctx(),v->e()->id(),NULL,constants().var_true); } } } _ead(env); iterItems(_ead,e.model());; bool hadSolveItem = false; // Flatten main model class FV : public ItemVisitor { public: EnvI& env; bool& hadSolveItem; FV(EnvI& env0, bool& hadSolveItem0) : env(env0), hadSolveItem(hadSolveItem0) {} bool enter(Item* i) { return !(i->isa() && env.flat()->failed()); } void vVarDeclI(VarDeclI* v) { if (v->e()->type().isvar() || v->e()->type().isann()) { (void) flat_exp(env,Ctx(),v->e()->id(),NULL,constants().var_true); } else { if (v->e()->e()==NULL) { if (!v->e()->type().isann()) throw EvalError(env, v->e()->loc(), "Undefined parameter", v->e()->id()->v()); } else { CallStackItem csi(env,v->e()); GCLock lock; Location v_loc = v->e()->e()->loc(); if (!v->e()->e()->type().cv()) { v->e()->e(eval_par(env,v->e()->e())); } else { EE ee = flat_exp(env, Ctx(), v->e()->e(), NULL, constants().var_true); v->e()->e(ee.r()); } if (v->e()->type().dim() > 0) { checkIndexSets(env,v->e(), v->e()->e()); if (v->e()->ti()->domain() != NULL) { ArrayLit* al = eval_array_lit(env,v->e()->e()); for (unsigned int i=0; iv().size(); i++) { if (!checkParDomain(env,al->v()[i], v->e()->ti()->domain())) { throw EvalError(env, v_loc, "parameter value out of range"); } } } } else { if (v->e()->ti()->domain() != NULL) { if (!checkParDomain(env,v->e()->e(), v->e()->ti()->domain())) { throw EvalError(env, v_loc, "parameter value out of range"); } } } } } } void vConstraintI(ConstraintI* ci) { (void) flat_exp(env,Ctx(),ci->e(),constants().var_true,constants().var_true); } void vSolveI(SolveI* si) { if (hadSolveItem) throw FlatteningError(env,si->loc(), "Only one solve item allowed"); hadSolveItem = true; GCLock lock; SolveI* nsi = NULL; switch (si->st()) { case SolveI::ST_SAT: nsi = SolveI::sat(Location()); break; case SolveI::ST_MIN: nsi = SolveI::min(Location().introduce(),flat_exp(env,Ctx(),si->e(),NULL,constants().var_true).r()); break; case SolveI::ST_MAX: nsi = SolveI::max(Location().introduce(),flat_exp(env,Ctx(),si->e(),NULL,constants().var_true).r()); break; } for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) { nsi->ann().add(flat_exp(env,Ctx(),*it,NULL,constants().var_true).r()); } env.flat_addItem(nsi); } } _fv(env,hadSolveItem); iterItems(_fv,e.model()); if (!hadSolveItem) { e.envi().errorStack.clear(); Location modelLoc; modelLoc.filename = e.model()->filepath(); throw FlatteningError(e.envi(),modelLoc, "Model does not have a solve item"); } // Create output model if (opt.keepOutputInFzn) { copyOutput(env); } else { createOutput(env); } // Flatten remaining redefinitions Model& m = *e.flat(); int startItem = 0; int endItem = m.size()-1; FunctionI* int_lin_eq; { std::vector int_lin_eq_t(3); int_lin_eq_t[0] = Type::parint(1); int_lin_eq_t[1] = Type::varint(1); int_lin_eq_t[2] = Type::parint(0); GCLock lock; FunctionI* fi = env.orig->matchFn(env, constants().ids.int_.lin_eq, int_lin_eq_t); int_lin_eq = (fi && fi->e()) ? fi : NULL; } FunctionI* array_bool_and; FunctionI* array_bool_or; FunctionI* array_bool_clause; FunctionI* array_bool_clause_reif; FunctionI* bool_xor; { std::vector array_bool_andor_t(2); array_bool_andor_t[0] = Type::varbool(1); array_bool_andor_t[1] = Type::varbool(0); GCLock lock; FunctionI* fi = env.orig->matchFn(env, ASTString("array_bool_and"), array_bool_andor_t); array_bool_and = (fi && fi->e()) ? fi : NULL; fi = env.orig->matchFn(env, ASTString("array_bool_or"), array_bool_andor_t); array_bool_or = (fi && fi->e()) ? fi : NULL; array_bool_andor_t[1] = Type::varbool(1); fi = env.orig->matchFn(env, ASTString("bool_clause"), array_bool_andor_t); array_bool_clause = (fi && fi->e()) ? fi : NULL; array_bool_andor_t.push_back(Type::varbool()); fi = env.orig->matchFn(env, ASTString("bool_clause_reif"), array_bool_andor_t); array_bool_clause_reif = (fi && fi->e()) ? fi : NULL; std::vector bool_xor_t(3); bool_xor_t[0] = Type::varbool(); bool_xor_t[1] = Type::varbool(); bool_xor_t[2] = Type::varbool(); fi = env.orig->matchFn(env, constants().ids.bool_xor, bool_xor_t); bool_xor = (fi && fi->e()) ? fi : NULL; } std::vector deletedVarDecls; std::vector removedItems; env.collectVarDecls(true); while (startItem <= endItem || !env.modifiedVarDecls.empty()) { if (env.flat()->failed()) return; std::vector agenda; for (int i=startItem; i<=endItem; i++) { agenda.push_back(i); } for (unsigned int i=0; idyn_cast(); bool keptVariable = true; if (vdi!=NULL && !isOutput(vdi->e()) && env.vo.occurrences(vdi->e())==0 ) { if (vdi->e()->e() && vdi->e()->ti()->domain()) { if (vdi->e()->type().isvar() && vdi->e()->type().isbool() && !vdi->e()->type().isopt() && Expression::equal(vdi->e()->ti()->domain(),constants().lit_true)) { GCLock lock; ConstraintI* ci = new ConstraintI(vdi->loc(),vdi->e()->e()); if (vdi->e()->introduced()) { removedItems.push_back(vdi); vdi->remove(); keptVariable = false; } else { vdi->e()->e(NULL); } env.flat_addItem(ci); } else if (vdi->e()->type().ispar() || vdi->e()->ti()->computedDomain()) { removedItems.push_back(vdi); keptVariable = false; } } else { removedItems.push_back(vdi); vdi->remove(); keptVariable = false; } } if (vdi && keptVariable && vdi->e()->type().dim() > 0 && vdi->e()->type().isvar()) { vdi->e()->ti()->domain(NULL); } if (vdi && keptVariable && vdi->e()->type().isint() && vdi->e()->type().isvar() && vdi->e()->ti()->domain() != NULL) { GCLock lock; IntSetVal* dom = eval_intset(env,vdi->e()->ti()->domain()); bool needRangeDomain = onlyRangeDomains; if (!needRangeDomain && dom->size() > 0) { if (dom->min(0).isMinusInfinity() || dom->max(dom->size()-1).isPlusInfinity()) needRangeDomain = true; } if (needRangeDomain) { if (dom->min(0).isMinusInfinity() || dom->max(dom->size()-1).isPlusInfinity()) { TypeInst* nti = copy(env,vdi->e()->ti())->cast(); nti->domain(NULL); vdi->e()->ti(nti); if (dom->min(0).isFinite()) { std::vector args(2); args[0] = IntLit::a(dom->min(0)); args[1] = vdi->e()->id(); Call* call = new Call(Location().introduce(),constants().ids.int_.le,args); call->type(Type::varbool()); call->decl(env.orig->matchFn(env, call)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } else if (dom->max(dom->size()-1).isFinite()) { std::vector args(2); args[0] = vdi->e()->id(); args[1] = IntLit::a(dom->max(dom->size()-1)); Call* call = new Call(Location().introduce(),constants().ids.int_.le,args); call->type(Type::varbool()); call->decl(env.orig->matchFn(env, call)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } } else if (dom->size() > 1) { SetLit* newDom = new SetLit(Location().introduce(),IntSetVal::a(dom->min(0),dom->max(dom->size()-1))); TypeInst* nti = copy(env,vdi->e()->ti())->cast(); nti->domain(newDom); vdi->e()->ti(nti); } if (dom->size() > 1) { IntVal firstHole = dom->max(0)+1; IntSetRanges domr(dom); ++domr; for (; domr(); ++domr) { for (IntVal i=firstHole; i args(2); args[0] = vdi->e()->id(); args[1] = IntLit::a(i); Call* call = new Call(Location().introduce(),constants().ids.int_.ne,args); call->type(Type::varbool()); call->decl(env.orig->matchFn(env, call)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); firstHole = domr.max().plus(1); } } } } } if (vdi && keptVariable && vdi->e()->type().isfloat() && vdi->e()->type().isvar() && vdi->e()->ti()->domain() != NULL) { GCLock lock; BinOp* bo = vdi->e()->ti()->domain()->cast(); FloatVal vmin = eval_float(env, bo->lhs()); FloatVal vmax = eval_float(env, bo->rhs()); if (vmin == -std::numeric_limits::infinity() && vmax == std::numeric_limits::infinity()) { vdi->e()->ti()->domain(NULL); } else if (vmin == -std::numeric_limits::infinity()) { vdi->e()->ti()->domain(NULL); std::vector args(2); args[0] = vdi->e()->id(); args[1] = FloatLit::a(vmax); Call* call = new Call(Location().introduce(),constants().ids.float_.le,args); call->type(Type::varbool()); call->decl(env.orig->matchFn(env, call)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } else if (vmax == std::numeric_limits::infinity()) { vdi->e()->ti()->domain(NULL); std::vector args(2); args[0] = FloatLit::a(vmin); args[1] = vdi->e()->id(); Call* call = new Call(Location().introduce(),constants().ids.float_.le,args); call->type(Type::varbool()); call->decl(env.orig->matchFn(env, call)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } } } // rewrite some constraints if there are redefinitions for (int ai=0; aidyn_cast()) { VarDecl* vd = vdi->e(); if (!vdi->removed() && vd->e()) { if (Call* c = vd->e()->dyn_cast()) { GCLock lock; Call* nc = NULL; if (c->id() == constants().ids.lin_exp) { if (int_lin_eq) { std::vector args(c->args().size()); ArrayLit* le_c = follow_id(c->args()[0])->cast(); std::vector nc_c(le_c->v().size()); std::copy(le_c->v().begin(),le_c->v().end(),nc_c.begin()); nc_c.push_back(IntLit::a(-1)); args[0] = new ArrayLit(Location().introduce(),nc_c); args[0]->type(Type::parint(1)); ArrayLit* le_x = follow_id(c->args()[1])->cast(); std::vector nx(le_x->v().size()); std::copy(le_x->v().begin(),le_x->v().end(),nx.begin()); nx.push_back(vd->id()); args[1] = new ArrayLit(Location().introduce(),nx); args[1]->type(Type::varint(1)); IntVal d = c->args()[2]->cast()->v(); args[2] = IntLit::a(-d); args[2]->type(Type::parint(0)); nc = new Call(c->loc().introduce(),ASTString("int_lin_eq"),args); nc->type(Type::varbool()); nc->decl(int_lin_eq); } } else if (c->id() == constants().ids.exists) { if (array_bool_or) { std::vector args(2); args[0] = c->args()[0]; args[1] = vd->id(); nc = new Call(c->loc().introduce(),array_bool_or->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_or); } } else if (c->id() == constants().ids.forall) { if (array_bool_and) { std::vector args(2); args[0] = c->args()[0]; args[1] = vd->id(); nc = new Call(c->loc().introduce(),array_bool_and->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_and); } } else if (c->id() == constants().ids.clause && array_bool_clause_reif) { std::vector args(3); args[0] = c->args()[0]; args[1] = c->args()[1]; args[2] = vd->id(); nc = new Call(c->loc().introduce(),array_bool_clause_reif->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_clause_reif); } else { if ( (!vd->type().isbool()) || (!Expression::equal(vd->ti()->domain(), constants().lit_true))) { std::vector args(c->args().size()); std::copy(c->args().begin(),c->args().end(),args.begin()); args.push_back(vd->id()); ASTString cid = c->id(); if (cid == constants().ids.clause && array_bool_clause_reif) { nc = new Call(c->loc().introduce(),array_bool_clause_reif->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_clause_reif); } else { if (c->type().isbool() && vd->type().isbool()) { cid = env.reifyId(c->id()); } FunctionI* decl = env.orig->matchFn(env,cid,args); if (decl && decl->e()) { nc = new Call(c->loc().introduce(),cid,args); nc->type(Type::varbool()); nc->decl(decl); } } } else { FunctionI* decl = env.orig->matchFn(env,c); if (decl->e()) { c->decl(decl); nc = c; } } } if (nc != NULL) { CollectDecls cd(env.vo,deletedVarDecls,vdi); topDown(cd,c); vd->e(NULL); if (nc != c) { vd->addAnnotation(constants().ann.is_defined_var); nc->addAnnotation(definesVarAnn(vd->id())); } (void) flat_exp(env, Ctx(), nc, constants().var_true, constants().var_true); } } } } else if (ConstraintI* ci = m[i]->dyn_cast()) { if (Call* c = ci->e()->dyn_cast()) { GCLock lock; Call* nc = NULL; if (c->id() == constants().ids.exists) { if (array_bool_or) { std::vector args(2); args[0] = c->args()[0]; args[1] = constants().lit_true; nc = new Call(c->loc().introduce(),array_bool_or->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_or); } } else if (c->id() == constants().ids.forall) { if (array_bool_and) { std::vector args(2); args[0] = c->args()[0]; args[1] = constants().lit_true; nc = new Call(c->loc().introduce(),array_bool_and->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_and); } } else if (c->id() == constants().ids.clause) { if (array_bool_clause) { std::vector args(2); args[0] = c->args()[0]; args[1] = c->args()[1]; nc = new Call(c->loc().introduce(),array_bool_clause->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_clause); } } else if (c->id() == constants().ids.bool_xor) { if (bool_xor) { std::vector args(3); args[0] = c->args()[0]; args[1] = c->args()[1]; args[2] = c->args().size()==2 ? constants().lit_true : c->args()[2]; nc = new Call(c->loc().introduce(),bool_xor->id(),args); nc->type(Type::varbool()); nc->decl(bool_xor); } } else { FunctionI* decl = env.orig->matchFn(env,c); if (decl && decl->e()) { nc = c; nc->decl(decl); } } if (nc != NULL) { CollectDecls cd(env.vo,deletedVarDecls,ci); topDown(cd,c); ci->e(constants().lit_true); env.flat_removeItem(i); (void) flat_exp(env, Ctx(), nc, constants().var_true, constants().var_true); } } } } startItem = endItem+1; endItem = m.size()-1; } for (unsigned int i=0; ie())==0) { CollectDecls cd(env.vo,deletedVarDecls,removedItems[i]); topDown(cd,removedItems[i]->e()->e()); env.flat_removeItem(removedItems[i]); } } // Add redefinitions for output variables that may have been redefined since createOutput for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*env.output)[i]->dyn_cast()) { IdMap::iterator it; GCLock lock; if (!vdi->e()->type().ispar() && vdi->e()->e()==NULL && (it = env.reverseMappers.find(vdi->e()->id())) != env.reverseMappers.end()) { GCLock lock; Call* rhs = copy(env,env.cmap,it->second())->cast(); std::vector tv(rhs->args().size()); for (unsigned int i=rhs->args().size(); i--;) { tv[i] = rhs->args()[i]->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, rhs->id(), tv); Type t; if (decl==NULL) { FunctionI* origdecl = env.orig->matchFn(env, rhs->id(), tv); if (origdecl == NULL) { throw FlatteningError(env,rhs->loc(),"function is used in output, par version needed"); } if (!isBuiltin(origdecl)) { decl = copy(env,env.cmap,origdecl)->cast(); CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); outputVarDecls(env,vdi,rhs); removeIsOutput(vdi->e()->flat()); vdi->e()->e(rhs); } } } for (unsigned int i=0; idyn_cast()) { if (Call* c = ci->e()->dyn_cast()) { if (c->decl()==constants().var_redef) { CollectDecls cd(env.vo,deletedVarDecls,ci); topDown(cd,c); env.flat_removeItem(i); } } } } while (!deletedVarDecls.empty()) { VarDecl* cur = deletedVarDecls.back(); deletedVarDecls.pop_back(); if (env.vo.occurrences(cur) == 0 && !isOutput(cur)) { IdMap::iterator cur_idx = env.vo.idx.find(cur->id()); if (cur_idx != env.vo.idx.end() && !m[cur_idx->second]->removed()) { CollectDecls cd(env.vo,deletedVarDecls,m[cur_idx->second]->cast()); topDown(cd,cur->e()); env.flat_removeItem(cur_idx->second); } } } if (!opt.keepOutputInFzn) { createOutput(env); } cleanupOutput(env); } void oldflatzinc(Env& e) { Model* m = e.flat(); for (unsigned int i=0; isize(); i++) { Item* item = (*m)[i]; if (item->isa() && (item->cast()->e()->type().ot() == Type::OT_OPTIONAL || item->cast()->e()->type().bt() == Type::BT_ANN) ) { e.envi().flat_removeItem(i); } } m->compact(); EnvI& env = e.envi(); int msize = m->size(); UNORDERED_NAMESPACE::unordered_set globals; std::vector declsWithIds; for (int i=0; iremoved()) continue; if (VarDeclI* vdi = (*m)[i]->dyn_cast()) { GCLock lock; VarDecl* vd = vdi->e(); if (vd->type().ispar()) { vd->ann().clear(); vd->introduced(false); vd->ti()->domain(NULL); } vd->ann().remove(constants().ctx.mix); vd->ann().remove(constants().ctx.pos); vd->ann().remove(constants().ctx.neg); vd->ann().remove(constants().ctx.root); vd->ann().remove(constants().ann.promise_total); if (vd->e() && vd->e()->isa()) { declsWithIds.push_back(i); vdi->e()->payload(-static_cast(i)-1); } else { vdi->e()->payload(i); } if (vd->type().isvar() && vd->type().isbool()) { if (Expression::equal(vd->ti()->domain(),constants().lit_true)) { Expression* ve = vd->e(); vd->e(constants().lit_true); vd->ti()->domain(NULL); if (ve != NULL) { if (Call* vcc = ve->dyn_cast()) { ASTString cid; std::vector args; if (vcc->id() == constants().ids.exists) { cid = constants().ids.array_bool_or; args.push_back(vcc->args()[0]); args.push_back(constants().lit_true); } else if (vcc->id() == constants().ids.forall) { cid = constants().ids.array_bool_and; args.push_back(vcc->args()[0]); args.push_back(constants().lit_true); } else if (vcc->id() == constants().ids.clause) { cid = constants().ids.bool_clause; args.push_back(vcc->args()[0]); args.push_back(vcc->args()[1]); } if (args.size()==0) { ve = vcc; } else { Call* nc = new Call(vcc->loc().introduce(),cid,args); nc->type(vcc->type()); nc->ann().merge(vcc->ann()); ve = nc; } } else if (Id* id = ve->dyn_cast()) { if (id->decl()->ti()->domain() != constants().lit_true) { std::vector args(2); args[0] = id; args[1] = constants().lit_true; GCLock lock; ve = new Call(Location().introduce(),constants().ids.bool_eq,args); } else { ve = constants().lit_true; } } if (ve != constants().lit_true) { e.envi().flat_addItem(new ConstraintI(Location().introduce(),ve)); } } } else { if (vd->e() != NULL) { if (vd->e()->eid()==Expression::E_CALL) { const Call* c = vd->e()->cast(); GCLock lock; vd->e(NULL); vd->addAnnotation(constants().ann.is_defined_var); ASTString cid; if (c->id() == constants().ids.exists) { cid = constants().ids.array_bool_or; } else if (c->id() == constants().ids.forall) { cid = constants().ids.array_bool_and; } else if (c->id() == constants().ids.clause) { cid = constants().ids.bool_clause_reif; } else { cid = e.envi().reifyId(c->id()); } std::vector args(c->args().size()); std::copy(c->args().begin(),c->args().end(),args.begin()); args.push_back(vd->id()); Call * nc = new Call(c->loc().introduce(),cid,args); nc->type(c->type()); nc->decl(env.orig->matchFn(env, nc)); if (nc->decl()==NULL) { throw FlatteningError(env,c->loc(),"'"+c->id().str()+"' is used in a reified context but no reified version is available"); } nc->addAnnotation(definesVarAnn(vd->id())); nc->ann().merge(c->ann()); e.envi().flat_addItem(new ConstraintI(Location().introduce(),nc)); } else { assert(vd->e()->eid() == Expression::E_ID || vd->e()->eid() == Expression::E_BOOLLIT); } } if (Expression::equal(vd->ti()->domain(),constants().lit_false)) { vd->ti()->domain(NULL); vd->e(constants().lit_false); } } } else if (vd->type().isvar() && vd->type().dim()==0) { if (vd->e() != NULL) { if (const Call* cc = vd->e()->dyn_cast()) { vd->e(NULL); vd->addAnnotation(constants().ann.is_defined_var); std::vector args(cc->args().size()); ASTString cid; if (cc->id() == constants().ids.lin_exp) { ArrayLit* le_c = follow_id(cc->args()[0])->cast(); std::vector nc(le_c->v().size()); std::copy(le_c->v().begin(),le_c->v().end(),nc.begin()); if (le_c->type().bt()==Type::BT_INT) { cid = constants().ids.int_.lin_eq; nc.push_back(IntLit::a(-1)); args[0] = new ArrayLit(Location().introduce(),nc); args[0]->type(Type::parint(1)); ArrayLit* le_x = follow_id(cc->args()[1])->cast(); std::vector nx(le_x->v().size()); std::copy(le_x->v().begin(),le_x->v().end(),nx.begin()); nx.push_back(vd->id()); args[1] = new ArrayLit(Location().introduce(),nx); args[1]->type(le_x->type()); IntVal d = cc->args()[2]->cast()->v(); args[2] = IntLit::a(-d); } else { // float cid = constants().ids.float_.lin_eq; nc.push_back(FloatLit::a(-1.0)); args[0] = new ArrayLit(Location().introduce(),nc); args[0]->type(Type::parfloat(1)); ArrayLit* le_x = follow_id(cc->args()[1])->cast(); std::vector nx(le_x->v().size()); std::copy(le_x->v().begin(),le_x->v().end(),nx.begin()); nx.push_back(vd->id()); args[1] = new ArrayLit(Location().introduce(),nx); args[1]->type(le_x->type()); FloatVal d = cc->args()[2]->cast()->v(); args[2] = FloatLit::a(-d); } } else { if (cc->id() == "card") { // card is 'set_card' in old FlatZinc cid = constants().ids.set_card; } else { cid = cc->id(); } std::copy(cc->args().begin(),cc->args().end(),args.begin()); args.push_back(vd->id()); } Call* nc = new Call(cc->loc().introduce(),cid,args); nc->type(cc->type()); nc->addAnnotation(definesVarAnn(vd->id())); nc->ann().merge(cc->ann()); e.envi().flat_addItem(new ConstraintI(Location().introduce(),nc)); } else { assert(vd->e()->eid() == Expression::E_ID || vd->e()->eid() == Expression::E_INTLIT || vd->e()->eid() == Expression::E_FLOATLIT || vd->e()->eid() == Expression::E_BOOLLIT || vd->e()->eid() == Expression::E_SETLIT); } } } else if (vd->type().dim() > 0) { if (!vd->e()->isa()) { vd->e(follow_id(vd->e())); } if (vd->ti()->ranges().size() == 1 && vd->ti()->ranges()[0]->domain() != NULL && vd->ti()->ranges()[0]->domain()->isa()) { IntSetVal* isv = vd->ti()->ranges()[0]->domain()->cast()->isv(); if (isv && (isv->size()==0 || isv->min(0)==1)) continue; } assert(vd->e() != NULL); ArrayLit* al = NULL; Expression* e = vd->e(); while (al==NULL) { switch (e->eid()) { case Expression::E_ARRAYLIT: al = e->cast(); break; case Expression::E_ID: e = e->cast()->decl()->e(); break; default: assert(false); } } std::vector dims(2); dims[0] = 1; dims[1] = al->length(); al->setDims(ASTIntVec(dims)); IntSetVal* isv = IntSetVal::a(1,al->length()); if (vd->ti()->ranges().size() == 1) { vd->ti()->ranges()[0]->domain(new SetLit(Location().introduce(),isv)); } else { std::vector r(1); r[0] = new TypeInst(vd->ti()->ranges()[0]->loc(), vd->ti()->ranges()[0]->type(), new SetLit(Location().introduce(),isv)); ASTExprVec ranges(r); TypeInst* ti = new TypeInst(vd->ti()->loc(),vd->ti()->type(),ranges,vd->ti()->domain()); vd->ti(ti); } } } else if (ConstraintI* ci = (*m)[i]->dyn_cast()) { std::vector removeAnns; for (ExpressionSetIter anns = ci->e()->ann().begin(); anns != ci->e()->ann().end(); ++anns) { if (Call* c = (*anns)->dyn_cast()) { if (c->id() == constants().ann.defines_var && c->args()[0]->type().ispar()) { removeAnns.push_back(c); } } } for (unsigned int i=0; ie()->ann().remove(removeAnns[i]); } if (Call* vc = ci->e()->dyn_cast()) { for (unsigned int i=0; iargs().size(); i++) { if (ArrayLit* al = vc->args()[i]->dyn_cast()) { if (al->dims()>1 || al->min(0)!= 1) { std::vector dims(2); dims[0] = 1; dims[1] = al->length(); GCLock lock; al->setDims(ASTIntVec(dims)); } } } if (vc->id() == constants().ids.exists) { GCLock lock; vc->id(ASTString("array_bool_or")); std::vector args(2); args[0] = vc->args()[0]; args[1] = constants().lit_true; ASTExprVec argsv(args); vc->args(argsv); vc->decl(e.envi().orig->matchFn(env, vc)); } else if (vc->id() == constants().ids.forall) { GCLock lock; vc->id(ASTString("array_bool_and")); std::vector args(2); args[0] = vc->args()[0]; args[1] = constants().lit_true; ASTExprVec argsv(args); vc->args(argsv); vc->decl(e.envi().orig->matchFn(env, vc)); } else if (vc->id() == constants().ids.clause) { GCLock lock; vc->id(ASTString("bool_clause")); vc->decl(e.envi().orig->matchFn(env, vc)); } else if (vc->id() == constants().ids.bool_xor && vc->args().size()==2) { GCLock lock; std::vector args(3); args[0] = vc->args()[0]; args[1] = vc->args()[1]; args[2] = constants().lit_true; ASTExprVec argsv(args); vc->args(argsv); vc->decl(e.envi().orig->matchFn(env, vc)); } if (vc->decl() && vc->decl() != constants().var_redef && !isBuiltin(vc->decl()) && globals.find(vc->decl())==globals.end()) { e.envi().flat_addItem(vc->decl()); globals.insert(vc->decl()); } } else if (Id* id = ci->e()->dyn_cast()) { std::vector args(2); args[0] = id; args[1] = constants().lit_true; GCLock lock; ci->e(new Call(Location().introduce(),constants().ids.bool_eq,args)); } else if (BoolLit* bl = ci->e()->dyn_cast()) { if (!bl->v()) { GCLock lock; std::vector args(2); args[0] = constants().lit_false; args[1] = constants().lit_true; Call* neq = new Call(Location().introduce(),constants().ids.bool_eq,args); ci->e(neq); } else { ci->remove(); } } } else if (SolveI* si = (*m)[i]->dyn_cast()) { if (si->e() && si->e()->type().ispar()) { GCLock lock; TypeInst* ti = new TypeInst(Location().introduce(),si->e()->type(),NULL); VarDecl* constantobj = new VarDecl(Location().introduce(),ti,e.envi().genId(),si->e()); si->e(constantobj->id()); e.envi().flat_addItem(new VarDeclI(Location().introduce(),constantobj)); } } } std::vector sortedVarDecls(declsWithIds.size()); int vdCount = 0; for (unsigned int i=0; icast()->e(); std::vector stack; while (cur && cur->payload() < 0) { stack.push_back(cur->payload()); if (Id* id = cur->e()->dyn_cast()) { cur = id->decl(); } else { cur = NULL; } } for (unsigned int i=stack.size(); i--;) { VarDeclI* vdi = (*m)[-stack[i]-1]->cast(); vdi->e()->payload(-vdi->e()->payload()-1); sortedVarDecls[vdCount++] = vdi; } } for (unsigned int i=0; icompact(); e.envi().output->compact(); for (IdMap::iterator it = env.vo._m.begin(); it != env.vo._m.end(); ++it) { std::vector toRemove; for (VarOccurrences::Items::iterator iit = it->second.begin(); iit != it->second.end(); ++iit) { if ((*iit)->removed()) { toRemove.push_back(*iit); } } for (unsigned int i=0; isecond.erase(toRemove[i]); } } class Cmp { public: bool operator() (Item* i, Item* j) { if (i->iid()==Item::II_FUN || j->iid()==Item::II_FUN) { if (i->iid()==j->iid()) return false; return i->iid()==Item::II_FUN; } if (i->iid()==Item::II_SOL) { assert(j->iid() != i->iid()); return false; } if (j->iid()==Item::II_SOL) { assert(j->iid() != i->iid()); return true; } if (i->iid()==Item::II_VD) { if (j->iid() != i->iid()) return true; if (i->cast()->e()->type().ispar() && j->cast()->e()->type().isvar()) return true; if (j->cast()->e()->type().ispar() && i->cast()->e()->type().isvar()) return false; if (i->cast()->e()->type().dim() == 0 && j->cast()->e()->type().dim() != 0) return true; if (i->cast()->e()->type().dim() != 0 && j->cast()->e()->type().dim() == 0) return false; if (i->cast()->e()->e()==NULL && j->cast()->e()->e() != NULL) return true; if (i->cast()->e()->e() && j->cast()->e()->e() && !i->cast()->e()->e()->isa() && j->cast()->e()->e()->isa()) return true; } return false; } } _cmp; std::stable_sort(m->begin(),m->end(),_cmp); } FlatModelStatistics statistics(Env& m) { Model* flat = m.flat(); FlatModelStatistics stats; for (unsigned int i=0; isize(); i++) { if (!(*flat)[i]->removed()) { if (VarDeclI* vdi = (*flat)[i]->dyn_cast()) { Type t = vdi->e()->type(); if (t.isvar() && t.dim()==0) { if (t.is_set()) stats.n_set_vars++; else if (t.isint()) stats.n_int_vars++; else if (t.isbool()) stats.n_bool_vars++; else if (t.isfloat()) stats.n_float_vars++; } } else if (ConstraintI* ci = (*flat)[i]->dyn_cast()) { if (Call* call = ci->e()->dyn_cast()) { if (call->args().size() > 0) { Type all_t; for (unsigned int i=0; iargs().size(); i++) { Type t = call->args()[i]->type(); if (t.isvar()) { if (t.st()==Type::ST_SET) all_t = t; else if (t.bt()==Type::BT_FLOAT && all_t.st()!=Type::ST_SET) all_t = t; else if (t.bt()==Type::BT_INT && all_t.bt()!=Type::BT_FLOAT && all_t.st()!=Type::ST_SET) all_t = t; else if (t.bt()==Type::BT_BOOL && all_t.bt()!=Type::BT_INT && all_t.bt()!=Type::BT_FLOAT && all_t.st()!=Type::ST_SET) all_t = t; } } if (all_t.isvar()) { if (all_t.st()==Type::ST_SET) stats.n_set_ct++; else if (all_t.bt()==Type::BT_INT) stats.n_int_ct++; else if (all_t.bt()==Type::BT_BOOL) stats.n_bool_ct++; else if (all_t.bt()==Type::BT_FLOAT) stats.n_float_ct++; } } } } } } return stats; } } libminizinc-2.0.11/lib/optimize.cpp0000644000175000017500000015446712646030173015675 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include #include #include #include #include #include #include namespace MiniZinc { void VarOccurrences::add(VarDeclI *i, int idx_i) { idx.insert(i->e()->id(), idx_i); } void VarOccurrences::add(VarDecl *e, int idx_i) { assert(find(e) == -1); idx.insert(e->id(), idx_i); } int VarOccurrences::find(VarDecl* vd) { IdMap::iterator it = idx.find(vd->id()); return it==idx.end() ? -1 : it->second; } void VarOccurrences::remove(VarDecl *vd) { idx.remove(vd->id()); } void VarOccurrences::add(VarDecl* v, Item* i) { IdMap::iterator vi = _m.find(v->id()->decl()->id()); if (vi==_m.end()) { Items items; items.insert(i); _m.insert(v->id()->decl()->id(), items); } else { vi->second.insert(i); } } int VarOccurrences::remove(VarDecl* v, Item* i) { IdMap::iterator vi = _m.find(v->id()->decl()->id()); assert(vi!=_m.end()); vi->second.erase(i); return vi->second.size(); } void VarOccurrences::unify(EnvI& env, Model* m, Id* id0_0, Id *id1_0) { Id* id0 = id0_0->decl()->id(); Id* id1 = id1_0->decl()->id(); VarDecl* v0 = id0->decl(); VarDecl* v1 = id1->decl(); if (v0==v1) return; int v0idx = find(v0); assert(v0idx != -1); env.flat_removeItem(v0idx); IdMap::iterator vi0 = _m.find(v0->id()); if (vi0 != _m.end()) { IdMap::iterator vi1 = _m.find(v1->id()); if (vi1 == _m.end()) { _m.insert(v1->id(), vi0->second); } else { vi1->second.insert(vi0->second.begin(), vi0->second.end()); } _m.remove(v0->id()); } id0->redirect(id1); remove(v0); } void VarOccurrences::clear(void) { _m.clear(); idx.clear(); } int VarOccurrences::occurrences(VarDecl* v) { IdMap::iterator vi = _m.find(v->id()->decl()->id()); return (vi==_m.end() ? 0 : vi->second.size()); } void CollectOccurrencesI::vVarDeclI(VarDeclI* v) { CollectOccurrencesE ce(vo,v); topDown(ce,v->e()); } void CollectOccurrencesI::vConstraintI(ConstraintI* ci) { CollectOccurrencesE ce(vo,ci); topDown(ce,ci->e()); for (ExpressionSetIter it = ci->e()->ann().begin(); it != ci->e()->ann().end(); ++it) topDown(ce, *it); } void CollectOccurrencesI::vSolveI(SolveI* si) { CollectOccurrencesE ce(vo,si); topDown(ce,si->e()); for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++si) topDown(ce,*it); } bool isOutput(VarDecl* vd) { for (ExpressionSetIter it = vd->ann().begin(); it != vd->ann().end(); ++it) { if (*it) { if (*it==constants().ann.output_var) return true; if (Call* c = (*it)->dyn_cast()) { if (c->id() == constants().ann.output_array) return true; } } } return false; } void unify(EnvI& env, std::vector& deletedVarDecls, Id* id0, Id* id1) { if (id0->decl() != id1->decl()) { if (isOutput(id0->decl())) { std::swap(id0,id1); } if (id0->decl()->e() != NULL) { Expression* rhs = id0->decl()->e(); VarDeclI* vdi1 = (*env.flat())[env.vo.find(id1->decl())]->cast(); CollectOccurrencesE ce(env.vo, vdi1); topDown(ce, rhs); id1->decl()->e(rhs); id0->decl()->e(NULL); VarDeclI* vdi0 = (*env.flat())[env.vo.find(id0->decl())]->cast(); CollectDecls cd(env.vo, deletedVarDecls, vdi0); topDown(cd, rhs); } // Compute intersection of domains if (id0->decl()->ti()->domain() != NULL) { if (id1->decl()->ti()->domain() != NULL) { if (id0->type().isint() || id0->type().isintset()) { IntSetVal* isv0 = eval_intset(env,id0->decl()->ti()->domain()); IntSetVal* isv1 = eval_intset(env,id1->decl()->ti()->domain()); IntSetRanges isv0r(isv0); IntSetRanges isv1r(isv1); Ranges::Inter inter(isv0r,isv1r); IntSetVal* nd = IntSetVal::ai(inter); if (nd->size()==0) { env.flat()->fail(env); } else if (nd->card() != isv1->card()) { id1->decl()->ti()->domain(new SetLit(Location(), nd)); if (nd->card()==isv0->card()) { id1->decl()->ti()->setComputedDomain(id0->decl()->ti()->computedDomain()); } else { id1->decl()->ti()->setComputedDomain(false); } } } else if (id0->type().isbool()) { if (eval_bool(env,id0->decl()->ti()->domain()) != eval_bool(env,id1->decl()->ti()->domain())) { env.flat()->fail(env); } } else { // float BinOp* dom0 = id0->decl()->ti()->domain()->cast(); BinOp* dom1 = id1->decl()->ti()->domain()->cast(); FloatVal lb0 = dom0->lhs()->cast()->v(); FloatVal ub0 = dom0->rhs()->cast()->v(); FloatVal lb1 = dom1->lhs()->cast()->v(); FloatVal ub1 = dom1->rhs()->cast()->v(); FloatVal lb = std::max(lb0,lb1); FloatVal ub = std::min(ub0,ub1); if (lb != lb1 || ub != ub1) { BinOp* newdom = new BinOp(Location(), FloatLit::a(lb), BOT_DOTDOT, FloatLit::a(ub)); newdom->type(Type::parsetfloat()); id1->decl()->ti()->domain(newdom); if (lb==lb0 && ub==ub0) { id1->decl()->ti()->setComputedDomain(id0->decl()->ti()->computedDomain()); } else { id1->decl()->ti()->setComputedDomain(false); } } } } else { id1->decl()->ti()->domain(id0->decl()->ti()->domain()); } } // If both variables are output variables, unify them in the output model if (isOutput(id0->decl())) { assert(env.output_vo.find(id0->decl()) != -1); VarDecl* id0_output = (*env.output)[env.output_vo.find(id0->decl())]->cast()->e(); assert(env.output_vo.find(id1->decl()) != -1); VarDecl* id1_output = (*env.output)[env.output_vo.find(id1->decl())]->cast()->e(); if (id0_output->e() == NULL) { id0_output->e(id1_output->id()); } } env.vo.unify(env, env.flat(), id0, id1); } } void substituteFixedVars(EnvI& env, Item* ii, std::vector& deletedVarDecls); void simplifyBoolConstraint(EnvI& env, Item* ii, VarDecl* vd, bool& remove, std::vector& vardeclQueue, std::vector& constraintQueue, std::vector& toRemove, UNORDERED_NAMESPACE::unordered_map& nonFixedLiteralCount); bool simplifyConstraint(EnvI& env, Item* ii, std::vector& deletedVarDecls, std::vector& constraintQueue, std::vector& vardeclQueue); void pushVarDecl(EnvI& env, VarDeclI* vdi, int vd_idx, std::vector& q) { if (!vdi->removed() && !vdi->flag()) { vdi->flag(true); q.push_back(vd_idx); } } void pushVarDecl(EnvI& env, int vd_idx, std::vector& q) { pushVarDecl(env, (*env.flat())[vd_idx]->cast(), vd_idx, q); } void pushDependentConstraints(EnvI& env, Id* id, std::vector& q) { IdMap::iterator it = env.vo._m.find(id->decl()->id()); if (it != env.vo._m.end()) { for (VarOccurrences::Items::iterator item = it->second.begin(); item != it->second.end(); ++item) { if (ConstraintI* ci = (*item)->dyn_cast()) { if (!ci->removed() && !ci->flag()) { ci->flag(true); q.push_back(ci); } } else if (VarDeclI* vdi = (*item)->dyn_cast()) { if (vdi->e()->id()->decl() != vdi->e()) { vdi = (*env.flat())[env.vo.find(vdi->e()->id()->decl())]->cast(); } if (!vdi->removed() && !vdi->flag() && vdi->e()->e()) { vdi->flag(true); q.push_back(vdi); } } } } } void optimize(Env& env) { EnvI& envi = env.envi(); Model& m = *envi.flat(); std::vector toAssignBoolVars; std::vector toRemoveConstraints; std::vector deletedVarDecls; std::vector constraintQueue; std::vector vardeclQueue; std::vector boolConstraints; GCLock lock; for (unsigned int i=0; iremoved()) { if (ConstraintI* ci = m[i]->dyn_cast()) { ci->flag(false); } else if (VarDeclI* vdi = m[i]->dyn_cast()) { vdi->flag(false); } } } for (unsigned int i=0; iremoved()) continue; if (ConstraintI* ci = m[i]->dyn_cast()) { ci->flag(false); if (!ci->removed()) { if (Call* c = ci->e()->dyn_cast()) { if ( (c->id() == constants().ids.int_.eq || c->id() == constants().ids.bool_eq || c->id() == constants().ids.float_.eq || c->id() == constants().ids.set_eq) && c->args()[0]->isa() && c->args()[1]->isa() && (c->args()[0]->cast()->decl()->e()==NULL || c->args()[1]->cast()->decl()->e()==NULL) ) { unify(envi, deletedVarDecls, c->args()[0]->cast(), c->args()[1]->cast()); { VarDecl* vd = c->args()[0]->cast()->decl(); int v0idx = envi.vo.find(vd); pushVarDecl(envi, m[v0idx]->cast(), v0idx, vardeclQueue); } pushDependentConstraints(envi, c->args()[0]->cast(), constraintQueue); CollectDecls cd(envi.vo,deletedVarDecls,ci); topDown(cd,c); ci->e(constants().lit_true); envi.flat_removeItem(i); } else if (c->id()==constants().ids.forall) { ArrayLit* al = follow_id(c->args()[0])->cast(); for (unsigned int j=al->v().size(); j--;) { if (Id* id = al->v()[j]->dyn_cast()) { if (id->decl()->ti()->domain()==NULL) { toAssignBoolVars.push_back(envi.vo.idx.find(id->decl()->id())->second); } else if (id->decl()->ti()->domain() == constants().lit_false) { env.flat()->fail(env.envi()); id->decl()->e(constants().lit_true); } } } toRemoveConstraints.push_back(i); } else if (c->id()==constants().ids.exists || c->id()==constants().ids.clause) { boolConstraints.push_back(i); } } else if (Id* id = ci->e()->dyn_cast()) { if (id->decl()->ti()->domain() == constants().lit_false) { env.flat()->fail(env.envi()); ci->e(constants().lit_false); } else { if (id->decl()->ti()->domain()==NULL) { toAssignBoolVars.push_back(envi.vo.idx.find(id->decl()->id())->second); } toRemoveConstraints.push_back(i); } } } } else if (VarDeclI* vdi = m[i]->dyn_cast()) { vdi->flag(false); if (vdi->e()->e() && vdi->e()->e()->isa() && vdi->e()->type().dim()==0) { Id* id1 = vdi->e()->e()->cast(); vdi->e()->e(NULL); unify(envi, deletedVarDecls, vdi->e()->id(), id1); pushDependentConstraints(envi, id1, constraintQueue); } if (vdi->e()->type().isbool() && vdi->e()->type().isvar() && vdi->e()->type().dim()==0 && (vdi->e()->ti()->domain() == constants().lit_true || vdi->e()->ti()->domain() == constants().lit_false)) { pushVarDecl(envi, vdi, i, vardeclQueue); pushDependentConstraints(envi, vdi->e()->id(), constraintQueue); } if (Call* c = Expression::dyn_cast(vdi->e()->e())) { if (c->id()==constants().ids.forall || c->id()==constants().ids.exists || c->id()==constants().ids.clause) { boolConstraints.push_back(i); } } if (vdi->e()->type().isint()) { if ((vdi->e()->e() && vdi->e()->e()->isa()) || (vdi->e()->ti()->domain() && vdi->e()->ti()->domain()->isa() && vdi->e()->ti()->domain()->cast()->isv()->size()==1 && vdi->e()->ti()->domain()->cast()->isv()->min()==vdi->e()->ti()->domain()->cast()->isv()->max())) { pushVarDecl(envi, vdi, i, vardeclQueue); pushDependentConstraints(envi, vdi->e()->id(), constraintQueue); } } } } for (unsigned int i=boolConstraints.size(); i--;) { Item* bi = m[boolConstraints[i]]; if (bi->removed()) continue; Call* c; if (bi->isa()) { c = bi->cast()->e()->dyn_cast(); } else { c = bi->cast()->e()->e()->dyn_cast(); } if (c==NULL) continue; bool isConjunction = (c->id() == constants().ids.forall); bool subsumed = false; Id* finalId = NULL; bool finalIdNeg = false; int idCount = 0; std::vector pos; std::vector neg; for (unsigned int j=0; jargs().size(); j++) { bool unit = (j==0 ? isConjunction : !isConjunction); ArrayLit* al = follow_id(c->args()[j])->cast(); for (unsigned int k=0; kv().size(); k++) { if (Id* ident = al->v()[k]->dyn_cast()) { if (ident->decl()->ti()->domain() || (ident->decl()->e() && ident->decl()->e()->type().ispar()) ) { bool identValue = ident->decl()->ti()->domain() ? eval_bool(envi, ident->decl()->ti()->domain()) : eval_bool(envi, ident->decl()->e()); if (identValue != unit) { subsumed = true; goto subsumed_check_done; } } else { idCount++; finalId = ident; finalIdNeg = (j==1); if (j==0) pos.push_back(ident->decl()); else neg.push_back(ident->decl()); } } else { if (al->v()[k]->cast()->v()!=unit) { subsumed = true; goto subsumed_check_done; } } } } if (pos.size() > 0 && neg.size() > 0) { std::sort(pos.begin(),pos.end()); std::sort(neg.begin(), neg.end()); unsigned int ix=0; unsigned int iy=0; for (;;) { if (pos[ix]==neg[iy]) { subsumed = true; break; } if (pos[ix] < neg[iy]) { ix++; } else { iy++; } if (ix==pos.size() || iy==neg.size()) break; } } subsumed_check_done: if (subsumed) { if (isConjunction) { if (bi->isa()) { env.envi().flat()->fail(env.envi()); } else { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()->e()); bi->cast()->e()->ti()->domain(constants().lit_false); bi->cast()->e()->ti()->setComputedDomain(true); bi->cast()->e()->e(constants().lit_false); pushVarDecl(envi, bi->cast(), boolConstraints[i], vardeclQueue); pushDependentConstraints(envi, bi->cast()->e()->id(), constraintQueue); } } else { if (bi->isa()) { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()); bi->remove(); } else { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()->e()); bi->cast()->e()->ti()->domain(constants().lit_true); bi->cast()->e()->ti()->setComputedDomain(true); bi->cast()->e()->e(constants().lit_true); pushVarDecl(envi, bi->cast(), boolConstraints[i], vardeclQueue); pushDependentConstraints(envi, bi->cast()->e()->id(), constraintQueue); } } } else if (idCount==1 && bi->isa()) { assert(finalId->decl()->ti()->domain()==NULL); finalId->decl()->ti()->domain(constants().boollit(!finalIdNeg)); if (finalId->decl()->e()==NULL) finalId->decl()->e(constants().boollit(!finalIdNeg)); CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()); bi->remove(); pushVarDecl(envi, envi.vo.idx.find(finalId->decl()->id())->second, vardeclQueue); pushDependentConstraints(envi, finalId, constraintQueue); } } for (unsigned int i=toAssignBoolVars.size(); i--;) { if (m[toAssignBoolVars[i]]->removed()) continue; VarDeclI* vdi = m[toAssignBoolVars[i]]->cast(); if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().lit_true); pushVarDecl(envi, vdi, toAssignBoolVars[i], vardeclQueue); pushDependentConstraints(envi, vdi->e()->id(), constraintQueue); } } UNORDERED_NAMESPACE::unordered_map nonFixedLiteralCount; while (!vardeclQueue.empty() || !constraintQueue.empty()) { while (!vardeclQueue.empty()) { int var_idx = vardeclQueue.back(); vardeclQueue.pop_back(); m[var_idx]->cast()->flag(false); VarDecl* vd = m[var_idx]->cast()->e(); if (vd->type().isbool() && vd->ti()->domain()) { bool isTrue = vd->ti()->domain() == constants().lit_true; bool remove = false; if (vd->e()) { if (Id* id = vd->e()->dyn_cast()) { if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(vd->ti()->domain()); pushVarDecl(envi, envi.vo.idx.find(id->decl()->id())->second, vardeclQueue); } else if (id->decl()->ti()->domain() != vd->ti()->domain()) { env.flat()->fail(env.envi()); } remove = true; } else if (Call* c = vd->e()->dyn_cast()) { if (isTrue && c->id()==constants().ids.forall) { remove = true; ArrayLit* al = follow_id(c->args()[0])->cast(); for (unsigned int i=0; iv().size(); i++) { if (Id* id = al->v()[i]->dyn_cast()) { if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(constants().lit_true); pushVarDecl(envi, envi.vo.idx.find(id->decl()->id())->second, vardeclQueue); } else if (id->decl()->ti()->domain() == constants().lit_false) { env.flat()->fail(env.envi()); remove = true; } } } } else if (!isTrue && (c->id()==constants().ids.exists || c->id()==constants().ids.clause)) { remove = true; for (unsigned int i=0; iargs().size(); i++) { bool ispos = i==0; ArrayLit* al = follow_id(c->args()[i])->cast(); for (unsigned int j=0; jv().size(); j++) { if (Id* id = al->v()[j]->dyn_cast()) { if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(constants().boollit(!ispos)); pushVarDecl(envi, envi.vo.idx.find(id->decl()->id())->second, vardeclQueue); } else if (id->decl()->ti()->domain() == constants().boollit(ispos)) { env.flat()->fail(env.envi()); remove = true; } } } } } } } else { remove = true; } pushDependentConstraints(envi, vd->id(), constraintQueue); std::vector toRemove; IdMap::iterator it = envi.vo._m.find(vd->id()->decl()->id()); if (it != envi.vo._m.end()) { for (VarOccurrences::Items::iterator item = it->second.begin(); item != it->second.end(); ++item) { if ((*item)->removed()) continue; if (VarDeclI* vdi = (*item)->dyn_cast()) { if (vdi->e()->e() && vdi->e()->e()->isa()) { IdMap::iterator ait = envi.vo._m.find(vdi->e()->id()->decl()->id()); if (ait != envi.vo._m.end()) { for (VarOccurrences::Items::iterator aitem = ait->second.begin(); aitem != ait->second.end(); ++aitem) { simplifyBoolConstraint(envi,*aitem,vd,remove,vardeclQueue,constraintQueue,toRemove,nonFixedLiteralCount); } } continue; } } simplifyBoolConstraint(envi,*item,vd,remove,vardeclQueue,constraintQueue,toRemove,nonFixedLiteralCount); } } for (unsigned int i=toRemove.size(); i--;) { if (ConstraintI* ci = toRemove[i]->dyn_cast()) { CollectDecls cd(envi.vo,deletedVarDecls,ci); topDown(cd,ci->e()); envi.flat_removeItem(ci); } else { VarDeclI* vdi = toRemove[i]->cast(); CollectDecls cd(envi.vo,deletedVarDecls,vdi); topDown(cd,vdi->e()->e()); vdi->e()->e(NULL); } } if (remove) { deletedVarDecls.push_back(vd); } else { simplifyConstraint(envi,m[var_idx],deletedVarDecls,constraintQueue,vardeclQueue); } } else if (vd->type().isint() && vd->ti()->domain()) { IntSetVal* isv = eval_intset(envi, vd->ti()->domain()); if (isv->size()==1 && isv->card()==1) { simplifyConstraint(envi,m[var_idx],deletedVarDecls,constraintQueue,vardeclQueue); } } } bool handledConstraint = false; while (!handledConstraint && !constraintQueue.empty()) { Item* item = constraintQueue.back(); constraintQueue.pop_back(); Call* c; ArrayLit* al; if (ConstraintI* ci = item->dyn_cast()) { ci->flag(false); c = Expression::dyn_cast(ci->e()); al = NULL; } else { item->cast()->flag(false); c = Expression::dyn_cast(item->cast()->e()->e()); al = Expression::dyn_cast(item->cast()->e()->e()); } if (al) { substituteFixedVars(envi, item, deletedVarDecls); pushDependentConstraints(envi, item->cast()->e()->id(), constraintQueue); } else if (!c || !(c->id()==constants().ids.forall || c->id()==constants().ids.exists || c->id()==constants().ids.clause) ) { substituteFixedVars(envi, item, deletedVarDecls); handledConstraint = simplifyConstraint(envi,item,deletedVarDecls,constraintQueue,vardeclQueue); } } } for (unsigned int i=toRemoveConstraints.size(); i--;) { ConstraintI* ci = m[toRemoveConstraints[i]]->cast(); CollectDecls cd(envi.vo,deletedVarDecls,ci); topDown(cd,ci->e()); envi.flat_removeItem(toRemoveConstraints[i]); } for (unsigned int i=boolConstraints.size(); i--;) { Item* bi = m[boolConstraints[i]]; if (bi->removed()) continue; Call* c; std::vector removedVarDecls; if (bi->isa()) { c = bi->cast()->e()->dyn_cast(); } else { c = Expression::dyn_cast(bi->cast()->e()->e()); } if (c==NULL) continue; bool isConjunction = (c->id() == constants().ids.forall); bool subsumed = false; for (unsigned int j=0; jargs().size(); j++) { bool unit = (j==0 ? isConjunction : !isConjunction); ArrayLit* al = follow_id(c->args()[j])->cast(); std::vector compactedAl; for (unsigned int k=0; kv().size(); k++) { if (Id* ident = al->v()[k]->dyn_cast()) { if (ident->decl()->ti()->domain()) { if (!(ident->decl()->ti()->domain()==constants().boollit(unit))) { subsumed = true; } removedVarDecls.push_back(ident->decl()); } else { compactedAl.push_back(ident); } } else { if (al->v()[k]->cast()->v()!=unit) { subsumed = true; } } } if (compactedAl.size() < al->v().size()) { c->args()[j] = new ArrayLit(al->loc(), compactedAl); c->args()[j]->type(Type::varbool(1)); } } if (subsumed) { if (isConjunction) { if (bi->isa()) { env.envi().flat()->fail(env.envi()); } else { ArrayLit* al = follow_id(c->args()[0])->cast(); for (unsigned int j=0; jv().size(); j++) { removedVarDecls.push_back(al->v()[j]->cast()->decl()); } bi->cast()->e()->ti()->domain(constants().lit_false); bi->cast()->e()->ti()->setComputedDomain(true); bi->cast()->e()->e(constants().lit_false); } } else { if (bi->isa()) { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()); bi->remove(); } else { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()->e()); bi->cast()->e()->ti()->domain(constants().lit_true); bi->cast()->e()->ti()->setComputedDomain(true); bi->cast()->e()->e(constants().lit_true); } } } for (unsigned int j=0; je()==NULL || removedVarDecls[j]->ti()->domain()==NULL || removedVarDecls[j]->ti()->computedDomain()) && !isOutput(removedVarDecls[j]) ) { deletedVarDecls.push_back(removedVarDecls[j]); } } } if (VarDeclI* vdi = bi->dyn_cast()) { if (envi.vo.occurrences(vdi->e())==0) { if ( (vdi->e()->e()==NULL || vdi->e()->ti()->domain()==NULL || vdi->e()->ti()->computedDomain()) && !isOutput(vdi->e()) ) { deletedVarDecls.push_back(vdi->e()); } } } } while (!deletedVarDecls.empty()) { VarDecl* cur = deletedVarDecls.back(); deletedVarDecls.pop_back(); if (envi.vo.occurrences(cur) == 0) { IdMap::iterator cur_idx = envi.vo.idx.find(cur->id()); if (cur_idx != envi.vo.idx.end() && !m[cur_idx->second]->removed()) { if (isOutput(cur)) { Expression* val = NULL; if (cur->type().isbool() && cur->ti()->domain()) { val = cur->ti()->domain(); } else if (cur->type().isint()) { if (cur->e() && cur->e()->isa()) { val = cur->e(); } else if (cur->ti()->domain() && cur->ti()->domain()->isa() && cur->ti()->domain()->cast()->isv()->size()==1 && cur->ti()->domain()->cast()->isv()->min()==cur->ti()->domain()->cast()->isv()->max()) { val = IntLit::a(cur->ti()->domain()->cast()->isv()->min()); } } if (val) { VarDecl* vd_out = (*envi.output)[envi.output_vo.find(cur)]->cast()->e(); vd_out->e(val); CollectDecls cd(envi.vo,deletedVarDecls,m[cur_idx->second]->cast()); topDown(cd,cur->e()); envi.flat_removeItem(cur_idx->second); } } else { CollectDecls cd(envi.vo,deletedVarDecls,m[cur_idx->second]->cast()); topDown(cd,cur->e()); envi.flat_removeItem(cur_idx->second); } } } } } class SubstitutionVisitor : public EVisitor { protected: std::vector removed; Expression* subst(Expression* e) { if (VarDecl* vd = follow_id_to_decl(e)->dyn_cast()) { if (vd->type().isbool() && vd->ti()->domain()) { removed.push_back(vd); return vd->ti()->domain(); } if (vd->type().isint()) { if (vd->e() && vd->e()->isa()) { removed.push_back(vd); return vd->e(); } if (vd->ti()->domain() && vd->ti()->domain()->isa() && vd->ti()->domain()->cast()->isv()->size()==1 && vd->ti()->domain()->cast()->isv()->min()==vd->ti()->domain()->cast()->isv()->max()) { removed.push_back(vd); return IntLit::a(vd->ti()->domain()->cast()->isv()->min()); } } } return e; } public: /// Visit array literal void vArrayLit(const ArrayLit& al) { for (unsigned int i=0; iisa(); } void remove(EnvI& env, Item* item, std::vector& deletedVarDecls) { for (unsigned int i=0; iann().remove(constants().ann.is_defined_var); if (env.vo.remove(removed[i], item) == 0) { if ( (removed[i]->e()==NULL || removed[i]->ti()->domain()==NULL || removed[i]->ti()->computedDomain()) && !isOutput(removed[i]) ) { deletedVarDecls.push_back(removed[i]); } } } } }; void substituteFixedVars(EnvI& env, Item* ii, std::vector& deletedVarDecls) { SubstitutionVisitor sv; if (ConstraintI* ci = ii->dyn_cast()) { topDown(sv, ci->e()); for (ExpressionSetIter it = ci->e()->ann().begin(); it != ci->e()->ann().end(); ++it) { topDown(sv, *it); } } else if (VarDeclI* vdi = ii->dyn_cast()) { topDown(sv, vdi->e()); for (ExpressionSetIter it = vdi->e()->ann().begin(); it != vdi->e()->ann().end(); ++it) { topDown(sv, *it); } } else { SolveI* si = ii->cast(); topDown(sv, si->e()); for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) { topDown(sv, *it); } } sv.remove(env, ii, deletedVarDecls); } bool simplifyConstraint(EnvI& env, Item* ii, std::vector& deletedVarDecls, std::vector& constraintQueue, std::vector& vardeclQueue) { Expression* con_e; bool is_true; bool is_false; if (ConstraintI* ci = ii->dyn_cast()) { con_e = ci->e(); is_true = true; is_false = false; } else { VarDeclI* vdi = ii->cast(); con_e = vdi->e()->e(); is_true = (vdi->e()->type().isbool() && vdi->e()->ti()->domain()==constants().lit_true); is_false = (vdi->e()->type().isbool() && vdi->e()->ti()->domain()==constants().lit_false); assert(is_true || is_false || !vdi->e()->type().isbool() || vdi->e()->ti()->domain()==NULL); } if (Call* c = Expression::dyn_cast(con_e)) { if (c->id()==constants().ids.int_.eq || c->id()==constants().ids.bool_eq || c->id()==constants().ids.float_.eq) { if (is_true && c->args()[0]->isa() && c->args()[1]->isa() && (c->args()[0]->cast()->decl()->e()==NULL || c->args()[1]->cast()->decl()->e()==NULL) ) { unify(env, deletedVarDecls, c->args()[0]->cast(), c->args()[1]->cast()); pushDependentConstraints(env, c->args()[0]->cast(), constraintQueue); CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } else if (c->args()[0]->type().ispar() && c->args()[1]->type().ispar()) { Expression* e0 = eval_par(env,c->args()[0]); Expression* e1 = eval_par(env,c->args()[1]); bool is_equal = Expression::equal(e0, e1); if ((is_true && is_equal) || (is_false && !is_equal)) { // do nothing } else if ((is_true && !is_equal) || (is_false && is_equal)) { env.flat()->fail(env); } else { VarDeclI* vdi = ii->cast(); CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); vdi->e()->e(constants().boollit(is_equal)); vdi->e()->ti()->domain(constants().boollit(is_equal)); vdi->e()->ti()->setComputedDomain(true); pushVarDecl(env, vdi, env.vo.find(vdi->e()), vardeclQueue); pushDependentConstraints(env, vdi->e()->id(), constraintQueue); } if (ii->isa()) { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } } else if (is_true && ((c->args()[0]->isa() && c->args()[1]->type().ispar()) || (c->args()[1]->isa() && c->args()[0]->type().ispar())) ) { Id* ident = c->args()[0]->isa() ? c->args()[0]->cast() : c->args()[1]->cast(); Expression* arg = c->args()[0]->isa() ? c->args()[1] : c->args()[0]; bool canRemove = false; TypeInst* ti = ident->decl()->ti(); switch (ident->type().bt()) { case Type::BT_BOOL: if (ti->domain() == NULL) { ti->domain(constants().boollit(eval_bool(env,arg))); ti->setComputedDomain(false); canRemove = true; } else { if (eval_bool(env,ti->domain())==eval_bool(env,arg)) { canRemove = true; } else { env.flat()->fail(env); canRemove = true; } } break; case Type::BT_INT: { IntVal d = eval_int(env,arg); if (ti->domain() == NULL) { ti->domain(new SetLit(Location().introduce(), IntSetVal::a(d,d))); ti->setComputedDomain(false); canRemove = true; } else { IntSetVal* isv = eval_intset(env,ti->domain()); if (isv->contains(d)) { ident->decl()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(d,d))); ident->decl()->ti()->setComputedDomain(false); canRemove = true; } else { env.flat()->fail(env); canRemove = true; } } } break; case Type::BT_FLOAT: { if (ti->domain() == NULL) { ti->domain(new BinOp(Location().introduce(), arg, BOT_DOTDOT, arg)); ti->setComputedDomain(false); canRemove = true; } else { FloatVal value = eval_float(env,arg); if (LinearTraits::domain_contains(ti->domain()->cast(), value)) { ti->domain(new BinOp(Location().introduce(), arg, BOT_DOTDOT, arg)); ti->setComputedDomain(false); canRemove = true; } else { env.flat()->fail(env); canRemove = true; } } } break; default: break; } if (ident->decl()->e()==NULL) { ident->decl()->e(c->args()[0]->isa() ? c->args()[1] : c->args()[0]); ti->setComputedDomain(true); canRemove = true; } if (ident->decl()->e()->isa()) constraintQueue.push_back((*env.flat())[env.vo.find(ident->decl())]); pushDependentConstraints(env, ident, constraintQueue); if (canRemove) { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } } } else if ((is_true || is_false) && c->id()==constants().ids.int_.le && ((c->args()[0]->isa() && c->args()[1]->type().ispar()) || (c->args()[1]->isa() && c->args()[0]->type().ispar())) ) { Id* ident = c->args()[0]->isa() ? c->args()[0]->cast() : c->args()[1]->cast(); Expression* arg = c->args()[0]->isa() ? c->args()[1] : c->args()[0]; IntSetVal* domain = ident->decl()->ti()->domain() ? eval_intset(env,ident->decl()->ti()->domain()) : NULL; if (domain) { BinOpType bot = c->args()[0]->isa() ? (is_true ? BOT_LQ : BOT_GR) : (is_true ? BOT_GQ: BOT_LE); IntSetVal* newDomain = LinearTraits::limit_domain(bot, domain, eval_int(env,arg)); ident->decl()->ti()->domain(new SetLit(Location().introduce(), newDomain)); ident->decl()->ti()->setComputedDomain(false); if (newDomain->min()==newDomain->max()) { pushDependentConstraints(env, ident, constraintQueue); } CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } } else if (c->id()==constants().ids.bool2int) { VarDeclI* vdi = ii->cast(); bool fixed = false; bool b_val = false; IntSetVal* vdi_dom = NULL; if (vdi->e()->ti()->domain()) { vdi_dom = eval_intset(env, vdi->e()->ti()->domain()); if (vdi_dom->max()<0 || vdi_dom->min()>1) { env.flat()->fail(env); return true; } fixed = vdi_dom->min()==vdi_dom->max(); b_val = (vdi_dom->min() == 1); } if (fixed) { if (c->args()[0]->type().ispar()) { } else { Id* ident = c->args()[0]->cast(); TypeInst* ti = ident->decl()->ti(); if (ti->domain() == NULL) { ti->domain(constants().boollit(b_val)); ti->setComputedDomain(false); } else if (eval_bool(env,ti->domain())!=b_val) { env.flat()->fail(env); } CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); vdi->e()->e(IntLit::a(b_val)); vdi->e()->ti()->setComputedDomain(true); pushDependentConstraints(env, ident, constraintQueue); if (env.vo.occurrences(vdi->e())==0) { vdi->remove(); } } } else { IntVal v = -1; if (BoolLit* bl = c->args()[0]->dyn_cast()) { v = bl->v() ? 1 : 0; } else if (Id* ident = c->args()[0]->dyn_cast()) { if (ident->decl()->ti()->domain()) { v = eval_bool(env,ident->decl()->ti()->domain()) ? 1 : 0; } } if (v != -1) { if (vdi_dom && !vdi_dom->contains(v)) { env.flat()->fail(env); } else { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); vdi->e()->e(IntLit::a(v)); vdi->e()->ti()->domain(new SetLit(Location().introduce(),IntSetVal::a(v, v))); vdi->e()->ti()->setComputedDomain(true); pushVarDecl(env, vdi, env.vo.find(vdi->e()), vardeclQueue); pushDependentConstraints(env, vdi->e()->id(), constraintQueue); } } } } else { Expression* rewrite = NULL; GCLock lock; switch (OptimizeRegistry::registry().process(env, ii, c, rewrite)) { case OptimizeRegistry::CS_NONE: return false; case OptimizeRegistry::CS_OK: return true; case OptimizeRegistry::CS_FAILED: if (is_true) { env.flat()->fail(env); return true; } else if (is_false) { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); return true; } else { VarDeclI* vdi = ii->cast(); vdi->e()->ti()->domain(constants().lit_false); pushVarDecl(env, vdi, env.vo.find(vdi->e()), vardeclQueue); return true; } case OptimizeRegistry::CS_ENTAILED: if (is_true) { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); return true; } else if (is_false) { env.flat()->fail(env); return true; } else { VarDeclI* vdi = ii->cast(); vdi->e()->ti()->domain(constants().lit_true); pushVarDecl(env, vdi, env.vo.find(vdi->e()), vardeclQueue); return true; } case OptimizeRegistry::CS_REWRITE: { std::vector tdv; CollectDecls cd(env.vo,tdv,ii); topDown(cd,c); CollectOccurrencesE ce(env.vo,ii); topDown(ce,rewrite); for (unsigned int i=0; idyn_cast()) { ci->e(rewrite); constraintQueue.push_back(ii); } else { VarDeclI* vdi = ii->cast(); vdi->e()->e(rewrite); if (vdi->e()->e() && vdi->e()->e()->isa() && vdi->e()->type().dim()==0) { Id* id1 = vdi->e()->e()->cast(); vdi->e()->e(NULL); unify(env, deletedVarDecls, vdi->e()->id(), id1); pushDependentConstraints(env, id1, constraintQueue); } pushVarDecl(env, vdi, env.vo.find(vdi->e()), vardeclQueue); } return true; } } } } return false; } int boolState(EnvI& env, Expression* e) { if (e->type().ispar()) { return eval_bool(env,e); } else { Id* id = e->cast(); if (id->decl()->ti()->domain()==NULL) return 2; return id->decl()->ti()->domain()==constants().lit_true; } } int decrementNonFixedVars(UNORDERED_NAMESPACE::unordered_map& nonFixedLiteralCount, Call* c) { UNORDERED_NAMESPACE::unordered_map::iterator it = nonFixedLiteralCount.find(c); if (it==nonFixedLiteralCount.end()) { int nonFixedVars = 0; for (unsigned int i=0; iargs().size(); i++) { ArrayLit* al = follow_id(c->args()[i])->cast(); nonFixedVars += al->v().size(); for (unsigned int j=al->v().size(); j--;) { if (al->v()[j]->type().ispar()) nonFixedVars--; } } nonFixedVars--; // for the identifier we're currently processing nonFixedLiteralCount.insert(std::make_pair(c, nonFixedVars)); return nonFixedVars; } else { it->second--; return it->second; } } void simplifyBoolConstraint(EnvI& env, Item* ii, VarDecl* vd, bool& remove, std::vector& vardeclQueue, std::vector& constraintQueue, std::vector& toRemove, UNORDERED_NAMESPACE::unordered_map& nonFixedLiteralCount) { if (ii->isa()) { remove = false; return; } bool isTrue = vd->ti()->domain()==constants().lit_true; Expression* e = NULL; ConstraintI* ci = ii->dyn_cast(); VarDeclI* vdi = ii->dyn_cast(); if (ci) { e = ci->e(); } else if (vdi) { e = vdi->e()->e(); if (e==NULL) return; if (Id* id = e->dyn_cast()) { assert(id->decl()==vd); if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().boollit(isTrue)); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (id->decl()->ti()->domain() == constants().boollit(!isTrue)) { env.flat()->fail(env); remove = false; } return; } } if (Id* ident = e->dyn_cast()) { assert(ident->decl() == vd); return; } if (e->isa()) { if (e == constants().lit_true && ci) { toRemove.push_back(ci); } return; } Call* c = e->cast(); if (c->id()==constants().ids.bool_eq) { Expression* b0 = c->args()[0]; Expression* b1 = c->args()[1]; int b0s = boolState(env,b0); int b1s = boolState(env,b1); if (b0s==2) { std::swap(b0,b1); std::swap(b0s,b1s); } assert(b0s!=2); if (ci || vdi->e()->ti()->domain()==constants().lit_true) { if (b0s != b1s) { if (b1s==2) { b1->cast()->decl()->ti()->domain(constants().boollit(isTrue)); vardeclQueue.push_back(env.vo.idx.find(b1->cast()->decl()->id())->second); if (ci) toRemove.push_back(ci); } else { env.flat()->fail(env); remove = false; } } else { if (ci) toRemove.push_back(ci); } } else if (vdi && vdi->e()->ti()->domain()==constants().lit_false) { if (b0s != b1s) { if (b1s==2) { b1->cast()->decl()->ti()->domain(constants().boollit(isTrue)); vardeclQueue.push_back(env.vo.idx.find(b1->cast()->decl()->id())->second); } } else { env.flat()->fail(env); remove = false; } } else { remove = false; } } else if (c->id()==constants().ids.forall || c->id()==constants().ids.exists || c->id()==constants().ids.clause) { if (isTrue && c->id()==constants().ids.exists) { if (ci) { toRemove.push_back(ci); } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().lit_true); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().lit_true) { env.flat()->fail(env); vdi->e()->e(constants().lit_true); } } } else if (!isTrue && c->id()==constants().ids.forall) { if (ci) { env.flat()->fail(env); toRemove.push_back(ci); } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().lit_false); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().lit_false) { env.flat()->fail(env); vdi->e()->e(constants().lit_false); } } } else { int nonfixed = decrementNonFixedVars(nonFixedLiteralCount,c); bool isConjunction = (c->id() == constants().ids.forall); assert(nonfixed >=0); if (nonfixed<=1) { bool subsumed = false; int nonfixed_i=-1; int nonfixed_j=-1; int realNonFixed = 0; for (unsigned int i=0; iargs().size(); i++) { bool unit = (i==0 ? isConjunction : !isConjunction); ArrayLit* al = follow_id(c->args()[i])->cast(); realNonFixed += al->v().size(); for (unsigned int j=al->v().size(); j--;) { if (al->v()[j]->type().ispar() || al->v()[j]->cast()->decl()->ti()->domain()) realNonFixed--; if (al->v()[j]->type().ispar() && eval_bool(env,al->v()[j]) != unit) { subsumed = true; i=2; // break out of outer loop break; } else if (Id* id = al->v()[j]->dyn_cast()) { if (id->decl()->ti()->domain()) { bool idv = (id->decl()->ti()->domain()==constants().lit_true); if (unit != idv) { subsumed = true; i=2; // break out of outer loop break; } } else { nonfixed_i = i; nonfixed_j = j; } } } } if (subsumed) { if (ci) { if (isConjunction) { env.flat()->fail(env); ci->e(constants().lit_false); } else { toRemove.push_back(ci); } } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().boollit(!isConjunction)); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().boollit(!isConjunction)) { env.flat()->fail(env); vdi->e()->e(constants().boollit(!isConjunction)); } } } else if (realNonFixed==0) { if (ci) { if (isConjunction) { toRemove.push_back(ci); } else { env.flat()->fail(env); ci->e(constants().lit_false); } } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().boollit(isConjunction)); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().boollit(isConjunction)) { env.flat()->fail(env); vdi->e()->e(constants().boollit(isConjunction)); } toRemove.push_back(vdi); } } else { // not subsumed, nonfixed==1 assert(nonfixed_i != -1); ArrayLit* al = follow_id(c->args()[nonfixed_i])->cast(); Id* id = al->v()[nonfixed_j]->cast(); if (ci || vdi->e()->ti()->domain()) { bool result = nonfixed_i==0; if (vdi && vdi->e()->ti()->domain()==constants().lit_false) result = !result; VarDecl* vd = id->decl(); if (vd->ti()->domain()==NULL) { vd->ti()->domain(constants().boollit(result)); vardeclQueue.push_back(env.vo.idx.find(vd->id())->second); } else if (vd->ti()->domain()!=constants().boollit(result)) { env.flat()->fail(env); vd->e(constants().lit_true); } } else { remove = false; } } } else if (c->id()==constants().ids.clause) { int posOrNeg = isTrue ? 0 : 1; ArrayLit* al = follow_id(c->args()[posOrNeg])->cast(); ArrayLit* al_other = follow_id(c->args()[1-posOrNeg])->cast(); if (ci && al->v().size()==1 && al->v()[0]!=vd->id() && al_other->v().size()==1) { // simple implication assert(al_other->v()[0]==vd->id()); if (ci) { if (al->v()[0]->type().ispar()) { if (eval_bool(env,al->v()[0])==isTrue) { toRemove.push_back(ci); } else { env.flat()->fail(env); remove = false; } } else { Id* id = al->v()[0]->cast(); if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(constants().boollit(isTrue)); vardeclQueue.push_back(env.vo.idx.find(id->decl()->id())->second); } else { if (id->decl()->ti()->domain()==constants().boollit(isTrue)) { toRemove.push_back(ci); } else { env.flat()->fail(env); remove = false; } } } } } else { // proper clause for (unsigned int i=0; iv().size(); i++) { if (al->v()[i]==vd->id()) { if (ci) { toRemove.push_back(ci); } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().lit_true); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().lit_true) { env.flat()->fail(env); vdi->e()->e(constants().lit_true); } } break; } } } } } } else { remove = false; } } } libminizinc-2.0.11/lib/astvec.cpp0000644000175000017500000000134512646030173015304 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include namespace MiniZinc { ASTIntVecO::ASTIntVecO(const std::vector& v) : ASTChunk(sizeof(int)*v.size()) { for (unsigned int i=v.size(); i--;) (*this)[i] = v[i]; } ASTIntVecO* ASTIntVecO::a(const std::vector& v) { ASTIntVecO* ao = static_cast(alloc(sizeof(int)*v.size())); new (ao) ASTIntVecO(v); return ao; } }libminizinc-2.0.11/lib/copy.cpp0000644000175000017500000004462512646030173015001 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include namespace MiniZinc { void CopyMap::insert(Expression* e0, Expression* e1) { m.insert(std::pair(e0,e1)); m.insert(std::pair(e1,e1)); } Expression* CopyMap::find(Expression* e) { MyMap::iterator it = m.find(e); if (it==m.end()) return NULL; return static_cast(it->second); } void CopyMap::insert(Item* e0, Item* e1) { m.insert(std::pair(e0,e1)); } Item* CopyMap::find(Item* e) { MyMap::iterator it = m.find(e); if (it==m.end()) return NULL; return static_cast(it->second); } void CopyMap::insert(Model* e0, Model* e1) { m.insert(std::pair(e0,e1)); } Model* CopyMap::find(Model* e) { MyMap::iterator it = m.find(e); if (it==m.end()) return NULL; return static_cast(it->second); } void CopyMap::insert(const ASTString& e0, const ASTString& e1) { m.insert(std::pair(e0.aststr(),e1.aststr())); } ASTStringO* CopyMap::find(const ASTString& e) { MyMap::iterator it = m.find(e.aststr()); if (it==m.end()) return NULL; return static_cast(it->second); } void CopyMap::insert(IntSetVal* e0, IntSetVal* e1) { m.insert(std::pair(e0,e1)); } IntSetVal* CopyMap::find(IntSetVal* e) { MyMap::iterator it = m.find(e); if (it==m.end()) return NULL; return static_cast(it->second); } Location copy_location(CopyMap& m, const Location& _loc) { Location loc; loc.first_line = _loc.first_line; loc.first_column = _loc.first_column; loc.last_line = _loc.last_line; loc.last_column = _loc.last_column; loc.is_introduced = _loc.is_introduced; if (_loc.filename != "") { if (ASTStringO* f = m.find(ASTString(_loc.filename))) { loc.filename = ASTString(f); } else { ASTString fn(_loc.filename.str()); m.insert(ASTString(_loc.filename), fn); loc.filename = fn; } } else { loc.filename = ASTString(); } return loc; } Location copy_location(CopyMap& m, Expression* e) { return copy_location(m,e->loc()); } Location copy_location(CopyMap& m, Item* i) { return copy_location(m,i->loc()); } void copy_ann(EnvI& env, CopyMap& m, Annotation& oldAnn, Annotation& newAnn, bool followIds, bool copyFundecls, bool isFlatModel); Expression* copy(EnvI& env, CopyMap& m, Expression* e, bool followIds, bool copyFundecls, bool isFlatModel) { if (e==NULL) return NULL; if (Expression* cached = m.find(e)) return cached; Expression* ret = NULL; switch (e->eid()) { case Expression::E_INTLIT: { IntLit* c = new IntLit(copy_location(m,e), e->cast()->v()); m.insert(e,c); ret = c; } break; case Expression::E_FLOATLIT: { FloatLit* c = new FloatLit(copy_location(m,e), e->cast()->v()); m.insert(e,c); ret = c; } break; case Expression::E_SETLIT: { SetLit* s = e->cast(); SetLit* c = new SetLit(copy_location(m,e),NULL); m.insert(e,c); if (s->isv()) { IntSetVal* isv; if (IntSetVal* isvc = m.find(s->isv())) { isv = isvc; } else { IntSetRanges r(s->isv()); isv = IntSetVal::ai(r); m.insert(s->isv(),isv); } c->isv(isv); } else { if (ASTExprVecO* ve = m.find(s->v())) { c->v(ASTExprVec(ve)); } else { std::vector elems(s->v().size()); for (unsigned int i=s->v().size(); i--;) elems[i] = copy(env,m,s->v()[i],followIds,copyFundecls,isFlatModel); ASTExprVec ce(elems); m.insert(s->v(),ce); c->v(ce); } } ret = c; } break; case Expression::E_BOOLLIT: { ret = e; } break; case Expression::E_STRINGLIT: { StringLit* sl = e->cast(); StringLit* c; if (ASTStringO* cs = m.find(sl->v())) { c = new StringLit(copy_location(m,e),ASTString(cs)); } else { ASTString s(sl->v().str()); m.insert(sl->v(),s); c = new StringLit(copy_location(m,e),s); } m.insert(e,c); ret = c; } break; case Expression::E_ID: { if (e==constants().absent) return e; Id* id = e->cast(); if (followIds) { Id* prevId = id; Expression* cur = e; bool done = false; do { if (cur==NULL) { cur = prevId; done = true; } else { switch (cur->eid()) { case Expression::E_ID: prevId = cur->cast(); cur = prevId->decl(); break; case Expression::E_VARDECL: if (cur->cast()->e()) { cur = cur->cast()->e(); } else { cur = prevId; done = true; } break; default: done = true; } } } while (!done); if (cur->isa()) { return cur; } else { return copy(env,m,cur,false); } } else { Id* c; if (id->decl()) { VarDecl* vd = static_cast(copy(env,m,id->decl(),followIds,copyFundecls,isFlatModel)); c = vd->id(); } else { if (id->idn()!=-1) { c = new Id(copy_location(m,e),id->idn(),NULL); } else { ASTString id_v; if (ASTStringO* cs = m.find(id->v())) { id_v = ASTString(cs); } else { id_v = ASTString(id->v().str()); m.insert(id->v(),id_v); } c = new Id(copy_location(m,e),id_v,NULL); } } m.insert(e,c); ret = c; } } break; case Expression::E_ANON: { AnonVar* c = new AnonVar(copy_location(m,e)); m.insert(e,c); ret = c; } break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); std::vector > dims(al->dims()); for (unsigned int i=al->dims(); i--;) { dims[i].first = al->min(i); dims[i].second = al->max(i); } ArrayLit* c = new ArrayLit(copy_location(m,e),std::vector(),dims); m.insert(e,c); ASTExprVecO* v; if (ASTExprVecO* cv = m.find(al->v())) { v = cv; } else { std::vector elems(al->v().size()); for (unsigned int i=al->v().size(); i--;) elems[i] = copy(env,m,al->v()[i],followIds,copyFundecls,isFlatModel); ASTExprVec ce(elems); m.insert(al->v(),ce); v = ce.vec(); } c->v(ASTExprVec(v)); ret = c; } break; case Expression::E_ARRAYACCESS: { ArrayAccess* aa = e->cast(); ArrayAccess* c = new ArrayAccess(copy_location(m,e),NULL,std::vector()); m.insert(e,c); ASTExprVecO* idx; if (ASTExprVecO* cidx = m.find(aa->idx())) { idx = cidx; } else { std::vector elems(aa->idx().size()); for (unsigned int i=aa->idx().size(); i--;) elems[i] = copy(env,m,aa->idx()[i],followIds,copyFundecls,isFlatModel); ASTExprVec ce(elems); m.insert(aa->idx(),ce); idx = ce.vec(); } c->v(copy(env,m,aa->v(),followIds,copyFundecls,isFlatModel)); c->idx(ASTExprVec(idx)); ret = c; } break; case Expression::E_COMP: { Comprehension* c = e->cast(); Generators g; Comprehension* cc = new Comprehension(copy_location(m,e),NULL,g,c->set()); m.insert(c,cc); g._w = copy(env,m,c->where(),followIds,copyFundecls,isFlatModel); for (int i=0; in_generators(); i++) { std::vector vv; for (int j=0; jn_decls(i); j++) vv.push_back(static_cast(copy(env,m,c->decl(i,j),followIds,copyFundecls,isFlatModel))); g._g.push_back(Generator(vv,copy(env,m,c->in(i),followIds,copyFundecls,isFlatModel))); } cc->init(copy(env,m,c->e(),followIds,copyFundecls,isFlatModel),g); ret = cc; } break; case Expression::E_ITE: { ITE* ite = e->cast(); ITE* c = new ITE(copy_location(m,e),std::vector(),NULL); m.insert(e,c); std::vector ifthen(2*ite->size()); for (unsigned int i=ite->size(); i--;) { ifthen[2*i] = copy(env,m,ite->e_if(i),followIds,copyFundecls,isFlatModel); ifthen[2*i+1] = copy(env,m,ite->e_then(i),followIds,copyFundecls,isFlatModel); } c->init(ifthen,copy(env,m,ite->e_else(),followIds,copyFundecls,isFlatModel)); ret = c; } break; case Expression::E_BINOP: { BinOp* b = e->cast(); BinOp* c = new BinOp(copy_location(m,e),NULL,b->op(),NULL); m.insert(e,c); c->lhs(copy(env,m,b->lhs(),followIds,copyFundecls,isFlatModel)); c->rhs(copy(env,m,b->rhs(),followIds,copyFundecls,isFlatModel)); ret = c; } break; case Expression::E_UNOP: { UnOp* b = e->cast(); UnOp* c = new UnOp(copy_location(m,e),b->op(),NULL); m.insert(e,c); c->e(copy(env,m,b->e(),followIds,copyFundecls,isFlatModel)); ret = c; } break; case Expression::E_CALL: { Call* ca = e->cast(); ASTString id_v; if (ASTStringO* cs = m.find(ca->id())) { id_v = ASTString(cs); } else { id_v = ASTString(ca->id().str()); m.insert(ca->id(),id_v); } Call* c = new Call(copy_location(m,e),id_v,std::vector()); if (copyFundecls) { c->decl(Item::cast(copy(env,m,ca->decl()))); } else { c->decl(ca->decl()); } m.insert(e,c); std::vector args(ca->args().size()); for (unsigned int i=ca->args().size(); i--;) args[i] = copy(env,m,ca->args()[i],followIds,copyFundecls,isFlatModel); c->args(args); ret = c; } break; case Expression::E_VARDECL: { VarDecl* vd = e->cast(); VarDecl* c; if (vd->id()->idn()==-1) { ASTString id_v; if (ASTStringO* cs = m.find(vd->id()->v())) { id_v = ASTString(cs); } else { id_v = ASTString(vd->id()->v().str()); m.insert(vd->id()->v(),id_v); } c = new VarDecl(copy_location(m,e),NULL,id_v,NULL); } else { c = new VarDecl(copy_location(m,e),NULL,vd->id()->idn(),NULL); } c->toplevel(vd->toplevel()); c->introduced(vd->introduced()); if (isFlatModel && vd->flat()==vd) c->flat(c); else c->flat(vd->flat()); c->payload(vd->payload()); m.insert(e,c); c->ti(static_cast(copy(env,m,vd->ti(),followIds,copyFundecls,isFlatModel))); c->e(copy(env,m,vd->e(),followIds,copyFundecls,isFlatModel)); c->type(c->ti()->type()); c->id()->type(c->type()); ret = c; } break; case Expression::E_LET: { Let* l = e->cast(); std::vector let(l->let().size()); for (unsigned int i=l->let().size(); i--;) let[i] = copy(env,m,l->let()[i],followIds,copyFundecls,isFlatModel); Let* c = new Let(copy_location(m,e),let,copy(env,m,l->in(),followIds,copyFundecls,isFlatModel)); for (unsigned int i=l->let().size(); i--;) { c->_let_orig[i] = copy(env,m,l->_let_orig[i],followIds,copyFundecls,isFlatModel); } m.insert(e,c); ret = c; } break; case Expression::E_TI: { TypeInst* t = e->cast(); ASTExprVecO* r; if (t->ranges().size()==0) { r = NULL; } else if (ASTExprVecO* cr = m.find(t->ranges())) { r = cr; } else { std::vector rr(t->ranges().size()); for (unsigned int i=t->ranges().size(); i--;) rr[i] = static_cast(copy(env,m,t->ranges()[i],followIds,copyFundecls,isFlatModel)); r = ASTExprVecO::a(rr); } TypeInst* c = new TypeInst(copy_location(m,e),t->type(), ASTExprVec(r),copy(env,m,t->domain(),followIds,copyFundecls,isFlatModel)); m.insert(e,c); ret = c; } break; case Expression::E_TIID: { TIId* t = e->cast(); TIId* c = new TIId(copy_location(m,e),t->v().str()); m.insert(e,c); ret = c; } break; default: assert(false); } if (!ret->isa() || ret->cast()->decl()==NULL) ret->type(e->type()); copy_ann(env,m,e->ann(),ret->ann(),followIds,copyFundecls,isFlatModel); return ret; } void copy_ann(EnvI& env, CopyMap& m, Annotation& oldAnn, Annotation& newAnn, bool followIds, bool copyFundecls, bool isFlatModel) { for (ExpressionSetIter it = oldAnn.begin(); it != oldAnn.end(); ++it) newAnn.add(copy(env,m,*it,followIds,copyFundecls,isFlatModel)); } Expression* copy(EnvI& env, Expression* e, bool followIds, bool copyFundecls, bool isFlatModel) { CopyMap m; return copy(env,m,e,followIds,copyFundecls,isFlatModel); } Model* copy(EnvI& env, CopyMap& cm, Model* m, bool isFlatModel); Item* copy(EnvI& env, CopyMap& m, Item* i, bool followIds, bool copyFundecls, bool isFlatModel) { if (i==NULL) return NULL; if (Item* cached = m.find(i)) return cached; switch (i->iid()) { case Item::II_INC: { IncludeI* ii = i->cast(); IncludeI* c = new IncludeI(copy_location(m,i), ASTString(ii->f().str())); m.insert(i,c); c->m(copy(env,m,ii->m()),ii->own()); return c; } case Item::II_VD: { VarDeclI* v = i->cast(); VarDeclI* c = new VarDeclI(copy_location(m,i), NULL); m.insert(i,c); c->e(static_cast(copy(env,m,v->e(),followIds,copyFundecls,isFlatModel))); return c; } case Item::II_ASN: { AssignI* a = i->cast(); AssignI* c = new AssignI(copy_location(m,i), a->id().str(),NULL); m.insert(i,c); c->e(copy(env,m,a->e(),followIds,copyFundecls,isFlatModel)); c->decl(static_cast(copy(env,m,a->decl(),followIds,copyFundecls,isFlatModel))); return c; } case Item::II_CON: { ConstraintI* cc = i->cast(); ConstraintI* c = new ConstraintI(copy_location(m,i),NULL); m.insert(i,c); c->e(copy(env,m,cc->e(),followIds,copyFundecls,isFlatModel)); return c; } case Item::II_SOL: { SolveI* s = i->cast(); SolveI* c; switch (s->st()) { case SolveI::ST_SAT: c = SolveI::sat(Location()); break; case SolveI::ST_MIN: c = SolveI::min(Location(),copy(env,m,s->e(),followIds,copyFundecls,isFlatModel)); break; case SolveI::ST_MAX: c = SolveI::max(Location(),copy(env,m,s->e(),followIds,copyFundecls,isFlatModel)); break; } copy_ann(env,m, s->ann(), c->ann(), followIds,copyFundecls,isFlatModel); m.insert(i,c); return c; } case Item::II_OUT: { OutputI* o = i->cast(); OutputI* c = new OutputI(copy_location(m,i),copy(env,m,o->e(),followIds,copyFundecls,isFlatModel)); m.insert(i,c); return c; } case Item::II_FUN: { FunctionI* f = i->cast(); std::vector params(f->params().size()); for (unsigned int j=f->params().size(); j--;) params[j] = static_cast(copy(env,m,f->params()[j],followIds,copyFundecls,isFlatModel)); FunctionI* c = new FunctionI(copy_location(m,i),f->id().str(), static_cast(copy(env,m,f->ti(),followIds,copyFundecls,isFlatModel)), params, copy(env,m,f->e(),followIds,copyFundecls,isFlatModel)); c->_builtins.e = f->_builtins.e; c->_builtins.i = f->_builtins.i; c->_builtins.f = f->_builtins.f; c->_builtins.b = f->_builtins.b; c->_builtins.s = f->_builtins.s; c->_builtins.str = f->_builtins.str; copy_ann(env,m, f->ann(), c->ann(), followIds,copyFundecls,isFlatModel); m.insert(i,c); return c; } default: assert(false); return NULL; } } Item* copy(EnvI& env, Item* i, bool followIds, bool copyFundecls, bool isFlatModel) { CopyMap m; return copy(env,m,i,followIds,copyFundecls,isFlatModel); } Model* copy(EnvI& env, CopyMap& cm, Model* m, bool isFlatModel) { if (m==NULL) return NULL; if (Model* cached = cm.find(m)) return cached; Model* c = new Model; for (unsigned int i=0; isize(); i++) c->addItem(copy(env,cm,(*m)[i],false,true)); for (Model::FnMap::iterator it = m->fnmap.begin(); it != m->fnmap.end(); ++it) { for (unsigned int i=0; isecond.size(); i++) c->registerFn(env,copy(env,cm,it->second[i],false,true,isFlatModel)->cast()); } cm.insert(m,c); return c; } Model* copy(EnvI& env, Model* m) { CopyMap cm; return copy(env,cm,m); } } libminizinc-2.0.11/lib/aststring.cpp0000644000175000017500000000202512646030173016031 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #ifndef HAS_MEMCPY_S namespace { void memcpy_s(char* dest, size_t, const char* src, size_t count) { memcpy(dest,src,count); } } #endif namespace MiniZinc { ASTStringO::ASTStringO(const std::string& s) : ASTChunk(s.size()+sizeof(size_t)+1) { memcpy_s(_data+sizeof(size_t),s.size()+1,s.c_str(),s.size()); *(_data+sizeof(size_t)+s.size())=0; HASH_NAMESPACE::hash h; reinterpret_cast(_data)[0] = h(s); } ASTStringO* ASTStringO::a(const std::string& s) { ASTStringO* as = static_cast(alloc(1+sizeof(size_t)+s.size())); new (as) ASTStringO(s); return as; } } libminizinc-2.0.11/lib/lexer.lxx0000644000175000017500000006160212646030173015171 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ %option reentrant %option bison-bridge bison-locations %option noyywrap %option stack %{ #if defined __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wdeprecated" #elif defined _MSC_VER #pragma warning(push, 1) #endif namespace MiniZinc{ class Location; } #define YYLTYPE MiniZinc::Location #define YYLTYPE_IS_DECLARED 1 #define YYLTYPE_IS_TRIVIAL 0 #include int yy_input_proc(char* buf, int size, yyscan_t yyscanner); #define YY_INPUT(buf, result, max_size) \ result = yy_input_proc(buf, max_size, yyscanner); #define YY_USER_ACTION \ { MiniZinc::ParserState* parm = \ static_cast(yyget_extra(yyscanner)); \ yylloc->first_line = yylloc->last_line = parm->lineno; \ } bool hexstrtointval(const char* s, long long int& v) { std::istringstream iss(s); iss >> std::hex >> v; return !iss.fail(); } bool octstrtointval(const char* s, long long int& v) { std::istringstream iss(s); iss >> std::oct >> v; return !iss.fail(); } bool fast_strtointval(const char* s, long long int& v) { MiniZinc::IntVal x = 0; try { for (; *s != '\0'; ++s) { x = (x*10) + (*s - '0'); } } catch (MiniZinc::ArithmeticError&) { return false; } v = x.toInt(); return true; } bool strtofloatval(const char* s, double& v) { std::istringstream iss(s); iss >> v; return !iss.fail(); } void beginToken(void* parm, YYLTYPE* yyloc, char* t) { MiniZinc::ParserState* pp = static_cast(parm); int tokenLength = strlen(t); yyloc->first_column = pp->nTokenNextStart; pp->nTokenNextStart += tokenLength; yyloc->last_column = pp->nTokenNextStart-1; } void clearBuffer(void* parm) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer = ""; } void appendBufferString(void* parm, const char* s) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer += s; } void appendBufferChar(void* parm, char s) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer += s; } char* bufferData(void* parm) { MiniZinc::ParserState* pp = static_cast(parm); return strdup(pp->stringBuffer.c_str()); } %} %x string %x string_quote %x multilinecomment %x doccomment %x doccomment_file %s bracket_exp %s quoted_exp %% <*>\x0 { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INVALID_NULL; } \xa { MiniZinc::ParserState* parm = static_cast( yyget_extra(yyscanner)); parm->lineno++; parm->lineStartPos += parm->nTokenNextStart; parm->nTokenNextStart=1; } [ \f\xd\t] { /* ignore whitespace */ beginToken(yyget_extra(yyscanner), yylloc, yytext); } "/**" { yy_push_state(doccomment,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); clearBuffer(yyget_extra(yyscanner)); } { "*/" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_DOC_COMMENT; } [^*\xa]+ { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } "*" { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } \xa { MiniZinc::ParserState* parm = static_cast( yyget_extra(yyscanner)); parm->lineno++; parm->lineStartPos += parm->nTokenNextStart; parm->nTokenNextStart=1; appendBufferString(yyget_extra(yyscanner), yytext); } } "/***" { yy_push_state(doccomment_file,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); clearBuffer(yyget_extra(yyscanner)); } { "*/" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_DOC_FILE_COMMENT; } [^*\xa]+ { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } "*" { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } \xa { MiniZinc::ParserState* parm = static_cast( yyget_extra(yyscanner)); parm->lineno++; parm->lineStartPos += parm->nTokenNextStart; parm->nTokenNextStart=1; appendBufferString(yyget_extra(yyscanner), yytext); } } "/*" { yy_push_state(multilinecomment,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); } { "*/" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yy_pop_state(yyscanner); } [^*\xa]+ { beginToken(yyget_extra(yyscanner), yylloc, yytext); } "*" { beginToken(yyget_extra(yyscanner), yylloc, yytext); } \xa { MiniZinc::ParserState* parm = static_cast( yyget_extra(yyscanner)); parm->lineno++; parm->lineStartPos += parm->nTokenNextStart; parm->nTokenNextStart=1; } } "[" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LEFT_BRACKET; } "[|" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LEFT_2D_BRACKET; } "]" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RIGHT_BRACKET; } "|]" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RIGHT_2D_BRACKET; } %[^\xa]* { beginToken(yyget_extra(yyscanner), yylloc, yytext); /* ignore comments */ } "true" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->iValue = 1; return MZN_BOOL_LITERAL; } "false" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->iValue = 0; return MZN_BOOL_LITERAL; } 0[xX]([0-9a-fA-F]*\.[0-9a-fA-F]+|[0-9a-fA-F]+\.)([pP][+-]?[0-9]+)|(0[xX][0-9a-fA-F]+[pP][+-]?[0-9]+) { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } 0[xX][0-9A-Fa-f]+ { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (hexstrtointval(yytext+2, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } 0o[0-7]+ { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (octstrtointval(yytext+2, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } [0-9]+ { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (fast_strtointval(yytext, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } [0-9]+\.[0-9]+ { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } [0-9]+\.[0-9]+[Ee][+-]?[0-9]+ { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } [0-9]+[Ee][+-]?[0-9]+ { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } [:;|{},\[\]\.] { beginToken(yyget_extra(yyscanner), yylloc, yytext); return *yytext; } \.\. { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DOTDOT; } "'\.\.'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DOTDOT_QUOTED; } :: { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_COLONCOLON; } _ { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_UNDERSCORE; } "ann" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ANN; } "annotation" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ANNOTATION; } "any" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ANY; } "array" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ARRAY; } "bool" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_BOOL; } "case" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_CASE; } "constraint" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_CONSTRAINT; } "default" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DEFAULT; } "div" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IDIV; } "'div'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IDIV_QUOTED; } "diff" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DIFF; } "'diff'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DIFF_QUOTED; } "else" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ELSE; } "elseif" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ELSEIF; } "endif" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ENDIF; } "enum" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ENUM; } "float" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_FLOAT; } "function" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_FUNCTION; } "if" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IF; } "include" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INCLUDE; } "infinity" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INFINITY; } "intersect" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INTERSECT; } "'intersect'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INTERSECT_QUOTED; } "in" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IN; } "'in'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IN_QUOTED; } "int" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INT; } "let" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LET; } "list" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LIST; } "maximize" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->bValue = false; return MZN_MAXIMIZE; } "minimize" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->bValue = true; return MZN_MINIMIZE; } "mod" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MOD; } "'mod'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MOD_QUOTED; } "not" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_NOT; } "'not'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_NOT_QUOTED; } "of" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OF; } "output" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OUTPUT; } "opt" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OPT; } "par" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PAR; } "predicate" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PREDICATE; } "record" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RECORD; } "satisfy" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SATISFY; } "set" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SET; } "solve" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SOLVE; } "string" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_STRING; } "subset" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SUBSET; } "'subset'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SUBSET_QUOTED; } "superset" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SUPERSET; } "'superset'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SUPERSET_QUOTED; } "symdiff" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SYMDIFF; } "'symdiff'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SYMDIFF_QUOTED; } "test" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_TEST; } "then" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_THEN; } "tuple" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_TUPLE; } "type" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_TYPE; } "union" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_UNION; } "'union'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_UNION_QUOTED; } "var" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_VAR; } "variant_record" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_VARIANT_RECORD; } "where" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_WHERE; } "xor" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_XOR; } "'xor'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_XOR_QUOTED; } "+" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PLUS; } "'+'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PLUS_QUOTED; } "-" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MINUS; } "'-'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MINUS_QUOTED; } "*" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MULT; } "'*'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MULT_QUOTED; } "/" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DIV; } "'/'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DIV_QUOTED; } "++" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PLUSPLUS; } "'++'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PLUSPLUS_QUOTED; } "<>" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ABSENT; } "<" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LE; } "'<'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LE_QUOTED; } "<=" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LQ; } "'<='" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LQ_QUOTED; } ">" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_GR; } "'>'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_GR_QUOTED; } ">=" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_GQ; } "'>='" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_GQ_QUOTED; } "==" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQ; } "'=='" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQ_QUOTED; } "=" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQ; } "'='" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQ_QUOTED; } "!=" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_NQ; } "'!='" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_NQ_QUOTED; } "->" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IMPL; } "'->'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IMPL_QUOTED; } "<-" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RIMPL; } "'<-'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RIMPL_QUOTED; } "<->" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQUIV; } "'<->'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQUIV_QUOTED; } "\\/" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OR; } "'\\/'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OR_QUOTED; } "/\\" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_AND; } "'/\\'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_AND_QUOTED; } "~"[+*=-] { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext); return MZN_QUOTED_IDENTIFIER; } "'~"[+*=-]"'" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext+1); yylval->sValue[strlen(yytext)-2] = 0; return MZN_IDENTIFIER; } [A-Za-z][A-Za-z0-9_]* { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } _[A-Za-z][A-Za-z0-9_]* { beginToken(yyget_extra(yyscanner), yylloc, yytext); MiniZinc::ParserState* parm = static_cast(yyget_extra(yyscanner)); if (parm->isFlatZinc) { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } else { return FLATZINC_IDENTIFIER; } } "\xE2\x88\x80" { yylval->sValue = strdup("forall"); return MZN_IDENTIFIER; } "\xE2\x88\x83" { yylval->sValue = strdup("exists"); return MZN_IDENTIFIER; } "\xE2\x88\x88" { return MZN_IN; } "\xE2\x8A\x86" { return MZN_SUBSET; } "\xE2\x8A\x87" { return MZN_SUPERSET; } "\xE2\x88\x9E" { return MZN_INFINITY; } "\xC2\xAC" { return MZN_NOT; } "\xE2\x86\x90" { return MZN_RIMPL; } "\xE2\x86\x92" { return MZN_IMPL; } "\xE2\x86\x94" { return MZN_EQUIV; } "\xE2\x88\xA7" { return MZN_AND; } "\xE2\x88\xA8" { return MZN_OR; } "\xE2\x89\xA0" { return MZN_NQ; } "\xE2\x89\xA4" { return MZN_LQ; } "\xE2\x89\xA5" { return MZN_GQ; } "\xE2\x88\xAA" { return MZN_UNION; } "\xE2\x88\xA9" { return MZN_INTERSECT; } $[A-Za-z][A-Za-z0-9_]* { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext+1); return MZN_TI_IDENTIFIER; } "(" { yy_push_state(bracket_exp,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); return *yytext; } ")" { yy_pop_state(yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); return *yytext; } ")" { yy_pop_state(yyscanner); yy_pop_state(yyscanner); yy_push_state(string_quote,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); clearBuffer(yyget_extra(yyscanner)); } \" { yy_push_state(string,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); clearBuffer(yyget_extra(yyscanner)); } [^\\"\xa\xd\x0]* { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } \\n { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferChar(yyget_extra(yyscanner), '\n'); } \\t { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferChar(yyget_extra(yyscanner), '\t'); } \\[\\'] { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferChar(yyget_extra(yyscanner), yytext[1]); } \\[\\"] { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferChar(yyget_extra(yyscanner), yytext[1]); } \\"(" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_push_state(quoted_exp,yyscanner); return MZN_STRING_QUOTE_START; } \\"(" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_push_state(quoted_exp,yyscanner); return MZN_STRING_QUOTE_MID; } \" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_STRING_LITERAL; } \" { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_STRING_QUOTE_END; } . { beginToken(yyget_extra(yyscanner), yylloc, yytext); return (unsigned char)yytext[0]; } <> { yy_pop_state(yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_UNTERMINATED_STRING; } `[A-Za-z][A-Za-z0-9_]*` { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext+1); yylval->sValue[strlen(yytext)-2] = 0; return MZN_QUOTED_IDENTIFIER; } . { beginToken(yyget_extra(yyscanner), yylloc, yytext); return (unsigned char)yytext[0]; } %% int yy_input_proc(char* buf, int size, yyscan_t yyscanner) { MiniZinc::ParserState* parm = static_cast(yyget_extra(yyscanner)); return parm->fillBuffer(buf, size); // work around warning that yyunput is unused yyunput (0,buf,yyscanner); } libminizinc-2.0.11/lib/gc.cpp0000644000175000017500000004762612646030173014424 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include #include #include #include #include //#define MINIZINC_GC_STATS #if defined(MINIZINC_GC_STATS) #include #endif namespace MiniZinc { GC*& GC::gc(void) { #if defined(HAS_DECLSPEC_THREAD) __declspec (thread) static GC* gc = NULL; #elif defined(HAS_ATTR_THREAD) static __thread GC* gc = NULL; #else #error Need thread-local storage #endif return gc; } bool GC::locked(void) { assert(gc()); return gc()->_lock_count > 0; } GCLock::GCLock(void) { GC::lock(); } GCLock::~GCLock(void) { GC::unlock(); } class FreeListNode : public ASTNode { public: FreeListNode* next; size_t size; FreeListNode(size_t s, FreeListNode* n) : ASTNode(ASTNode::NID_FL) , next(n) , size(s) { _gc_mark = 1; } FreeListNode(size_t s) : ASTNode(ASTNode::NID_FL), next(NULL), size(s) {} }; class HeapPage { public: HeapPage* next; size_t size; size_t used; char data[1]; HeapPage(HeapPage* n, size_t s) : next(n), size(s), used(0) {} }; /// Memory managed by the garbage collector class GC::Heap { friend class GC; #if defined(MINIZINC_GC_STATS) static const char* _nodeid[Item::II_END+1]; struct GCStat { int first; int second; int keepalive; int inmodel; size_t total; GCStat(void) : first(0), second(0), keepalive(0), inmodel(0), total(0) {} }; std::map gc_stats; #endif protected: HeapPage* _page; Model* _rootset; KeepAlive* _roots; WeakRef* _weakRefs; static const int _max_fl = 5; FreeListNode* _fl[_max_fl+1]; static const size_t _fl_size[_max_fl+1]; int _fl_slot(size_t _size) { size_t size = _size; assert(size <= _fl_size[_max_fl]); assert(size >= _fl_size[0]); size -= sizeof(Item); assert(size % sizeof(void*) == 0); size /= sizeof(void*); assert(size >= 1); int slot = static_cast(size)-1; return slot; } /// Total amount of memory allocated size_t _alloced_mem; /// Total amount of memory currently free size_t _free_mem; /// Memory threshold for next garbage collection size_t _gc_threshold; /// High water mark of all allocated memory size_t _max_alloced_mem; /// A trail item struct TItem { Expression** l; Expression* v; bool mark; TItem(Expression** l0, Expression* v0) : l(l0), v(v0), mark(false) {} }; /// Trail std::vector trail; Heap(void) : _page(NULL) , _rootset(NULL) , _roots(NULL) , _weakRefs(NULL) , _alloced_mem(0) , _free_mem(0) , _gc_threshold(10) , _max_alloced_mem(0) { for (int i=_max_fl+1; i--;) _fl[i] = NULL; } /// Default size of pages to allocate static const size_t pageSize = 1<<20; HeapPage* allocPage(size_t s, bool exact=false) { if (!exact) s = std::max(s,pageSize); HeapPage* newPage = static_cast(::malloc(sizeof(HeapPage)+s-1)); #ifndef NDEBUG memset(newPage,255,sizeof(HeapPage)+s-1); #endif _alloced_mem += s; _max_alloced_mem = std::max(_max_alloced_mem, _alloced_mem); _free_mem += s; if (exact && _page) { new (newPage) HeapPage(_page->next,s); _page->next = newPage; } else { if (_page) { size_t ns = _page->size-_page->used; assert(ns <= _fl_size[_max_fl]); if (ns >= _fl_size[0]) { // Remainder of page can be added to free lists FreeListNode* fln = reinterpret_cast(_page->data+_page->used); _page->used += ns; new (fln) FreeListNode(ns, _fl[_fl_slot(ns)]); _fl[_fl_slot(ns)] = fln; } else { // Waste a little memory (less than smallest free list slot) _free_mem -= ns; assert(_alloced_mem >= _free_mem); } } new (newPage) HeapPage(_page,s); _page = newPage; } return newPage; } void* alloc(size_t size, bool exact=false) { assert(size<=80 || exact); /// Align to word boundary size += ((8 - (size & 7)) & 7); HeapPage* p = _page; if (exact || _page==NULL || _page->used+size >= _page->size) p = allocPage(size,exact); char* ret = p->data+p->used; p->used += size; _free_mem -= size; assert(_alloced_mem >= _free_mem); return ret; } /// Allocate one object of type T (no initialisation) template T* alloc(void) { return static_cast(alloc(sizeof(T))); } /// Allocate \a n objects of type T (no initialisation) template T* alloc(int n) { return static_cast(alloc(n*sizeof(T))); } void* fl(size_t size) { int slot = _fl_slot(size); assert(slot <= _max_fl); if (_fl[slot]) { FreeListNode* p = _fl[slot]; _fl[slot] = p->next; _free_mem -= size; return p; } return alloc(size); } void rungc(void) { if (_alloced_mem > _gc_threshold) { #ifdef MINIZINC_GC_STATS std::cerr << "GC\n\talloced " << (_alloced_mem/1024) << "\n\tfree " << (_free_mem/1024) << "\n\tdiff " << ((_alloced_mem-_free_mem)/1024) << "\n\tthreshold " << (_gc_threshold/1024) << "\n"; #endif mark(); sweep(); _gc_threshold = static_cast(_alloced_mem * 1.5); #ifdef MINIZINC_GC_STATS std::cerr << "done\n\talloced " << (_alloced_mem/1024) << "\n\tfree " << (_free_mem/1024) << "\n\tdiff " << ((_alloced_mem-_free_mem)/1024) << "\n\tthreshold " << (_gc_threshold/1024) << "\n"; #endif } } void mark(void); void sweep(void); static size_t nodesize(ASTNode* n) { static const size_t _nodesize[Item::II_END+1] = { 0, // NID_FL 0, // NID_CHUNK 0, // NID_VEC sizeof(IntLit), // E_INTLIT sizeof(FloatLit), // E_FLOATLIT sizeof(SetLit), // E_SETLIT sizeof(BoolLit), // E_BOOLLIT sizeof(StringLit), // E_STRINGLIT sizeof(Id), // E_ID sizeof(AnonVar), // E_ANON sizeof(ArrayLit), // E_ARRAYLIT sizeof(ArrayAccess), // E_ARRAYACCESS sizeof(Comprehension), // E_COMP sizeof(ITE), // E_ITE sizeof(BinOp), // E_BINOP sizeof(UnOp), // E_UNOP sizeof(Call), // E_CALL sizeof(VarDecl), // E_VARDECL sizeof(Let), // E_LET sizeof(TypeInst), // E_TI sizeof(TIId), // E_TIID sizeof(IncludeI), // II_INC sizeof(VarDeclI), // II_VD sizeof(AssignI), // II_ASN sizeof(ConstraintI), // II_CON sizeof(SolveI), // II_SOL sizeof(OutputI), // II_OUT sizeof(FunctionI) // II_FUN }; size_t ns; switch (n->_id) { case ASTNode::NID_FL: ns = static_cast(n)->size; break; case ASTNode::NID_CHUNK: ns = static_cast(n)->memsize(); break; case ASTNode::NID_VEC: ns = static_cast(n)->memsize(); break; default: assert(n->_id <= Item::II_END); ns = _nodesize[n->_id]; break; } ns += ((8 - (ns & 7)) & 7); return ns; } }; #ifdef MINIZINC_GC_STATS const char* GC::Heap::_nodeid[] = { "FreeList ", // NID_FL "Chunk ", // NID_CHUNK "Vec ", // NID_VEC "IntLit ", // E_INTLIT "FloatLit ", // E_FLOATLIT "SetLit ", // E_SETLIT "BoolLit ", // E_BOOLLIT "StringLit ", // E_STRINGLIT "Id ", // E_ID "AnonVar ", // E_ANON "ArrayLit ", // E_ARRAYLIT "ArrayAccess ", // E_ARRAYACCESS "Comprehension ", // E_COMP "ITE ", // E_ITE "BinOp ", // E_BINOP "UnOp ", // E_UNOP "Call ", // E_CALL "VarDecl ", // E_VARDECL "Let ", // E_LET "TypeInst ", // E_TI "TIId ", // E_TIID "IncludeI ", // II_INC "VarDeclI ", // II_VD "AssignI ", // II_ASN "ConstraintI ", // II_CON "SolveI ", // II_SOL "OutputI ", // II_OUT "FunctionI " // II_FUN }; #endif void GC::lock(void) { if (gc()==NULL) { gc() = new GC(); } if (gc()->_lock_count==0) gc()->_heap->rungc(); gc()->_lock_count++; } void GC::unlock(void) { assert(locked()); gc()->_lock_count--; } const size_t GC::Heap::pageSize; const size_t GC::Heap::_fl_size[GC::Heap::_max_fl+1] = { sizeof(Item)+1*sizeof(void*), sizeof(Item)+2*sizeof(void*), sizeof(Item)+3*sizeof(void*), sizeof(Item)+4*sizeof(void*), sizeof(Item)+5*sizeof(void*), sizeof(Item)+6*sizeof(void*), }; GC::GC(void) : _heap(new Heap()), _lock_count(0) {} void GC::add(Model* m) { GC* gc = GC::gc(); if (gc->_heap->_rootset) { m->_roots_next = gc->_heap->_rootset; m->_roots_prev = m->_roots_next->_roots_prev; m->_roots_prev->_roots_next = m; m->_roots_next->_roots_prev = m; } else { gc->_heap->_rootset = m->_roots_next = m->_roots_prev = m; } } void GC::remove(Model* m) { GC* gc = GC::gc(); if (m->_roots_next == m) { gc->_heap->_rootset = NULL; } else { m->_roots_next->_roots_prev = m->_roots_prev; m->_roots_prev->_roots_next = m->_roots_next; if (m==gc->_heap->_rootset) gc->_heap->_rootset = m->_roots_prev; } } void* GC::alloc(size_t size) { assert(locked()); void* ret; if (size < _heap->_fl_size[0] || size > _heap->_fl_size[_heap->_max_fl]) { ret = _heap->alloc(size,true); } else { ret = _heap->fl(size); } new (ret) FreeListNode(size); return ret; } void GC::Heap::mark(void) { #if defined(MINIZINC_GC_STATS) std::cerr << "================= mark =================: "; gc_stats.clear(); #endif for (KeepAlive* e = _roots; e != NULL; e = e->next()) { if ((*e)() && (*e)()->_gc_mark==0) { Expression::mark((*e)()); #if defined(MINIZINC_GC_STATS) gc_stats[(*e)()->_id].keepalive++; #endif } } #if defined(MINIZINC_GC_STATS) std::cerr << "+"; #endif Model* m = _rootset; if (m==NULL) return; do { m->_filepath.mark(); m->_filename.mark(); for (unsigned int j=0; j_items.size(); j++) { Item* i = m->_items[j]; if (i->_gc_mark==0) { i->_gc_mark = 1; i->loc().mark(); switch (i->iid()) { case Item::II_INC: i->cast()->f().mark(); break; case Item::II_VD: Expression::mark(i->cast()->e()); #if defined(MINIZINC_GC_STATS) gc_stats[i->cast()->e()->Expression::eid()].inmodel++; #endif break; case Item::II_ASN: i->cast()->id().mark(); Expression::mark(i->cast()->e()); Expression::mark(i->cast()->decl()); break; case Item::II_CON: Expression::mark(i->cast()->e()); #if defined(MINIZINC_GC_STATS) gc_stats[i->cast()->e()->Expression::eid()].inmodel++; #endif break; case Item::II_SOL: { SolveI* si = i->cast(); for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) { Expression::mark(*it); } } Expression::mark(i->cast()->e()); break; case Item::II_OUT: Expression::mark(i->cast()->e()); break; case Item::II_FUN: { FunctionI* fi = i->cast(); fi->id().mark(); Expression::mark(fi->ti()); for (ExpressionSetIter it = fi->ann().begin(); it != fi->ann().end(); ++it) { Expression::mark(*it); } Expression::mark(fi->e()); fi->params().mark(); for (unsigned int k=0; kparams().size(); k++) { Expression::mark(fi->params()[k]); } } break; } } } m = m->_roots_next; } while (m != _rootset); for (unsigned int i=trail.size(); i--;) { Expression::mark(trail[i].v); } bool fixPrev = false; for (WeakRef* wr = _weakRefs; wr != NULL; wr = wr->next()) { if (fixPrev) { fixPrev = false; WeakRef* p = wr->_p; removeWeakRef(p); p->_n = p; p->_p = p; } if ((*wr)() && (*wr)()->_gc_mark==0) { wr->_e = NULL; wr->_valid = false; fixPrev = true; } } #if defined(MINIZINC_GC_STATS) std::cerr << "+"; std::cerr << "\n"; #endif } void GC::Heap::sweep(void) { #if defined(MINIZINC_GC_STATS) std::cerr << "=============== GC sweep =============\n"; #endif HeapPage* p = _page; HeapPage* prev = NULL; while (p) { size_t off = 0; bool wholepage = false; while (off < p->used) { ASTNode* n = reinterpret_cast(p->data+off); size_t ns = nodesize(n); assert(ns != 0); #if defined(MINIZINC_GC_STATS) GCStat& stats = gc_stats[n->_id]; stats.first++; stats.total += ns; #endif if (n->_gc_mark==0) { switch (n->_id) { case Item::II_FUN: static_cast(n)->ann().~Annotation(); break; case Item::II_SOL: static_cast(n)->ann().~Annotation(); break; case Expression::E_VARDECL: // Reset WeakRef inside VarDecl static_cast(n)->flat(NULL); // fall through default: if (n->_id >= ASTNode::NID_END+1 && n->_id <= Expression::EID_END) { static_cast(n)->ann().~Annotation(); } } if (ns >= _fl_size[0] && ns <= _fl_size[_max_fl]) { FreeListNode* fln = static_cast(n); new (fln) FreeListNode(ns, _fl[_fl_slot(ns)]); _fl[_fl_slot(ns)] = fln; _free_mem += ns; #if defined(MINIZINC_GC_STATS) gc_stats[fln->_id].second++; #endif assert(_alloced_mem >= _free_mem); } else { assert(off==0); assert(p->used==p->size); wholepage = true; } } else { #if defined(MINIZINC_GC_STATS) stats.second++; #endif if (n->_id != ASTNode::NID_FL) n->_gc_mark=0; } off += ns; } if (wholepage) { #ifndef NDEBUG memset(p->data,42,p->size); #endif if (prev) { prev->next = p->next; } else { assert(p==_page); _page = p->next; } HeapPage* pf = p; p = p->next; _alloced_mem -= pf->size; assert(_alloced_mem >= _free_mem); ::free(pf); } else { prev = p; p = p->next; } } #if defined(MINIZINC_GC_STATS) for (auto stat: gc_stats) { std::cerr << _nodeid[stat.first] << ":\t" << stat.second.first << " / " << stat.second.second << " / " << stat.second.keepalive << " / " << stat.second.inmodel << " / "; if (stat.second.total > 1024) { if (stat.second.total > 1024*1024) { std::cerr << (stat.second.total / 1024 / 1024) << "M"; } else { std::cerr << (stat.second.total / 1024) << "K"; } } else { std::cerr << (stat.second.total); } std::cerr << std::endl; } #endif } ASTVec::ASTVec(size_t size) : ASTNode(NID_VEC), _size(size) {} void* ASTVec::alloc(size_t size) { size_t s = sizeof(ASTVec)+(size<=2?0:size-2)*sizeof(void*); s += ((8 - (s & 7)) & 7); return GC::gc()->alloc(s); } ASTChunk::ASTChunk(size_t size) : ASTNode(NID_CHUNK), _size(size) {} void* ASTChunk::alloc(size_t size) { size_t s = sizeof(ASTChunk)+(size<=4?0:size-4)*sizeof(char); s += ((8 - (s & 7)) & 7); return GC::gc()->alloc(s); } void GC::mark(void) { GC* gc = GC::gc(); if (!gc->_heap->trail.empty()) gc->_heap->trail.back().mark = true; } void GC::trail(Expression** l,Expression* v) { GC* gc = GC::gc(); gc->_heap->trail.push_back(GC::Heap::TItem(l,v)); } void GC::untrail(void) { GC* gc = GC::gc(); while (!gc->_heap->trail.empty() && !gc->_heap->trail.back().mark) { *gc->_heap->trail.back().l = gc->_heap->trail.back().v; gc->_heap->trail.pop_back(); } if (!gc->_heap->trail.empty()) gc->_heap->trail.back().mark = false; } size_t GC::maxMem(void) { GC* gc = GC::gc(); return gc->_heap->_max_alloced_mem; } void* ASTNode::operator new(size_t size) { return GC::gc()->alloc(size); } void GC::addKeepAlive(KeepAlive* e) { assert(e->_p==NULL); assert(e->_n==NULL); e->_n = GC::gc()->_heap->_roots; if (GC::gc()->_heap->_roots) GC::gc()->_heap->_roots->_p = e; GC::gc()->_heap->_roots = e; } void GC::removeKeepAlive(KeepAlive* e) { if (e->_p) { e->_p->_n = e->_n; } else { assert(GC::gc()->_heap->_roots==e); GC::gc()->_heap->_roots = e->_n; } if (e->_n) { e->_n->_p = e->_p; } } KeepAlive::KeepAlive(Expression* e) : _e(e), _p(NULL), _n(NULL) { if (_e) GC::gc()->addKeepAlive(this); } KeepAlive::~KeepAlive(void) { if (_e) GC::gc()->removeKeepAlive(this); } KeepAlive::KeepAlive(const KeepAlive& e) : _e(e._e), _p(NULL), _n(NULL) { if (_e) GC::gc()->addKeepAlive(this); } KeepAlive& KeepAlive::operator =(const KeepAlive& e) { if (_e) { if (e._e==NULL) GC::gc()->removeKeepAlive(this); } else { if (e._e!=NULL) GC::gc()->addKeepAlive(this); } _e = e._e; return *this; } void GC::addWeakRef(WeakRef* e) { assert(e->_p==NULL); assert(e->_n==NULL); e->_n = GC::gc()->_heap->_weakRefs; if (GC::gc()->_heap->_weakRefs) GC::gc()->_heap->_weakRefs->_p = e; GC::gc()->_heap->_weakRefs = e; } void GC::removeWeakRef(MiniZinc::WeakRef *e) { if (e->_p) { e->_p->_n = e->_n; } else { assert(GC::gc()->_heap->_weakRefs==e); GC::gc()->_heap->_weakRefs = e->_n; } if (e->_n) { e->_n->_p = e->_p; } } WeakRef::WeakRef(Expression* e) : _e(e), _p(NULL), _n(NULL), _valid(true) { if (_e) GC::gc()->addWeakRef(this); } WeakRef::~WeakRef(void) { if (_e || !_valid) GC::gc()->removeWeakRef(this); } WeakRef::WeakRef(const WeakRef& e) : _e(e()), _p(NULL), _n(NULL), _valid(true) { if (_e) GC::gc()->addWeakRef(this); } WeakRef& WeakRef::operator =(const WeakRef& e) { if (_e || !_valid) { if (e()==NULL) { GC::gc()->removeWeakRef(this); _n = _p = NULL; } } else { if (e()!=NULL) GC::gc()->addWeakRef(this); } _e = e(); _valid = true; return *this; } } libminizinc-2.0.11/lib/model.cpp0000644000175000017500000002225412646030173015121 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #include #include #include #undef MZN_DEBUG_FUNCTION_REGISTRY namespace MiniZinc { Model::Model(void) : _parent(NULL), _solveItem(NULL), _outputItem(NULL), _failed(false) { GC::add(this); } Model::~Model(void) { for (unsigned int j=0; j<_items.size(); j++) { Item* i = _items[j]; if (IncludeI* ii = i->dyn_cast()) { if (ii->own() && ii->m()) { delete ii->m(); ii->m(NULL); } } } GC::remove(this); } VarDeclIterator Model::begin_vardecls(void) { return VarDeclIterator(this, begin()); } VarDeclIterator Model::end_vardecls(void) { return VarDeclIterator(this, end()); } ConstraintIterator Model::begin_constraints(void) { return ConstraintIterator(this, begin()); } ConstraintIterator Model::end_constraints(void) { return ConstraintIterator(this, end()); } SolveI* Model::solveItem() { return _solveItem; } OutputI* Model::outputItem() { return _outputItem; } void Model::registerFn(EnvI& env, FunctionI* fi) { Model* m = this; while (m->_parent) m = m->_parent; FnMap::iterator i_id = m->fnmap.find(fi->id()); if (i_id == m->fnmap.end()) { // new element std::vector v; v.push_back(fi); m->fnmap.insert(std::pair >(fi->id(),v)); } else { // add to list of existing elements std::vector& v = i_id->second; for (unsigned int i=0; iparams().size() == fi->params().size()) { bool alleq=true; for (unsigned int j=0; jparams().size(); j++) { if (v[i]->params()[j]->type() != fi->params()[j]->type()) { alleq=false; break; } } if (alleq) { if (v[i]->e() && fi->e()) { throw TypeError(env, fi->loc(), "function with the same type already defined in " +v[i]->loc().toString()); } else { if (fi->e()) v[i] = fi; return; } } } } v.push_back(fi); } } FunctionI* Model::matchFn(EnvI& env, const ASTString& id, const std::vector& t) { if (id==constants().var_redef->id()) return constants().var_redef; Model* m = this; while (m->_parent) m = m->_parent; FnMap::iterator i_id = m->fnmap.find(id); if (i_id == m->fnmap.end()) { return NULL; } std::vector& v = i_id->second; for (unsigned int i=0; iparams().size() == t.size()) { bool match=true; for (unsigned int j=0; jparams()[j]->type())) { #ifdef MZN_DEBUG_FUNCTION_REGISTRY std::cerr << t[j].toString() << " does not match " << fi->params()[j]->type().toString() << "\n"; #endif match=false; break; } } if (match) { return fi; } } } return NULL; } namespace { class FunSort { public: bool operator()(FunctionI* x, FunctionI* y) const { if (x->params().size() < y->params().size()) return true; if (x->params().size() == y->params().size()) { for (unsigned int i=0; iparams().size(); i++) { switch (x->params()[i]->type().cmp(y->params()[i]->type())) { case -1: return true; case 1: return false; } } } return false; } }; } void Model::sortFn(void) { Model* m = this; while (m->_parent) m = m->_parent; FunSort funsort; for (FnMap::iterator it=m->fnmap.begin(); it!=m->fnmap.end(); ++it) { std::sort(it->second.begin(),it->second.end(),funsort); } } FunctionI* Model::matchFn(EnvI& env, const ASTString& id, const std::vector& args) const { if (id==constants().var_redef->id()) return constants().var_redef; const Model* m = this; while (m->_parent) m = m->_parent; FnMap::const_iterator it = m->fnmap.find(id); if (it == m->fnmap.end()) { return NULL; } const std::vector& v = it->second; std::vector matched; Expression* botarg = NULL; for (unsigned int i=0; iparams().size() == args.size()) { bool match=true; for (unsigned int j=0; jtype().isSubtypeOf(fi->params()[j]->type())) { #ifdef MZN_DEBUG_FUNCTION_REGISTRY std::cerr << args[j]->type().toString() << " does not match " << fi->params()[j]->type().toString() << "\n"; #endif match=false; break; } if (args[j]->type().isbot() && fi->params()[j]->type().bt()!=Type::BT_TOP) { botarg = args[j]; } } if (match) { if (botarg) matched.push_back(fi); else return fi; } } } if (matched.empty()) return NULL; if (matched.size()==1) return matched[0]; Type t = matched[0]->ti()->type(); t.ti(Type::TI_PAR); for (unsigned int i=1; iti()->type())) throw TypeError(env, botarg->loc(), "ambiguous overloading on return type of function"); } return matched[0]; } FunctionI* Model::matchFn(EnvI& env, Call* c) const { if (c->id()==constants().var_redef->id()) return constants().var_redef; const Model* m = this; while (m->_parent) m = m->_parent; FnMap::const_iterator it = m->fnmap.find(c->id()); if (it == m->fnmap.end()) { return NULL; } const std::vector& v = it->second; std::vector matched; Expression* botarg = NULL; for (unsigned int i=0; iparams().size() == c->args().size()) { bool match=true; for (unsigned int j=0; jargs().size(); j++) { if (!c->args()[j]->type().isSubtypeOf(fi->params()[j]->type())) { #ifdef MZN_DEBUG_FUNCTION_REGISTRY std::cerr << c->args()[j]->type().toString() << " does not match " << fi->params()[j]->type().toString() << "\n"; std::cerr << "Wrong argument is " << *c->args()[j]; #endif match=false; break; } if (c->args()[j]->type().isbot() && fi->params()[j]->type().bt()!=Type::BT_TOP) { botarg = c->args()[j]; } } if (match) { if (botarg) matched.push_back(fi); else return fi; } } } if (matched.empty()) return NULL; if (matched.size()==1) return matched[0]; Type t = matched[0]->ti()->type(); t.ti(Type::TI_PAR); for (unsigned int i=1; iti()->type())) throw TypeError(env, botarg->loc(), "ambiguous overloading on return type of function"); } return matched[0]; } Item*& Model::operator[] (int i) { assert(i < _items.size()); return _items[i]; } const Item* Model::operator[] (int i) const { assert(i < _items.size()); return _items[i]; } unsigned int Model::size(void) const { return _items.size(); } std::vector::iterator Model::begin(void) { return _items.begin(); } std::vector::const_iterator Model::begin(void) const { return _items.begin(); } std::vector::iterator Model::end(void) { return _items.end(); } std::vector::const_iterator Model::end(void) const { return _items.end(); } void Model::compact(void) { struct { bool operator() (const Item* i) { return i->removed(); }} isremoved; _items.erase(remove_if(_items.begin(),_items.end(),isremoved), _items.end()); } void Model::fail(EnvI& env) { if (!_failed) { env.addWarning("model inconsistency detected"); _failed = true; for (unsigned int i=0; i<_items.size(); i++) if (ConstraintI* ci = _items[i]->dyn_cast()) ci->remove(); ConstraintI* failedConstraint = new ConstraintI(Location().introduce(),constants().lit_false); _items.push_back(failedConstraint); } } bool Model::failed() const { return _failed; } } libminizinc-2.0.11/lib/cached/0000755000175000017500000000000012646030173014517 5ustar kaolkaollibminizinc-2.0.11/lib/cached/md5_cached.cmake0000644000175000017500000000017212646030173017475 0ustar kaolkaolset(lexer_lxx_md5_cached "2519048554e50060cca5b436e2a13f8c") set(parser_yxx_md5_cached "4b0375f16b4d31f327b87e33613f64bd")libminizinc-2.0.11/lib/cached/minizinc/0000755000175000017500000000000012646030173016337 5ustar kaolkaollibminizinc-2.0.11/lib/cached/minizinc/parser.tab.hh0000644000175000017500000002224112646030173020722 0ustar kaolkaol/* A Bison parser, made by GNU Bison 2.3. */ /* Skeleton interface for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { END = 0, MZN_INTEGER_LITERAL = 258, MZN_BOOL_LITERAL = 259, MZN_FLOAT_LITERAL = 260, MZN_IDENTIFIER = 261, MZN_QUOTED_IDENTIFIER = 262, MZN_STRING_LITERAL = 263, MZN_STRING_QUOTE_START = 264, MZN_STRING_QUOTE_MID = 265, MZN_STRING_QUOTE_END = 266, MZN_TI_IDENTIFIER = 267, MZN_DOC_COMMENT = 268, MZN_DOC_FILE_COMMENT = 269, MZN_VAR = 270, MZN_PAR = 271, MZN_ABSENT = 272, MZN_ANN = 273, MZN_ANNOTATION = 274, MZN_ANY = 275, MZN_ARRAY = 276, MZN_BOOL = 277, MZN_CASE = 278, MZN_CONSTRAINT = 279, MZN_DEFAULT = 280, MZN_ELSE = 281, MZN_ELSEIF = 282, MZN_ENDIF = 283, MZN_ENUM = 284, MZN_FLOAT = 285, MZN_FUNCTION = 286, MZN_IF = 287, MZN_INCLUDE = 288, MZN_INFINITY = 289, MZN_INT = 290, MZN_LET = 291, MZN_LIST = 292, MZN_MAXIMIZE = 293, MZN_MINIMIZE = 294, MZN_OF = 295, MZN_OPT = 296, MZN_SATISFY = 297, MZN_OUTPUT = 298, MZN_PREDICATE = 299, MZN_RECORD = 300, MZN_SET = 301, MZN_SOLVE = 302, MZN_STRING = 303, MZN_TEST = 304, MZN_THEN = 305, MZN_TUPLE = 306, MZN_TYPE = 307, MZN_UNDERSCORE = 308, MZN_VARIANT_RECORD = 309, MZN_WHERE = 310, MZN_LEFT_BRACKET = 311, MZN_LEFT_2D_BRACKET = 312, MZN_RIGHT_BRACKET = 313, MZN_RIGHT_2D_BRACKET = 314, FLATZINC_IDENTIFIER = 315, MZN_INVALID_INTEGER_LITERAL = 316, MZN_INVALID_FLOAT_LITERAL = 317, MZN_UNTERMINATED_STRING = 318, MZN_INVALID_NULL = 319, MZN_EQUIV = 320, MZN_IMPL = 321, MZN_RIMPL = 322, MZN_OR = 323, MZN_XOR = 324, MZN_AND = 325, MZN_LE = 326, MZN_GR = 327, MZN_LQ = 328, MZN_GQ = 329, MZN_EQ = 330, MZN_NQ = 331, MZN_IN = 332, MZN_SUBSET = 333, MZN_SUPERSET = 334, MZN_UNION = 335, MZN_DIFF = 336, MZN_SYMDIFF = 337, MZN_DOTDOT = 338, MZN_PLUS = 339, MZN_MINUS = 340, MZN_MULT = 341, MZN_DIV = 342, MZN_IDIV = 343, MZN_MOD = 344, MZN_INTERSECT = 345, MZN_NOT = 346, MZN_PLUSPLUS = 347, MZN_COLONCOLON = 348, PREC_ANNO = 349, MZN_EQUIV_QUOTED = 350, MZN_IMPL_QUOTED = 351, MZN_RIMPL_QUOTED = 352, MZN_OR_QUOTED = 353, MZN_XOR_QUOTED = 354, MZN_AND_QUOTED = 355, MZN_LE_QUOTED = 356, MZN_GR_QUOTED = 357, MZN_LQ_QUOTED = 358, MZN_GQ_QUOTED = 359, MZN_EQ_QUOTED = 360, MZN_NQ_QUOTED = 361, MZN_IN_QUOTED = 362, MZN_SUBSET_QUOTED = 363, MZN_SUPERSET_QUOTED = 364, MZN_UNION_QUOTED = 365, MZN_DIFF_QUOTED = 366, MZN_SYMDIFF_QUOTED = 367, MZN_DOTDOT_QUOTED = 368, MZN_PLUS_QUOTED = 369, MZN_MINUS_QUOTED = 370, MZN_MULT_QUOTED = 371, MZN_DIV_QUOTED = 372, MZN_IDIV_QUOTED = 373, MZN_MOD_QUOTED = 374, MZN_INTERSECT_QUOTED = 375, MZN_NOT_QUOTED = 376, MZN_COLONCOLON_QUOTED = 377, MZN_PLUSPLUS_QUOTED = 378 }; #endif /* Tokens. */ #define END 0 #define MZN_INTEGER_LITERAL 258 #define MZN_BOOL_LITERAL 259 #define MZN_FLOAT_LITERAL 260 #define MZN_IDENTIFIER 261 #define MZN_QUOTED_IDENTIFIER 262 #define MZN_STRING_LITERAL 263 #define MZN_STRING_QUOTE_START 264 #define MZN_STRING_QUOTE_MID 265 #define MZN_STRING_QUOTE_END 266 #define MZN_TI_IDENTIFIER 267 #define MZN_DOC_COMMENT 268 #define MZN_DOC_FILE_COMMENT 269 #define MZN_VAR 270 #define MZN_PAR 271 #define MZN_ABSENT 272 #define MZN_ANN 273 #define MZN_ANNOTATION 274 #define MZN_ANY 275 #define MZN_ARRAY 276 #define MZN_BOOL 277 #define MZN_CASE 278 #define MZN_CONSTRAINT 279 #define MZN_DEFAULT 280 #define MZN_ELSE 281 #define MZN_ELSEIF 282 #define MZN_ENDIF 283 #define MZN_ENUM 284 #define MZN_FLOAT 285 #define MZN_FUNCTION 286 #define MZN_IF 287 #define MZN_INCLUDE 288 #define MZN_INFINITY 289 #define MZN_INT 290 #define MZN_LET 291 #define MZN_LIST 292 #define MZN_MAXIMIZE 293 #define MZN_MINIMIZE 294 #define MZN_OF 295 #define MZN_OPT 296 #define MZN_SATISFY 297 #define MZN_OUTPUT 298 #define MZN_PREDICATE 299 #define MZN_RECORD 300 #define MZN_SET 301 #define MZN_SOLVE 302 #define MZN_STRING 303 #define MZN_TEST 304 #define MZN_THEN 305 #define MZN_TUPLE 306 #define MZN_TYPE 307 #define MZN_UNDERSCORE 308 #define MZN_VARIANT_RECORD 309 #define MZN_WHERE 310 #define MZN_LEFT_BRACKET 311 #define MZN_LEFT_2D_BRACKET 312 #define MZN_RIGHT_BRACKET 313 #define MZN_RIGHT_2D_BRACKET 314 #define FLATZINC_IDENTIFIER 315 #define MZN_INVALID_INTEGER_LITERAL 316 #define MZN_INVALID_FLOAT_LITERAL 317 #define MZN_UNTERMINATED_STRING 318 #define MZN_INVALID_NULL 319 #define MZN_EQUIV 320 #define MZN_IMPL 321 #define MZN_RIMPL 322 #define MZN_OR 323 #define MZN_XOR 324 #define MZN_AND 325 #define MZN_LE 326 #define MZN_GR 327 #define MZN_LQ 328 #define MZN_GQ 329 #define MZN_EQ 330 #define MZN_NQ 331 #define MZN_IN 332 #define MZN_SUBSET 333 #define MZN_SUPERSET 334 #define MZN_UNION 335 #define MZN_DIFF 336 #define MZN_SYMDIFF 337 #define MZN_DOTDOT 338 #define MZN_PLUS 339 #define MZN_MINUS 340 #define MZN_MULT 341 #define MZN_DIV 342 #define MZN_IDIV 343 #define MZN_MOD 344 #define MZN_INTERSECT 345 #define MZN_NOT 346 #define MZN_PLUSPLUS 347 #define MZN_COLONCOLON 348 #define PREC_ANNO 349 #define MZN_EQUIV_QUOTED 350 #define MZN_IMPL_QUOTED 351 #define MZN_RIMPL_QUOTED 352 #define MZN_OR_QUOTED 353 #define MZN_XOR_QUOTED 354 #define MZN_AND_QUOTED 355 #define MZN_LE_QUOTED 356 #define MZN_GR_QUOTED 357 #define MZN_LQ_QUOTED 358 #define MZN_GQ_QUOTED 359 #define MZN_EQ_QUOTED 360 #define MZN_NQ_QUOTED 361 #define MZN_IN_QUOTED 362 #define MZN_SUBSET_QUOTED 363 #define MZN_SUPERSET_QUOTED 364 #define MZN_UNION_QUOTED 365 #define MZN_DIFF_QUOTED 366 #define MZN_SYMDIFF_QUOTED 367 #define MZN_DOTDOT_QUOTED 368 #define MZN_PLUS_QUOTED 369 #define MZN_MINUS_QUOTED 370 #define MZN_MULT_QUOTED 371 #define MZN_DIV_QUOTED 372 #define MZN_IDIV_QUOTED 373 #define MZN_MOD_QUOTED 374 #define MZN_INTERSECT_QUOTED 375 #define MZN_NOT_QUOTED 376 #define MZN_COLONCOLON_QUOTED 377 #define MZN_PLUSPLUS_QUOTED 378 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { long long int iValue; char* sValue; bool bValue; double dValue; MiniZinc::Item* item; MiniZinc::VarDecl* vardeclexpr; std::vector* vardeclexpr_v; MiniZinc::TypeInst* tiexpr; std::vector* tiexpr_v; MiniZinc::Expression* expression; std::vector* expression_v; std::vector >* expression_vv; std::vector > >* expression_vvv; MiniZinc::Generator* generator; std::vector* generator_v; std::vector* string_v; std::pair, MiniZinc::Expression*>* expression_p; MiniZinc::Generators* generators; } /* Line 1529 of yacc.c. */ YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; } YYLTYPE; # define yyltype YYLTYPE /* obsolescent; will be withdrawn */ # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif libminizinc-2.0.11/lib/cached/lexer.yy.cpp0000644000175000017500000030524112646030173017007 0ustar kaolkaol #line 3 "/Users/tack/Programming/MiniZinc/libmzn/build_xcode/lexer.yy.cpp" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 35 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; typedef uint64_t flex_uint64_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ /* C99 requires __STDC__ to be defined as 1. */ #if defined (__STDC__) #define YY_USE_CONST #endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yyg->yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yyg->yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ,yyscanner ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = yyg->yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] void yyrestart (FILE *input_file ,yyscan_t yyscanner ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); void yypop_buffer_state (yyscan_t yyscanner ); static void yyensure_buffer_stack (yyscan_t yyscanner ); static void yy_load_buffer_state (yyscan_t yyscanner ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner ); void *yyalloc (yy_size_t ,yyscan_t yyscanner ); void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); void yyfree (void * ,yyscan_t yyscanner ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define yywrap(n) 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; typedef int yy_state_type; #define yytext_ptr yytext_r static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); static int yy_get_next_buffer (yyscan_t yyscanner ); static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ yyleng = (yy_size_t) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; #define YY_NUM_RULES 171 #define YY_END_OF_BUFFER 172 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[471] = { 0, 0, 0, 159, 159, 159, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 170, 3, 2, 170, 158, 170, 23, 170, 155, 102, 98, 32, 100, 32, 104, 26, 26, 32, 109, 119, 113, 135, 19, 170, 21, 36, 170, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 32, 170, 170, 170, 1, 159, 171, 168, 166, 168, 1, 167, 168, 16, 18, 17, 1, 6, 8, 7, 1, 11, 13, 12, 1, 156, 157, 121, 154, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 123, 33, 14, 131, 0, 26, 0, 0, 0, 35, 125, 111, 108, 117, 115, 135, 20, 129, 136, 0, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 55, 60, 135, 135, 135, 135, 135, 135, 71, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 22, 133, 143, 0, 0, 0, 0, 159, 163, 162, 164, 162, 160, 161, 165, 16, 15, 6, 5, 11, 10, 154, 0, 103, 99, 0, 101, 0, 0, 105, 0, 110, 0, 0, 120, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 29, 0, 31, 28, 27, 127, 136, 0, 169, 37, 39, 135, 135, 135, 135, 135, 135, 45, 135, 135, 135, 135, 135, 135, 135, 135, 62, 63, 135, 135, 135, 67, 69, 73, 135, 74, 135, 135, 135, 78, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 93, 135, 96, 144, 145, 146, 137, 138, 139, 142, 147, 148, 153, 152, 149, 150, 151, 140, 141, 122, 107, 124, 34, 132, 126, 0, 112, 118, 116, 130, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 134, 9, 0, 135, 135, 41, 42, 135, 135, 47, 49, 135, 52, 135, 135, 135, 135, 135, 135, 64, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 87, 88, 24, 135, 90, 135, 135, 135, 128, 0, 46, 0, 68, 70, 0, 0, 0, 0, 97, 0, 30, 135, 40, 135, 135, 135, 51, 25, 53, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 79, 135, 135, 135, 135, 89, 91, 135, 95, 48, 0, 0, 0, 0, 0, 135, 135, 135, 50, 135, 135, 135, 135, 135, 135, 72, 135, 76, 135, 80, 81, 135, 135, 135, 0, 0, 0, 0, 92, 135, 135, 44, 135, 56, 135, 135, 135, 135, 135, 77, 135, 85, 135, 0, 82, 0, 0, 135, 135, 54, 57, 135, 65, 66, 135, 83, 135, 0, 0, 86, 135, 135, 58, 75, 135, 0, 84, 38, 43, 135, 59, 135, 135, 135, 94, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6, 1, 7, 8, 1, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 19, 19, 19, 19, 19, 20, 20, 21, 14, 22, 23, 24, 1, 1, 25, 25, 25, 25, 26, 25, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 29, 30, 1, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 27, 27, 42, 43, 44, 45, 46, 27, 47, 48, 49, 50, 51, 52, 53, 54, 55, 14, 56, 14, 57, 1, 58, 1, 1, 59, 1, 1, 60, 61, 62, 63, 64, 1, 1, 1, 1, 1, 65, 1, 66, 1, 67, 1, 1, 1, 1, 1, 1, 1, 1, 1, 68, 1, 69, 1, 1, 1, 70, 71, 1, 72, 73, 74, 75, 1, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 77, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 78, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[80] = { 0, 1, 1, 2, 3, 1, 3, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 1, 1, 6, 6, 6, 1, 3, 1, 5, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 } ; static yyconst flex_int16_t yy_base[487] = { 0, 0, 0, 77, 81, 85, 89, 87, 91, 93, 95, 97, 99, 619, 618, 617, 616, 626, 631, 631, 631, 602, 631, 0, 0, 174, 631, 631, 611, 631, 599, 606, 92, 97, 106, 600, 104, 597, 596, 0, 562, 600, 631, 0, 0, 86, 571, 75, 45, 87, 102, 101, 60, 108, 570, 108, 104, 577, 155, 176, 569, 579, 571, 565, 579, 150, 532, 120, 631, 0, 631, 631, 631, 219, 631, 631, 226, 0, 631, 590, 0, 0, 631, 589, 0, 0, 631, 588, 0, 631, 631, 631, 0, 0, 581, 594, 127, 184, 586, 138, 146, 148, 172, 584, 559, 555, 553, 552, 152, 552, 550, 226, 631, 631, 631, 582, 631, 201, 224, 238, 193, 246, 631, 569, 631, 631, 631, 631, 0, 631, 631, 0, 560, 94, 544, 545, 541, 544, 549, 156, 538, 149, 543, 539, 539, 0, 224, 533, 533, 527, 535, 542, 528, 0, 527, 526, 527, 536, 537, 522, 521, 527, 521, 199, 524, 518, 528, 514, 517, 516, 520, 513, 522, 511, 631, 631, 631, 211, 227, 221, 186, 0, 631, 631, 631, 631, 631, 631, 631, 0, 631, 0, 631, 0, 631, 0, 548, 631, 631, 547, 631, 546, 545, 631, 544, 631, 228, 543, 631, 542, 631, 541, 540, 163, 225, 512, 498, 259, 503, 504, 497, 534, 530, 278, 288, 291, 269, 294, 631, 0, 509, 631, 495, 0, 506, 496, 500, 488, 502, 496, 0, 496, 491, 488, 482, 496, 493, 485, 485, 488, 0, 475, 482, 481, 0, 0, 0, 475, 0, 484, 474, 477, 0, 466, 475, 467, 477, 477, 463, 467, 473, 467, 471, 462, 465, 458, 0, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 495, 631, 631, 631, 631, 465, 493, 631, 464, 491, 490, 450, 460, 460, 450, 485, 631, 631, 303, 444, 438, 0, 0, 442, 440, 0, 448, 450, 0, 450, 437, 436, 434, 439, 435, 0, 438, 437, 429, 437, 430, 428, 438, 430, 436, 425, 430, 0, 0, 0, 433, 0, 425, 435, 430, 631, 457, 631, 418, 631, 631, 427, 416, 421, 417, 631, 306, 315, 427, 0, 412, 416, 419, 0, 0, 0, 415, 419, 413, 405, 411, 410, 401, 414, 412, 409, 0, 407, 396, 396, 405, 0, 0, 398, 0, 631, 393, 391, 391, 400, 428, 387, 402, 385, 0, 388, 395, 382, 393, 374, 373, 0, 394, 0, 372, 0, 0, 388, 386, 374, 385, 412, 383, 381, 631, 377, 376, 0, 372, 0, 361, 379, 376, 375, 362, 0, 361, 0, 378, 373, 631, 348, 386, 345, 344, 0, 0, 334, 0, 0, 344, 0, 328, 325, 356, 631, 273, 254, 0, 0, 257, 260, 631, 0, 0, 232, 631, 215, 207, 141, 0, 631, 335, 342, 349, 356, 169, 363, 366, 153, 106, 372, 379, 386, 393, 396, 398, 400 } ; static yyconst flex_int16_t yy_def[487] = { 0, 470, 1, 471, 471, 471, 471, 472, 472, 473, 473, 474, 474, 1, 1, 1, 1, 470, 470, 470, 470, 470, 470, 475, 476, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 477, 470, 470, 470, 478, 479, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 470, 470, 470, 470, 470, 480, 470, 470, 470, 470, 470, 470, 470, 481, 470, 470, 481, 482, 470, 470, 482, 483, 470, 470, 483, 470, 470, 470, 484, 476, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 477, 470, 470, 485, 486, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 470, 470, 470, 470, 470, 470, 470, 480, 470, 470, 470, 470, 470, 470, 470, 481, 470, 482, 470, 483, 470, 484, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 485, 486, 470, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 470, 470, 470, 470, 470, 470, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 470, 470, 470, 470, 470, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 470, 470, 470, 470, 477, 477, 477, 477, 477, 477, 477, 477, 477, 477, 470, 470, 470, 477, 477, 477, 477, 477, 470, 470, 477, 477, 477, 470, 477, 477, 477, 477, 0, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470 } ; static yyconst flex_int16_t yy_nxt[711] = { 0, 18, 19, 20, 19, 21, 22, 23, 24, 25, 26, 18, 27, 28, 29, 30, 31, 32, 33, 34, 34, 35, 36, 37, 38, 39, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 39, 39, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 39, 39, 64, 65, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 66, 67, 68, 70, 71, 138, 72, 70, 71, 139, 72, 70, 71, 78, 75, 70, 71, 78, 75, 82, 147, 82, 79, 86, 148, 86, 79, 115, 83, 73, 83, 136, 87, 73, 87, 132, 117, 76, 118, 118, 118, 76, 123, 137, 116, 117, 119, 118, 118, 118, 124, 125, 140, 133, 141, 119, 134, 119, 142, 198, 156, 232, 145, 199, 149, 120, 119, 143, 146, 153, 203, 233, 150, 121, 157, 144, 151, 154, 205, 74, 208, 155, 131, 74, 206, 175, 175, 74, 175, 80, 204, 74, 207, 80, 209, 84, 175, 84, 92, 88, 469, 88, 94, 177, 210, 178, 179, 180, 242, 95, 96, 159, 97, 98, 99, 160, 200, 239, 211, 100, 101, 102, 243, 161, 304, 217, 103, 162, 163, 218, 240, 201, 164, 104, 226, 226, 165, 305, 105, 166, 106, 107, 223, 223, 223, 108, 167, 109, 182, 168, 110, 183, 184, 169, 111, 182, 265, 306, 183, 188, 298, 221, 221, 117, 221, 118, 118, 118, 266, 291, 292, 185, 221, 119, 224, 299, 224, 468, 185, 225, 225, 225, 247, 467, 119, 248, 186, 227, 227, 227, 466, 187, 465, 186, 227, 227, 249, 307, 187, 277, 278, 279, 227, 227, 227, 227, 227, 227, 280, 281, 226, 226, 282, 288, 289, 290, 310, 464, 283, 223, 223, 223, 284, 285, 286, 287, 463, 317, 311, 225, 225, 225, 225, 225, 225, 227, 227, 227, 317, 365, 462, 365, 227, 227, 366, 366, 366, 366, 366, 366, 227, 227, 227, 227, 227, 227, 366, 366, 366, 69, 69, 69, 69, 69, 69, 69, 77, 77, 77, 77, 77, 77, 77, 81, 81, 81, 81, 81, 81, 81, 85, 85, 85, 85, 85, 85, 85, 93, 461, 93, 93, 93, 93, 93, 128, 128, 181, 460, 459, 181, 181, 181, 181, 189, 458, 189, 457, 189, 189, 189, 191, 456, 191, 455, 191, 191, 191, 193, 454, 193, 453, 193, 193, 193, 195, 195, 229, 229, 230, 230, 230, 452, 451, 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, 440, 439, 438, 437, 436, 435, 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, 398, 397, 396, 395, 394, 393, 392, 391, 390, 389, 388, 387, 386, 385, 384, 383, 382, 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, 370, 369, 368, 367, 364, 363, 362, 361, 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324, 323, 322, 321, 320, 319, 318, 231, 316, 315, 314, 313, 312, 309, 308, 303, 302, 301, 300, 297, 296, 295, 294, 293, 276, 275, 274, 273, 272, 271, 270, 269, 268, 267, 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 246, 245, 244, 241, 238, 237, 236, 235, 234, 231, 228, 222, 220, 219, 216, 215, 214, 213, 212, 202, 197, 196, 194, 192, 190, 176, 174, 173, 172, 171, 170, 158, 152, 135, 130, 129, 127, 126, 122, 114, 113, 112, 91, 470, 90, 90, 89, 89, 17, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470 } ; static yyconst flex_int16_t yy_chk[711] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 48, 3, 4, 4, 48, 4, 5, 5, 7, 5, 6, 6, 8, 6, 9, 52, 10, 7, 11, 52, 12, 8, 32, 9, 3, 10, 47, 11, 4, 12, 479, 33, 5, 33, 33, 33, 6, 36, 47, 32, 34, 33, 34, 34, 34, 36, 36, 49, 45, 49, 34, 45, 33, 50, 96, 56, 133, 51, 96, 53, 33, 34, 50, 51, 55, 99, 133, 53, 33, 56, 50, 53, 55, 100, 3, 101, 55, 478, 4, 100, 65, 65, 5, 65, 7, 99, 6, 100, 8, 101, 9, 65, 10, 475, 11, 468, 12, 25, 67, 102, 67, 67, 67, 141, 25, 25, 58, 25, 25, 25, 58, 97, 139, 102, 25, 25, 25, 141, 58, 213, 108, 25, 58, 58, 108, 139, 97, 58, 25, 120, 120, 59, 213, 25, 59, 25, 25, 117, 117, 117, 25, 59, 25, 73, 59, 25, 73, 73, 59, 25, 76, 163, 214, 76, 76, 206, 111, 111, 118, 111, 118, 118, 118, 163, 180, 180, 73, 111, 118, 119, 206, 119, 467, 76, 119, 119, 119, 146, 466, 118, 146, 73, 121, 121, 121, 464, 73, 460, 76, 121, 121, 146, 214, 76, 177, 177, 177, 121, 121, 121, 121, 121, 121, 178, 178, 226, 226, 178, 179, 179, 179, 217, 459, 178, 223, 223, 223, 178, 178, 178, 178, 456, 223, 217, 224, 224, 224, 225, 225, 225, 227, 227, 227, 223, 317, 455, 317, 227, 227, 317, 317, 317, 365, 365, 365, 227, 227, 227, 227, 227, 227, 366, 366, 366, 471, 471, 471, 471, 471, 471, 471, 472, 472, 472, 472, 472, 472, 472, 473, 473, 473, 473, 473, 473, 473, 474, 474, 474, 474, 474, 474, 474, 476, 453, 476, 476, 476, 476, 476, 477, 477, 480, 452, 451, 480, 480, 480, 480, 481, 449, 481, 446, 481, 481, 481, 482, 443, 482, 442, 482, 482, 482, 483, 441, 483, 440, 483, 483, 483, 484, 484, 485, 485, 486, 486, 486, 438, 437, 435, 433, 432, 431, 430, 429, 427, 425, 424, 422, 421, 420, 419, 418, 417, 416, 413, 411, 409, 408, 407, 406, 405, 404, 402, 401, 400, 399, 398, 397, 396, 395, 392, 389, 388, 387, 386, 384, 383, 382, 381, 380, 379, 378, 377, 376, 375, 371, 370, 369, 367, 363, 362, 361, 360, 357, 355, 353, 352, 351, 349, 345, 344, 343, 342, 341, 340, 339, 338, 337, 336, 335, 333, 332, 331, 330, 329, 328, 326, 325, 323, 322, 319, 318, 314, 313, 312, 311, 310, 309, 308, 307, 305, 304, 299, 275, 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 261, 260, 259, 257, 253, 252, 251, 249, 248, 247, 246, 245, 244, 243, 242, 241, 239, 238, 237, 236, 235, 234, 232, 230, 222, 221, 220, 219, 218, 216, 215, 212, 211, 209, 207, 204, 202, 201, 199, 196, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 162, 161, 160, 159, 158, 157, 156, 155, 154, 152, 151, 150, 149, 148, 147, 144, 143, 142, 140, 138, 137, 136, 135, 134, 132, 123, 115, 110, 109, 107, 106, 105, 104, 103, 98, 95, 94, 87, 83, 79, 66, 64, 63, 62, 61, 60, 57, 54, 46, 41, 40, 38, 37, 35, 31, 30, 28, 21, 17, 16, 15, 14, 13, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, 470 } ; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #if defined __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wdeprecated" #elif defined _MSC_VER #pragma warning(push, 1) #endif namespace MiniZinc{ class Location; } #define YYLTYPE MiniZinc::Location #define YYLTYPE_IS_DECLARED 1 #define YYLTYPE_IS_TRIVIAL 0 #include int yy_input_proc(char* buf, int size, yyscan_t yyscanner); #define YY_INPUT(buf, result, max_size) \ result = yy_input_proc(buf, max_size, yyscanner); #define YY_USER_ACTION \ { MiniZinc::ParserState* parm = \ static_cast(yyget_extra(yyscanner)); \ yylloc->first_line = yylloc->last_line = parm->lineno; \ } bool strtointval(const char* s, long long int& v) { std::istringstream iss(s); iss >> v; return !iss.fail(); } bool strtofloatval(const char* s, double& v) { std::istringstream iss(s); iss >> v; return !iss.fail(); } void beginToken(void* parm, YYLTYPE* yyloc, char* t) { MiniZinc::ParserState* pp = static_cast(parm); int tokenLength = strlen(t); yyloc->first_column = pp->nTokenNextStart; pp->nTokenNextStart += tokenLength; yyloc->last_column = pp->nTokenNextStart-1; } void clearBuffer(void* parm) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer = ""; } void appendBufferString(void* parm, const char* s) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer += s; } void appendBufferChar(void* parm, char s) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer += s; } char* bufferData(void* parm) { MiniZinc::ParserState* pp = static_cast(parm); return strdup(pp->stringBuffer.c_str()); } #define INITIAL 0 #define string 1 #define string_quote 2 #define multilinecomment 3 #define doccomment 4 #define doccomment_file 5 #define bracket_exp 6 #define quoted_exp 7 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Holds the entire state of the reentrant scanner. */ struct yyguts_t { /* User-defined. Not touched by flex. */ YY_EXTRA_TYPE yyextra_r; /* The rest are the same as the globals declared in the non-reentrant scanner. */ FILE *yyin_r, *yyout_r; size_t yy_buffer_stack_top; /**< index of top of stack. */ size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; yy_size_t yy_n_chars; yy_size_t yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; int yy_did_buffer_switch_on_eof; int yy_start_stack_ptr; int yy_start_stack_depth; int *yy_start_stack; yy_state_type yy_last_accepting_state; char* yy_last_accepting_cpos; int yylineno_r; int yy_flex_debug_r; char *yytext_r; int yy_more_flag; int yy_more_len; YYSTYPE * yylval_r; YYLTYPE * yylloc_r; }; /* end struct yyguts_t */ static int yy_init_globals (yyscan_t yyscanner ); /* This must go here because YYSTYPE and YYLTYPE are included * from bison output in section 1.*/ # define yylval yyg->yylval_r # define yylloc yyg->yylloc_r int yylex_init (yyscan_t* scanner); int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy (yyscan_t yyscanner ); int yyget_debug (yyscan_t yyscanner ); void yyset_debug (int debug_flag ,yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); FILE *yyget_in (yyscan_t yyscanner ); void yyset_in (FILE * in_str ,yyscan_t yyscanner ); FILE *yyget_out (yyscan_t yyscanner ); void yyset_out (FILE * out_str ,yyscan_t yyscanner ); yy_size_t yyget_leng (yyscan_t yyscanner ); char *yyget_text (yyscan_t yyscanner ); int yyget_lineno (yyscan_t yyscanner ); void yyset_lineno (int line_number ,yyscan_t yyscanner ); YYSTYPE * yyget_lval (yyscan_t yyscanner ); void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); YYLTYPE *yyget_lloc (yyscan_t yyscanner ); void yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (yyscan_t yyscanner ); #else extern int yywrap (yyscan_t yyscanner ); #endif #endif static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner ); #else static int input (yyscan_t yyscanner ); #endif #endif static void yy_push_state (int new_state ,yyscan_t yyscanner); static void yy_pop_state (yyscan_t yyscanner ); static int yy_top_state (yyscan_t yyscanner ); /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ yy_size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex \ (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); #define YY_DECL int yylex \ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; yylloc = yylloc_param; if ( !yyg->yy_init ) { yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yyg->yy_start ) yyg->yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); } yy_load_buffer_state(yyscanner ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ *yy_cp = yyg->yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yyg->yy_start; yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 471 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 631 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yyg->yy_hold_char; yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INVALID_NULL; } YY_BREAK case 2: /* rule 2 can match eol */ YY_RULE_SETUP { MiniZinc::ParserState* parm = static_cast( yyget_extra(yyscanner)); parm->lineno++; parm->lineStartPos += parm->nTokenNextStart; parm->nTokenNextStart=1; } YY_BREAK case 3: YY_RULE_SETUP { /* ignore whitespace */ beginToken(yyget_extra(yyscanner), yylloc, yytext); } YY_BREAK case 4: YY_RULE_SETUP { yy_push_state(doccomment,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); clearBuffer(yyget_extra(yyscanner)); } YY_BREAK case 5: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_DOC_COMMENT; } YY_BREAK case 6: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 7: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 8: /* rule 8 can match eol */ YY_RULE_SETUP { MiniZinc::ParserState* parm = static_cast( yyget_extra(yyscanner)); parm->lineno++; parm->lineStartPos += parm->nTokenNextStart; parm->nTokenNextStart=1; appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 9: YY_RULE_SETUP { yy_push_state(doccomment_file,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); clearBuffer(yyget_extra(yyscanner)); } YY_BREAK case 10: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_DOC_FILE_COMMENT; } YY_BREAK case 11: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 12: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 13: /* rule 13 can match eol */ YY_RULE_SETUP { MiniZinc::ParserState* parm = static_cast( yyget_extra(yyscanner)); parm->lineno++; parm->lineStartPos += parm->nTokenNextStart; parm->nTokenNextStart=1; appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 14: YY_RULE_SETUP { yy_push_state(multilinecomment,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); } YY_BREAK case 15: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yy_pop_state(yyscanner); } YY_BREAK case 16: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); } YY_BREAK case 17: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); } YY_BREAK case 18: /* rule 18 can match eol */ YY_RULE_SETUP { MiniZinc::ParserState* parm = static_cast( yyget_extra(yyscanner)); parm->lineno++; parm->lineStartPos += parm->nTokenNextStart; parm->nTokenNextStart=1; } YY_BREAK case 19: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LEFT_BRACKET; } YY_BREAK case 20: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LEFT_2D_BRACKET; } YY_BREAK case 21: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RIGHT_BRACKET; } YY_BREAK case 22: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RIGHT_2D_BRACKET; } YY_BREAK case 23: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); /* ignore comments */ } YY_BREAK case 24: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->iValue = 1; return MZN_BOOL_LITERAL; } YY_BREAK case 25: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->iValue = 0; return MZN_BOOL_LITERAL; } YY_BREAK case 26: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtointval(yytext, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } YY_BREAK case 27: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtointval(yytext, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } YY_BREAK case 28: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtointval(yytext, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } YY_BREAK case 29: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } YY_BREAK case 30: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } YY_BREAK case 31: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); if (strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } YY_BREAK case 32: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return *yytext; } YY_BREAK case 33: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DOTDOT; } YY_BREAK case 34: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DOTDOT_QUOTED; } YY_BREAK case 35: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_COLONCOLON; } YY_BREAK case 36: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_UNDERSCORE; } YY_BREAK case 37: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ANN; } YY_BREAK case 38: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ANNOTATION; } YY_BREAK case 39: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ANY; } YY_BREAK case 40: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ARRAY; } YY_BREAK case 41: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_BOOL; } YY_BREAK case 42: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_CASE; } YY_BREAK case 43: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_CONSTRAINT; } YY_BREAK case 44: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DEFAULT; } YY_BREAK case 45: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IDIV; } YY_BREAK case 46: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IDIV_QUOTED; } YY_BREAK case 47: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DIFF; } YY_BREAK case 48: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DIFF_QUOTED; } YY_BREAK case 49: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ELSE; } YY_BREAK case 50: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ELSEIF; } YY_BREAK case 51: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ENDIF; } YY_BREAK case 52: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ENUM; } YY_BREAK case 53: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_FLOAT; } YY_BREAK case 54: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_FUNCTION; } YY_BREAK case 55: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IF; } YY_BREAK case 56: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INCLUDE; } YY_BREAK case 57: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INFINITY; } YY_BREAK case 58: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INTERSECT; } YY_BREAK case 59: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INTERSECT_QUOTED; } YY_BREAK case 60: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IN; } YY_BREAK case 61: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IN_QUOTED; } YY_BREAK case 62: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_INT; } YY_BREAK case 63: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LET; } YY_BREAK case 64: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LIST; } YY_BREAK case 65: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->bValue = false; return MZN_MAXIMIZE; } YY_BREAK case 66: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->bValue = true; return MZN_MINIMIZE; } YY_BREAK case 67: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MOD; } YY_BREAK case 68: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MOD_QUOTED; } YY_BREAK case 69: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_NOT; } YY_BREAK case 70: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_NOT_QUOTED; } YY_BREAK case 71: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OF; } YY_BREAK case 72: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OUTPUT; } YY_BREAK case 73: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OPT; } YY_BREAK case 74: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PAR; } YY_BREAK case 75: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PREDICATE; } YY_BREAK case 76: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RECORD; } YY_BREAK case 77: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SATISFY; } YY_BREAK case 78: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SET; } YY_BREAK case 79: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SOLVE; } YY_BREAK case 80: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_STRING; } YY_BREAK case 81: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SUBSET; } YY_BREAK case 82: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SUBSET_QUOTED; } YY_BREAK case 83: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SUPERSET; } YY_BREAK case 84: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SUPERSET_QUOTED; } YY_BREAK case 85: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SYMDIFF; } YY_BREAK case 86: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_SYMDIFF_QUOTED; } YY_BREAK case 87: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_TEST; } YY_BREAK case 88: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_THEN; } YY_BREAK case 89: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_TUPLE; } YY_BREAK case 90: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_TYPE; } YY_BREAK case 91: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_UNION; } YY_BREAK case 92: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_UNION_QUOTED; } YY_BREAK case 93: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_VAR; } YY_BREAK case 94: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_VARIANT_RECORD; } YY_BREAK case 95: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_WHERE; } YY_BREAK case 96: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_XOR; } YY_BREAK case 97: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_XOR_QUOTED; } YY_BREAK case 98: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PLUS; } YY_BREAK case 99: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PLUS_QUOTED; } YY_BREAK case 100: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MINUS; } YY_BREAK case 101: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MINUS_QUOTED; } YY_BREAK case 102: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MULT; } YY_BREAK case 103: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_MULT_QUOTED; } YY_BREAK case 104: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DIV; } YY_BREAK case 105: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_DIV_QUOTED; } YY_BREAK case 106: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PLUSPLUS; } YY_BREAK case 107: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_PLUSPLUS_QUOTED; } YY_BREAK case 108: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_ABSENT; } YY_BREAK case 109: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LE; } YY_BREAK case 110: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LE_QUOTED; } YY_BREAK case 111: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LQ; } YY_BREAK case 112: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_LQ_QUOTED; } YY_BREAK case 113: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_GR; } YY_BREAK case 114: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_GR_QUOTED; } YY_BREAK case 115: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_GQ; } YY_BREAK case 116: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_GQ_QUOTED; } YY_BREAK case 117: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQ; } YY_BREAK case 118: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQ_QUOTED; } YY_BREAK case 119: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQ; } YY_BREAK case 120: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQ_QUOTED; } YY_BREAK case 121: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_NQ; } YY_BREAK case 122: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_NQ_QUOTED; } YY_BREAK case 123: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IMPL; } YY_BREAK case 124: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_IMPL_QUOTED; } YY_BREAK case 125: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RIMPL; } YY_BREAK case 126: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_RIMPL_QUOTED; } YY_BREAK case 127: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQUIV; } YY_BREAK case 128: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_EQUIV_QUOTED; } YY_BREAK case 129: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OR; } YY_BREAK case 130: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_OR_QUOTED; } YY_BREAK case 131: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_AND; } YY_BREAK case 132: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_AND_QUOTED; } YY_BREAK case 133: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext); return MZN_QUOTED_IDENTIFIER; } YY_BREAK case 134: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext+1); yylval->sValue[strlen(yytext)-2] = 0; return MZN_IDENTIFIER; } YY_BREAK case 135: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } YY_BREAK case 136: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); MiniZinc::ParserState* parm = static_cast(yyget_extra(yyscanner)); if (parm->isFlatZinc) { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } else { return FLATZINC_IDENTIFIER; } } YY_BREAK case 137: YY_RULE_SETUP { yylval->sValue = strdup("forall"); return MZN_IDENTIFIER; } YY_BREAK case 138: YY_RULE_SETUP { yylval->sValue = strdup("exists"); return MZN_IDENTIFIER; } YY_BREAK case 139: YY_RULE_SETUP { return MZN_IN; } YY_BREAK case 140: YY_RULE_SETUP { return MZN_SUBSET; } YY_BREAK case 141: YY_RULE_SETUP { return MZN_SUPERSET; } YY_BREAK case 142: YY_RULE_SETUP { return MZN_INFINITY; } YY_BREAK case 143: YY_RULE_SETUP { return MZN_NOT; } YY_BREAK case 144: YY_RULE_SETUP { return MZN_RIMPL; } YY_BREAK case 145: YY_RULE_SETUP { return MZN_IMPL; } YY_BREAK case 146: YY_RULE_SETUP { return MZN_EQUIV; } YY_BREAK case 147: YY_RULE_SETUP { return MZN_AND; } YY_BREAK case 148: YY_RULE_SETUP { return MZN_OR; } YY_BREAK case 149: YY_RULE_SETUP { return MZN_NQ; } YY_BREAK case 150: YY_RULE_SETUP { return MZN_LQ; } YY_BREAK case 151: YY_RULE_SETUP { return MZN_GQ; } YY_BREAK case 152: YY_RULE_SETUP { return MZN_UNION; } YY_BREAK case 153: YY_RULE_SETUP { return MZN_INTERSECT; } YY_BREAK case 154: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext+1); return MZN_TI_IDENTIFIER; } YY_BREAK case 155: YY_RULE_SETUP { yy_push_state(bracket_exp,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); return *yytext; } YY_BREAK case 156: YY_RULE_SETUP { yy_pop_state(yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); return *yytext; } YY_BREAK case 157: YY_RULE_SETUP { yy_pop_state(yyscanner); yy_pop_state(yyscanner); yy_push_state(string_quote,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); clearBuffer(yyget_extra(yyscanner)); } YY_BREAK case 158: YY_RULE_SETUP { yy_push_state(string,yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); clearBuffer(yyget_extra(yyscanner)); } YY_BREAK case 159: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 160: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferChar(yyget_extra(yyscanner), '\n'); } YY_BREAK case 161: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferChar(yyget_extra(yyscanner), '\t'); } YY_BREAK case 162: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferChar(yyget_extra(yyscanner), yytext[1]); } YY_BREAK case 163: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); appendBufferChar(yyget_extra(yyscanner), yytext[1]); } YY_BREAK case 164: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_push_state(quoted_exp,yyscanner); return MZN_STRING_QUOTE_START; } YY_BREAK case 165: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_push_state(quoted_exp,yyscanner); return MZN_STRING_QUOTE_MID; } YY_BREAK case 166: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_STRING_LITERAL; } YY_BREAK case 167: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_STRING_QUOTE_END; } YY_BREAK case 168: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return (unsigned char)yytext[0]; } YY_BREAK case YY_STATE_EOF(string): case YY_STATE_EOF(string_quote): { yy_pop_state(yyscanner); beginToken(yyget_extra(yyscanner), yylloc, yytext); return MZN_UNTERMINATED_STRING; } YY_BREAK case 169: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); yylval->sValue = strdup(yytext+1); yylval->sValue[strlen(yytext)-2] = 0; return MZN_QUOTED_IDENTIFIER; } YY_BREAK case 170: YY_RULE_SETUP { beginToken(yyget_extra(yyscanner), yylloc, yytext); return (unsigned char)yytext[0]; } YY_BREAK case 171: YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(multilinecomment): case YY_STATE_EOF(doccomment): case YY_STATE_EOF(doccomment_file): case YY_STATE_EOF(bracket_exp): case YY_STATE_EOF(quoted_exp): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yyg->yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yyg->yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yyg->yy_c_buf_p; goto yy_find_action; } } else switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_END_OF_FILE: { yyg->yy_did_buffer_switch_on_eof = 0; if ( yywrap(yyscanner ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yyg->yy_c_buf_p = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = yyg->yytext_ptr; register int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; else { yy_size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) (yyg->yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { yy_size_t new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), yyg->yy_n_chars, num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } if ( yyg->yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ,yyscanner); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } yyg->yy_n_chars += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { register yy_state_type yy_current_state; register char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 79); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 471 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { register int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ register char *yy_cp = yyg->yy_c_buf_p; register YY_CHAR yy_c = 79; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 471 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 470); return yy_is_jam ? 0 : yy_current_state; } static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) { register char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_cp = yyg->yy_c_buf_p; /* undo effects of setting up yytext */ *yy_cp = yyg->yy_hold_char; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register yy_size_t number_to_move = yyg->yy_n_chars + 2; register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; yyg->yytext_ptr = yy_bp; yyg->yy_hold_char = *yy_cp; yyg->yy_c_buf_p = yy_cp; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) #else static int input (yyscan_t yyscanner) #endif { int c; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; *yyg->yy_c_buf_p = yyg->yy_hold_char; if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) /* This was really a NUL. */ *yyg->yy_c_buf_p = '\0'; else { /* need more input */ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr; ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ,yyscanner); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap(yyscanner ) ) return 0; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(yyscanner); #else return input(yyscanner); #endif } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + offset; break; } } } c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ yyg->yy_hold_char = *++yyg->yy_c_buf_p; return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * @param yyscanner The scanner object. * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); yy_load_buffer_state(yyscanner ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * @param yyscanner The scanner object. */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (yyscanner); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state(yyscanner ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yyg->yy_did_buffer_switch_on_eof = 1; } static void yy_load_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; yyg->yy_hold_char = *yyg->yy_c_buf_p; } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * @param yyscanner The scanner object. * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ,yyscanner); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * @param yyscanner The scanner object. */ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ,yyscanner ); yyfree((void *) b ,yyscanner ); } #ifndef __cplusplus extern int isatty (int ); #endif /* __cplusplus */ /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) { int oerrno = errno; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flush_buffer(b ,yyscanner); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * @param yyscanner The scanner object. */ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state(yyscanner ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * @param yyscanner The scanner object. */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (new_buffer == NULL) return; yyensure_buffer_stack(yyscanner); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state(yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * @param yyscanner The scanner object. */ void yypop_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; if (yyg->yy_buffer_stack_top > 0) --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { yy_load_buffer_state(yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (yyscan_t yyscanner) { yy_size_t num_to_alloc; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!yyg->yy_buffer_stack) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; } if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc (yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ,yyscanner ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * @param yyscanner The scanner object. * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) { return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param bytes the byte buffer to scan * @param len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n, i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) yyalloc(n ,yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ,yyscanner); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } static void yy_push_state (int new_state , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth ) { yy_size_t new_size; yyg->yy_start_stack_depth += YY_START_STACK_INCR; new_size = yyg->yy_start_stack_depth * sizeof( int ); if ( ! yyg->yy_start_stack ) yyg->yy_start_stack = (int *) yyalloc(new_size ,yyscanner ); else yyg->yy_start_stack = (int *) yyrealloc((void *) yyg->yy_start_stack,new_size ,yyscanner ); if ( ! yyg->yy_start_stack ) YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); } yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START; BEGIN(new_state); } static void yy_pop_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( --yyg->yy_start_stack_ptr < 0 ) YY_FATAL_ERROR( "start-condition stack underflow" ); BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]); } static int yy_top_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1]; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ yyg->yy_hold_char = *yyg->yy_c_buf_p; \ *yyg->yy_c_buf_p = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the user-defined data for this scanner. * @param yyscanner The scanner object. */ YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyextra; } /** Get the current line number. * @param yyscanner The scanner object. */ int yyget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yylineno; } /** Get the current column number. * @param yyscanner The scanner object. */ int yyget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yycolumn; } /** Get the input stream. * @param yyscanner The scanner object. */ FILE *yyget_in (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyin; } /** Get the output stream. * @param yyscanner The scanner object. */ FILE *yyget_out (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyout; } /** Get the length of the current token. * @param yyscanner The scanner object. */ yy_size_t yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; } /** Get the current token. * @param yyscanner The scanner object. */ char *yyget_text (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yytext; } /** Set the user-defined data. This data is never touched by the scanner. * @param user_defined The data to be associated with this scanner. * @param yyscanner The scanner object. */ void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyextra = user_defined ; } /** Set the current line number. * @param line_number * @param yyscanner The scanner object. */ void yyset_lineno (int line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner); yylineno = line_number; } /** Set the current column. * @param line_number * @param yyscanner The scanner object. */ void yyset_column (int column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) yy_fatal_error( "yyset_column called with no buffer" , yyscanner); yycolumn = column_no; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * @param yyscanner The scanner object. * @see yy_switch_to_buffer */ void yyset_in (FILE * in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyin = in_str ; } void yyset_out (FILE * out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyout = out_str ; } int yyget_debug (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yy_flex_debug; } void yyset_debug (int bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flex_debug = bdebug ; } /* Accessor methods for yylval and yylloc */ YYSTYPE * yyget_lval (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylval; } void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; } YYLTYPE *yyget_lloc (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylloc; } void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylloc = yylloc_param; } /* User-visible API */ /* yylex_init is special because it creates the scanner itself, so it is * the ONLY reentrant function that doesn't take the scanner as the last argument. * That's why we explicitly handle the declaration, instead of using our macros. */ int yylex_init(yyscan_t* ptr_yy_globals) { if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); return yy_init_globals ( *ptr_yy_globals ); } /* yylex_init_extra has the same functionality as yylex_init, but follows the * convention of taking the scanner as the last argument. Note however, that * this is a *pointer* to a scanner, as it will be allocated by this call (and * is the reason, too, why this function also must handle its own declaration). * The user defined value in the first argument will be available to yyalloc in * the yyextra field. */ int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) { struct yyguts_t dummy_yyguts; yyset_extra (yy_user_defined, &dummy_yyguts); if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); yyset_extra (yy_user_defined, *ptr_yy_globals); return yy_init_globals ( *ptr_yy_globals ); } static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ yyg->yy_buffer_stack = 0; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = (char *) 0; yyg->yy_init = 0; yyg->yy_start = 0; yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = (FILE *) 0; yyout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(yyscanner); } /* Destroy the stack itself. */ yyfree(yyg->yy_buffer_stack ,yyscanner); yyg->yy_buffer_stack = NULL; /* Destroy the start condition stack. */ yyfree(yyg->yy_start_stack ,yyscanner ); yyg->yy_start_stack = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( yyscanner); /* Destroy the main struct (reentrant only). */ yyfree ( yyscanner , yyscanner ); yyscanner = NULL; return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size , yyscan_t yyscanner) { return (void *) malloc( size ); } void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (void * ptr , yyscan_t yyscanner) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" int yy_input_proc(char* buf, int size, yyscan_t yyscanner) { MiniZinc::ParserState* parm = static_cast(yyget_extra(yyscanner)); return parm->fillBuffer(buf, size); // work around warning that yyunput is unused yyunput (0,buf,yyscanner); } libminizinc-2.0.11/lib/cached/parser.tab.cpp0000644000175000017500000060470312646030173017276 0ustar kaolkaol/* A Bison parser, made by GNU Bison 2.3. */ /* Skeleton implementation for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.3" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 1 /* Using locations. */ #define YYLSP_NEEDED 1 /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { END = 0, MZN_INTEGER_LITERAL = 258, MZN_BOOL_LITERAL = 259, MZN_FLOAT_LITERAL = 260, MZN_IDENTIFIER = 261, MZN_QUOTED_IDENTIFIER = 262, MZN_STRING_LITERAL = 263, MZN_STRING_QUOTE_START = 264, MZN_STRING_QUOTE_MID = 265, MZN_STRING_QUOTE_END = 266, MZN_TI_IDENTIFIER = 267, MZN_DOC_COMMENT = 268, MZN_DOC_FILE_COMMENT = 269, MZN_VAR = 270, MZN_PAR = 271, MZN_ABSENT = 272, MZN_ANN = 273, MZN_ANNOTATION = 274, MZN_ANY = 275, MZN_ARRAY = 276, MZN_BOOL = 277, MZN_CASE = 278, MZN_CONSTRAINT = 279, MZN_DEFAULT = 280, MZN_ELSE = 281, MZN_ELSEIF = 282, MZN_ENDIF = 283, MZN_ENUM = 284, MZN_FLOAT = 285, MZN_FUNCTION = 286, MZN_IF = 287, MZN_INCLUDE = 288, MZN_INFINITY = 289, MZN_INT = 290, MZN_LET = 291, MZN_LIST = 292, MZN_MAXIMIZE = 293, MZN_MINIMIZE = 294, MZN_OF = 295, MZN_OPT = 296, MZN_SATISFY = 297, MZN_OUTPUT = 298, MZN_PREDICATE = 299, MZN_RECORD = 300, MZN_SET = 301, MZN_SOLVE = 302, MZN_STRING = 303, MZN_TEST = 304, MZN_THEN = 305, MZN_TUPLE = 306, MZN_TYPE = 307, MZN_UNDERSCORE = 308, MZN_VARIANT_RECORD = 309, MZN_WHERE = 310, MZN_LEFT_BRACKET = 311, MZN_LEFT_2D_BRACKET = 312, MZN_RIGHT_BRACKET = 313, MZN_RIGHT_2D_BRACKET = 314, FLATZINC_IDENTIFIER = 315, MZN_INVALID_INTEGER_LITERAL = 316, MZN_INVALID_FLOAT_LITERAL = 317, MZN_UNTERMINATED_STRING = 318, MZN_INVALID_NULL = 319, MZN_EQUIV = 320, MZN_IMPL = 321, MZN_RIMPL = 322, MZN_OR = 323, MZN_XOR = 324, MZN_AND = 325, MZN_LE = 326, MZN_GR = 327, MZN_LQ = 328, MZN_GQ = 329, MZN_EQ = 330, MZN_NQ = 331, MZN_IN = 332, MZN_SUBSET = 333, MZN_SUPERSET = 334, MZN_UNION = 335, MZN_DIFF = 336, MZN_SYMDIFF = 337, MZN_DOTDOT = 338, MZN_PLUS = 339, MZN_MINUS = 340, MZN_MULT = 341, MZN_DIV = 342, MZN_IDIV = 343, MZN_MOD = 344, MZN_INTERSECT = 345, MZN_NOT = 346, MZN_PLUSPLUS = 347, MZN_COLONCOLON = 348, PREC_ANNO = 349, MZN_EQUIV_QUOTED = 350, MZN_IMPL_QUOTED = 351, MZN_RIMPL_QUOTED = 352, MZN_OR_QUOTED = 353, MZN_XOR_QUOTED = 354, MZN_AND_QUOTED = 355, MZN_LE_QUOTED = 356, MZN_GR_QUOTED = 357, MZN_LQ_QUOTED = 358, MZN_GQ_QUOTED = 359, MZN_EQ_QUOTED = 360, MZN_NQ_QUOTED = 361, MZN_IN_QUOTED = 362, MZN_SUBSET_QUOTED = 363, MZN_SUPERSET_QUOTED = 364, MZN_UNION_QUOTED = 365, MZN_DIFF_QUOTED = 366, MZN_SYMDIFF_QUOTED = 367, MZN_DOTDOT_QUOTED = 368, MZN_PLUS_QUOTED = 369, MZN_MINUS_QUOTED = 370, MZN_MULT_QUOTED = 371, MZN_DIV_QUOTED = 372, MZN_IDIV_QUOTED = 373, MZN_MOD_QUOTED = 374, MZN_INTERSECT_QUOTED = 375, MZN_NOT_QUOTED = 376, MZN_COLONCOLON_QUOTED = 377, MZN_PLUSPLUS_QUOTED = 378 }; #endif /* Tokens. */ #define END 0 #define MZN_INTEGER_LITERAL 258 #define MZN_BOOL_LITERAL 259 #define MZN_FLOAT_LITERAL 260 #define MZN_IDENTIFIER 261 #define MZN_QUOTED_IDENTIFIER 262 #define MZN_STRING_LITERAL 263 #define MZN_STRING_QUOTE_START 264 #define MZN_STRING_QUOTE_MID 265 #define MZN_STRING_QUOTE_END 266 #define MZN_TI_IDENTIFIER 267 #define MZN_DOC_COMMENT 268 #define MZN_DOC_FILE_COMMENT 269 #define MZN_VAR 270 #define MZN_PAR 271 #define MZN_ABSENT 272 #define MZN_ANN 273 #define MZN_ANNOTATION 274 #define MZN_ANY 275 #define MZN_ARRAY 276 #define MZN_BOOL 277 #define MZN_CASE 278 #define MZN_CONSTRAINT 279 #define MZN_DEFAULT 280 #define MZN_ELSE 281 #define MZN_ELSEIF 282 #define MZN_ENDIF 283 #define MZN_ENUM 284 #define MZN_FLOAT 285 #define MZN_FUNCTION 286 #define MZN_IF 287 #define MZN_INCLUDE 288 #define MZN_INFINITY 289 #define MZN_INT 290 #define MZN_LET 291 #define MZN_LIST 292 #define MZN_MAXIMIZE 293 #define MZN_MINIMIZE 294 #define MZN_OF 295 #define MZN_OPT 296 #define MZN_SATISFY 297 #define MZN_OUTPUT 298 #define MZN_PREDICATE 299 #define MZN_RECORD 300 #define MZN_SET 301 #define MZN_SOLVE 302 #define MZN_STRING 303 #define MZN_TEST 304 #define MZN_THEN 305 #define MZN_TUPLE 306 #define MZN_TYPE 307 #define MZN_UNDERSCORE 308 #define MZN_VARIANT_RECORD 309 #define MZN_WHERE 310 #define MZN_LEFT_BRACKET 311 #define MZN_LEFT_2D_BRACKET 312 #define MZN_RIGHT_BRACKET 313 #define MZN_RIGHT_2D_BRACKET 314 #define FLATZINC_IDENTIFIER 315 #define MZN_INVALID_INTEGER_LITERAL 316 #define MZN_INVALID_FLOAT_LITERAL 317 #define MZN_UNTERMINATED_STRING 318 #define MZN_INVALID_NULL 319 #define MZN_EQUIV 320 #define MZN_IMPL 321 #define MZN_RIMPL 322 #define MZN_OR 323 #define MZN_XOR 324 #define MZN_AND 325 #define MZN_LE 326 #define MZN_GR 327 #define MZN_LQ 328 #define MZN_GQ 329 #define MZN_EQ 330 #define MZN_NQ 331 #define MZN_IN 332 #define MZN_SUBSET 333 #define MZN_SUPERSET 334 #define MZN_UNION 335 #define MZN_DIFF 336 #define MZN_SYMDIFF 337 #define MZN_DOTDOT 338 #define MZN_PLUS 339 #define MZN_MINUS 340 #define MZN_MULT 341 #define MZN_DIV 342 #define MZN_IDIV 343 #define MZN_MOD 344 #define MZN_INTERSECT 345 #define MZN_NOT 346 #define MZN_PLUSPLUS 347 #define MZN_COLONCOLON 348 #define PREC_ANNO 349 #define MZN_EQUIV_QUOTED 350 #define MZN_IMPL_QUOTED 351 #define MZN_RIMPL_QUOTED 352 #define MZN_OR_QUOTED 353 #define MZN_XOR_QUOTED 354 #define MZN_AND_QUOTED 355 #define MZN_LE_QUOTED 356 #define MZN_GR_QUOTED 357 #define MZN_LQ_QUOTED 358 #define MZN_GQ_QUOTED 359 #define MZN_EQ_QUOTED 360 #define MZN_NQ_QUOTED 361 #define MZN_IN_QUOTED 362 #define MZN_SUBSET_QUOTED 363 #define MZN_SUPERSET_QUOTED 364 #define MZN_UNION_QUOTED 365 #define MZN_DIFF_QUOTED 366 #define MZN_SYMDIFF_QUOTED 367 #define MZN_DOTDOT_QUOTED 368 #define MZN_PLUS_QUOTED 369 #define MZN_MINUS_QUOTED 370 #define MZN_MULT_QUOTED 371 #define MZN_DIV_QUOTED 372 #define MZN_IDIV_QUOTED 373 #define MZN_MOD_QUOTED 374 #define MZN_INTERSECT_QUOTED 375 #define MZN_NOT_QUOTED 376 #define MZN_COLONCOLON_QUOTED 377 #define MZN_PLUSPLUS_QUOTED 378 /* Copy the first part of user declarations. */ #define SCANNER static_cast(parm)->yyscanner #include #include #include #include namespace MiniZinc{ class Location; } #define YYLTYPE MiniZinc::Location #define YYLTYPE_IS_DECLARED 1 #define YYLTYPE_IS_TRIVIAL 0 #include #include using namespace std; using namespace MiniZinc; #define YYLLOC_DEFAULT(Current, Rhs, N) \ Current.filename = Rhs[1].filename; \ Current.first_line = Rhs[1].first_line; \ Current.first_column = Rhs[1].first_column; \ Current.last_line = Rhs[N].last_line; \ Current.last_column = Rhs[N].last_column; int yyparse(void*); int yylex(YYSTYPE*, YYLTYPE*, void* scanner); int yylex_init (void** scanner); int yylex_destroy (void* scanner); int yyget_lineno (void* scanner); void yyset_extra (void* user_defined ,void* yyscanner ); extern int yydebug; void yyerror(YYLTYPE* location, void* parm, const string& str) { ParserState* pp = static_cast(parm); Model* m = pp->model; while (m->parent() != NULL) { m = m->parent(); pp->err << "(included from file '" << m->filename() << "')" << endl; } pp->err << location->filename << ":" << location->first_line << ":" << endl; pp->printCurrentLine(); for (int i=0; i(location->first_column)-1; i++) pp->err << " "; for (unsigned int i=location->first_column; i<=location->last_column; i++) pp->err << "^"; pp->err << std::endl << "Error: " << str << std::endl << std::endl; pp->hadError = true; } bool notInDatafile(YYLTYPE* location, void* parm, const string& item) { ParserState* pp = static_cast(parm); if (pp->isDatafile) { yyerror(location,parm,item+" item not allowed in data file"); return false; } return true; } void filepath(const string& f, string& dirname, string& basename) { dirname = ""; basename = f; for (size_t p=basename.find_first_of('/'); p!=string::npos; dirname+=basename.substr(0,p+1), basename=basename.substr(p+1), p=basename.find_first_of('/') ) {} } // fastest way to read a file into a string (especially big files) // see: http://insanecoding.blogspot.be/2011/11/how-to-read-in-file-in-c.html std::string get_file_contents(std::ifstream &in) { if (in) { std::string contents; in.seekg(0, std::ios::end); contents.resize(static_cast(in.tellg())); in.seekg(0, std::ios::beg); in.read(&contents[0], contents.size()); in.close(); return(contents); } throw(errno); } Expression* createDocComment(const Location& loc, const std::string& s) { std::vector args(1); args[0] = new StringLit(loc, s); Call* c = new Call(loc, constants().ann.doc_comment, args); c->type(Type::ann()); return c; } Expression* createArrayAccess(const Location& loc, Expression* e, std::vector >& idx) { Expression* ret = e; for (unsigned int i=0; i& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { GCLock lock; vector includePaths; for (unsigned int i=0; i > files; map seenModels; Model* model = new Model(); model->setFilename(filename); if (!ignoreStdlib) { Model* stdlib = new Model; stdlib->setFilename("stdlib.mzn"); files.push_back(pair("./",stdlib)); seenModels.insert(pair("stdlib.mzn",stdlib)); IncludeI* stdlibinc = new IncludeI(Location(),stdlib->filename()); stdlibinc->m(stdlib,true); model->addItem(stdlibinc); } model->setFilepath(filename); bool isFzn; if (filename=="") { isFzn = false; } else { isFzn = (filename.compare(filename.length()-4,4,".fzn")==0); isFzn |= (filename.compare(filename.length()-4,4,".ozn")==0); isFzn |= (filename.compare(filename.length()-4,4,".szn")==0); } ParserState pp(filename,text, err, files, seenModels, model, false, isFzn, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } while (!files.empty()) { pair& np = files.back(); string parentPath = np.first; Model* m = np.second; files.pop_back(); string f(m->filename().str()); for (Model* p=m->parent(); p; p=p->parent()) { if (f == p->filename().c_str()) { err << "Error: cyclic includes: " << std::endl; for (Model* pe=m; pe; pe=pe->parent()) { err << " " << pe->filename() << std::endl; } goto error; } } ifstream file; string fullname; if (parentPath=="") { fullname = filename; if (FileUtils::file_exists(fullname)) { file.open(fullname.c_str(), std::ios::binary); } } else { includePaths.push_back(parentPath); for (unsigned int i=0; isetFilepath(fullname); bool isFzn = (fullname.compare(fullname.length()-4,4,".fzn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".ozn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".szn")==0); ParserState pp(fullname,s, err, files, seenModels, m, false, isFzn, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } return model; error: for (unsigned int i=0; i& datafiles, const vector& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { GCLock lock; string fileDirname; string fileBasename; filepath(filename, fileDirname, fileBasename); vector includePaths; for (unsigned int i=0; i > files; map seenModels; Model* model = new Model(); model->setFilename(fileBasename); if (!ignoreStdlib) { Model* stdlib = new Model; stdlib->setFilename("stdlib.mzn"); files.push_back(pair("./",stdlib)); seenModels.insert(pair("stdlib.mzn",stdlib)); Location stdlibloc; stdlibloc.filename=ASTString(filename); IncludeI* stdlibinc = new IncludeI(stdlibloc,stdlib->filename()); stdlibinc->m(stdlib,true); model->addItem(stdlibinc); } files.push_back(pair("",model)); while (!files.empty()) { pair& np = files.back(); string parentPath = np.first; Model* m = np.second; files.pop_back(); string f(m->filename().str()); for (Model* p=m->parent(); p; p=p->parent()) { if (f == p->filename().c_str()) { err << "Error: cyclic includes: " << std::endl; for (Model* pe=m; pe; pe=pe->parent()) { err << " " << pe->filename() << std::endl; } goto error; } } ifstream file; string fullname; if (parentPath=="") { fullname = filename; if (FileUtils::file_exists(fullname)) { file.open(fullname.c_str(), std::ios::binary); } } else { includePaths.push_back(parentPath); for (unsigned int i=0; isetFilepath(fullname); bool isFzn = (fullname.compare(fullname.length()-4,4,".fzn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".ozn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".szn")==0); ParserState pp(fullname,s, err, files, seenModels, m, false, isFzn, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } for (unsigned int i=0; i 5 && f.substr(0,5)=="cmd:/") { s = f.substr(5); } else { std::ifstream file; file.open(f.c_str(), std::ios::binary); if (!FileUtils::file_exists(f) || !file.is_open()) { err << "Error: cannot open data file '" << f << "'." << endl; goto error; } if (verbose) std::cerr << "processing data file '" << f << "'" << endl; s = get_file_contents(file); } ParserState pp(f, s, err, files, seenModels, model, true, false, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } return model; error: for (unsigned int i=0; i& datafiles, const vector& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { GCLock lock; vector > files; map seenModels; if (!ignoreStdlib) { Model* stdlib = new Model; stdlib->setFilename("stdlib.mzn"); files.push_back(pair("./",stdlib)); seenModels.insert(pair("stdlib.mzn",stdlib)); IncludeI* stdlibinc = new IncludeI(Location(),stdlib->filename()); stdlibinc->m(stdlib,true); model->addItem(stdlibinc); } while (!files.empty()) { pair& np = files.back(); string parentPath = np.first; Model* m = np.second; files.pop_back(); string f(m->filename().str()); for (Model* p=m->parent(); p; p=p->parent()) { if (f == p->filename().c_str()) { err << "Error: cyclic includes: " << std::endl; for (Model* pe=m; pe; pe=pe->parent()) { err << " " << pe->filename() << std::endl; } goto error; } } ifstream file; string fullname; if (parentPath=="") { err << "Internal error." << std::endl; goto error; } else { for (unsigned int i=0; isetFilepath(fullname); bool isFzn = (fullname.compare(fullname.length()-4,4,".fzn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".ozn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".szn")==0); ParserState pp(fullname,s, err, files, seenModels, m, false, isFzn, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } for (unsigned int i=0; i 5 && f.substr(0,5)=="cmd:/") { s = f.substr(5); } else { std::ifstream file; file.open(f.c_str(), std::ios::binary); if (!FileUtils::file_exists(f) || !file.is_open()) { err << "Error: cannot open data file '" << f << "'." << endl; goto error; } if (verbose) std::cerr << "processing data file '" << f << "'" << endl; s = get_file_contents(file); } ParserState pp(f, s, err, files, seenModels, model, true, false, parseDocComments); yylex_init(&pp.yyscanner); yyset_extra(&pp, pp.yyscanner); yyparse(&pp); if (pp.yyscanner) yylex_destroy(pp.yyscanner); if (pp.hadError) { goto error; } } return model; error: for (unsigned int i=0; i* vardeclexpr_v; MiniZinc::TypeInst* tiexpr; std::vector* tiexpr_v; MiniZinc::Expression* expression; std::vector* expression_v; std::vector >* expression_vv; std::vector > >* expression_vvv; MiniZinc::Generator* generator; std::vector* generator_v; std::vector* string_v; std::pair, MiniZinc::Expression*>* expression_p; MiniZinc::Generators* generators; } /* Line 193 of yacc.c. */ YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; } YYLTYPE; # define yyltype YYLTYPE /* obsolescent; will be withdrawn */ # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif /* Copy the second part of user declarations. */ /* Line 216 of yacc.c. */ #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ # define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(e) ((void) (e)) #else # define YYUSE(e) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int i) #else static int YYID (i) int i; #endif { return i; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss; YYSTYPE yyvs; YYLTYPE yyls; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (YYID (0)) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack, Stack, yysize); \ Stack = &yyptr->Stack; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 151 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 4073 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 132 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 64 /* YYNRULES -- Number of rules. */ #define YYNRULES 268 /* YYNRULES -- Number of states. */ #define YYNSTATES 458 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 378 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 126, 127, 2, 2, 128, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 124, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 129, 131, 130, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint16 yyprhs[] = { 0, 0, 3, 5, 6, 9, 11, 14, 18, 23, 27, 29, 32, 33, 35, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 61, 64, 69, 73, 76, 80, 85, 90, 93, 99, 105, 113, 122, 126, 132, 133, 136, 137, 141, 145, 146, 149, 151, 155, 156, 158, 160, 162, 166, 169, 171, 175, 177, 184, 188, 190, 193, 197, 201, 206, 212, 218, 219, 221, 223, 225, 227, 229, 231, 233, 235, 238, 240, 244, 246, 250, 254, 258, 262, 266, 273, 277, 281, 285, 289, 293, 297, 301, 305, 309, 312, 315, 317, 321, 325, 329, 333, 337, 341, 345, 349, 353, 357, 361, 365, 369, 373, 377, 381, 385, 389, 393, 397, 404, 408, 412, 416, 420, 424, 428, 432, 436, 440, 443, 446, 449, 453, 458, 460, 463, 465, 468, 470, 472, 474, 476, 478, 480, 482, 485, 487, 490, 492, 495, 497, 500, 502, 505, 507, 510, 512, 514, 517, 519, 522, 525, 529, 533, 538, 541, 545, 551, 553, 557, 560, 562, 566, 570, 573, 575, 579, 582, 586, 589, 593, 598, 602, 605, 609, 615, 617, 621, 627, 636, 637, 643, 645, 647, 649, 651, 653, 655, 657, 659, 661, 663, 665, 667, 669, 671, 673, 675, 677, 679, 681, 683, 685, 687, 689, 691, 693, 695, 697, 704, 709, 713, 715, 720, 728, 730, 734, 741, 749, 751, 753, 757, 761, 763, 765, 768, 773, 774, 776, 779, 783, 785, 787, 789, 791, 793, 795, 797, 799, 801, 803, 805, 807, 809, 811, 813, 815, 817, 819, 821, 823, 825, 827, 829, 831, 833, 835, 837, 839 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { 133, 0, -1, 134, -1, -1, 135, 137, -1, 138, -1, 136, 138, -1, 135, 124, 138, -1, 135, 124, 136, 138, -1, 1, 124, 138, -1, 14, -1, 136, 14, -1, -1, 124, -1, 13, 139, -1, 139, -1, 140, -1, 141, -1, 142, -1, 143, -1, 144, -1, 145, -1, 146, -1, 147, -1, 148, -1, 33, 8, -1, 155, 193, -1, 155, 193, 75, 165, -1, 6, 75, 165, -1, 24, 165, -1, 47, 193, 42, -1, 47, 193, 39, 165, -1, 47, 193, 38, 165, -1, 43, 165, -1, 44, 6, 150, 193, 149, -1, 49, 6, 150, 193, 149, -1, 31, 158, 125, 195, 150, 193, 149, -1, 158, 125, 6, 126, 151, 127, 193, 149, -1, 19, 6, 150, -1, 19, 6, 150, 75, 165, -1, -1, 75, 165, -1, -1, 126, 151, 127, -1, 126, 1, 127, -1, -1, 152, 153, -1, 154, -1, 152, 128, 154, -1, -1, 128, -1, 155, -1, 158, -1, 158, 125, 6, -1, 157, 153, -1, 158, -1, 157, 128, 158, -1, 159, -1, 21, 56, 156, 58, 40, 159, -1, 37, 40, 159, -1, 161, -1, 41, 161, -1, 16, 160, 161, -1, 15, 160, 161, -1, 160, 46, 40, 161, -1, 16, 160, 46, 40, 161, -1, 15, 160, 46, 40, 161, -1, -1, 41, -1, 35, -1, 22, -1, 30, -1, 48, -1, 18, -1, 164, -1, 12, -1, 163, 153, -1, 165, -1, 163, 128, 165, -1, 166, -1, 164, 93, 166, -1, 164, 80, 164, -1, 164, 81, 164, -1, 164, 82, 164, -1, 164, 83, 164, -1, 113, 126, 165, 128, 165, 127, -1, 164, 90, 164, -1, 164, 92, 164, -1, 164, 84, 164, -1, 164, 85, 164, -1, 164, 86, 164, -1, 164, 87, 164, -1, 164, 88, 164, -1, 164, 89, 164, -1, 164, 7, 164, -1, 84, 164, -1, 85, 164, -1, 166, -1, 165, 93, 166, -1, 165, 65, 165, -1, 165, 66, 165, -1, 165, 67, 165, -1, 165, 68, 165, -1, 165, 69, 165, -1, 165, 70, 165, -1, 165, 71, 165, -1, 165, 72, 165, -1, 165, 73, 165, -1, 165, 74, 165, -1, 165, 75, 165, -1, 165, 76, 165, -1, 165, 77, 165, -1, 165, 78, 165, -1, 165, 79, 165, -1, 165, 80, 165, -1, 165, 81, 165, -1, 165, 82, 165, -1, 165, 83, 165, -1, 113, 126, 165, 128, 165, 127, -1, 165, 90, 165, -1, 165, 92, 165, -1, 165, 84, 165, -1, 165, 85, 165, -1, 165, 86, 165, -1, 165, 87, 165, -1, 165, 88, 165, -1, 165, 89, 165, -1, 165, 7, 165, -1, 91, 165, -1, 84, 165, -1, 85, 165, -1, 126, 165, 127, -1, 126, 165, 127, 169, -1, 6, -1, 6, 169, -1, 53, -1, 53, 169, -1, 4, -1, 3, -1, 34, -1, 5, -1, 167, -1, 17, -1, 170, -1, 170, 169, -1, 171, -1, 171, 169, -1, 178, -1, 178, 169, -1, 179, -1, 179, 169, -1, 182, -1, 182, 169, -1, 183, -1, 183, 169, -1, 189, -1, 187, -1, 187, 169, -1, 8, -1, 9, 168, -1, 163, 11, -1, 163, 10, 168, -1, 56, 162, 58, -1, 169, 56, 162, 58, -1, 129, 130, -1, 129, 162, 130, -1, 129, 165, 131, 172, 130, -1, 173, -1, 173, 55, 165, -1, 174, 153, -1, 175, -1, 174, 128, 175, -1, 176, 77, 165, -1, 177, 153, -1, 6, -1, 177, 128, 6, -1, 56, 58, -1, 56, 162, 58, -1, 57, 59, -1, 57, 181, 59, -1, 57, 181, 131, 59, -1, 57, 180, 59, -1, 131, 131, -1, 131, 181, 131, -1, 180, 128, 131, 181, 131, -1, 162, -1, 181, 131, 162, -1, 56, 165, 131, 172, 58, -1, 32, 165, 50, 165, 184, 26, 165, 28, -1, -1, 184, 27, 165, 50, 165, -1, 95, -1, 96, -1, 97, -1, 98, -1, 99, -1, 100, -1, 101, -1, 102, -1, 103, -1, 104, -1, 105, -1, 106, -1, 107, -1, 108, -1, 109, -1, 110, -1, 111, -1, 112, -1, 114, -1, 115, -1, 116, -1, 117, -1, 118, -1, 119, -1, 120, -1, 123, -1, 121, -1, 185, 126, 165, 128, 165, 127, -1, 185, 126, 165, 127, -1, 6, 126, 127, -1, 186, -1, 6, 126, 188, 127, -1, 6, 126, 188, 127, 126, 165, 127, -1, 162, -1, 162, 55, 165, -1, 36, 129, 190, 130, 77, 165, -1, 36, 129, 190, 191, 130, 77, 165, -1, 192, -1, 143, -1, 190, 191, 192, -1, 190, 191, 143, -1, 128, -1, 124, -1, 155, 193, -1, 155, 193, 75, 165, -1, -1, 194, -1, 93, 166, -1, 194, 93, 166, -1, 6, -1, 95, -1, 96, -1, 97, -1, 98, -1, 99, -1, 100, -1, 101, -1, 102, -1, 103, -1, 104, -1, 105, -1, 106, -1, 107, -1, 108, -1, 109, -1, 110, -1, 111, -1, 112, -1, 113, -1, 114, -1, 115, -1, 116, -1, 117, -1, 118, -1, 119, -1, 120, -1, 121, -1, 123, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 650, 650, 652, 654, 657, 662, 667, 672, 677, 680, 688, 697, 697, 699, 715, 719, 721, 723, 724, 726, 728, 730, 732, 734, 738, 761, 766, 774, 780, 784, 789, 794, 801, 805, 813, 823, 830, 839, 851, 859, 860, 865, 866, 868, 873, 874, 878, 882, 887, 887, 890, 892, 896, 901, 905, 907, 911, 912, 918, 927, 930, 938, 946, 955, 964, 973, 986, 987, 991, 993, 995, 997, 999, 1001, 1003, 1009, 1012, 1014, 1020, 1021, 1023, 1025, 1027, 1029, 1036, 1043, 1045, 1047, 1049, 1051, 1053, 1055, 1057, 1059, 1065, 1067, 1082, 1083, 1085, 1087, 1089, 1091, 1093, 1095, 1097, 1099, 1101, 1103, 1105, 1107, 1109, 1111, 1113, 1115, 1117, 1119, 1121, 1128, 1135, 1137, 1139, 1141, 1143, 1145, 1147, 1149, 1151, 1157, 1159, 1166, 1179, 1181, 1183, 1185, 1188, 1190, 1193, 1195, 1197, 1199, 1201, 1202, 1204, 1205, 1208, 1209, 1212, 1213, 1216, 1217, 1220, 1221, 1224, 1225, 1228, 1229, 1230, 1235, 1237, 1243, 1248, 1256, 1263, 1272, 1274, 1278, 1284, 1286, 1289, 1292, 1294, 1298, 1301, 1304, 1306, 1310, 1312, 1316, 1318, 1329, 1340, 1380, 1383, 1388, 1395, 1400, 1404, 1410, 1426, 1427, 1431, 1433, 1435, 1437, 1439, 1441, 1443, 1445, 1447, 1449, 1451, 1453, 1455, 1457, 1459, 1461, 1463, 1465, 1467, 1469, 1471, 1473, 1475, 1477, 1479, 1481, 1483, 1487, 1495, 1527, 1529, 1530, 1541, 1584, 1589, 1596, 1598, 1602, 1604, 1612, 1614, 1623, 1623, 1626, 1632, 1643, 1644, 1647, 1651, 1655, 1657, 1659, 1661, 1663, 1665, 1667, 1669, 1671, 1673, 1675, 1677, 1679, 1681, 1683, 1685, 1687, 1689, 1691, 1693, 1695, 1697, 1699, 1701, 1703, 1705, 1707, 1709, 1711 }; #endif #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "$undefined", "\"integer literal\"", "\"bool literal\"", "\"float literal\"", "\"identifier\"", "\"quoted identifier\"", "\"string literal\"", "\"interpolated string start\"", "\"interpolated string middle\"", "\"interpolated string end\"", "\"type-inst identifier\"", "\"documentation comment\"", "\"file-level documentation comment\"", "\"var\"", "\"par\"", "\"<>\"", "\"ann\"", "\"annotation\"", "\"any\"", "\"array\"", "\"bool\"", "\"case\"", "\"constraint\"", "\"default\"", "\"else\"", "\"elseif\"", "\"endif\"", "\"enum\"", "\"float\"", "\"function\"", "\"if\"", "\"include\"", "\"infinity\"", "\"int\"", "\"let\"", "\"list\"", "\"maximize\"", "\"minimize\"", "\"of\"", "\"opt\"", "\"satisfy\"", "\"output\"", "\"predicate\"", "\"record\"", "\"set\"", "\"solve\"", "\"string\"", "\"test\"", "\"then\"", "\"tuple\"", "\"type\"", "\"_\"", "\"variant_record\"", "\"where\"", "\"[\"", "\"[|\"", "\"]\"", "\"|]\"", "FLATZINC_IDENTIFIER", "\"invalid integer literal\"", "\"invalid float literal\"", "\"unterminated string\"", "\"null character\"", "\"<->\"", "\"->\"", "\"<-\"", "\"\\\\/\"", "\"xor\"", "\"/\\\\\"", "\"<\"", "\">\"", "\"<=\"", "\">=\"", "\"=\"", "\"!=\"", "\"in\"", "\"subset\"", "\"superset\"", "\"union\"", "\"diff\"", "\"symdiff\"", "\"..\"", "\"+\"", "\"-\"", "\"*\"", "\"/\"", "\"div\"", "\"mod\"", "\"intersect\"", "\"not\"", "\"++\"", "\"::\"", "PREC_ANNO", "\"'<->'\"", "\"'->'\"", "\"'<-'\"", "\"'\\\\/'\"", "\"'xor'\"", "\"'/\\\\'\"", "\"'<'\"", "\"'>'\"", "\"'<='\"", "\"'>='\"", "\"'='\"", "\"'!='\"", "\"'in'\"", "\"'subset'\"", "\"'superset'\"", "\"'union'\"", "\"'diff'\"", "\"'symdiff'\"", "\"'..'\"", "\"'+'\"", "\"'-'\"", "\"'*'\"", "\"'/'\"", "\"'div'\"", "\"'mod'\"", "\"'intersect'\"", "\"'not'\"", "\"'::'\"", "\"'++'\"", "';'", "':'", "'('", "')'", "','", "'{'", "'}'", "'|'", "$accept", "model", "item_list", "item_list_head", "doc_file_comments", "semi_or_none", "item", "item_tail", "include_item", "vardecl_item", "assign_item", "constraint_item", "solve_item", "output_item", "predicate_item", "function_item", "annotation_item", "operation_item_tail", "params", "params_list", "params_list_head", "comma_or_none", "ti_expr_and_id_or_anon", "ti_expr_and_id", "ti_expr_list", "ti_expr_list_head", "ti_expr", "base_ti_expr", "opt_opt", "base_ti_expr_tail", "expr_list", "expr_list_head", "set_expr", "expr", "expr_atom_head", "string_expr", "string_quote_rest", "array_access_tail", "set_literal", "set_comp", "comp_tail", "generator_list", "generator_list_head", "generator", "id_list", "id_list_head", "simple_array_literal", "simple_array_literal_2d", "simple_array_literal_3d_list", "simple_array_literal_2d_list", "simple_array_comp", "if_then_else_expr", "elseif_list", "quoted_op", "quoted_op_call", "call_expr", "comp_or_expr", "let_expr", "let_vardecl_item_list", "comma_or_semi", "let_vardecl_item", "annotations", "ne_annotations", "id_or_quoted_op", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 59, 58, 40, 41, 44, 123, 125, 124 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 132, 133, 134, 134, 135, 135, 135, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 139, 139, 139, 139, 139, 139, 139, 140, 141, 141, 142, 143, 144, 144, 144, 145, 146, 146, 147, 147, 148, 148, 149, 149, 150, 150, 150, 151, 151, 152, 152, 153, 153, 154, 154, 155, 156, 157, 157, 158, 158, 158, 159, 159, 159, 159, 159, 159, 159, 160, 160, 161, 161, 161, 161, 161, 161, 161, 162, 163, 163, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 167, 167, 168, 168, 169, 169, 170, 170, 171, 172, 172, 173, 174, 174, 175, 176, 177, 177, 178, 178, 179, 179, 179, 179, 180, 180, 180, 181, 181, 182, 183, 184, 184, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 186, 186, 187, 187, 187, 187, 188, 188, 189, 189, 190, 190, 190, 190, 191, 191, 192, 192, 193, 193, 194, 194, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 0, 2, 1, 2, 3, 4, 3, 1, 2, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 3, 2, 3, 4, 4, 2, 5, 5, 7, 8, 3, 5, 0, 2, 0, 3, 3, 0, 2, 1, 3, 0, 1, 1, 1, 3, 2, 1, 3, 1, 6, 3, 1, 2, 3, 3, 4, 5, 5, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 3, 1, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 4, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 2, 3, 3, 4, 2, 3, 5, 1, 3, 2, 1, 3, 3, 2, 1, 3, 2, 3, 2, 3, 4, 3, 2, 3, 5, 1, 3, 5, 8, 0, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 4, 3, 1, 4, 7, 1, 3, 6, 7, 1, 1, 3, 3, 1, 1, 2, 4, 0, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint16 yydefact[] = { 0, 0, 138, 137, 140, 133, 158, 0, 75, 67, 10, 67, 67, 142, 73, 0, 0, 70, 0, 71, 67, 0, 0, 139, 69, 0, 0, 68, 0, 0, 236, 72, 0, 135, 0, 0, 0, 0, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 0, 209, 210, 211, 212, 213, 214, 215, 217, 216, 0, 0, 0, 2, 12, 67, 5, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 236, 0, 57, 0, 60, 74, 79, 141, 143, 145, 147, 149, 151, 153, 0, 221, 156, 155, 67, 0, 0, 0, 134, 133, 0, 0, 0, 0, 0, 77, 97, 159, 14, 68, 0, 0, 42, 67, 29, 0, 0, 25, 67, 67, 61, 33, 42, 0, 0, 237, 42, 136, 176, 0, 49, 77, 178, 0, 185, 0, 0, 95, 96, 0, 0, 164, 0, 77, 1, 13, 4, 11, 6, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 146, 148, 150, 152, 154, 0, 157, 9, 0, 28, 220, 224, 0, 0, 129, 130, 128, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 62, 0, 38, 0, 49, 55, 0, 0, 229, 236, 0, 0, 228, 59, 236, 238, 0, 0, 30, 0, 236, 177, 50, 76, 0, 182, 0, 181, 0, 179, 0, 0, 131, 165, 0, 67, 7, 0, 53, 0, 94, 81, 82, 83, 84, 88, 89, 90, 91, 92, 93, 86, 87, 80, 0, 162, 0, 222, 0, 0, 161, 78, 127, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 121, 122, 123, 124, 125, 126, 119, 120, 98, 0, 0, 0, 0, 49, 47, 51, 52, 0, 0, 50, 54, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 42, 189, 234, 0, 233, 232, 0, 67, 40, 32, 31, 239, 40, 174, 0, 167, 49, 170, 0, 49, 183, 0, 180, 186, 0, 132, 0, 8, 27, 45, 64, 219, 0, 225, 0, 163, 0, 66, 65, 44, 43, 50, 46, 39, 67, 56, 236, 0, 0, 53, 0, 0, 231, 230, 0, 34, 35, 187, 0, 50, 169, 0, 50, 173, 0, 0, 166, 0, 0, 0, 0, 48, 58, 40, 0, 0, 235, 226, 0, 41, 168, 171, 172, 175, 184, 85, 236, 218, 223, 118, 36, 0, 0, 227, 40, 188, 0, 37, 190 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 68, 69, 70, 71, 153, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 414, 229, 321, 322, 250, 323, 83, 230, 231, 84, 85, 86, 87, 141, 137, 88, 112, 113, 90, 114, 105, 91, 92, 373, 374, 375, 376, 377, 378, 93, 94, 142, 143, 95, 96, 406, 97, 98, 99, 186, 100, 238, 366, 239, 131, 132, 359 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -351 static const yytype_int16 yypact[] = { 501, -100, -351, -351, -351, -43, -351, 3055, -351, 1658, -351, -15, -15, -351, -351, 22, -25, -351, 3055, -351, 2039, 3055, 35, -351, -351, -84, 6, 2547, 3055, 44, -42, -351, 46, -3, 2674, 763, 3182, 3182, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -72, -351, -351, -351, -351, -351, -351, -351, -351, -351, 3055, 1149, 55, -351, -68, 1404, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -42, -67, -351, 11, -351, 57, -351, -351, -3, -3, -3, -3, -3, -3, -66, -351, -3, -351, 1531, 3055, 3055, 2801, 3, -26, 3055, 3055, 3055, -65, 8, 3952, -351, -351, -351, -351, 2293, 2420, -64, 2039, 3952, -62, 3839, -351, 1785, 2166, -351, 3952, -64, 3217, -2, -28, -64, 3, -351, 9, -60, 390, -351, 892, -351, -36, -32, 15, 15, 3055, 3529, -351, -52, 3297, -351, 1277, -351, -351, -351, -9, 64, 39, 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3217, 3, 3, 3, 3, 3, 3, 3055, 3, -351, 23, 3952, -351, 29, -41, 3055, 18, 18, 18, 3055, 3055, -351, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3055, 3217, 47, -351, 48, -351, 636, 19, 43, -35, -351, 3676, 3055, -351, -42, -23, -95, -351, -351, -42, -351, 3055, 3055, -351, 3217, -42, -351, 3055, -351, 91, -351, 0, -351, 1, -351, 2928, 3416, -3, -351, 91, 1404, -351, 3055, -21, 2547, 20, 234, 234, 234, 251, 141, 141, 15, 15, 15, 15, 234, 15, -351, 3332, -351, 3055, 7, 76, 3445, -351, 3952, 42, 3980, 626, 626, 753, 753, 880, 1009, 1009, 1009, 1009, 1009, 1009, 37, 37, 37, 268, 268, 268, 477, 167, 167, 18, 18, 18, 18, 268, 18, -351, 2547, 2547, 24, 25, 28, -351, -351, -23, 3055, 113, 1912, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -64, 3952, 82, 152, -351, -351, 86, 1021, 89, 3952, 3952, -351, 89, -351, 107, 112, 40, -351, 92, 78, 3055, 3055, -351, -351, 3055, 3, 41, -351, 3952, 1912, -351, -351, 3055, 3952, 3055, -351, 3055, -351, -351, -351, -351, 1912, -351, 3952, 2166, -351, -42, 12, 3055, -351, 3055, 93, -351, -351, 3055, -351, -351, -351, 3055, 91, -351, 3055, 166, -351, 79, 3558, -351, 80, 3642, 3671, 3755, -351, -351, 89, 3055, 3055, 3952, 3952, 3055, 3952, 3952, -351, 3952, -351, 3055, -351, -42, -351, -351, -351, -351, 3868, 3923, 3952, 89, -351, 3055, -351, 3952 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -351, -351, -351, -351, 59, -351, -54, 200, -351, -351, -351, -118, -351, -351, -351, -351, -351, -350, -121, -213, -351, -216, -187, -116, -351, -351, -16, -120, 30, -22, -33, 13, 279, -18, 262, -351, 26, -19, -351, -351, -47, -351, -351, -203, -351, -351, -351, -351, -351, -129, -351, -351, -351, -351, -351, -351, -351, -351, -351, -351, -149, -81, -351, -351 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -68 static const yytype_int16 yytable[] = { 121, 136, 156, 123, 122, 127, 240, 235, 241, 236, 128, 253, 247, 102, 134, 329, 138, 155, 192, 193, 111, 415, 159, 254, 101, 195, 116, 256, 119, 363, 102, 120, 103, 364, 149, 365, 243, 244, 433, 434, 245, 117, 118, 124, 195, 125, 126, 181, 147, 150, 129, 130, 133, 102, 146, 151, 152, 158, 157, 187, 179, 191, 228, 233, 159, 246, 264, 248, 249, 182, 265, 185, 173, 174, 175, 176, 177, 178, 260, 266, 180, 282, 449, 104, 283, 183, 284, 318, 319, 188, 189, 190, 255, 328, 326, 225, 227, 372, 263, 257, 104, 327, 362, 456, 232, 388, 401, 171, 172, 237, 222, 223, 324, 172, -68, -68, -68, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 258, 222, 223, 379, 380, 393, 394, 223, 194, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 159, 171, 172, 398, 399, 403, 285, 361, 400, 407, 408, 419, 367, 281, 422, 409, 413, 416, 371, 417, 418, 420, 437, 425, 442, 286, 195, 426, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 111, 421, 445, 386, 115, 443, 262, 325, 430, 385, 440, 360, 412, 287, 0, 0, 0, 0, 0, 382, 368, 369, 166, 167, 168, 169, 288, 0, 171, 172, 0, 0, 0, 405, 0, 384, 159, 0, 0, 389, 0, 387, 0, 411, 0, 236, 423, 0, 217, 218, 219, 220, 0, 159, 222, 223, 0, 89, 0, 0, 392, 0, 0, 0, 0, 0, 89, 324, 0, 0, 195, 0, 0, 0, 0, 0, 0, 89, 431, 324, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 396, 397, 89, 89, 0, 0, 0, 0, 0, 0, 0, 0, 402, 0, 0, 0, 404, 0, 0, 144, 145, 163, 164, 165, 166, 167, 168, 169, 432, 0, 171, 172, 0, 0, 0, 0, 0, 89, -68, 164, 165, 166, 167, 168, 169, 0, 0, 171, 172, 0, 382, 0, 0, 0, 237, 214, 215, 216, 217, 218, 219, 220, 0, 0, 222, 223, 0, 89, 453, 424, 0, 0, 0, 0, 0, 0, 325, 427, 0, 428, 0, 429, 0, 89, 89, 0, 89, 0, 325, 0, 0, 89, 89, 435, 0, 436, 242, 0, 0, 438, 0, 195, 0, 439, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0, 382, 0, 0, 0, 89, 450, 451, 0, 0, 452, 0, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 280, 0, 0, 457, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 0, 0, 0, 0, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 195, 317, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 1, 0, 2, 3, 4, 5, 370, 6, 7, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, 251, 16, 17, 89, 18, 0, 0, 89, 0, 0, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 27, 0, 28, 29, 0, -67, 30, 31, 32, 0, 0, 0, 33, 0, 0, 34, 35, 0, -68, 215, 216, 217, 218, 219, 220, 0, 0, 222, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 89, 0, 0, 0, 36, 37, 0, 0, 0, 89, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 89, 0, 67, 0, 0, 195, 0, 0, 0, 320, 0, 2, 3, 4, 106, 0, 6, 7, 0, 0, 8, 0, 89, 11, 12, 13, 14, 0, 0, 16, 17, 0, 0, 0, 89, 0, 0, 89, 19, 0, 21, 0, 23, 24, 25, 26, 0, 0, 0, 27, 0, 0, 0, 0, -67, 0, 31, 0, 0, 0, 0, 33, 0, 0, 34, 35, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 195, 0, 66, -45, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 139, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 107, 108, 0, 0, 0, 0, 0, 109, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 110, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 195, 0, 66, 0, 0, 67, 0, 140, 2, 3, 4, 106, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 0, 0, 107, 108, 0, 0, 0, 0, 0, 109, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 110, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 195, 0, 66, 0, 0, 67, 0, 252, 2, 3, 4, 106, 0, 6, 7, 0, 0, 8, 0, 0, 11, 12, 13, 14, 0, 0, 16, 17, 0, 18, 0, 0, 0, 0, 0, 19, 0, 21, 0, 23, 24, 25, 26, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, -68, -68, -68, -68, -68, -68, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 410, 2, 3, 4, 106, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 108, 0, 0, 0, 0, 0, 109, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 110, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 148, 2, 3, 4, 5, 0, 6, 7, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, 0, 16, 17, 0, 18, 0, 0, 0, 0, 0, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 27, 0, 28, 29, 0, -67, 30, 31, 32, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 5, 0, 6, 7, 0, 0, 8, 9, 154, 11, 12, 13, 14, 15, 0, 16, 17, 0, 18, 0, 0, 0, 0, 0, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 27, 0, 28, 29, 0, 0, 30, 31, 32, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 5, 0, 6, 7, 0, 0, 8, 9, 0, 11, 12, 13, 14, 15, 0, 16, 17, 0, 18, 0, 0, 0, 0, 0, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 27, 0, 28, 29, 0, 0, 30, 31, 32, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 5, 0, 6, 7, 0, 0, 8, 0, 0, 11, 12, 13, 14, 15, 0, 16, 17, 0, 18, 0, 0, 0, 0, 0, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 27, 0, 28, 29, 0, 0, 30, 31, 32, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 8, 0, 0, 11, 12, 13, 14, 0, 0, 16, 17, 0, 18, 0, 0, 0, 0, 0, 19, 0, 21, 0, 23, 24, 25, 26, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 8, 0, 0, 11, 12, 13, 14, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 19, 0, 21, 0, 23, 24, 25, 26, 0, 0, 0, 27, 0, 0, 0, 0, -67, 0, 31, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 8, 0, 0, 11, 12, 13, 14, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 19, 0, 21, 0, 23, 24, 25, 26, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 8, 0, 0, 11, 12, 13, 14, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 19, 0, 21, 0, 23, 24, 25, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 8, 0, 0, 0, 0, 13, 14, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 19, 0, 21, 0, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 31, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 8, 0, 0, 0, 0, 13, 14, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 19, 0, 21, 0, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 0, 31, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 8, 0, 0, 0, 0, 13, 14, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 19, 0, 21, 0, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 35, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 108, 0, 0, 0, 0, 0, 109, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 110, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 108, 0, 0, 0, 0, 0, 109, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 110, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 184, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 381, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 108, 0, 0, 0, 0, 0, 109, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 110, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 108, 0, 0, 0, 0, 0, 109, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 110, 57, 58, 59, 60, 61, 62, 63, 64, 0, 65, 0, 0, 66, 0, 0, 67, 2, 3, 4, 106, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 0, 2, 3, 4, 106, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 13, 33, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 33, 0, 0, 34, 35, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 195, 65, 0, 0, 66, 0, 0, 67, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 0, 57, 58, 59, 60, 61, 62, 63, 64, 195, 65, 0, 0, 66, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 0, 0, 0, 0, 0, 0, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 195, 222, 223, 0, 0, 261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, 390, 391, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 195, 222, 223, 0, 0, 0, 0, 0, 383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, 0, 395, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 195, 222, 223, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, 330, 0, 0, 444, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 195, 222, 223, 0, 0, 0, 0, 446, 0, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 447, 358, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 195, 222, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, 448, 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 454, 0, 0, 0, 0, 0, 0, 0, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 195, 222, 223, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 195, 222, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 455, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 0, 222, 223 }; static const yytype_int16 yycheck[] = { 18, 34, 83, 21, 20, 27, 126, 125, 129, 125, 28, 140, 133, 56, 33, 231, 34, 71, 10, 11, 7, 371, 7, 59, 124, 7, 41, 59, 6, 124, 56, 56, 75, 128, 67, 130, 38, 39, 26, 27, 42, 11, 12, 8, 7, 129, 40, 101, 66, 67, 6, 93, 6, 56, 126, 0, 124, 46, 125, 56, 126, 126, 126, 125, 7, 93, 75, 58, 128, 102, 6, 104, 91, 92, 93, 94, 95, 96, 130, 40, 99, 58, 432, 126, 55, 103, 127, 40, 40, 107, 108, 109, 128, 128, 75, 117, 118, 6, 152, 131, 126, 58, 125, 453, 120, 126, 322, 92, 93, 125, 92, 93, 228, 93, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 146, 92, 93, 131, 131, 126, 58, 93, 128, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 7, 92, 93, 127, 127, 40, 187, 236, 128, 75, 6, 375, 241, 179, 378, 77, 75, 58, 247, 55, 128, 77, 77, 130, 6, 191, 7, 388, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 192, 128, 127, 262, 9, 131, 152, 228, 400, 261, 418, 234, 366, 192, -1, -1, -1, -1, -1, 257, 243, 244, 86, 87, 88, 89, 249, -1, 92, 93, -1, -1, -1, 359, -1, 259, 7, -1, -1, 266, -1, 264, -1, 366, -1, 366, 380, -1, 86, 87, 88, 89, -1, 7, 92, 93, -1, 0, -1, -1, 283, -1, -1, -1, -1, -1, 9, 388, -1, -1, 7, -1, -1, -1, -1, -1, -1, 20, 403, 400, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, -1, 318, 319, 36, 37, -1, -1, -1, -1, -1, -1, -1, -1, 326, -1, -1, -1, 328, -1, -1, 36, 37, 83, 84, 85, 86, 87, 88, 89, 405, -1, 92, 93, -1, -1, -1, -1, -1, 71, 83, 84, 85, 86, 87, 88, 89, -1, -1, 92, 93, -1, 379, -1, -1, -1, 366, 83, 84, 85, 86, 87, 88, 89, -1, -1, 92, 93, -1, 101, 445, 383, -1, -1, -1, -1, -1, -1, 388, 391, -1, 393, -1, 395, -1, 117, 118, -1, 120, -1, 400, -1, -1, 125, 126, 407, -1, 409, 130, -1, -1, 413, -1, 7, -1, 417, -1, -1, 420, -1, -1, -1, -1, -1, -1, -1, 443, -1, -1, -1, 152, 433, 434, -1, -1, 437, -1, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, -1, -1, 455, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, 7, 223, -1, -1, -1, -1, 228, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, 3, 4, 5, 6, 246, 8, 9, -1, -1, 12, 13, 14, 15, 16, 17, 18, 19, 131, 21, 22, 262, 24, -1, -1, 266, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, -1, -1, -1, 41, -1, 43, 44, -1, 46, 47, 48, 49, -1, -1, -1, 53, -1, -1, 56, 57, -1, 83, 84, 85, 86, 87, 88, 89, -1, -1, 92, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, 318, 319, -1, -1, -1, 84, 85, -1, -1, -1, 328, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, 366, -1, 129, -1, -1, 7, -1, -1, -1, 1, -1, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, 388, 15, 16, 17, 18, -1, -1, 21, 22, -1, -1, -1, 400, -1, -1, 403, 30, -1, 32, -1, 34, 35, 36, 37, -1, -1, -1, 41, -1, -1, -1, -1, 46, -1, 48, -1, -1, -1, -1, 53, -1, -1, 56, 57, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, 7, -1, 126, 127, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, 34, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, 59, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, 84, 85, -1, -1, -1, -1, -1, 91, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, 7, -1, 126, -1, -1, 129, -1, 131, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, 34, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, -1, -1, 84, 85, -1, -1, -1, -1, -1, 91, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, 7, -1, 126, -1, -1, 129, -1, 131, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, -1, 15, 16, 17, 18, -1, -1, 21, 22, -1, 24, -1, -1, -1, -1, -1, 30, -1, 32, -1, 34, 35, 36, 37, -1, -1, -1, 41, -1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 130, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, 34, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, 91, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 130, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, 14, 15, 16, 17, 18, 19, -1, 21, 22, -1, 24, -1, -1, -1, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, -1, -1, -1, 41, -1, 43, 44, -1, 46, 47, 48, 49, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, 14, 15, 16, 17, 18, 19, -1, 21, 22, -1, 24, -1, -1, -1, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, -1, -1, -1, 41, -1, 43, 44, -1, -1, 47, 48, 49, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, 15, 16, 17, 18, 19, -1, 21, 22, -1, 24, -1, -1, -1, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, -1, -1, -1, 41, -1, 43, 44, -1, -1, 47, 48, 49, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, -1, 15, 16, 17, 18, 19, -1, 21, 22, -1, 24, -1, -1, -1, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, -1, -1, -1, 41, -1, 43, 44, -1, -1, 47, 48, 49, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, -1, 15, 16, 17, 18, -1, -1, 21, 22, -1, 24, -1, -1, -1, -1, -1, 30, -1, 32, -1, 34, 35, 36, 37, -1, -1, -1, 41, -1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, -1, 15, 16, 17, 18, -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, -1, 30, -1, 32, -1, 34, 35, 36, 37, -1, -1, -1, 41, -1, -1, -1, -1, 46, -1, 48, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, -1, 15, 16, 17, 18, -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, -1, 30, -1, 32, -1, 34, 35, 36, 37, -1, -1, -1, 41, -1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, -1, 15, 16, 17, 18, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, 30, -1, 32, -1, 34, 35, 36, -1, -1, -1, -1, 41, -1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, 17, 18, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, 30, -1, 32, -1, 34, 35, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, 48, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, 17, 18, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, 30, -1, 32, -1, 34, 35, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, 48, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, 17, 18, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, 30, -1, 32, -1, 34, 35, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, 34, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, 56, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, 91, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, 34, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, 91, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, 127, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, 34, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, 91, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, 34, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, -1, -1, -1, 91, -1, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, -1, 123, -1, -1, 126, -1, -1, 129, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, 34, -1, 36, -1, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, 53, -1, -1, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, 34, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, 85, -1, -1, 53, -1, -1, 56, 57, -1, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 7, 123, -1, -1, 126, -1, -1, 129, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, -1, 114, 115, 116, 117, 118, 119, 120, 121, 7, 123, -1, -1, 126, -1, -1, 129, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 7, 92, 93, -1, -1, 131, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, 127, 128, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 7, 92, 93, -1, -1, -1, -1, -1, 128, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, 128, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 7, 92, 93, -1, -1, -1, -1, 127, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 6, -1, -1, 127, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 7, 92, 93, -1, -1, -1, -1, 127, -1, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 127, 123, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 7, 92, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, 127, -1, -1, -1, -1, -1, -1, 50, -1, -1, -1, -1, -1, -1, 28, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 7, 92, 93, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 7, 92, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, -1, 92, 93 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 1, 3, 4, 5, 6, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 24, 30, 31, 32, 33, 34, 35, 36, 37, 41, 43, 44, 47, 48, 49, 53, 56, 57, 84, 85, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, 126, 129, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 155, 158, 159, 160, 161, 164, 166, 167, 170, 171, 178, 179, 182, 183, 185, 186, 187, 189, 124, 56, 75, 126, 169, 6, 84, 85, 91, 113, 163, 165, 166, 168, 139, 41, 160, 160, 6, 56, 165, 158, 165, 8, 129, 40, 161, 165, 6, 93, 193, 194, 6, 169, 58, 162, 163, 165, 59, 131, 162, 180, 181, 164, 164, 126, 165, 130, 162, 165, 0, 124, 137, 14, 138, 193, 125, 46, 7, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 92, 93, 169, 169, 169, 169, 169, 169, 126, 169, 138, 162, 165, 127, 162, 188, 56, 165, 165, 165, 126, 10, 11, 128, 7, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 92, 93, 46, 161, 46, 161, 126, 150, 156, 157, 158, 125, 50, 143, 155, 158, 190, 192, 159, 150, 166, 38, 39, 42, 93, 150, 58, 128, 153, 131, 131, 181, 59, 128, 59, 131, 165, 127, 130, 131, 136, 138, 75, 6, 40, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 166, 165, 58, 55, 127, 162, 165, 168, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 166, 40, 40, 1, 151, 152, 154, 155, 158, 75, 58, 128, 153, 6, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 123, 195, 165, 193, 125, 124, 128, 130, 191, 193, 165, 165, 166, 193, 6, 172, 173, 174, 175, 176, 177, 131, 131, 59, 162, 128, 169, 172, 138, 165, 126, 161, 127, 128, 165, 126, 58, 128, 161, 161, 127, 127, 128, 153, 165, 40, 158, 150, 184, 75, 6, 77, 130, 143, 192, 75, 149, 149, 58, 55, 128, 153, 77, 128, 153, 181, 165, 130, 151, 165, 165, 165, 154, 159, 193, 26, 27, 165, 165, 77, 165, 165, 175, 165, 6, 131, 127, 127, 127, 127, 127, 149, 165, 165, 165, 193, 28, 50, 149, 165 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ else \ { \ yyerror (&yylloc, parm, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ (Loc).last_line, (Loc).last_column) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) #else # define YYLEX yylex (&yylval, &yylloc, SCANNER) #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value, Location, parm); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *parm) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parm) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; YYLTYPE const * const yylocationp; void *parm; #endif { if (!yyvaluep) return; YYUSE (yylocationp); YYUSE (parm); # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *parm) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, parm) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; YYLTYPE const * const yylocationp; void *parm; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); YY_LOCATION_PRINT (yyoutput, *yylocationp); YYFPRINTF (yyoutput, ": "); yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parm); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) #else static void yy_stack_print (bottom, top) yytype_int16 *bottom; yytype_int16 *top; #endif { YYFPRINTF (stderr, "Stack now"); for (; bottom <= top; ++bottom) YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, void *parm) #else static void yy_reduce_print (yyvsp, yylsp, yyrule, parm) YYSTYPE *yyvsp; YYLTYPE *yylsp; int yyrule; void *parm; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { fprintf (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) , &(yylsp[(yyi + 1) - (yynrhs)]) , parm); fprintf (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, yylsp, Rule, parm); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into YYRESULT an error message about the unexpected token YYCHAR while in state YYSTATE. Return the number of bytes copied, including the terminating null byte. If YYRESULT is null, do not copy anything; just return the number of bytes that would be copied. As a special case, return 0 if an ordinary "syntax error" message will do. Return YYSIZE_MAXIMUM if overflow occurs during size calculation. */ static YYSIZE_T yysyntax_error (char *yyresult, int yystate, int yychar) { int yyn = yypact[yystate]; if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) return 0; else { int yytype = YYTRANSLATE (yychar); YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; int yysize_overflow = 0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; int yyx; # if 0 /* This is so xgettext sees the translatable formats that are constructed on the fly. */ YY_("syntax error, unexpected %s"); YY_("syntax error, unexpected %s, expecting %s"); YY_("syntax error, unexpected %s, expecting %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); # endif char *yyfmt; char const *yyf; static char const yyunexpected[] = "syntax error, unexpected %s"; static char const yyexpecting[] = ", expecting %s"; static char const yyor[] = " or %s"; char yyformat[sizeof yyunexpected + sizeof yyexpecting - 1 + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) * (sizeof yyor - 1))]; char const *yyprefix = yyexpecting; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yycount = 1; yyarg[0] = yytname[yytype]; yyfmt = yystpcpy (yyformat, yyunexpected); for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; yyformat[sizeof yyunexpected - 1] = '\0'; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (0, yytname[yyx]); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; yyfmt = yystpcpy (yyfmt, yyprefix); yyprefix = yyor; } yyf = YY_(yyformat); yysize1 = yysize + yystrlen (yyf); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; if (yysize_overflow) return YYSIZE_MAXIMUM; if (yyresult) { /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ char *yyp = yyresult; int yyi = 0; while ((*yyp = *yyf) != '\0') { if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyf += 2; } else { yyp++; yyf++; } } } return yysize; } } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, void *parm) #else static void yydestruct (yymsg, yytype, yyvaluep, yylocationp, parm) const char *yymsg; int yytype; YYSTYPE *yyvaluep; YYLTYPE *yylocationp; void *parm; #endif { YYUSE (yyvaluep); YYUSE (yylocationp); YYUSE (parm); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void *parm); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /*----------. | yyparse. | `----------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *parm) #else int yyparse (parm) void *parm; #endif #endif { /* The look-ahead symbol. */ int yychar; /* The semantic value of the look-ahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /* Location data for the look-ahead symbol. */ YYLTYPE yylloc; int yystate; int yyn; int yyresult; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* Look-ahead token as an internal (translated) token number. */ int yytoken = 0; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif /* Three stacks and their tools: `yyss': related to states, `yyvs': related to semantic values, `yyls': related to locations. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss = yyssa; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp; /* The location stack. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls = yylsa; YYLTYPE *yylsp; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[2]; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) YYSIZE_T yystacksize = YYINITDEPTH; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; YYLTYPE yyloc; /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; yylsp = yyls; #if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL /* Initialize the default location before parsing starts. */ yylloc.first_line = yylloc.last_line = 1; yylloc.first_column = yylloc.last_column = 0; #endif /* User initialization code. */ { GCLock lock; yylloc.filename = ASTString(static_cast(parm)->filename); } /* Line 1078 of yacc.c. */ yylsp[0] = yylloc; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yyls1, yysize * sizeof (*yylsp), &yystacksize); yyls = yyls1; yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss); YYSTACK_RELOCATE (yyvs); YYSTACK_RELOCATE (yyls); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a look-ahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to look-ahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; /* Not known => get a look-ahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yyn == 0 || yyn == YYTABLE_NINF) goto yyerrlab; yyn = -yyn; goto yyreduce; } if (yyn == YYFINAL) YYACCEPT; /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the look-ahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token unless it is eof. */ if (yychar != YYEOF) yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; *++yylsp = yylloc; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; /* Default location. */ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); YY_REDUCE_PRINT (yyn); switch (yyn) { case 5: { ParserState* pp = static_cast(parm); if ((yyvsp[(1) - (1)].item)) pp->model->addItem((yyvsp[(1) - (1)].item)); ;} break; case 6: { ParserState* pp = static_cast(parm); if ((yyvsp[(2) - (2)].item)) pp->model->addItem((yyvsp[(2) - (2)].item)); ;} break; case 7: { ParserState* pp = static_cast(parm); if ((yyvsp[(3) - (3)].item)) pp->model->addItem((yyvsp[(3) - (3)].item)); ;} break; case 8: { ParserState* pp = static_cast(parm); if ((yyvsp[(4) - (4)].item)) pp->model->addItem((yyvsp[(4) - (4)].item)); ;} break; case 10: { ParserState* pp = static_cast(parm); if (pp->parseDocComments && (yyvsp[(1) - (1)].sValue)) { pp->model->addDocComment((yyvsp[(1) - (1)].sValue)); } free((yyvsp[(1) - (1)].sValue)); ;} break; case 11: { ParserState* pp = static_cast(parm); if (pp->parseDocComments && (yyvsp[(2) - (2)].sValue)) { pp->model->addDocComment((yyvsp[(2) - (2)].sValue)); } free((yyvsp[(2) - (2)].sValue)); ;} break; case 14: { (yyval.item) = (yyvsp[(2) - (2)].item); ParserState* pp = static_cast(parm); if (FunctionI* fi = Item::dyn_cast((yyval.item))) { if (pp->parseDocComments) { fi->ann().add(createDocComment((yylsp[(1) - (2)]),(yyvsp[(1) - (2)].sValue))); } } else if (VarDeclI* vdi = Item::dyn_cast((yyval.item))) { if (pp->parseDocComments) { vdi->e()->addAnnotation(createDocComment((yylsp[(1) - (2)]),(yyvsp[(1) - (2)].sValue))); } } else { yyerror(&(yylsp[(2) - (2)]), parm, "documentation comments are only supported for function, predicate and variable declarations"); } free((yyvsp[(1) - (2)].sValue)); ;} break; case 15: { (yyval.item) = (yyvsp[(1) - (1)].item); ;} break; case 16: { (yyval.item)=notInDatafile(&(yyloc),parm,"include") ? (yyvsp[(1) - (1)].item) : NULL; ;} break; case 17: { (yyval.item)=notInDatafile(&(yyloc),parm,"variable declaration") ? (yyvsp[(1) - (1)].item) : NULL; ;} break; case 19: { (yyval.item)=notInDatafile(&(yyloc),parm,"constraint") ? (yyvsp[(1) - (1)].item) : NULL; ;} break; case 20: { (yyval.item)=notInDatafile(&(yyloc),parm,"solve") ? (yyvsp[(1) - (1)].item) : NULL; ;} break; case 21: { (yyval.item)=notInDatafile(&(yyloc),parm,"output") ? (yyvsp[(1) - (1)].item) : NULL; ;} break; case 22: { (yyval.item)=notInDatafile(&(yyloc),parm,"predicate") ? (yyvsp[(1) - (1)].item) : NULL; ;} break; case 23: { (yyval.item)=notInDatafile(&(yyloc),parm,"predicate") ? (yyvsp[(1) - (1)].item) : NULL; ;} break; case 24: { (yyval.item)=notInDatafile(&(yyloc),parm,"annotation") ? (yyvsp[(1) - (1)].item) : NULL; ;} break; case 25: { ParserState* pp = static_cast(parm); map::iterator ret = pp->seenModels.find((yyvsp[(2) - (2)].sValue)); IncludeI* ii = new IncludeI((yyloc),ASTString((yyvsp[(2) - (2)].sValue))); (yyval.item) = ii; if (ret == pp->seenModels.end()) { Model* im = new Model; im->setParent(pp->model); im->setFilename((yyvsp[(2) - (2)].sValue)); string fpath, fbase; filepath(pp->filename, fpath, fbase); if (fpath=="") fpath="./"; pair pm(fpath, im); pp->files.push_back(pm); ii->m(im); pp->seenModels.insert(pair((yyvsp[(2) - (2)].sValue),im)); } else { ii->m(ret->second, false); } free((yyvsp[(2) - (2)].sValue)); ;} break; case 26: { if ((yyvsp[(1) - (2)].vardeclexpr) && (yyvsp[(2) - (2)].expression_v)) (yyvsp[(1) - (2)].vardeclexpr)->addAnnotations(*(yyvsp[(2) - (2)].expression_v)); (yyval.item) = new VarDeclI((yyloc),(yyvsp[(1) - (2)].vardeclexpr)); delete (yyvsp[(2) - (2)].expression_v); ;} break; case 27: { if ((yyvsp[(1) - (4)].vardeclexpr)) (yyvsp[(1) - (4)].vardeclexpr)->e((yyvsp[(4) - (4)].expression)); if ((yyvsp[(1) - (4)].vardeclexpr) && (yyvsp[(2) - (4)].expression_v)) (yyvsp[(1) - (4)].vardeclexpr)->addAnnotations(*(yyvsp[(2) - (4)].expression_v)); (yyval.item) = new VarDeclI((yyloc),(yyvsp[(1) - (4)].vardeclexpr)); delete (yyvsp[(2) - (4)].expression_v); ;} break; case 28: { (yyval.item) = new AssignI((yyloc),(yyvsp[(1) - (3)].sValue),(yyvsp[(3) - (3)].expression)); free((yyvsp[(1) - (3)].sValue)); ;} break; case 29: { (yyval.item) = new ConstraintI((yyloc),(yyvsp[(2) - (2)].expression));;} break; case 30: { (yyval.item) = SolveI::sat((yyloc)); if ((yyval.item) && (yyvsp[(2) - (3)].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[(2) - (3)].expression_v)); delete (yyvsp[(2) - (3)].expression_v); ;} break; case 31: { (yyval.item) = SolveI::min((yyloc),(yyvsp[(4) - (4)].expression)); if ((yyval.item) && (yyvsp[(2) - (4)].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[(2) - (4)].expression_v)); delete (yyvsp[(2) - (4)].expression_v); ;} break; case 32: { (yyval.item) = SolveI::max((yyloc),(yyvsp[(4) - (4)].expression)); if ((yyval.item) && (yyvsp[(2) - (4)].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[(2) - (4)].expression_v)); delete (yyvsp[(2) - (4)].expression_v); ;} break; case 33: { (yyval.item) = new OutputI((yyloc),(yyvsp[(2) - (2)].expression));;} break; case 34: { (yyval.item) = new FunctionI((yyloc),(yyvsp[(2) - (5)].sValue),new TypeInst((yyloc), Type::varbool()),*(yyvsp[(3) - (5)].vardeclexpr_v),(yyvsp[(5) - (5)].expression)); if ((yyval.item) && (yyvsp[(4) - (5)].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[(4) - (5)].expression_v)); free((yyvsp[(2) - (5)].sValue)); delete (yyvsp[(3) - (5)].vardeclexpr_v); delete (yyvsp[(4) - (5)].expression_v); ;} break; case 35: { (yyval.item) = new FunctionI((yyloc),(yyvsp[(2) - (5)].sValue),new TypeInst((yyloc), Type::parbool()),*(yyvsp[(3) - (5)].vardeclexpr_v),(yyvsp[(5) - (5)].expression)); if ((yyval.item) && (yyvsp[(4) - (5)].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[(4) - (5)].expression_v)); free((yyvsp[(2) - (5)].sValue)); delete (yyvsp[(3) - (5)].vardeclexpr_v); delete (yyvsp[(4) - (5)].expression_v); ;} break; case 36: { (yyval.item) = new FunctionI((yyloc),(yyvsp[(4) - (7)].sValue),(yyvsp[(2) - (7)].tiexpr),*(yyvsp[(5) - (7)].vardeclexpr_v),(yyvsp[(7) - (7)].expression)); if ((yyval.item) && (yyvsp[(6) - (7)].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[(6) - (7)].expression_v)); free((yyvsp[(4) - (7)].sValue)); delete (yyvsp[(5) - (7)].vardeclexpr_v); delete (yyvsp[(6) - (7)].expression_v); ;} break; case 37: { (yyval.item) = new FunctionI((yyloc),(yyvsp[(3) - (8)].sValue),(yyvsp[(1) - (8)].tiexpr),*(yyvsp[(5) - (8)].vardeclexpr_v),(yyvsp[(8) - (8)].expression)); if ((yyval.item) && (yyvsp[(7) - (8)].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[(7) - (8)].expression_v)); free((yyvsp[(3) - (8)].sValue)); delete (yyvsp[(5) - (8)].vardeclexpr_v); delete (yyvsp[(7) - (8)].expression_v); ;} break; case 38: { TypeInst* ti=new TypeInst((yylsp[(1) - (3)]),Type::ann()); if ((yyvsp[(3) - (3)].vardeclexpr_v)==NULL || (yyvsp[(3) - (3)].vardeclexpr_v)->empty()) { VarDecl* vd = new VarDecl((yyloc),ti,(yyvsp[(2) - (3)].sValue)); (yyval.item) = new VarDeclI((yyloc),vd); } else { (yyval.item) = new FunctionI((yyloc),(yyvsp[(2) - (3)].sValue),ti,*(yyvsp[(3) - (3)].vardeclexpr_v),NULL); } free((yyvsp[(2) - (3)].sValue)); delete (yyvsp[(3) - (3)].vardeclexpr_v); ;} break; case 39: { TypeInst* ti=new TypeInst((yylsp[(1) - (5)]),Type::ann()); (yyval.item) = new FunctionI((yyloc),(yyvsp[(2) - (5)].sValue),ti,*(yyvsp[(3) - (5)].vardeclexpr_v),(yyvsp[(5) - (5)].expression)); delete (yyvsp[(3) - (5)].vardeclexpr_v); ;} break; case 40: { (yyval.expression)=NULL; ;} break; case 41: { (yyval.expression)=(yyvsp[(2) - (2)].expression); ;} break; case 42: { (yyval.vardeclexpr_v)=new vector(); ;} break; case 43: { (yyval.vardeclexpr_v)=(yyvsp[(2) - (3)].vardeclexpr_v); ;} break; case 44: { (yyval.vardeclexpr_v)=new vector(); ;} break; case 45: { (yyval.vardeclexpr_v)=new vector(); ;} break; case 46: { (yyval.vardeclexpr_v)=(yyvsp[(1) - (2)].vardeclexpr_v); ;} break; case 47: { (yyval.vardeclexpr_v)=new vector(); if ((yyvsp[(1) - (1)].vardeclexpr)) (yyvsp[(1) - (1)].vardeclexpr)->toplevel(false); if ((yyvsp[(1) - (1)].vardeclexpr)) (yyval.vardeclexpr_v)->push_back((yyvsp[(1) - (1)].vardeclexpr)); ;} break; case 48: { (yyval.vardeclexpr_v)=(yyvsp[(1) - (3)].vardeclexpr_v); if ((yyvsp[(3) - (3)].vardeclexpr)) (yyvsp[(3) - (3)].vardeclexpr)->toplevel(false); if ((yyvsp[(1) - (3)].vardeclexpr_v) && (yyvsp[(3) - (3)].vardeclexpr)) (yyvsp[(1) - (3)].vardeclexpr_v)->push_back((yyvsp[(3) - (3)].vardeclexpr)); ;} break; case 51: { (yyval.vardeclexpr)=(yyvsp[(1) - (1)].vardeclexpr); ;} break; case 52: { (yyval.vardeclexpr)=new VarDecl((yyloc), (yyvsp[(1) - (1)].tiexpr), ""); ;} break; case 53: { (yyval.vardeclexpr) = new VarDecl((yyloc), (yyvsp[(1) - (3)].tiexpr), (yyvsp[(3) - (3)].sValue)); free((yyvsp[(3) - (3)].sValue)); ;} break; case 54: { (yyval.tiexpr_v)=(yyvsp[(1) - (2)].tiexpr_v); ;} break; case 55: { (yyval.tiexpr_v)=new vector(); (yyval.tiexpr_v)->push_back((yyvsp[(1) - (1)].tiexpr)); ;} break; case 56: { (yyval.tiexpr_v)=(yyvsp[(1) - (3)].tiexpr_v); if ((yyvsp[(1) - (3)].tiexpr_v) && (yyvsp[(3) - (3)].tiexpr)) (yyvsp[(1) - (3)].tiexpr_v)->push_back((yyvsp[(3) - (3)].tiexpr)); ;} break; case 58: { (yyval.tiexpr) = (yyvsp[(6) - (6)].tiexpr); if ((yyval.tiexpr) && (yyvsp[(3) - (6)].tiexpr_v)) (yyval.tiexpr)->setRanges(*(yyvsp[(3) - (6)].tiexpr_v)); delete (yyvsp[(3) - (6)].tiexpr_v); ;} break; case 59: { (yyval.tiexpr) = (yyvsp[(3) - (3)].tiexpr); std::vector ti(1); ti[0] = new TypeInst((yyloc),Type::parint()); if ((yyval.tiexpr)) (yyval.tiexpr)->setRanges(ti); ;} break; case 60: { (yyval.tiexpr) = (yyvsp[(1) - (1)].tiexpr); ;} break; case 61: { (yyval.tiexpr) = (yyvsp[(2) - (2)].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } ;} break; case 62: { (yyval.tiexpr) = (yyvsp[(3) - (3)].tiexpr); if ((yyval.tiexpr) && (yyvsp[(2) - (3)].bValue)) { Type tt = (yyval.tiexpr)->type(); tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } ;} break; case 63: { (yyval.tiexpr) = (yyvsp[(3) - (3)].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.ti(Type::TI_VAR); if ((yyvsp[(2) - (3)].bValue)) tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } ;} break; case 64: { (yyval.tiexpr) = (yyvsp[(4) - (4)].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.st(Type::ST_SET); if ((yyvsp[(1) - (4)].bValue)) tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } ;} break; case 65: { (yyval.tiexpr) = (yyvsp[(5) - (5)].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.st(Type::ST_SET); if ((yyvsp[(2) - (5)].bValue)) tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } ;} break; case 66: { (yyval.tiexpr) = (yyvsp[(5) - (5)].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.ti(Type::TI_VAR); tt.st(Type::ST_SET); if ((yyvsp[(2) - (5)].bValue)) tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } ;} break; case 67: { (yyval.bValue) = false; ;} break; case 68: { (yyval.bValue) = true; ;} break; case 69: { (yyval.tiexpr) = new TypeInst((yyloc),Type::parint()); ;} break; case 70: { (yyval.tiexpr) = new TypeInst((yyloc),Type::parbool()); ;} break; case 71: { (yyval.tiexpr) = new TypeInst((yyloc),Type::parfloat()); ;} break; case 72: { (yyval.tiexpr) = new TypeInst((yyloc),Type::parstring()); ;} break; case 73: { (yyval.tiexpr) = new TypeInst((yyloc),Type::ann()); ;} break; case 74: { (yyval.tiexpr) = new TypeInst((yyloc),Type(),(yyvsp[(1) - (1)].expression)); ;} break; case 75: { (yyval.tiexpr) = new TypeInst((yyloc),Type::top(), new TIId((yyloc), (yyvsp[(1) - (1)].sValue))); free((yyvsp[(1) - (1)].sValue)); ;} break; case 77: { (yyval.expression_v)=new std::vector; (yyval.expression_v)->push_back((yyvsp[(1) - (1)].expression)); ;} break; case 78: { (yyval.expression_v)=(yyvsp[(1) - (3)].expression_v); if ((yyval.expression_v) && (yyvsp[(3) - (3)].expression)) (yyval.expression_v)->push_back((yyvsp[(3) - (3)].expression)); ;} break; case 80: { if ((yyvsp[(1) - (3)].expression) && (yyvsp[(3) - (3)].expression)) (yyvsp[(1) - (3)].expression)->addAnnotation((yyvsp[(3) - (3)].expression)); (yyval.expression)=(yyvsp[(1) - (3)].expression); ;} break; case 81: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_UNION, (yyvsp[(3) - (3)].expression)); ;} break; case 82: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_DIFF, (yyvsp[(3) - (3)].expression)); ;} break; case 83: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_SYMDIFF, (yyvsp[(3) - (3)].expression)); ;} break; case 84: { if ((yyvsp[(1) - (3)].expression)->isa() && (yyvsp[(3) - (3)].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a((yyvsp[(1) - (3)].expression)->cast()->v(),(yyvsp[(3) - (3)].expression)->cast()->v())); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_DOTDOT, (yyvsp[(3) - (3)].expression)); } ;} break; case 85: { if ((yyvsp[(3) - (6)].expression)->isa() && (yyvsp[(5) - (6)].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a((yyvsp[(3) - (6)].expression)->cast()->v(),(yyvsp[(5) - (6)].expression)->cast()->v())); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[(3) - (6)].expression), BOT_DOTDOT, (yyvsp[(5) - (6)].expression)); } ;} break; case 86: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_INTERSECT, (yyvsp[(3) - (3)].expression)); ;} break; case 87: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_PLUSPLUS, (yyvsp[(3) - (3)].expression)); ;} break; case 88: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_PLUS, (yyvsp[(3) - (3)].expression)); ;} break; case 89: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_MINUS, (yyvsp[(3) - (3)].expression)); ;} break; case 90: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_MULT, (yyvsp[(3) - (3)].expression)); ;} break; case 91: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_DIV, (yyvsp[(3) - (3)].expression)); ;} break; case 92: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_IDIV, (yyvsp[(3) - (3)].expression)); ;} break; case 93: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_MOD, (yyvsp[(3) - (3)].expression)); ;} break; case 94: { vector args; args.push_back((yyvsp[(1) - (3)].expression)); args.push_back((yyvsp[(3) - (3)].expression)); (yyval.expression)=new Call((yyloc), (yyvsp[(2) - (3)].sValue), args); free((yyvsp[(2) - (3)].sValue)); ;} break; case 95: { (yyval.expression)=new UnOp((yyloc), UOT_PLUS, (yyvsp[(2) - (2)].expression)); ;} break; case 96: { if ((yyvsp[(2) - (2)].expression) && (yyvsp[(2) - (2)].expression)->isa()) { (yyvsp[(2) - (2)].expression)->cast()->v(-(yyvsp[(2) - (2)].expression)->cast()->v()); (yyval.expression) = (yyvsp[(2) - (2)].expression); } else if ((yyvsp[(2) - (2)].expression) && (yyvsp[(2) - (2)].expression)->isa()) { (yyvsp[(2) - (2)].expression)->cast()->v(-(yyvsp[(2) - (2)].expression)->cast()->v()); (yyval.expression) = (yyvsp[(2) - (2)].expression); } else { (yyval.expression)=new UnOp((yyloc), UOT_MINUS, (yyvsp[(2) - (2)].expression)); } ;} break; case 98: { if ((yyvsp[(1) - (3)].expression) && (yyvsp[(3) - (3)].expression)) (yyvsp[(1) - (3)].expression)->addAnnotation((yyvsp[(3) - (3)].expression)); (yyval.expression)=(yyvsp[(1) - (3)].expression); ;} break; case 99: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_EQUIV, (yyvsp[(3) - (3)].expression)); ;} break; case 100: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_IMPL, (yyvsp[(3) - (3)].expression)); ;} break; case 101: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_RIMPL, (yyvsp[(3) - (3)].expression)); ;} break; case 102: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_OR, (yyvsp[(3) - (3)].expression)); ;} break; case 103: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_XOR, (yyvsp[(3) - (3)].expression)); ;} break; case 104: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_AND, (yyvsp[(3) - (3)].expression)); ;} break; case 105: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_LE, (yyvsp[(3) - (3)].expression)); ;} break; case 106: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_GR, (yyvsp[(3) - (3)].expression)); ;} break; case 107: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_LQ, (yyvsp[(3) - (3)].expression)); ;} break; case 108: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_GQ, (yyvsp[(3) - (3)].expression)); ;} break; case 109: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_EQ, (yyvsp[(3) - (3)].expression)); ;} break; case 110: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_NQ, (yyvsp[(3) - (3)].expression)); ;} break; case 111: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_IN, (yyvsp[(3) - (3)].expression)); ;} break; case 112: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_SUBSET, (yyvsp[(3) - (3)].expression)); ;} break; case 113: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_SUPERSET, (yyvsp[(3) - (3)].expression)); ;} break; case 114: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_UNION, (yyvsp[(3) - (3)].expression)); ;} break; case 115: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_DIFF, (yyvsp[(3) - (3)].expression)); ;} break; case 116: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_SYMDIFF, (yyvsp[(3) - (3)].expression)); ;} break; case 117: { if ((yyvsp[(1) - (3)].expression)->isa() && (yyvsp[(3) - (3)].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a((yyvsp[(1) - (3)].expression)->cast()->v(),(yyvsp[(3) - (3)].expression)->cast()->v())); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_DOTDOT, (yyvsp[(3) - (3)].expression)); } ;} break; case 118: { if ((yyvsp[(3) - (6)].expression)->isa() && (yyvsp[(5) - (6)].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a((yyvsp[(3) - (6)].expression)->cast()->v(),(yyvsp[(5) - (6)].expression)->cast()->v())); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[(3) - (6)].expression), BOT_DOTDOT, (yyvsp[(5) - (6)].expression)); } ;} break; case 119: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_INTERSECT, (yyvsp[(3) - (3)].expression)); ;} break; case 120: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_PLUSPLUS, (yyvsp[(3) - (3)].expression)); ;} break; case 121: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_PLUS, (yyvsp[(3) - (3)].expression)); ;} break; case 122: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_MINUS, (yyvsp[(3) - (3)].expression)); ;} break; case 123: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_MULT, (yyvsp[(3) - (3)].expression)); ;} break; case 124: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_DIV, (yyvsp[(3) - (3)].expression)); ;} break; case 125: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_IDIV, (yyvsp[(3) - (3)].expression)); ;} break; case 126: { (yyval.expression)=new BinOp((yyloc), (yyvsp[(1) - (3)].expression), BOT_MOD, (yyvsp[(3) - (3)].expression)); ;} break; case 127: { vector args; args.push_back((yyvsp[(1) - (3)].expression)); args.push_back((yyvsp[(3) - (3)].expression)); (yyval.expression)=new Call((yyloc), (yyvsp[(2) - (3)].sValue), args); free((yyvsp[(2) - (3)].sValue)); ;} break; case 128: { (yyval.expression)=new UnOp((yyloc), UOT_NOT, (yyvsp[(2) - (2)].expression)); ;} break; case 129: { if (((yyvsp[(2) - (2)].expression) && (yyvsp[(2) - (2)].expression)->isa()) || ((yyvsp[(2) - (2)].expression) && (yyvsp[(2) - (2)].expression)->isa())) { (yyval.expression) = (yyvsp[(2) - (2)].expression); } else { (yyval.expression)=new UnOp((yyloc), UOT_PLUS, (yyvsp[(2) - (2)].expression)); } ;} break; case 130: { if ((yyvsp[(2) - (2)].expression) && (yyvsp[(2) - (2)].expression)->isa()) { (yyvsp[(2) - (2)].expression)->cast()->v(-(yyvsp[(2) - (2)].expression)->cast()->v()); (yyval.expression) = (yyvsp[(2) - (2)].expression); } else if ((yyvsp[(2) - (2)].expression) && (yyvsp[(2) - (2)].expression)->isa()) { (yyvsp[(2) - (2)].expression)->cast()->v(-(yyvsp[(2) - (2)].expression)->cast()->v()); (yyval.expression) = (yyvsp[(2) - (2)].expression); } else { (yyval.expression)=new UnOp((yyloc), UOT_MINUS, (yyvsp[(2) - (2)].expression)); } ;} break; case 131: { (yyval.expression)=(yyvsp[(2) - (3)].expression); ;} break; case 132: { (yyval.expression)=createArrayAccess((yyloc), (yyvsp[(2) - (4)].expression), *(yyvsp[(4) - (4)].expression_vv)); delete (yyvsp[(4) - (4)].expression_vv); ;} break; case 133: { (yyval.expression)=new Id((yyloc), (yyvsp[(1) - (1)].sValue), NULL); free((yyvsp[(1) - (1)].sValue)); ;} break; case 134: { (yyval.expression)=createArrayAccess((yyloc), new Id((yylsp[(1) - (2)]),(yyvsp[(1) - (2)].sValue),NULL), *(yyvsp[(2) - (2)].expression_vv)); free((yyvsp[(1) - (2)].sValue)); delete (yyvsp[(2) - (2)].expression_vv); ;} break; case 135: { (yyval.expression)=new AnonVar((yyloc)); ;} break; case 136: { (yyval.expression)=createArrayAccess((yyloc), new AnonVar((yyloc)), *(yyvsp[(2) - (2)].expression_vv)); delete (yyvsp[(2) - (2)].expression_vv); ;} break; case 137: { (yyval.expression)=new BoolLit((yyloc), ((yyvsp[(1) - (1)].iValue)!=0)); ;} break; case 138: { (yyval.expression)=new IntLit((yyloc), (yyvsp[(1) - (1)].iValue)); ;} break; case 139: { (yyval.expression)=new IntLit((yyloc), IntVal::infinity); ;} break; case 140: { (yyval.expression)=new FloatLit((yyloc), (yyvsp[(1) - (1)].dValue)); ;} break; case 142: { (yyval.expression)=constants().absent; ;} break; case 144: { (yyval.expression)=createArrayAccess((yyloc), (yyvsp[(1) - (2)].expression), *(yyvsp[(2) - (2)].expression_vv)); delete (yyvsp[(2) - (2)].expression_vv); ;} break; case 146: { (yyval.expression)=createArrayAccess((yyloc), (yyvsp[(1) - (2)].expression), *(yyvsp[(2) - (2)].expression_vv)); delete (yyvsp[(2) - (2)].expression_vv); ;} break; case 148: { (yyval.expression)=createArrayAccess((yyloc), (yyvsp[(1) - (2)].expression), *(yyvsp[(2) - (2)].expression_vv)); delete (yyvsp[(2) - (2)].expression_vv); ;} break; case 150: { (yyval.expression)=createArrayAccess((yyloc), (yyvsp[(1) - (2)].expression), *(yyvsp[(2) - (2)].expression_vv)); delete (yyvsp[(2) - (2)].expression_vv); ;} break; case 152: { (yyval.expression)=createArrayAccess((yyloc), (yyvsp[(1) - (2)].expression), *(yyvsp[(2) - (2)].expression_vv)); delete (yyvsp[(2) - (2)].expression_vv); ;} break; case 154: { (yyval.expression)=createArrayAccess((yyloc), (yyvsp[(1) - (2)].expression), *(yyvsp[(2) - (2)].expression_vv)); delete (yyvsp[(2) - (2)].expression_vv); ;} break; case 157: { (yyval.expression)=createArrayAccess((yyloc), (yyvsp[(1) - (2)].expression), *(yyvsp[(2) - (2)].expression_vv)); delete (yyvsp[(2) - (2)].expression_vv); ;} break; case 158: { (yyval.expression)=new StringLit((yyloc), (yyvsp[(1) - (1)].sValue)); free((yyvsp[(1) - (1)].sValue)); ;} break; case 159: { (yyval.expression)=new BinOp((yyloc), new StringLit((yyloc), (yyvsp[(1) - (2)].sValue)), BOT_PLUSPLUS, (yyvsp[(2) - (2)].expression)); free((yyvsp[(1) - (2)].sValue)); ;} break; case 160: { (yyval.expression)=new BinOp((yyloc), new Call((yyloc), ASTString("format"), *(yyvsp[(1) - (2)].expression_v)), BOT_PLUSPLUS, new StringLit((yyloc),(yyvsp[(2) - (2)].sValue))); free((yyvsp[(2) - (2)].sValue)); delete (yyvsp[(1) - (2)].expression_v); ;} break; case 161: { (yyval.expression)=new BinOp((yyloc), new Call((yyloc), ASTString("format"), *(yyvsp[(1) - (3)].expression_v)), BOT_PLUSPLUS, new BinOp((yyloc), new StringLit((yyloc),(yyvsp[(2) - (3)].sValue)), BOT_PLUSPLUS, (yyvsp[(3) - (3)].expression))); free((yyvsp[(2) - (3)].sValue)); delete (yyvsp[(1) - (3)].expression_v); ;} break; case 162: { (yyval.expression_vv)=new std::vector >(); if ((yyvsp[(2) - (3)].expression_v)) { (yyval.expression_vv)->push_back(*(yyvsp[(2) - (3)].expression_v)); delete (yyvsp[(2) - (3)].expression_v); } ;} break; case 163: { (yyval.expression_vv)=(yyvsp[(1) - (4)].expression_vv); if ((yyval.expression_vv) && (yyvsp[(3) - (4)].expression_v)) { (yyval.expression_vv)->push_back(*(yyvsp[(3) - (4)].expression_v)); delete (yyvsp[(3) - (4)].expression_v); } ;} break; case 164: { (yyval.expression) = new SetLit((yyloc), std::vector()); ;} break; case 165: { (yyval.expression) = new SetLit((yyloc), *(yyvsp[(2) - (3)].expression_v)); delete (yyvsp[(2) - (3)].expression_v); ;} break; case 166: { (yyval.expression) = new Comprehension((yyloc), (yyvsp[(2) - (5)].expression), *(yyvsp[(4) - (5)].generators), true); delete (yyvsp[(4) - (5)].generators); ;} break; case 167: { (yyval.generators)=new Generators; (yyval.generators)->_g = *(yyvsp[(1) - (1)].generator_v); (yyval.generators)->_w = NULL; delete (yyvsp[(1) - (1)].generator_v); ;} break; case 168: { (yyval.generators)=new Generators; (yyval.generators)->_g = *(yyvsp[(1) - (3)].generator_v); (yyval.generators)->_w = (yyvsp[(3) - (3)].expression); delete (yyvsp[(1) - (3)].generator_v); ;} break; case 170: { (yyval.generator_v)=new std::vector; if ((yyvsp[(1) - (1)].generator)) (yyval.generator_v)->push_back(*(yyvsp[(1) - (1)].generator)); delete (yyvsp[(1) - (1)].generator); ;} break; case 171: { (yyval.generator_v)=(yyvsp[(1) - (3)].generator_v); if ((yyvsp[(3) - (3)].generator)) (yyval.generator_v)->push_back(*(yyvsp[(3) - (3)].generator)); delete (yyvsp[(3) - (3)].generator); ;} break; case 172: { if ((yyvsp[(3) - (3)].expression)) (yyval.generator)=new Generator(*(yyvsp[(1) - (3)].string_v),(yyvsp[(3) - (3)].expression)); else (yyval.generator)=NULL; delete (yyvsp[(1) - (3)].string_v); ;} break; case 174: { (yyval.string_v)=new std::vector; (yyval.string_v)->push_back((yyvsp[(1) - (1)].sValue)); free((yyvsp[(1) - (1)].sValue)); ;} break; case 175: { (yyval.string_v)=(yyvsp[(1) - (3)].string_v); (yyval.string_v)->push_back((yyvsp[(3) - (3)].sValue)); free((yyvsp[(3) - (3)].sValue)); ;} break; case 176: { (yyval.expression)=new ArrayLit((yyloc), std::vector()); ;} break; case 177: { (yyval.expression)=new ArrayLit((yyloc), *(yyvsp[(2) - (3)].expression_v)); delete (yyvsp[(2) - (3)].expression_v); ;} break; case 178: { (yyval.expression)=new ArrayLit((yyloc), std::vector >()); ;} break; case 179: { if ((yyvsp[(2) - (3)].expression_vv)) { (yyval.expression)=new ArrayLit((yyloc), *(yyvsp[(2) - (3)].expression_vv)); for (unsigned int i=1; i<(yyvsp[(2) - (3)].expression_vv)->size(); i++) if ((*(yyvsp[(2) - (3)].expression_vv))[i].size() != (*(yyvsp[(2) - (3)].expression_vv))[i-1].size()) yyerror(&(yylsp[(2) - (3)]), parm, "syntax error, all sub-arrays of 2d array literal must have the same length"); delete (yyvsp[(2) - (3)].expression_vv); } else { (yyval.expression) = NULL; } ;} break; case 180: { if ((yyvsp[(2) - (4)].expression_vv)) { (yyval.expression)=new ArrayLit((yyloc), *(yyvsp[(2) - (4)].expression_vv)); for (unsigned int i=1; i<(yyvsp[(2) - (4)].expression_vv)->size(); i++) if ((*(yyvsp[(2) - (4)].expression_vv))[i].size() != (*(yyvsp[(2) - (4)].expression_vv))[i-1].size()) yyerror(&(yylsp[(2) - (4)]), parm, "syntax error, all sub-arrays of 2d array literal must have the same length"); delete (yyvsp[(2) - (4)].expression_vv); } else { (yyval.expression) = NULL; } ;} break; case 181: { if ((yyvsp[(2) - (3)].expression_vvv)) { std::vector > dims(3); dims[0] = std::pair(1,(yyvsp[(2) - (3)].expression_vvv)->size()); if ((yyvsp[(2) - (3)].expression_vvv)->size()==0) { dims[1] = std::pair(1,0); dims[2] = std::pair(1,0); } else { dims[1] = std::pair(1,(*(yyvsp[(2) - (3)].expression_vvv))[0].size()); if ((*(yyvsp[(2) - (3)].expression_vvv))[0].size()==0) { dims[2] = std::pair(1,0); } else { dims[2] = std::pair(1,(*(yyvsp[(2) - (3)].expression_vvv))[0][0].size()); } } std::vector a; for (unsigned int i=0; i > >; ;} break; case 183: { (yyval.expression_vvv)=new std::vector > >; (yyval.expression_vvv)->push_back(*(yyvsp[(2) - (3)].expression_vv)); delete (yyvsp[(2) - (3)].expression_vv); ;} break; case 184: { (yyval.expression_vvv)=(yyvsp[(1) - (5)].expression_vvv); if ((yyval.expression_vvv)) (yyval.expression_vvv)->push_back(*(yyvsp[(4) - (5)].expression_vv)); delete (yyvsp[(4) - (5)].expression_vv); ;} break; case 185: { (yyval.expression_vv)=new std::vector >; (yyval.expression_vv)->push_back(*(yyvsp[(1) - (1)].expression_v)); delete (yyvsp[(1) - (1)].expression_v); ;} break; case 186: { (yyval.expression_vv)=(yyvsp[(1) - (3)].expression_vv); if ((yyval.expression_vv)) (yyval.expression_vv)->push_back(*(yyvsp[(3) - (3)].expression_v)); delete (yyvsp[(3) - (3)].expression_v); ;} break; case 187: { (yyval.expression)=new Comprehension((yyloc), (yyvsp[(2) - (5)].expression), *(yyvsp[(4) - (5)].generators), false); delete (yyvsp[(4) - (5)].generators); ;} break; case 188: { std::vector iexps; iexps.push_back((yyvsp[(2) - (8)].expression)); iexps.push_back((yyvsp[(4) - (8)].expression)); if ((yyvsp[(5) - (8)].expression_v)) { for (unsigned int i=0; i<(yyvsp[(5) - (8)].expression_v)->size(); i+=2) { iexps.push_back((*(yyvsp[(5) - (8)].expression_v))[i]); iexps.push_back((*(yyvsp[(5) - (8)].expression_v))[i+1]); } } (yyval.expression)=new ITE((yyloc), iexps,(yyvsp[(7) - (8)].expression)); delete (yyvsp[(5) - (8)].expression_v); ;} break; case 189: { (yyval.expression_v)=new std::vector; ;} break; case 190: { (yyval.expression_v)=(yyvsp[(1) - (5)].expression_v); if ((yyval.expression_v)) { (yyval.expression_v)->push_back((yyvsp[(3) - (5)].expression)); (yyval.expression_v)->push_back((yyvsp[(5) - (5)].expression)); } ;} break; case 191: { (yyval.iValue)=BOT_EQUIV; ;} break; case 192: { (yyval.iValue)=BOT_IMPL; ;} break; case 193: { (yyval.iValue)=BOT_RIMPL; ;} break; case 194: { (yyval.iValue)=BOT_OR; ;} break; case 195: { (yyval.iValue)=BOT_XOR; ;} break; case 196: { (yyval.iValue)=BOT_AND; ;} break; case 197: { (yyval.iValue)=BOT_LE; ;} break; case 198: { (yyval.iValue)=BOT_GR; ;} break; case 199: { (yyval.iValue)=BOT_LQ; ;} break; case 200: { (yyval.iValue)=BOT_GQ; ;} break; case 201: { (yyval.iValue)=BOT_EQ; ;} break; case 202: { (yyval.iValue)=BOT_NQ; ;} break; case 203: { (yyval.iValue)=BOT_IN; ;} break; case 204: { (yyval.iValue)=BOT_SUBSET; ;} break; case 205: { (yyval.iValue)=BOT_SUPERSET; ;} break; case 206: { (yyval.iValue)=BOT_UNION; ;} break; case 207: { (yyval.iValue)=BOT_DIFF; ;} break; case 208: { (yyval.iValue)=BOT_SYMDIFF; ;} break; case 209: { (yyval.iValue)=BOT_PLUS; ;} break; case 210: { (yyval.iValue)=BOT_MINUS; ;} break; case 211: { (yyval.iValue)=BOT_MULT; ;} break; case 212: { (yyval.iValue)=BOT_DIV; ;} break; case 213: { (yyval.iValue)=BOT_IDIV; ;} break; case 214: { (yyval.iValue)=BOT_MOD; ;} break; case 215: { (yyval.iValue)=BOT_INTERSECT; ;} break; case 216: { (yyval.iValue)=BOT_PLUSPLUS; ;} break; case 217: { (yyval.iValue)=-1; ;} break; case 218: { if ((yyvsp[(1) - (6)].iValue)==-1) { (yyval.expression)=NULL; yyerror(&(yylsp[(3) - (6)]), parm, "syntax error, unary operator with two arguments"); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[(3) - (6)].expression),static_cast((yyvsp[(1) - (6)].iValue)),(yyvsp[(5) - (6)].expression)); } ;} break; case 219: { int uot=-1; switch ((yyvsp[(1) - (4)].iValue)) { case -1: uot = UOT_NOT; break; case BOT_MINUS: uot = UOT_MINUS; break; case BOT_PLUS: uot = UOT_PLUS; break; default: yyerror(&(yylsp[(3) - (4)]), parm, "syntax error, binary operator with unary argument list"); break; } if (uot==-1) (yyval.expression)=NULL; else { if (uot==UOT_PLUS && (yyvsp[(3) - (4)].expression) && ((yyvsp[(3) - (4)].expression)->isa() || (yyvsp[(3) - (4)].expression)->isa())) { (yyval.expression) = (yyvsp[(3) - (4)].expression); } else if (uot==UOT_MINUS && (yyvsp[(3) - (4)].expression) && (yyvsp[(3) - (4)].expression)->isa()) { (yyvsp[(3) - (4)].expression)->cast()->v(-(yyvsp[(3) - (4)].expression)->cast()->v()); } else if (uot==UOT_MINUS && (yyvsp[(3) - (4)].expression) && (yyvsp[(3) - (4)].expression)->isa()) { (yyvsp[(3) - (4)].expression)->cast()->v(-(yyvsp[(3) - (4)].expression)->cast()->v()); } else { (yyval.expression)=new UnOp((yyloc), static_cast(uot),(yyvsp[(3) - (4)].expression)); } } ;} break; case 220: { (yyval.expression)=new Call((yyloc), (yyvsp[(1) - (3)].sValue), std::vector()); free((yyvsp[(1) - (3)].sValue)); ;} break; case 222: { if ((yyvsp[(3) - (4)].expression_p)==NULL || (yyvsp[(3) - (4)].expression_p)->second) { yyerror(&(yylsp[(3) - (4)]), parm, "syntax error, 'where' expression outside generator call"); (yyval.expression)=NULL; } else { (yyval.expression)=new Call((yyloc), (yyvsp[(1) - (4)].sValue), (yyvsp[(3) - (4)].expression_p)->first); } free((yyvsp[(1) - (4)].sValue)); delete (yyvsp[(3) - (4)].expression_p); ;} break; case 223: { vector gens; vector ids; if ((yyvsp[(3) - (7)].expression_p)) { for (unsigned int i=0; i<(yyvsp[(3) - (7)].expression_p)->first.size(); i++) { if (Id* id = Expression::dyn_cast((yyvsp[(3) - (7)].expression_p)->first[i])) { ids.push_back(id->v()); } else { if (BinOp* boe = Expression::dyn_cast((yyvsp[(3) - (7)].expression_p)->first[i])) { if (boe->lhs() && boe->rhs()) { Id* id = Expression::dyn_cast(boe->lhs()); if (id && boe->op() == BOT_IN) { ids.push_back(id->v()); gens.push_back(Generator(ids,boe->rhs())); ids = vector(); } else { yyerror(&(yylsp[(3) - (7)]), parm, "illegal expression in generator call"); } } } else { yyerror(&(yylsp[(3) - (7)]), parm, "illegal expression in generator call"); } } } } if (ids.size() != 0) { yyerror(&(yylsp[(3) - (7)]), parm, "illegal expression in generator call"); } ParserState* pp = static_cast(parm); if (pp->hadError) { (yyval.expression)=NULL; } else { Generators g; g._g = gens; g._w = (yyvsp[(3) - (7)].expression_p)->second; Comprehension* ac = new Comprehension((yyloc), (yyvsp[(6) - (7)].expression),g,false); vector args; args.push_back(ac); (yyval.expression)=new Call((yyloc), (yyvsp[(1) - (7)].sValue), args); } free((yyvsp[(1) - (7)].sValue)); delete (yyvsp[(3) - (7)].expression_p); ;} break; case 224: { (yyval.expression_p)=new pair,Expression*>; (yyval.expression_p)->first=*(yyvsp[(1) - (1)].expression_v); (yyval.expression_p)->second=NULL; delete (yyvsp[(1) - (1)].expression_v); ;} break; case 225: { (yyval.expression_p)=new pair,Expression*>; (yyval.expression_p)->first=*(yyvsp[(1) - (3)].expression_v); (yyval.expression_p)->second=(yyvsp[(3) - (3)].expression); delete (yyvsp[(1) - (3)].expression_v); ;} break; case 226: { (yyval.expression)=new Let((yyloc), *(yyvsp[(3) - (6)].expression_v), (yyvsp[(6) - (6)].expression)); delete (yyvsp[(3) - (6)].expression_v); ;} break; case 227: { (yyval.expression)=new Let((yyloc), *(yyvsp[(3) - (7)].expression_v), (yyvsp[(7) - (7)].expression)); delete (yyvsp[(3) - (7)].expression_v); ;} break; case 228: { (yyval.expression_v)=new vector; (yyval.expression_v)->push_back((yyvsp[(1) - (1)].vardeclexpr)); ;} break; case 229: { (yyval.expression_v)=new vector; if ((yyvsp[(1) - (1)].item)) { ConstraintI* ce = (yyvsp[(1) - (1)].item)->cast(); (yyval.expression_v)->push_back(ce->e()); ce->e(NULL); } ;} break; case 230: { (yyval.expression_v)=(yyvsp[(1) - (3)].expression_v); (yyval.expression_v)->push_back((yyvsp[(3) - (3)].vardeclexpr)); ;} break; case 231: { (yyval.expression_v)=(yyvsp[(1) - (3)].expression_v); if ((yyvsp[(3) - (3)].item)) { ConstraintI* ce = (yyvsp[(3) - (3)].item)->cast(); (yyval.expression_v)->push_back(ce->e()); ce->e(NULL); } ;} break; case 234: { (yyval.vardeclexpr) = (yyvsp[(1) - (2)].vardeclexpr); if ((yyval.vardeclexpr)) (yyval.vardeclexpr)->toplevel(false); if ((yyval.vardeclexpr) && (yyvsp[(2) - (2)].expression_v)) (yyval.vardeclexpr)->addAnnotations(*(yyvsp[(2) - (2)].expression_v)); delete (yyvsp[(2) - (2)].expression_v); ;} break; case 235: { if ((yyvsp[(1) - (4)].vardeclexpr)) (yyvsp[(1) - (4)].vardeclexpr)->e((yyvsp[(4) - (4)].expression)); (yyval.vardeclexpr) = (yyvsp[(1) - (4)].vardeclexpr); if ((yyval.vardeclexpr)) (yyval.vardeclexpr)->loc((yyloc)); if ((yyval.vardeclexpr)) (yyval.vardeclexpr)->toplevel(false); if ((yyval.vardeclexpr) && (yyvsp[(2) - (4)].expression_v)) (yyval.vardeclexpr)->addAnnotations(*(yyvsp[(2) - (4)].expression_v)); delete (yyvsp[(2) - (4)].expression_v); ;} break; case 236: { (yyval.expression_v)=NULL; ;} break; case 238: { (yyval.expression_v)=new std::vector(1); (*(yyval.expression_v))[0] = (yyvsp[(2) - (2)].expression); ;} break; case 239: { (yyval.expression_v)=(yyvsp[(1) - (3)].expression_v); if ((yyval.expression_v)) (yyval.expression_v)->push_back((yyvsp[(3) - (3)].expression)); ;} break; case 240: { (yyval.sValue)=(yyvsp[(1) - (1)].sValue); ;} break; case 241: { (yyval.sValue)=strdup("<->"); ;} break; case 242: { (yyval.sValue)=strdup("->"); ;} break; case 243: { (yyval.sValue)=strdup("<-"); ;} break; case 244: { (yyval.sValue)=strdup("\\/"); ;} break; case 245: { (yyval.sValue)=strdup("xor"); ;} break; case 246: { (yyval.sValue)=strdup("/\\"); ;} break; case 247: { (yyval.sValue)=strdup("<"); ;} break; case 248: { (yyval.sValue)=strdup(">"); ;} break; case 249: { (yyval.sValue)=strdup("<="); ;} break; case 250: { (yyval.sValue)=strdup(">="); ;} break; case 251: { (yyval.sValue)=strdup("="); ;} break; case 252: { (yyval.sValue)=strdup("!="); ;} break; case 253: { (yyval.sValue)=strdup("in"); ;} break; case 254: { (yyval.sValue)=strdup("subset"); ;} break; case 255: { (yyval.sValue)=strdup("superset"); ;} break; case 256: { (yyval.sValue)=strdup("union"); ;} break; case 257: { (yyval.sValue)=strdup("diff"); ;} break; case 258: { (yyval.sValue)=strdup("symdiff"); ;} break; case 259: { (yyval.sValue)=strdup(".."); ;} break; case 260: { (yyval.sValue)=strdup("+"); ;} break; case 261: { (yyval.sValue)=strdup("-"); ;} break; case 262: { (yyval.sValue)=strdup("*"); ;} break; case 263: { (yyval.sValue)=strdup("/"); ;} break; case 264: { (yyval.sValue)=strdup("div"); ;} break; case 265: { (yyval.sValue)=strdup("mod"); ;} break; case 266: { (yyval.sValue)=strdup("intersect"); ;} break; case 267: { (yyval.sValue)=strdup("not"); ;} break; case 268: { (yyval.sValue)=strdup("++"); ;} break; /* Line 1267 of yacc.c. */ default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; *++yylsp = yyloc; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (&yylloc, parm, YY_("syntax error")); #else { YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) { YYSIZE_T yyalloc = 2 * yysize; if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) yyalloc = YYSTACK_ALLOC_MAXIMUM; if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yyalloc); if (yymsg) yymsg_alloc = yyalloc; else { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; } } if (0 < yysize && yysize <= yymsg_alloc) { (void) yysyntax_error (yymsg, yystate, yychar); yyerror (&yylloc, parm, yymsg); } else { yyerror (&yylloc, parm, YY_("syntax error")); if (yysize != 0) goto yyexhaustedlab; } } #endif } yyerror_range[0] = yylloc; if (yyerrstatus == 3) { /* If just tried and failed to reuse look-ahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, &yylloc, parm); yychar = YYEMPTY; } } /* Else will try to reuse look-ahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; yyerror_range[0] = yylsp[1-yylen]; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yyerror_range[0] = *yylsp; yydestruct ("Error: popping", yystos[yystate], yyvsp, yylsp, parm); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } if (yyn == YYFINAL) YYACCEPT; *++yyvsp = yylval; yyerror_range[1] = yylloc; /* Using YYLLOC is tempting, but would change the location of the look-ahead. YYLOC is available though. */ YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); *++yylsp = yyloc; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #ifndef yyoverflow /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (&yylloc, parm, YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEOF && yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc, parm); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp, yylsp, parm); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); } libminizinc-2.0.11/md5_gen.cmake0000644000175000017500000000220012646030173015054 0ustar kaolkaol# Script to update the cached lexer and parser # Run after modifying lexer.lxx and/or parser.yxx # # 1. generate lexer and parser by building libminizinc # 2. run cmake -DPROJECT_SOURCE_DIR=. -DPROJECT_BINARY_DIR=build -P md5_gen.cmake # replacing . and build with the source and binary directory macro(MD5 filename md5sum) file(READ "${filename}" RAW_MD5_FILE) string(REGEX REPLACE "\r" "" STRIPPED_MD5_FILE "${RAW_MD5_FILE}") string(MD5 ${md5sum} "${STRIPPED_MD5_FILE}") endmacro(MD5) file(COPY "${PROJECT_BINARY_DIR}/lexer.yy.cpp" DESTINATION "${PROJECT_SOURCE_DIR}/lib/cached/") file(COPY "${PROJECT_BINARY_DIR}/parser.tab.cpp" DESTINATION "${PROJECT_SOURCE_DIR}/lib/cached/") file(COPY "${PROJECT_BINARY_DIR}/minizinc/parser.tab.hh" DESTINATION "${PROJECT_SOURCE_DIR}/lib/cached/minizinc/") MD5("${PROJECT_SOURCE_DIR}/lib/lexer.lxx" lexer_lxx_md5) MD5("${PROJECT_SOURCE_DIR}/lib/parser.yxx" parser_yxx_md5) set(MD5_TEMPLATE "set(lexer_lxx_md5_cached \"${lexer_lxx_md5}\")") set(MD5_TEMPLATE "${MD5_TEMPLATE}\nset(parser_yxx_md5_cached \"${parser_yxx_md5}\")") file(WRITE "${PROJECT_SOURCE_DIR}/lib/cached/md5_cached.cmake" ${MD5_TEMPLATE}) libminizinc-2.0.11/CHANGES.txt0000644000175000017500000004053212646030173014357 0ustar kaolkaol====================== # MiniZinc Changelog # ====================== All bug numbers refer to the issue tracker at https://github.com/MiniZinc/libminizinc/issues Version 2.0.11 ============== Bug fixes: - Fix parsing of hex and octal literals. Fixes #71. - Fix compilation of extended comprehensions. Fixes #72. - Fix computation of float array access bounds. - Fix aggregation of clauses (could sometimes ignore the negative literals). Version 2.0.10 ============== Bug fixes: - Fix a bug in the optimiser that could lead to undefined variables in the generated FlatZinc. Fixes #70. Version 2.0.9 ============= Bug fixes: - Need to take return type into account when copying functions to output model. Fixes #55. - Evaluate calls that result in arrays using eval_arraylit. Fixes #57. - Move inverse function to its own library file, so that it remains available when a solver provides an alternative for the inverse predicate. - Optimisation phase now recursively checks constraints when elements in an array become fixed. - Fix CMakeLists file to work for paths that contain spaces. - Distinguish between infix operators and regular functions in the generated html documentation. Fixes #61. - Made parser more robust against incorrect code. - Fix increment/decrement operators for IntVals and make all operations throw correct overflow exceptions. - Fix automatic type coercion for variables declared in let expressions. - Fix a crash when printing some error messages. - Fix compute_div_bounds builtin to return correct result for a division by zero. - Fix optimisation of Boolean constraints to use pointer equality instead of structural equality (same expression can occur multiple times in the FlatZinc). - Only optimise constraints that have not been removed yet. - Fix declaration of functional version of bin_packing_load. Fixes #64. - Set type of arrays returned from polymorphic functions. Fixes #65. - Fix parsing of quoted unary operator calls. - Only compute set functions when bounds are valid. Fixes #66. - Compute proper bounds for if-then-else expressions. - Report error when no reified version of a constraint is available. Fixes #67. - Fix type checking of annotations on binary operators. - Keep annotations when rewriting linear constraints and remove is_defined_var annotations from fixed variables. Fixes #69. Changes: - Integer, Boolean and float literals are now cached to achieve better memory performance for some models. - Improve performance of parsing integer literals. - Improve handling of clause constraints. - Add source files of MiniZinc specification to the repository. - Limit maximum array size to enable better error messages. - Add implied_constraint predicate as a synonym for redundant_constraint. Version 2.0.8 ============= Bug fixes: - Fix incorrect negation of some reified comparisons. - Make lb/ub functions work in more cases. - Fix several bugs in the optimisation phase (could lead to incorrect FlatZinc and crashes). - Fix a problem with reverse mapper functions when the result of the reverse mapper can be fixed to a constant. Version 2.0.7 ============= Changes: - Improved propagation of Boolean constants in the optimisation phase. This should result in far fewer aliases and improves simplification of conjunctions, disjunctions and clauses. - Add special case handling for integer division by 1. Bug fixes: - Fix FlatZinc generator phase, need to turn all array literal arguments into 1-based single dimensional arrays. - Fix compilation of if-then-else expressions with var conditions (which didn't implement proper partiality/totality semantics). Fixes #42. - Provide correct bounds for weak opt var arithmetic. Fixes #51. - Need to be able to handle unflattened annotations. Fixes #53. - Fix generation of output model (needs to ignore items that have been removed previously). - Add missing lb(var set of int) builtin. Fixes #47. - Check that var set declarations have a finite element type. Fixes #46. - Fix translation context for binary operators on arrays. - Need to access IntVal::infinity as a function, otherwise depending on linker etc it may become 0 in some cases. Fixes #40. - Change pretty printer to use one less digit when printing float literals. This fixes #41 (or at least provides a workaround), but some double constants may still be rounded incorrectly when pretty printing and reading them back in. The real fix will be to output hex float literals (coming soon). - Distinguish between generalised comprehensions (iterating over sets) and iterating over arrays. Fixes compilation of comprehensions where iteration over an array is combined with var where clauses. Fixes #45. - Fix bug in creation of output model where sometimes chains of variable definitions could lead to crashes. - Avoi creating mutually recursive definitions in some corner cases, which could cause the compiler to run into infinite loops. - Don't copy vardecl items to output model that are already there. Fixes #44. - Remove domain from array declarations in FlatZinc (avoids problems with domains where holes need to be removed and when there are infinities in the domains) - Fix flattening of equality operator between non-opt and opt vars - Check that model contains a single solve and output item during type checking (previously, multiple output items were not detected and resulted in incorrect .ozn files). - Fix flattening of xor (arguments need to be in mixed context). - Use is_fixed in cumulative definition. - Fix bug where a par right hand side of a variable mentioned in the output would cause a crash. - Fix variable dependency tracking during rewriting in the optimisation phase. Could previously lead to variables being removed that are still required. Fixes #54. Version 2.0.6 ============= Changes: - Add parser support for hexadecimal floating point constants. Bug fixes: - Fix bounds computation for some calls (abs, int_times). - Fix flattening of some array declarations (when right hand side is an identifier). - Add four missing GC locks (could lead to incorrect garbage collection). - Compact output model only after optimisation phase (could lead to incorrect items being removed from output model). Version 2.0.5 ============= Changes: - Improve the standard decomposition for the cumulative constraint. - Better handling of binary operators during type checking and flattening, can sometimes avoid stack overflows (e.g. for large conjunctions). - Make ++ operator left associative (avoid stack overflows in the parser). - Add ::domain annotations to linear constraints generated from multi-dimensional element constraints. - Greatly improved linearisation library. Bug fixes: - Fix recursive function calls that contain let expressions. - Fix compilation of comprehensions inside parametric functions. - Fix a memory leak in solns2out. - Fix a problem in the evaluation of binary operators. - Fix a bug in the flattening of array literals. - Fix a bug that would crash the parser on certain syntax errors in let expressions. Version 2.0.4 ============= Changes: - Models can now be read from standard input (using the "-" or "--input-from-stdin" command line options). Thanks to Sebastian Kosch. - Improved handling of bool2int during FlatZinc generation. Bug fixes: - Fix unification of aliased variables which could sometimes result in variables being removed although had a constraining right hand side. - Fix evaluation of set comprehensions. - Fix command line flag --no-output-ozn - Fix performance problem when evaluating array expressions inside lets. - Fix flattening of bool_xor redefinitions. - Fix partial evaluation of some array access expressions with var indexes. - Fix definition of geost constraint. - User-defined functions are now copied correctly into the output model if they are referenced in the output item. - Set comprehensions are fully evaluated. Version 2.0.3 ============= (Internal release that did not contain some essential fixes) Version 2.0.2 ============= Changes: - The optimiser now removes simple domain constraints from the FlatZinc - The compiler now checks for integer overflows in all built-in operations - Report an error when the FlatZinc or ozn file cannot be opened for writing - Add support for 3d array literals (e.g. [| |1,2|3,4|,|5,6|7,8| |] ) - Add show2d and show3d functions for formatting array output - Add row/col functions for variable arrays (github issue #2) - Introduce builtins for creating random distributions - Add reverse library function - Postpone flattening of some reified constraints - Slightly improved compilation of partial function calls when it can be inferred at compile time that their result is undefined - Allow functions with empty argument lists to be declared as function int: foo(); instead of just function int: foo; - Improve error reporting, in particular for errors in comprehensions - Enable expressions a..b where a and b are integer variables - Add redundant_constraint and symmetry_breaking_constraint builtins, these can be rewritten by solver libraries to allow e.g. local search solvers to ignore redundant constraints. - Improve flattening of predicates that simply return their arguments (makes the redundant_constraint and symmetry_breaking_constraint predicates work in more situations). - Replace command line option --only-range-domains by optional boolean value so that solver libraries can set the flag directly in their redefinitions file. - Stop flattening immediately when a model has been found to contain an inconsistency. - Improve flattening of array access expressions, in particular for nested array accesses that can be combined into a single element constraint - Add command line option -s or --statistics to print statistics about the generated FlatZinc - Improve bounds computation for if-then-else expressions - Clause arguments are compiled in positive and negative contexts instead of mixed. That means that predicates that introduce free variables can now be used in the positive part of a clause. Bug fixes: - Fix simplification of linear expressions, negative coefficients could sometimes result in incorrect bounds - Fix bounds computation for unary minus operator - Add missing par set comparison builtins - Fix bounds computation for extended comprehension syntax - Fix a bug in the garbage collector that could sometimes lead to premature deletion of expressions - Fix bounds computation for set difference - Fix duplication of some arrays in the FlatZinc (github issue #3) - Fix bounds inference for variables bound to empty sets (github bug #3) - Fix bug in error reporting function, which would sometimes not report the entire call stack - Fix the generation of fresh variable names for generator expressions - Fix subtype check to allow empty arrays as subtype of arrays of sets - Fix crash when using assert/2 - Fix bug when function used in output referred to par variable - Fix bug in type checker, the detection of cyclic definitions was not correct and could lead to stack overflows - Fix parser to accept expressions with two consecutive array accesses (like x[3][4], which are valid MiniZinc if x is an array of sets) - Fix error reporting when an evaluation error occurs within a comprehension generator - Report type error on some ambiguous function calls - Report type error on var sets with element type other than int - Report type error when trying to coerce a var set into an array - Report error when calling function with a value that is outside the declared parameter bounds - Fix arg_sort builtin to implement the correct semantics - Fix sort_by builtin to sort in non-decreasing order, and work with floats - Fix bug in type checker, now automatic coercions in functions defined with type variables (like the comparison operators) work correctly - Check that index sets match for arrays assigned in let expressions - Fix bug in bounds inference for integer expressions with annotations - Fix propagation of defines_var annotation to be pushed through calls - Fix parser to accept empty 2d and 3d array literals - Fix flattening to remove defines_var annotations with par argument, e.g. defines_var(2), which could be introduced by the optimisation pass - Fix output model creation for variables that have been redefined, and remove more unused variables from the FlatZinc. - Fix bug in the garbage collector that could result in function items not being kept alive in rare cases. Version 2.0.1 ============= Major bugs and changes: - Fix optimisation phase, which was previously incorrectly removing variables - Add support for trigonometric functions (built-ins were missing in 2.0.0) and pow (var versions were missing) - Fix equality operator on par arrays - All expressions in output model are now made par - Improve bounds computation for float variables - Fix translation of functions that need automatic coercion of their return value - Fix the array_lb and array_ub builtins, which would return incorrect bounds in some cases Minor bugs and changes: - Add space between "array" and "[" in the pretty printer, to be compatible with 1.6 output - Output all par declarations before the var declarations in FlatZinc - Fix parser, which could sometimes crash on invalid input - Improve efficiency of bounds computation on some float expressions - Add special case handling for division by 1 - Add missing float_times definition to the flatzinc builtins - Use correct version of var_dom for float variables - Output information about which files are included in verbose mode - Only compute bounds for "then" expressions if the "if" is not fixed to false Version 2.0.0 ============= MiniZinc 2.0 contains many new features and is based on a complete rewrite of the MiniZinc-to-FlatZinc compiler. If you are currently using the previous version 1.6, the new tools can be used as drop-in replacements. The generated FlatZinc is compatible with version 1.6, so all FlatZinc solvers should work without changes. ** MiniZinc language changes ** - MiniZinc now supports user-defined functions. Details have been published in the paper "MiniZinc with Functions". Both functions and predicates can be recursive. - MiniZinc now supports option types. Details have been published in the paper "Modelling with Option Types in MiniZinc". - Let expressions have been generalised. They can now contain constraint items in addition to variable declarations. - Array index sets can be declared using arbitrary set expressions as long as they evaluate to contiguous ranges. - The if-then-else expression has been generalised to allow the condition to be a var bool expression (instead of only par bool). - Array and set comprehensions as well as generator calls can now iterate over variables and use var bool where conditions. - Any bool expression can now automatically coerce to an int expression, likewise for int and float. This means that you don't have to write bool2int or int2float in your models any more. - Equality constraints can now be posted between array expressions. - Arbitrary expressions can now be included ("interpolated") into strings, using the syntax "some text \(e) some more text", where e is any expression. It is the same as writing "some text "++show(e)++" some more text". ** New built-in functions ** Array functions: array1d, arrayXd, row, col, has_index, has_element, sort_by, sort, arg_sort, arg_min, arg_max ** New global constraints ** - arg_max, arg_min - arg_sort - k-dimensional diffn - disjunctive - geost - knapsack - network_flow - regular with NFAs - symmetric all different - optional scheduling constraints: alternative, span, disjunctive, cumulative - functional versions of many global constraints ** New tool chain ** - There are a few new builtins that solvers can reimplement, these are listed in the redefinitions-2.0 file. - Include items use a different method for finding included files. Paths are now interpreted as relative to the file that has the include item. That way, the mzn2fzn compiler can be called from a different working directory. - A new tool, mzn2doc, can produce html output from the documentation comments. The MiniZinc distribution contains the documentation for global constraints and builtins generated directly from the library source code. libminizinc-2.0.11/include/0000755000175000017500000000000012646030173014165 5ustar kaolkaollibminizinc-2.0.11/include/minizinc/0000755000175000017500000000000012646030173016005 5ustar kaolkaollibminizinc-2.0.11/include/minizinc/model.hh0000644000175000017500000002337012646030173017433 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_MODEL_HH__ #define __MINIZINC_MODEL_HH__ #include #include #include #include namespace MiniZinc { class VarDeclIterator; class ConstraintIterator; class CopyMap; class EnvI; /// A MiniZinc model class Model { friend class GC; friend Model* copy(EnvI& env, CopyMap& cm, Model* m, bool isFlatModel); protected: /// Previous model in root set list Model* _roots_prev; /// Next model in root set list Model* _roots_next; /// Type of map from identifiers to function declarations typedef ASTStringMap >::t FnMap; /// Map from identifiers to function declarations FnMap fnmap; /// Filename of the model ASTString _filename; /// Path of the model ASTString _filepath; /// Parent model if model was included Model* _parent; /// Items in the model std::vector _items; /// Pointer to the solve item SolveI* _solveItem; /// Pointer to the output item OutputI* _outputItem; /// File-level documentation comment std::string _docComment; /// Flag whether model is failed bool _failed; public: /// Construct empty model Model(void); /// Destructor ~Model(void); /// Add \a i to the model void addItem(Item* i) { _items.push_back(i); if (i->isa()) { _solveItem = i->cast(); } else if (i->isa()) { _outputItem = i->cast(); } } /// Get parent model Model* parent(void) const { return _parent; } /// Set parent model to \a p void setParent(Model* p) { assert(_parent==NULL); _parent = p; } /// Get file name ASTString filename(void) const { return _filename; } /// Get file path ASTString filepath(void) const { return _filepath; } /// Set file name void setFilename(const std::string& f) { assert(_filename.size()==0); _filename = ASTString(f); } /// Set file path void setFilepath(const std::string& f) { assert(_filepath.size()==0); _filepath = ASTString(f); } /// Register a builtin function item void registerFn(EnvI& env, FunctionI* fi); /// Sort functions by type void sortFn(void); /// Return function declaration for \a id matching \a args FunctionI* matchFn(EnvI& env, const ASTString& id, const std::vector& args) const; /// Return function declaration for \a id matching types \a t FunctionI* matchFn(EnvI& env, const ASTString& id, const std::vector& t); /// Return function declaration matching call \a c FunctionI* matchFn(EnvI& env, Call* c) const; /// Return item \a i Item*& operator[] (int i); /// Return item \a i const Item* operator[] (int i) const; /// Return number of items unsigned int size(void) const; typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; /// Iterator for beginning of items iterator begin(void); /// Iterator for beginning of items const_iterator begin(void) const; /// Iterator for end of items iterator end(void); /// Iterator for end of items const_iterator end(void) const; ConstraintIterator begin_constraints(void); ConstraintIterator end_constraints(void); VarDeclIterator begin_vardecls(void); VarDeclIterator end_vardecls(void); SolveI* solveItem(void); OutputI* outputItem(void); /// Add a file-level documentation comment void addDocComment(std::string s) { _docComment += s; } /// Return the file-level documentation comment const std::string& docComment(void) const { return _docComment; } /// Remove all items marked as removed void compact(void); /// Make model failed void fail(EnvI& env); /// Return whether model is known to be failed bool failed(void) const; }; class VarDeclIterator { Model* _model; Model::iterator _it; public: typedef Model::iterator::difference_type difference_type; typedef Model::iterator::value_type value_type; typedef VarDeclI& reference; typedef VarDeclI* pointer; typedef std::forward_iterator_tag iterator_category; VarDeclIterator() {} VarDeclIterator(const VarDeclIterator& vi) : _it(vi._it) {} VarDeclIterator(Model* model, const Model::iterator& it) : _model(model), _it(it) { while (_it != _model->end() && !(*_it)->isa()) { ++_it; } } ~VarDeclIterator() {} VarDeclIterator& operator=(const VarDeclIterator& vi) { if (this != &vi) { _it = vi._it; } return *this; } bool operator==(const VarDeclIterator& vi) const { return _it == vi._it; } bool operator!=(const VarDeclIterator& vi) const { return _it != vi._it; } VarDeclIterator& operator++() { do { ++_it; } while (_it != _model->end() && !(*_it)->isa()); return *this; } reference operator*() const { return *(*_it)->cast(); } pointer operator->() const { return (*_it)->cast(); } }; class ConstraintIterator { Model* _model; Model::iterator _it; public: typedef Model::iterator::difference_type difference_type; typedef Model::iterator::value_type value_type; typedef ConstraintI& reference; typedef ConstraintI* pointer; typedef std::forward_iterator_tag iterator_category; ConstraintIterator() {} ConstraintIterator(const ConstraintIterator& vi) : _it(vi._it) {} ConstraintIterator(Model* model, const Model::iterator& it) : _model(model), _it(it) { while (_it != _model->end() && !(*_it)->isa()) { ++_it; } } ~ConstraintIterator() {} ConstraintIterator& operator=(const ConstraintIterator& vi) { if (this != &vi) { _it = vi._it; } return *this; } bool operator==(const ConstraintIterator& vi) const { return _it == vi._it; } bool operator!=(const ConstraintIterator& vi) const { return _it != vi._it; } ConstraintIterator& operator++() { do { ++_it; } while (_it != _model->end() && !(*_it)->isa()); return *this; } reference operator*() const { return *(*_it)->cast(); } pointer operator->() const { return (*_it)->cast(); } }; class EnvI; /// Environment class Env { private: EnvI* e; public: Env(Model* m); ~Env(void); Model* model(void); Model* flat(void); Model* output(void); EnvI& envi(void); const EnvI& envi(void) const; std::ostream& dumpErrorStack(std::ostream& os); const std::vector& warnings(void); void clearWarnings(void); unsigned int maxCallStack(void) const; }; class CallStackItem { public: EnvI& env; CallStackItem(EnvI& env0, Expression* e); CallStackItem(EnvI& env0, Id* ident, IntVal i); ~CallStackItem(void); }; /// Visitor for model items class ItemVisitor { public: /// Enter model bool enterModel(Model* m) { return true; } /// Enter item bool enter(Item* m) { return true; } /// Visit include item void vIncludeI(IncludeI*) {} /// Visit variable declaration void vVarDeclI(VarDeclI*) {} /// Visit assign item void vAssignI(AssignI*) {} /// Visit constraint item void vConstraintI(ConstraintI*) {} /// Visit solve item void vSolveI(SolveI*) {} /// Visit output item void vOutputI(OutputI*) {} /// Visit function item void vFunctionI(FunctionI*) {} }; /// Iterator over items in a model and all its included models template class ItemIter { protected: I& iter; public: ItemIter(I& iter0) : iter(iter0) {} void run(Model* m) { UNORDERED_NAMESPACE::unordered_set seen; std::vector models; models.push_back(m); seen.insert(m); while (!models.empty()) { Model* cm = models.back(); models.pop_back(); if (!iter.enterModel(cm)) continue; for (unsigned int i=0; isize(); i++) { if ((*cm)[i]->removed()) continue; if (!iter.enter((*cm)[i])) continue; switch ((*cm)[i]->iid()) { case Item::II_INC: if (seen.find((*cm)[i]->cast()->m()) == seen.end()) { models.push_back((*cm)[i]->cast()->m()); seen.insert((*cm)[i]->cast()->m()); } iter.vIncludeI((*cm)[i]->cast()); break; case Item::II_VD: iter.vVarDeclI((*cm)[i]->cast()); break; case Item::II_ASN: iter.vAssignI((*cm)[i]->cast()); break; case Item::II_CON: iter.vConstraintI((*cm)[i]->cast()); break; case Item::II_SOL: iter.vSolveI((*cm)[i]->cast()); break; case Item::II_OUT: iter.vOutputI((*cm)[i]->cast()); break; case Item::II_FUN: iter.vFunctionI((*cm)[i]->cast()); break; } } } } }; /// Run iterator \a i over all items of model \a m template void iterItems(I& i, Model* m) { ItemIter(i).run(m); } } #endif libminizinc-2.0.11/include/minizinc/thirdparty/0000755000175000017500000000000012646030173020177 5ustar kaolkaollibminizinc-2.0.11/include/minizinc/thirdparty/SafeInt3.hpp0000644000175000017500000073126612646030173022343 0ustar kaolkaol/*----------------------------------------------------------------------------------------------------------- SafeInt.hpp Version 3.0.18p This software is licensed under the Microsoft Public License (Ms-PL). For more information about Microsoft open source licenses, refer to http://www.microsoft.com/opensource/licenses.mspx This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. Definitions The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. A "contribution" is the original software, or any additions or changes to the software. A "contributor" is any person that distributes its contribution under this license. "Licensed patents" are a contributor's patent claims that read directly on its contribution. Grant of Rights (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. Conditions and Limitations (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees, or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. Copyright (c) Microsoft Corporation. All rights reserved. This header implements an integer handling class designed to catch unsafe integer operations This header compiles properly at Wall on Visual Studio, -Wall on gcc, and -Weverything on clang. Please read the leading comments before using the class. ---------------------------------------------------------------*/ #ifndef SAFEINT_HPP #define SAFEINT_HPP // It is a bit tricky to sort out what compiler we are actually using, // do this once here, and avoid cluttering the code #define VISUAL_STUDIO_COMPILER 0 #define CLANG_COMPILER 1 #define GCC_COMPILER 2 #define UNKNOWN_COMPILER -1 // Clang will sometimes pretend to be Visual Studio // and does pretend to be gcc. Check it first, as nothing else pretends to be clang #if defined __clang__ #define SAFEINT_COMPILER CLANG_COMPILER #elif defined __GNUC__ #define SAFEINT_COMPILER GCC_COMPILER #elif defined _MSC_VER #define SAFEINT_COMPILER VISUAL_STUDIO_COMPILER #else #define SAFEINT_COMPILER UNKNOWN_COMPILER #endif // Enable compiling with /Wall under VC #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER #pragma warning( push ) // Disable warnings coming from headers #pragma warning( disable:4987 4820 4987 4820 ) #endif // Need this for ptrdiff_t on some compilers #include #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER && defined _M_AMD64 #include #define SAFEINT_USE_INTRINSICS 1 #else #define SAFEINT_USE_INTRINSICS 0 #endif #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER #pragma warning( pop ) #endif // Various things needed for GCC #if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER #define NEEDS_INT_DEFINED #define IGNORE_UNUSED_TYPEDEF __attribute__((unused)) #if !defined NULL #define NULL 0 #endif // GCC warning suppression #if SAFEINT_COMPILER == GCC_COMPILER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #endif #include // clang only #if SAFEINT_COMPILER == CLANG_COMPILER #if __has_feature(cxx_nullptr) #define NEEDS_NULLPTR_DEFINED 0 #endif #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc++11-long-long" #pragma clang diagnostic ignored "-Wold-style-cast" #endif #else #define IGNORE_UNUSED_TYPEDEF #endif // If the user made a choice, respect it #if !defined #if !defined NEEDS_NULLPTR_DEFINED // Visual Studio 2010 and higher support this #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER #if (_MSC_VER < 1600) #define NEEDS_NULLPTR_DEFINED 1 #else #define NEEDS_NULLPTR_DEFINED 0 #endif #else // Let everything else trigger based on whether we have nullptr_t #if defined nullptr_t #define NEEDS_NULLPTR_DEFINED 0 #else #define NEEDS_NULLPTR_DEFINED 1 #endif #endif #endif #if NEEDS_NULLPTR_DEFINED #define nullptr NULL #endif #ifndef C_ASSERT #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] IGNORE_UNUSED_TYPEDEF #endif // Let's test some assumptions // We're assuming two's complement negative numbers C_ASSERT( -1 == static_cast(0xffffffff) ); /************* Compiler Options ***************************************************************************************************** SafeInt supports several compile-time options that can change the behavior of the class. Compiler options: SAFEINT_WARN_64BIT_PORTABILITY - this re-enables various warnings that happen when /Wp64 is used. Enabling this option is not recommended. NEEDS_INT_DEFINED - if your compiler does not support __int8, __int16, __int32 and __int64, you can enable this. SAFEINT_ASSERT_ON_EXCEPTION - it is often easier to stop on an assert and figure out a problem than to try and figure out how you landed in the catch block. SafeIntDefaultExceptionHandler - if you'd like to replace the exception handlers SafeInt provides, define your replacement and define this. Note - two built in (Windows-specific) options exist: - SAFEINT_FAILFAST - bypasses all exception handlers, exits the app with an exception - SAFEINT_RAISE_EXCEPTION - throws Win32 exceptions, which can be caught SAFEINT_DISALLOW_UNSIGNED_NEGATION - Invoking the unary negation operator creates warnings, but if you'd like it to completely fail to compile, define this. ANSI_CONVERSIONS - This changes the class to use default comparison behavior, which may be unsafe. Enabling this option is not recommended. SAFEINT_DISABLE_BINARY_ASSERT - binary AND, OR or XOR operations on mixed size types can produce unexpected results. If you do this, the default is to assert. Set this if you prefer not to assert under these conditions. SIZE_T_CAST_NEEDED - some compilers complain if there is not a cast to size_t, others complain if there is one. This lets you not have your compiler complain. SAFEINT_DISABLE_SHIFT_ASSERT - Set this option if you don't want to assert when shifting more bits than the type has. Enabling this option is not recommended. ************************************************************************************************************************************/ /* * The SafeInt class is designed to have as low an overhead as possible * while still ensuring that all integer operations are conducted safely. * Nearly every operator has been overloaded, with a very few exceptions. * * A usability-safety trade-off has been made to help ensure safety. This * requires that every operation return either a SafeInt or a bool. If we * allowed an operator to return a base integer type T, then the following * can happen: * * char i = SafeInt(32) * 2 + SafeInt(16) * 4; * * The * operators take precedence, get overloaded, return a char, and then * you have: * * char i = (char)64 + (char)64; //overflow! * * This situation would mean that safety would depend on usage, which isn't * acceptable. * * One key operator that is missing is an implicit cast to type T. The reason for * this is that if there is an implicit cast operator, then we end up with * an ambiguous compile-time precedence. Because of this amiguity, there * are two methods that are provided: * * Casting operators for every native integer type * Version 3 note - it now compiles correctly for size_t without warnings * * SafeInt::Ptr() - returns the address of the internal integer * Note - the '&' (address of) operator has been overloaded and returns * the address of the internal integer. * * The SafeInt class should be used in any circumstances where ensuring * integrity of the calculations is more important than performance. See Performance * Notes below for additional information. * * Many of the conditionals will optimize out or be inlined for a release * build (especially with /Ox), but it does have significantly more overhead, * especially for signed numbers. If you do not _require_ negative numbers, use * unsigned integer types - certain types of problems cannot occur, and this class * performs most efficiently. * * Here's an example of when the class should ideally be used - * * void* AllocateMemForStructs(int StructSize, int HowMany) * { * SafeInt s(StructSize); * * s *= HowMany; * * return malloc(s); * * } * * Here's when it should NOT be used: * * void foo() * { * int i; * * for(i = 0; i < 0xffff; i++) * .... * } * * Error handling - a SafeInt class will throw exceptions if something * objectionable happens. The exceptions are SafeIntException classes, * which contain an enum as a code. * * Typical usage might be: * * bool foo() * { * SafeInt s; //note that s == 0 unless set * * try{ * s *= 23; * .... * } * catch(SafeIntException err) * { * //handle errors here * } * } * * Update for 3.0 - the exception class is now a template parameter. * You can replace the exception class with any exception class you like. This is accomplished by: * 1) Create a class that has the following interface: * template <> class YourSafeIntExceptionHandler < YourException > { public: static __declspec(noreturn) void __stdcall SafeIntOnOverflow() { throw YourException( YourSafeIntArithmeticOverflowError ); } static __declspec(noreturn) void __stdcall SafeIntOnDivZero() { throw YourException( YourSafeIntDivideByZeroError ); } }; * * Note that you don't have to throw C++ exceptions, you can throw Win32 exceptions, or do * anything you like, just don't return from the call back into the code. * * 2) Either explicitly declare SafeInts like so: * SafeInt< int, YourSafeIntExceptionHandler > si; * or * #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler * * Performance: * * Due to the highly nested nature of this class, you can expect relatively poor * performance in unoptimized code. In tests of optimized code vs. correct inline checks * in native code, this class has been found to take approximately 8% more CPU time (this varies), * most of which is due to exception handling. Solutions: * * 1) Compile optimized code - /Ox is best, /O2 also performs well. Interestingly, /O1 * (optimize for size) does not work as well. * 2) If that 8% hit is really a serious problem, walk through the code and inline the * exact same checks as the class uses. * 3) Some operations are more difficult than others - avoid using signed integers, and if * possible keep them all the same size. 64-bit integers are also expensive. Mixing * different integer sizes and types may prove expensive. Be aware that literals are * actually ints. For best performance, cast literals to the type desired. * * * Performance update * The current version of SafeInt uses template specialization to force the compiler to invoke only the * operator implementation needed for any given pair of types. This will dramatically improve the perf * of debug builds. * * 3.0 update - not only have we maintained the specialization, there were some cases that were overly complex, * and using some additional cases (e.g. signed __int64 and unsigned __int64) resulted in some simplification. * Additionally, there was a lot of work done to better optimize the 64-bit multiplication. * * Binary Operators * * All of the binary operators have certain assumptions built into the class design. * This is to ensure correctness. Notes on each class of operator follow: * * Arithmetic Operators (*,/,+,-,%) * There are three possible variants: * SafeInt< T, E > op SafeInt< T, E > * SafeInt< T, E > op U * U op SafeInt< T, E > * * The SafeInt< T, E > op SafeInt< U, E > variant is explicitly not supported, and if you try to do * this the compiler with throw the following error: * * error C2593: 'operator *' is ambiguous * * This is because the arithmetic operators are required to return a SafeInt of some type. * The compiler cannot know whether you'd prefer to get a type T or a type U returned. If * you need to do this, you need to extract the value contained within one of the two using * the casting operator. For example: * * SafeInt< T, E > t, result; * SafeInt< U, E > u; * * result = t * (U)u; * * Comparison Operators * Because each of these operators return type bool, mixing SafeInts of differing types is * allowed. * * Shift Operators * Shift operators always return the type on the left hand side of the operator. Mixed type * operations are allowed because the return type is always known. * * Boolean Operators * Like comparison operators, these overloads always return type bool, and mixed-type SafeInts * are allowed. Additionally, specific overloads exist for type bool on both sides of the * operator. * * Binary Operators * Mixed-type operations are discouraged, however some provision has been made in order to * enable things like: * * SafeInt c = 2; * * if(c & 0x02) * ... * * The "0x02" is actually an int, and it needs to work. * In the case of binary operations on integers smaller than 32-bit, or of mixed type, corner * cases do exist where you could get unexpected results. In any case where SafeInt returns a different * result than the underlying operator, it will call assert(). You should examine your code and cast things * properly so that you are not programming with side effects. * * Documented issues: * * This header compiles correctly at /W4 using VC++ 8 (Version 14.00.50727.42) and later. * As of this writing, I believe it will also work for VC 7.1, but not for VC 7.0 or below. * If you need a version that will work with lower level compilers, try version 1.0.7. None * of them work with Visual C++ 6, and gcc didn't work very well, either, though this hasn't * been tried recently. * * It is strongly recommended that any code doing integer manipulation be compiled at /W4 * - there are a number of warnings which pertain to integer manipulation enabled that are * not enabled at /W3 (default for VC++) * * Perf note - postfix operators are slightly more costly than prefix operators. * Unless you're actually assigning it to something, ++SafeInt is less expensive than SafeInt++ * * The comparison operator behavior in this class varies from the ANSI definition, which is * arguably broken. As an example, consider the following: * * unsigned int l = 0xffffffff; * char c = -1; * * if(c == l) * printf("Why is -1 equal to 4 billion???\n"); * * The problem here is that c gets cast to an int, now has a value of 0xffffffff, and then gets * cast again to an unsigned int, losing the true value. This behavior is despite the fact that * an __int64 exists, and the following code will yield a different (and intuitively correct) * answer: * * if((__int64)c == (__int64)l)) * printf("Why is -1 equal to 4 billion???\n"); * else * printf("Why doesn't the compiler upcast to 64-bits when needed?\n"); * * Note that combinations with smaller integers won't display the problem - if you * changed "unsigned int" above to "unsigned short", you'd get the right answer. * * If you prefer to retain the ANSI standard behavior insert * #define ANSI_CONVERSIONS * into your source. Behavior differences occur in the following cases: * 8, 16, and 32-bit signed int, unsigned 32-bit int * any signed int, unsigned 64-bit int * Note - the signed int must be negative to show the problem * * * Revision history: * * Oct 12, 2003 - Created * Author - David LeBlanc - dleblanc@microsoft.com * * Oct 27, 2003 - fixed numerous items pointed out by michmarc and bdawson * Dec 28, 2003 - 1.0 * added support for mixed-type operations * thanks to vikramh * also fixed broken __int64 multiplication section * added extended support for mixed-type operations where possible * Jan 28, 2004 - 1.0.1 * changed WCHAR to wchar_t * fixed a construct in two mixed-type assignment overloads that was * not compiling on some compilers * Also changed name of private method to comply with standards on * reserved names * Thanks to Niels Dekker for the input * Feb 12, 2004 - 1.0.2 * Minor changes to remove dependency on Windows headers * Consistently used __int16, __int32 and __int64 to ensure * portability * May 10, 2004 - 1.0.3 * Corrected bug in one case of GreaterThan * July 22, 2004 - 1.0.4 * Tightened logic in addition check (saving 2 instructions) * Pulled error handler out into function to enable user-defined replacement * Made internal type of SafeIntException an enum (as per Niels' suggestion) * Added casts for base integer types (as per Scott Meyers' suggestion) * Updated usage information - see important new perf notes. * Cleaned up several const issues (more thanks to Niels) * * Oct 1, 2004 - 1.0.5 * Added support for SEH exceptions instead of C++ exceptions - Win32 only * Made handlers for DIV0 and overflows individually overridable * Commented out the destructor - major perf gains here * Added cast operator for type long, since long != __int32 * Corrected a couple of missing const modifiers * Fixed broken >= and <= operators for type U op SafeInt< T, E > * Nov 5, 2004 - 1.0.6 * Implemented new logic in binary operators to resolve issues with * implicit casts * Fixed casting operator because char != signed char * Defined __int32 as int instead of long * Removed unsafe SafeInt::Value method * Re-implemented casting operator as a result of removing Value method * Dec 1, 2004 - 1.0.7 * Implemented specialized operators for pointer arithmetic * Created overloads for cases of U op= SafeInt. What you do with U * after that may be dangerous. * Fixed bug in corner case of MixedSizeModulus * Fixed bug in MixedSizeMultiply and MixedSizeDivision with input of 0 * Added throw() decorations * * Apr 12, 2005 - 2.0 * Extensive revisions to leverage template specialization. * April, 2007 Extensive revisions for version 3.0 * Nov 22, 2009 Forked from MS internal code * Changes needed to support gcc compiler - many thanks to Niels Dekker * for determining not just the issues, but also suggesting fixes. * Also updating some of the header internals to be the same as the upcoming Visual Studio version. * * Jan 16, 2010 64-bit gcc has long == __int64, which means that many of the existing 64-bit * templates are over-specialized. This forces a redefinition of all the 64-bit * multiplication routines to use pointers instead of references for return * values. Also, let's use some intrinsics for x64 Microsoft compiler to * reduce code size, and hopefully improve efficiency. * * June 21, 2014 Better support for clang, higher warning levels supported for all 3 primary supported compilers (Visual Studio, clang, gcc). Also started to converge the code base such that the public CodePlex version will be a drop-in replacement for the Visual Studio version. * Note about code style - throughout this class, casts will be written using C-style (T), * not C++ style static_cast< T >. This is because the class is nearly always dealing with integer * types, and in this case static_cast and a C cast are equivalent. Given the large number of casts, * the code is a little more readable this way. In the event a cast is needed where static_cast couldn't * be substituted, we'll use the new templatized cast to make it explicit what the operation is doing. * ************************************************************************************************************ * Version 3.0 changes: * * 1) The exception type thrown is now replacable, and you can throw your own exception types. This should help * those using well-developed exception classes. * 2) The 64-bit multiplication code has had a lot of perf work done, and should be faster than 2.0. * 3) There is now limited floating point support. You can initialize a SafeInt with a floating point type, * and you can cast it out (or assign) to a float as well. * 4) There is now an Align method. I noticed people use this a lot, and rarely check errors, so now you have one. * * Another major improvement is the addition of external functions - if you just want to check an operation, this can now happen: * All of the following can be invoked without dealing with creating a class, or managing exceptions. This is especially handy * for 64-bit porting, since SafeCast compiles away for a 32-bit cast from size_t to unsigned long, but checks it for 64-bit. * * inline bool SafeCast( const T From, U& To ) throw() * inline bool SafeEquals( const T t, const U u ) throw() * inline bool SafeNotEquals( const T t, const U u ) throw() * inline bool SafeGreaterThan( const T t, const U u ) throw() * inline bool SafeGreaterThanEquals( const T t, const U u ) throw() * inline bool SafeLessThan( const T t, const U u ) throw() * inline bool SafeLessThanEquals( const T t, const U u ) throw() * inline bool SafeModulus( const T& t, const U& u, T& result ) throw() * inline bool SafeMultiply( T t, U u, T& result ) throw() * inline bool SafeDivide( T t, U u, T& result ) throw() * inline bool SafeAdd( T t, U u, T& result ) throw() * inline bool SafeSubtract( T t, U u, T& result ) throw() * */ //use these if the compiler does not support _intXX #ifdef NEEDS_INT_DEFINED #define __int8 char #define __int16 short #define __int32 int #define __int64 long long #endif #if defined VISUAL_STUDIO_SAFEINT_COMPAT namespace msl { namespace utilities { #endif // catch these to handle errors // Currently implemented code values: // ERROR_ARITHMETIC_OVERFLOW // EXCEPTION_INT_DIVIDE_BY_ZERO enum SafeIntError { SafeIntNoError = 0, SafeIntArithmeticOverflow, SafeIntDivideByZero }; #if defined VISUAL_STUDIO_SAFEINT_COMPAT } // utilities } // msl #endif /* * Error handler classes * Using classes to deal with exceptions is going to allow the most * flexibility, and we can mix different error handlers in the same project * or even the same file. It isn't advisable to do this in the same function * because a SafeInt< int, MyExceptionHandler > isn't the same thing as * SafeInt< int, YourExceptionHander >. * If for some reason you have to translate between the two, cast one of them back to its * native type. * * To use your own exception class with SafeInt, first create your exception class, * which may look something like the SafeIntException class below. The second step is to * create a template specialization that implements SafeIntOnOverflow and SafeIntOnDivZero. * For example: * * template <> class SafeIntExceptionHandler < YourExceptionClass > * { * static __declspec(noreturn) void __stdcall SafeIntOnOverflow() * { * throw YourExceptionClass( EXCEPTION_INT_OVERFLOW ); * } * * static __declspec(noreturn) void __stdcall SafeIntOnDivZero() * { * throw YourExceptionClass( EXCEPTION_INT_DIVIDE_BY_ZERO ); * } * }; * * typedef SafeIntExceptionHandler < YourExceptionClass > YourSafeIntExceptionHandler * You'd then declare your SafeInt objects like this: * SafeInt< int, YourSafeIntExceptionHandler > * * Unfortunately, there is no such thing as partial template specialization in typedef * statements, so you have three options if you find this cumbersome: * * 1) Create a holder class: * * template < typename T > * class MySafeInt * { * public: * SafeInt< T, MyExceptionClass> si; * }; * * You'd then declare an instance like so: * MySafeInt< int > i; * * You'd lose handy things like initialization - it would have to be initialized as: * * i.si = 0; * * 2) You could create a typedef for every int type you deal with: * * typedef SafeInt< int, MyExceptionClass > MySafeInt; * typedef SafeInt< char, MyExceptionClass > MySafeChar; * * and so on. The second approach is probably more usable, and will just drop into code * better, which is the original intent of the SafeInt class. * * 3) If you're going to consistently use a different class to handle your exceptions, * you can override the default typedef like so: * * #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler * * Overall, this is probably the best approach. * */ // On the Microsoft compiler, violating a throw() annotation is a silent error. // Other compilers might turn these into exceptions, and some users may want to not have throw() enabled. // In addition, some error handlers may not throw C++ exceptions, which makes everything no throw. #if defined SAFEINT_REMOVE_NOTHROW #define SAFEINT_NOTHROW #else #define SAFEINT_NOTHROW throw() #endif #if defined VISUAL_STUDIO_SAFEINT_COMPAT namespace msl { namespace utilities { #endif // If you would like to use your own custom assert // Define SAFEINT_ASSERT #if !defined SAFEINT_ASSERT #include #define SAFEINT_ASSERT(x) assert(x) #endif #if defined SAFEINT_ASSERT_ON_EXCEPTION inline void SafeIntExceptionAssert() SAFEINT_NOTHROW { SAFEINT_ASSERT(false); } #else inline void SafeIntExceptionAssert() SAFEINT_NOTHROW {} #endif #if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER #define SAFEINT_NORETURN __attribute__((noreturn)) #define SAFEINT_STDCALL #define SAFEINT_VISIBLE __attribute__ ((__visibility__("default"))) #if SAFEINT_COMPILER == CLANG_COMPILER #define SAFEINT_WEAK __attribute__ ((weak)) #else #define SAFEINT_WEAK #endif #else #define SAFEINT_NORETURN __declspec(noreturn) #define SAFEINT_STDCALL __stdcall #define SAFEINT_VISIBLE #define SAFEINT_WEAK #endif class SAFEINT_VISIBLE SAFEINT_WEAK SafeIntException { public: SafeIntException() SAFEINT_NOTHROW { m_code = SafeIntNoError; } SafeIntException( SafeIntError code ) SAFEINT_NOTHROW { m_code = code; } SafeIntError m_code; }; namespace SafeIntInternal { // Visual Studio version of SafeInt provides for two possible error // handlers: // SafeIntErrorPolicy_SafeIntException - C++ exception, default if not otherwise defined // SafeIntErrorPolicy_InvalidParameter - Calls fail fast (Windows-specific), bypasses any exception handlers, // exits the app with a crash template < typename E > class SafeIntExceptionHandler; template <> class SafeIntExceptionHandler < SafeIntException > { public: static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() { SafeIntExceptionAssert(); throw SafeIntException( SafeIntArithmeticOverflow ); } static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() { SafeIntExceptionAssert(); throw SafeIntException( SafeIntDivideByZero ); } }; #if !defined _CRT_SECURE_INVALID_PARAMETER // Calling fail fast is somewhat more robust than calling abort, // but abort is the closest we can manage without Visual Studio support // Need the header for abort() #include #define _CRT_SECURE_INVALID_PARAMETER(msg) abort() #endif class SafeInt_InvalidParameter { public: static SAFEINT_NORETURN void SafeIntOnOverflow() SAFEINT_NOTHROW { SafeIntExceptionAssert(); _CRT_SECURE_INVALID_PARAMETER("SafeInt Arithmetic Overflow"); } static SAFEINT_NORETURN void SafeIntOnDivZero() SAFEINT_NOTHROW { SafeIntExceptionAssert(); _CRT_SECURE_INVALID_PARAMETER("SafeInt Divide By Zero"); } }; #if defined _WINDOWS_ class SafeIntWin32ExceptionHandler { public: static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() SAFEINT_NOTHROW { SafeIntExceptionAssert(); RaiseException( static_cast(EXCEPTION_INT_OVERFLOW), EXCEPTION_NONCONTINUABLE, 0, 0); } static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() SAFEINT_NOTHROW { SafeIntExceptionAssert(); RaiseException( static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), EXCEPTION_NONCONTINUABLE, 0, 0); } }; #endif } // namespace SafeIntInternal // both of these have cross-platform support typedef SafeIntInternal::SafeIntExceptionHandler < SafeIntException > CPlusPlusExceptionHandler; typedef SafeIntInternal::SafeInt_InvalidParameter InvalidParameterExceptionHandler; // This exception handler is no longer recommended, but is left here in order not to break existing users #if defined _WINDOWS_ typedef SafeIntInternal::SafeIntWin32ExceptionHandler Win32ExceptionHandler; #endif // For Visual Studio compatibility #if defined VISUAL_STUDIO_SAFEINT_COMPAT typedef CPlusPlusExceptionHandler SafeIntErrorPolicy_SafeIntException; typedef InvalidParameterExceptionHandler SafeIntErrorPolicy_InvalidParameter; #endif // If the user hasn't defined a default exception handler, // define one now, depending on whether they would like Win32 or C++ exceptions // This library will use conditional noexcept soon, but not in this release // Some users might mix exception handlers, which is not advised, but is supported #if !defined SafeIntDefaultExceptionHandler #if defined SAFEINT_RAISE_EXCEPTION #if !defined _WINDOWS_ #error Include windows.h in order to use Win32 exceptions #endif #define SafeIntDefaultExceptionHandler Win32ExceptionHandler #elif defined SAFEINT_FAILFAST #define SafeIntDefaultExceptionHandler InvalidParameterExceptionHandler #else #define SafeIntDefaultExceptionHandler CPlusPlusExceptionHandler #if !defined SAFEINT_EXCEPTION_HANDLER_CPP #define SAFEINT_EXCEPTION_HANDLER_CPP 1 #endif #endif #endif #if !defined SAFEINT_EXCEPTION_HANDLER_CPP #define SAFEINT_EXCEPTION_HANDLER_CPP 0 #endif // If an error handler is chosen other than C++ exceptions, such as Win32 exceptions, fail fast, // or abort, then all methods become no throw. Some teams track throw() annotations closely, // and the following option provides for this. #if SAFEINT_EXCEPTION_HANDLER_CPP #define SAFEINT_CPP_THROW #else #define SAFEINT_CPP_THROW SAFEINT_NOTHROW #endif // Turns out we can fool the compiler into not seeing compile-time constants with // a simple template specialization template < int method > class CompileConst; template <> class CompileConst { public: static bool Value() SAFEINT_NOTHROW { return true; } }; template <> class CompileConst { public: static bool Value() SAFEINT_NOTHROW { return false; } }; // The following template magic is because we're now not allowed // to cast a float to an enum. This means that if we happen to assign // an enum to a SafeInt of some type, it won't compile, unless we prevent // isFloat = ( (T)( (float)1.1 ) > (T)1 ) // from compiling in the case of an enum, which is the point of the specialization // that follows. // If we have support for std, then we can do this easily, and detect enums as well template < typename T > class NumericType; #if defined _LIBCPP_TYPE_TRAITS || defined _TYPE_TRAITS_ // Continue to special case bool template <> class NumericType { public: enum{ isBool = true, isFloat = false, isInt = false }; }; template < typename T > class NumericType { public: enum { isBool = false, // We specialized out a bool isFloat = std::is_floating_point::value, // If it is an enum, then consider it an int type // This does allow someone to make a SafeInt from an enum type, which is not recommended, // but it also allows someone to add an enum value to a SafeInt, which is handy. isInt = std::is_integral::value || std::is_enum::value }; }; #else template <> class NumericType { public: enum{ isBool = true, isFloat = false, isInt = false }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; #if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; #endif template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType<__int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; }; template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; }; // Catch-all for anything not supported template < typename T > class NumericType { public: // We have some unknown type, which could be an enum. For parity with the code that uses , // We can try a static_cast - it if compiles, then it might be an enum, and should work. // If it is something else that just happens to have a constructor that takes an int, and a casting operator, // then it is possible something will go wrong, and for best results, cast it directly to an int before letting it // interact with a SafeInt enum { isBool = false, isFloat = false, isInt = static_cast( static_cast(0) ) == 0 }; }; #endif // type traits // Use this to avoid compile-time const truncation warnings template < int fSigned, int bits > class SafeIntMinMax; template <> class SafeIntMinMax< true, 8 > { public: const static signed __int8 min = (-0x7f - 1); const static signed __int8 max = 0x7f; }; template <> class SafeIntMinMax< true, 16 > { public: const static __int16 min = ( -0x7fff - 1 ); const static __int16 max = 0x7fff; }; template <> class SafeIntMinMax< true, 32 > { public: const static __int32 min = ( -0x7fffffff -1 ); const static __int32 max = 0x7fffffff; }; template <> class SafeIntMinMax< true, 64 > { public: const static __int64 min = static_cast<__int64>(0x8000000000000000LL); const static __int64 max = 0x7fffffffffffffffLL; }; template <> class SafeIntMinMax< false, 8 > { public: const static unsigned __int8 min = 0; const static unsigned __int8 max = 0xff; }; template <> class SafeIntMinMax< false, 16 > { public: const static unsigned __int16 min = 0; const static unsigned __int16 max = 0xffff; }; template <> class SafeIntMinMax< false, 32 > { public: const static unsigned __int32 min = 0; const static unsigned __int32 max = 0xffffffff; }; template <> class SafeIntMinMax< false, 64 > { public: const static unsigned __int64 min = 0; const static unsigned __int64 max = 0xffffffffffffffffULL; }; template < typename T > class IntTraits { public: C_ASSERT( NumericType::isInt ); enum { isSigned = ( (T)(-1) < 0 ), is64Bit = ( sizeof(T) == 8 ), is32Bit = ( sizeof(T) == 4 ), is16Bit = ( sizeof(T) == 2 ), is8Bit = ( sizeof(T) == 1 ), isLT32Bit = ( sizeof(T) < 4 ), isLT64Bit = ( sizeof(T) < 8 ), isInt8 = ( sizeof(T) == 1 && isSigned ), isUint8 = ( sizeof(T) == 1 && !isSigned ), isInt16 = ( sizeof(T) == 2 && isSigned ), isUint16 = ( sizeof(T) == 2 && !isSigned ), isInt32 = ( sizeof(T) == 4 && isSigned ), isUint32 = ( sizeof(T) == 4 && !isSigned ), isInt64 = ( sizeof(T) == 8 && isSigned ), isUint64 = ( sizeof(T) == 8 && !isSigned ), bitCount = ( sizeof(T)*8 ), isBool = ( (T)2 == (T)1 ) }; // On version 13.10 enums cannot define __int64 values // so we'll use const statics instead! // These must be cast to deal with the possibility of a SafeInt being given an enum as an argument const static T maxInt = static_cast(SafeIntMinMax< isSigned, bitCount >::max); const static T minInt = static_cast(SafeIntMinMax< isSigned, bitCount >::min); }; template < typename T > const T IntTraits< T >::maxInt; template < typename T > const T IntTraits< T >::minInt; template < typename T, typename U > class SafeIntCompare { public: enum { isBothSigned = (IntTraits< T >::isSigned && IntTraits< U >::isSigned), isBothUnsigned = (!IntTraits< T >::isSigned && !IntTraits< U >::isSigned), isLikeSigned = ((bool)(IntTraits< T >::isSigned) == (bool)(IntTraits< U >::isSigned)), isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) || (IntTraits< T >::isSigned && sizeof(T) > sizeof(U))), isBothLT32Bit = (IntTraits< T >::isLT32Bit && IntTraits< U >::isLT32Bit), isBothLT64Bit = (IntTraits< T >::isLT64Bit && IntTraits< U >::isLT64Bit) }; }; //all of the arithmetic operators can be solved by the same code within //each of these regions without resorting to compile-time constant conditionals //most operators collapse the problem into less than the 22 zones, but this is used //as the first cut //using this also helps ensure that we handle all of the possible cases correctly template < typename T, typename U > class IntRegion { public: enum { //unsigned-unsigned zone IntZone_UintLT32_UintLT32 = SafeIntCompare< T,U >::isBothUnsigned && SafeIntCompare< T,U >::isBothLT32Bit, IntZone_Uint32_UintLT64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, IntZone_UintLT32_Uint32 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, IntZone_Uint64_Uint = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is64Bit, IntZone_UintLT64_Uint64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, //unsigned-signed IntZone_UintLT32_IntLT32 = !IntTraits< T >::isSigned && IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, IntZone_Uint32_IntLT64 = IntTraits< T >::isUint32 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, IntZone_UintLT32_Int32 = !IntTraits< T >::isSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::isInt32, IntZone_Uint64_Int = IntTraits< T >::isUint64 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, IntZone_UintLT64_Int64 = !IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isInt64, IntZone_Uint64_Int64 = IntTraits< T >::isUint64 && IntTraits< U >::isInt64, //signed-signed IntZone_IntLT32_IntLT32 = SafeIntCompare< T,U >::isBothSigned && SafeIntCompare< T, U >::isBothLT32Bit, IntZone_Int32_IntLT64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit, IntZone_IntLT32_Int32 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit, IntZone_Int64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isInt64 && IntTraits< U >::isInt64, IntZone_Int64_Int = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is64Bit && IntTraits< U >::isLT64Bit, IntZone_IntLT64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit, //signed-unsigned IntZone_IntLT32_UintLT32 = IntTraits< T >::isSigned && !IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit, IntZone_Int32_UintLT32 = IntTraits< T >::isInt32 && !IntTraits< U >::isSigned && IntTraits< U >::isLT32Bit, IntZone_IntLT64_Uint32 = IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isUint32, IntZone_Int64_UintLT64 = IntTraits< T >::isInt64 && !IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit, IntZone_Int_Uint64 = IntTraits< T >::isSigned && IntTraits< U >::isUint64 && IntTraits< T >::isLT64Bit, IntZone_Int64_Uint64 = IntTraits< T >::isInt64 && IntTraits< U >::isUint64 }; }; // In all of the following functions, we have two versions // One for SafeInt, which throws C++ (or possibly SEH) exceptions // The non-throwing versions are for use by the helper functions that return success and failure. // Some of the non-throwing functions are not used, but are maintained for completeness. // There's no real alternative to duplicating logic, but keeping the two versions // immediately next to one another will help reduce problems // useful function to help with getting the magnitude of a negative number enum AbsMethod { AbsMethodInt, AbsMethodInt64, AbsMethodNoop }; template < typename T > class GetAbsMethod { public: enum { method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt : IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop }; }; // let's go ahead and hard-code a dependency on the // representation of negative numbers to keep compilers from getting overly // happy with optimizing away things like -MIN_INT. template < typename T, int > class AbsValueHelper; template < typename T > class AbsValueHelper < T, AbsMethodInt> { public: static unsigned __int32 Abs( T t ) SAFEINT_NOTHROW { SAFEINT_ASSERT( t < 0 ); return ~(unsigned __int32)t + 1; } }; template < typename T > class AbsValueHelper < T, AbsMethodInt64 > { public: static unsigned __int64 Abs( T t ) SAFEINT_NOTHROW { SAFEINT_ASSERT( t < 0 ); return ~(unsigned __int64)t + 1; } }; template < typename T > class AbsValueHelper < T, AbsMethodNoop > { public: static T Abs( T t ) SAFEINT_NOTHROW { // Why are you calling Abs on an unsigned number ??? SAFEINT_ASSERT( false ); return t; } }; template < typename T, bool > class NegationHelper; // Previous versions had an assert that the type being negated was 32-bit or higher // In retrospect, this seems like something to just document // Negation will normally upcast to int // For example -(unsigned short)0xffff == (int)0xffff0001 // This class will retain the type, and will truncate, which may not be what // you wanted // If you want normal operator casting behavior, do this: // SafeInt ss = 0xffff; // then: // -(SafeInt(ss)) // will then emit a signed int with the correct value and bitfield template < typename T > class NegationHelper // Signed { public: template static T NegativeThrow( T t ) SAFEINT_CPP_THROW { // corner case if( t != IntTraits< T >::minInt ) { // cast prevents unneeded checks in the case of small ints return -t; } E::SafeIntOnOverflow(); } static bool Negative( T t, T& ret ) SAFEINT_NOTHROW { // corner case if( t != IntTraits< T >::minInt ) { // cast prevents unneeded checks in the case of small ints ret = -t; return true; } return false; } }; // Helper classes to work keep compilers from // optimizing away negation template < typename T > class SignedNegation; template <> class SignedNegation { public: static signed __int32 Value(unsigned __int64 in) SAFEINT_NOTHROW { return (signed __int32)(~(unsigned __int32)in + 1); } static signed __int32 Value(unsigned __int32 in) SAFEINT_NOTHROW { return (signed __int32)(~in + 1); } }; template <> class SignedNegation { public: static signed __int64 Value(unsigned __int64 in) SAFEINT_NOTHROW { return (signed __int64)(~in + 1); } }; template < typename T > class NegationHelper // unsigned { public: template static T NegativeThrow( T t ) SAFEINT_CPP_THROW { #if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION C_ASSERT( sizeof(T) == 0 ); #endif #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER #pragma warning(push) //this avoids warnings from the unary '-' operator being applied to unsigned numbers #pragma warning(disable:4146) #endif // Note - this could be quenched on gcc // by doing something like: // return (T)-((__int64)t); // but it seems like you would want a warning when doing this. return (T)-t; #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER #pragma warning(pop) #endif } static bool Negative( T t, T& ret ) SAFEINT_NOTHROW { if( IntTraits::isLT32Bit ) { // See above SAFEINT_ASSERT( false ); } #if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION C_ASSERT( sizeof(T) == 0 ); #endif // Do it this way to avoid warning ret = -t; return true; } }; //core logic to determine casting behavior enum CastMethod { CastOK = 0, CastCheckLTZero, CastCheckGTMax, CastCheckSafeIntMinMaxUnsigned, CastCheckSafeIntMinMaxSigned, CastToFloat, CastFromFloat, CastToBool, CastFromBool }; template < typename ToType, typename FromType > class GetCastMethod { public: enum { method = ( IntTraits< FromType >::isBool && !IntTraits< ToType >::isBool ) ? CastFromBool : ( !IntTraits< FromType >::isBool && IntTraits< ToType >::isBool ) ? CastToBool : ( SafeIntCompare< ToType, FromType >::isCastOK ) ? CastOK : ( ( IntTraits< ToType >::isSigned && !IntTraits< FromType >::isSigned && sizeof( FromType ) >= sizeof( ToType ) ) || ( SafeIntCompare< ToType, FromType >::isBothUnsigned && sizeof( FromType ) > sizeof( ToType ) ) ) ? CastCheckGTMax : ( !IntTraits< ToType >::isSigned && IntTraits< FromType >::isSigned && sizeof( ToType ) >= sizeof( FromType ) ) ? CastCheckLTZero : ( !IntTraits< ToType >::isSigned ) ? CastCheckSafeIntMinMaxUnsigned : CastCheckSafeIntMinMaxSigned }; }; template < typename FromType > class GetCastMethod < float, FromType > { public: enum{ method = CastOK }; }; template < typename FromType > class GetCastMethod < double, FromType > { public: enum{ method = CastOK }; }; template < typename FromType > class GetCastMethod < long double, FromType > { public: enum{ method = CastOK }; }; template < typename ToType > class GetCastMethod < ToType, float > { public: enum{ method = CastFromFloat }; }; template < typename ToType > class GetCastMethod < ToType, double > { public: enum{ method = CastFromFloat }; }; template < typename ToType > class GetCastMethod < ToType, long double > { public: enum{ method = CastFromFloat }; }; template < typename T, typename U, int > class SafeCastHelper; template < typename T, typename U > class SafeCastHelper < T, U, CastOK > { public: static bool Cast( U u, T& t ) SAFEINT_NOTHROW { t = (T)u; return true; } template < typename E > static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW { t = (T)u; } }; // special case floats and doubles // tolerate loss of precision template < typename T, typename U > class SafeCastHelper < T, U, CastFromFloat > { public: static bool Cast( U u, T& t ) SAFEINT_NOTHROW { if( u <= (U)IntTraits< T >::maxInt && u >= (U)IntTraits< T >::minInt ) { t = (T)u; return true; } return false; } template < typename E > static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW { if( u <= (U)IntTraits< T >::maxInt && u >= (U)IntTraits< T >::minInt ) { t = (T)u; return; } E::SafeIntOnOverflow(); } }; // Match on any method where a bool is cast to type T template < typename T > class SafeCastHelper < T, bool, CastFromBool > { public: static bool Cast( bool b, T& t ) SAFEINT_NOTHROW { t = (T)( b ? 1 : 0 ); return true; } template < typename E > static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW { t = (T)( b ? 1 : 0 ); } }; template < typename T > class SafeCastHelper < bool, T, CastToBool > { public: static bool Cast( T t, bool& b ) SAFEINT_NOTHROW { b = !!t; return true; } template < typename E > static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW { b = !!t; } }; template < typename T, typename U > class SafeCastHelper < T, U, CastCheckLTZero > { public: static bool Cast( U u, T& t ) SAFEINT_NOTHROW { if( u < 0 ) return false; t = (T)u; return true; } template < typename E > static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW { if( u < 0 ) E::SafeIntOnOverflow(); t = (T)u; } }; template < typename T, typename U > class SafeCastHelper < T, U, CastCheckGTMax > { public: static bool Cast( U u, T& t ) SAFEINT_NOTHROW { if( u > (U)IntTraits< T >::maxInt ) return false; t = (T)u; return true; } template < typename E > static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW { if( u > (U)IntTraits< T >::maxInt ) E::SafeIntOnOverflow(); t = (T)u; } }; template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxUnsigned > { public: static bool Cast( U u, T& t ) SAFEINT_NOTHROW { // U is signed - T could be either signed or unsigned if( u > IntTraits< T >::maxInt || u < 0 ) return false; t = (T)u; return true; } template < typename E > static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW { // U is signed - T could be either signed or unsigned if( u > IntTraits< T >::maxInt || u < 0 ) E::SafeIntOnOverflow(); t = (T)u; } }; template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxSigned > { public: static bool Cast( U u, T& t ) SAFEINT_NOTHROW { // T, U are signed if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt ) return false; t = (T)u; return true; } template < typename E > static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW { //T, U are signed if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt ) E::SafeIntOnOverflow(); t = (T)u; } }; //core logic to determine whether a comparison is valid, or needs special treatment enum ComparisonMethod { ComparisonMethod_Ok = 0, ComparisonMethod_CastInt, ComparisonMethod_CastInt64, ComparisonMethod_UnsignedT, ComparisonMethod_UnsignedU }; // Note - the standard is arguably broken in the case of some integer // conversion operations // For example, signed char a = -1 = 0xff // unsigned int b = 0xffffffff // If you then test if a < b, a value-preserving cast // is made, and you're essentially testing // (unsigned int)a < b == false // // I do not think this makes sense - if you perform // a cast to an __int64, which can clearly preserve both value and signedness // then you get a different and intuitively correct answer // IMHO, -1 should be less than 4 billion // If you prefer to retain the ANSI standard behavior // insert #define ANSI_CONVERSIONS into your source // Behavior differences occur in the following cases: // 8, 16, and 32-bit signed int, unsigned 32-bit int // any signed int, unsigned 64-bit int // Note - the signed int must be negative to show the problem template < typename T, typename U > class ValidComparison { public: enum { #ifdef ANSI_CONVERSIONS method = ComparisonMethod_Ok #else method = ( ( SafeIntCompare< T, U >::isLikeSigned ) ? ComparisonMethod_Ok : ( ( IntTraits< T >::isSigned && sizeof(T) < 8 && sizeof(U) < 4 ) || ( IntTraits< U >::isSigned && sizeof(T) < 4 && sizeof(U) < 8 ) ) ? ComparisonMethod_CastInt : ( ( IntTraits< T >::isSigned && sizeof(U) < 8 ) || ( IntTraits< U >::isSigned && sizeof(T) < 8 ) ) ? ComparisonMethod_CastInt64 : ( !IntTraits< T >::isSigned ) ? ComparisonMethod_UnsignedT : ComparisonMethod_UnsignedU ) #endif }; }; template class EqualityTest; template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok > { public: static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( t == u ); } }; template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt > { public: static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t == (int)u ); } }; template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 > { public: static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t == (__int64)u ); } }; template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT > { public: static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller if( u < 0 ) return false; //else safe to cast to type T return ( t == (T)u ); } }; template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU> { public: static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller if( t < 0 ) return false; //else safe to cast to type U return ( (U)t == u ); } }; template class GreaterThanTest; template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok > { public: static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( t > u ); } }; template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt > { public: static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t > (int)u ); } }; template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 > { public: static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t > (__int64)u ); } }; template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT > { public: static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller if( u < 0 ) return true; // else safe to cast to type T return ( t > (T)u ); } }; template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU > { public: static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller if( t < 0 ) return false; // else safe to cast to type U return ( (U)t > u ); } }; // Modulus is simpler than comparison, but follows much the same logic // using this set of functions, it can't fail except in a div 0 situation template class ModulusHelper; template class ModulusHelper { public: static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if(u == 0) return SafeIntDivideByZero; //trap corner case if( CompileConst< IntTraits< U >::isSigned >::Value() ) { // Some compilers don't notice that this only compiles when u is signed // Add cast to make them happy if( u == (U)-1 ) { result = 0; return SafeIntNoError; } } result = (T)(t % u); return SafeIntNoError; } template < typename E > static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if(u == 0) E::SafeIntOnDivZero(); //trap corner case if( CompileConst< IntTraits< U >::isSigned >::Value() ) { if( u == (U)-1 ) { result = 0; return; } } result = (T)(t % u); } }; template class ModulusHelper { public: static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if(u == 0) return SafeIntDivideByZero; //trap corner case if( CompileConst< IntTraits< U >::isSigned >::Value() ) { if( u == (U)-1 ) { result = 0; return SafeIntNoError; } } result = (T)(t % u); return SafeIntNoError; } template < typename E > static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if(u == 0) E::SafeIntOnDivZero(); //trap corner case if( CompileConst< IntTraits< U >::isSigned >::Value() ) { if( u == (U)-1 ) { result = 0; return; } } result = (T)(t % u); } }; template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_CastInt64> { public: static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if(u == 0) return SafeIntDivideByZero; //trap corner case if( CompileConst< IntTraits< U >::isSigned >::Value() ) { if( u == (U)-1 ) { result = 0; return SafeIntNoError; } } result = (T)((__int64)t % (__int64)u); return SafeIntNoError; } template < typename E > static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if(u == 0) E::SafeIntOnDivZero(); if( CompileConst< IntTraits< U >::isSigned >::Value() ) { if( u == (U)-1 ) { result = 0; return; } } result = (T)((__int64)t % (__int64)u); } }; // T is unsigned __int64, U is any signed int template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedT> { public: static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if(u == 0) return SafeIntDivideByZero; // u could be negative - if so, need to convert to positive // casts below are always safe due to the way modulus works if(u < 0) result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs(u)); else result = (T)(t % u); return SafeIntNoError; } template < typename E > static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if(u == 0) E::SafeIntOnDivZero(); // u could be negative - if so, need to convert to positive if(u < 0) result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u )); else result = (T)(t % u); } }; // U is unsigned __int64, T any signed int template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedU> { public: static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if(u == 0) return SafeIntDivideByZero; //t could be negative - if so, need to convert to positive if(t < 0) result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1 ); else result = (T)((T)t % u); return SafeIntNoError; } template < typename E > static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if(u == 0) E::SafeIntOnDivZero(); //t could be negative - if so, need to convert to positive if(t < 0) result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1); else result = (T)( (T)t % u ); } }; //core logic to determine method to check multiplication enum MultiplicationState { MultiplicationState_CastInt = 0, // One or both signed, smaller than 32-bit MultiplicationState_CastInt64, // One or both signed, smaller than 64-bit MultiplicationState_CastUint, // Both are unsigned, smaller than 32-bit MultiplicationState_CastUint64, // Both are unsigned, both 32-bit or smaller MultiplicationState_Uint64Uint, // Both are unsigned, lhs 64-bit, rhs 32-bit or smaller MultiplicationState_Uint64Uint64, // Both are unsigned int64 MultiplicationState_Uint64Int, // lhs is unsigned int64, rhs int32 MultiplicationState_Uint64Int64, // lhs is unsigned int64, rhs signed int64 MultiplicationState_UintUint64, // Both are unsigned, lhs 32-bit or smaller, rhs 64-bit MultiplicationState_UintInt64, // lhs unsigned 32-bit or less, rhs int64 MultiplicationState_Int64Uint, // lhs int64, rhs unsigned int32 MultiplicationState_Int64Int64, // lhs int64, rhs int64 MultiplicationState_Int64Int, // lhs int64, rhs int32 MultiplicationState_IntUint64, // lhs int, rhs unsigned int64 MultiplicationState_IntInt64, // lhs int, rhs int64 MultiplicationState_Int64Uint64, // lhs int64, rhs uint64 MultiplicationState_Error }; template < typename T, typename U > class MultiplicationMethod { public: enum { // unsigned-unsigned method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? MultiplicationState_CastUint : (IntRegion< T,U >::IntZone_Uint32_UintLT64 || IntRegion< T,U >::IntZone_UintLT32_Uint32) ? MultiplicationState_CastUint64 : SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isUint64 && IntTraits< U >::isUint64 ? MultiplicationState_Uint64Uint64 : (IntRegion< T,U >::IntZone_Uint64_Uint) ? MultiplicationState_Uint64Uint : (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? MultiplicationState_UintUint64 : // unsigned-signed (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? MultiplicationState_CastInt : (IntRegion< T,U >::IntZone_Uint32_IntLT64 || IntRegion< T,U >::IntZone_UintLT32_Int32) ? MultiplicationState_CastInt64 : (IntRegion< T,U >::IntZone_Uint64_Int) ? MultiplicationState_Uint64Int : (IntRegion< T,U >::IntZone_UintLT64_Int64) ? MultiplicationState_UintInt64 : (IntRegion< T,U >::IntZone_Uint64_Int64) ? MultiplicationState_Uint64Int64 : // signed-signed (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? MultiplicationState_CastInt : (IntRegion< T,U >::IntZone_Int32_IntLT64 || IntRegion< T,U >::IntZone_IntLT32_Int32) ? MultiplicationState_CastInt64 : (IntRegion< T,U >::IntZone_Int64_Int64) ? MultiplicationState_Int64Int64 : (IntRegion< T,U >::IntZone_Int64_Int) ? MultiplicationState_Int64Int : (IntRegion< T,U >::IntZone_IntLT64_Int64) ? MultiplicationState_IntInt64 : // signed-unsigned (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? MultiplicationState_CastInt : (IntRegion< T,U >::IntZone_Int32_UintLT32 || IntRegion< T,U >::IntZone_IntLT64_Uint32) ? MultiplicationState_CastInt64 : (IntRegion< T,U >::IntZone_Int64_UintLT64) ? MultiplicationState_Int64Uint : (IntRegion< T,U >::IntZone_Int_Uint64) ? MultiplicationState_IntUint64 : (IntRegion< T,U >::IntZone_Int64_Uint64 ? MultiplicationState_Int64Uint64 : MultiplicationState_Error ) ) }; }; template class MultiplicationHelper; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt> { public: //accepts signed, both less than 32-bit static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW { int tmp = t * u; if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt ) return false; ret = (T)tmp; return true; } template < typename E > static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW { int tmp = t * u; if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt ) E::SafeIntOnOverflow(); ret = (T)tmp; } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint > { public: //accepts unsigned, both less than 32-bit static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW { unsigned int tmp = (unsigned int)(t * u); if( tmp > IntTraits< T >::maxInt ) return false; ret = (T)tmp; return true; } template < typename E > static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW { unsigned int tmp = (unsigned int)( t * u ); if( tmp > IntTraits< T >::maxInt ) E::SafeIntOnOverflow(); ret = (T)tmp; } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt64> { public: //mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW { __int64 tmp = (__int64)t * (__int64)u; if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt) return false; ret = (T)tmp; return true; } template < typename E > static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW { __int64 tmp = (__int64)t * (__int64)u; if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt) E::SafeIntOnOverflow(); ret = (T)tmp; } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint64> { public: //both unsigned where at least one argument is 32-bit, and both are 32-bit or less static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW { unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u; if(tmp > (unsigned __int64)IntTraits< T >::maxInt) return false; ret = (T)tmp; return true; } template < typename E > static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW { unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u; if(tmp > (unsigned __int64)IntTraits< T >::maxInt) E::SafeIntOnOverflow(); ret = (T)tmp; } }; // T = left arg and return type // U = right arg template < typename T, typename U > class LargeIntRegMultiply; #if SAFEINT_USE_INTRINSICS // As usual, unsigned is easy inline bool IntrinsicMultiplyUint64( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW { unsigned __int64 ulHigh = 0; *pRet = _umul128(a , b, &ulHigh); return ulHigh == 0; } // Signed, is not so easy inline bool IntrinsicMultiplyInt64( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW { __int64 llHigh = 0; *pRet = _mul128(a , b, &llHigh); // Now we need to figure out what we expect // If llHigh is 0, then treat *pRet as unsigned // If llHigh is < 0, then treat *pRet as signed if( (a ^ b) < 0 ) { // Negative result expected if( llHigh == -1 && *pRet < 0 || llHigh == 0 && *pRet == 0 ) { // Everything is within range return true; } } else { // Result should be positive // Check for overflow if( llHigh == 0 && (unsigned __int64)*pRet <= IntTraits< signed __int64 >::maxInt ) return true; } return false; } #endif template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 > { public: static bool RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS return IntrinsicMultiplyUint64( a, b, pRet ); #else unsigned __int32 aHigh, aLow, bHigh, bLow; // Consider that a*b can be broken up into: // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) // Note - same approach applies for 128 bit math on a 64-bit system aHigh = (unsigned __int32)(a >> 32); aLow = (unsigned __int32)a; bHigh = (unsigned __int32)(b >> 32); bLow = (unsigned __int32)b; *pRet = 0; if(aHigh == 0) { if(bHigh != 0) { *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh; } } else if(bHigh == 0) { if(aHigh != 0) { *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow; } } else { return false; } if(*pRet != 0) { unsigned __int64 tmp; if((unsigned __int32)(*pRet >> 32) != 0) return false; *pRet <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)bLow; *pRet += tmp; if(*pRet < tmp) return false; return true; } *pRet = (unsigned __int64)aLow * (unsigned __int64)bLow; return true; #endif } template < typename E > static void RegMultiplyThrow( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS if( !IntrinsicMultiplyUint64( a, b, pRet ) ) E::SafeIntOnOverflow(); #else unsigned __int32 aHigh, aLow, bHigh, bLow; // Consider that a*b can be broken up into: // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) // Note - same approach applies for 128 bit math on a 64-bit system aHigh = (unsigned __int32)(a >> 32); aLow = (unsigned __int32)a; bHigh = (unsigned __int32)(b >> 32); bLow = (unsigned __int32)b; *pRet = 0; if(aHigh == 0) { if(bHigh != 0) { *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh; } } else if(bHigh == 0) { if(aHigh != 0) { *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow; } } else { E::SafeIntOnOverflow(); } if(*pRet != 0) { unsigned __int64 tmp; if((unsigned __int32)(*pRet >> 32) != 0) E::SafeIntOnOverflow(); *pRet <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)bLow; *pRet += tmp; if(*pRet < tmp) E::SafeIntOnOverflow(); return; } *pRet = (unsigned __int64)aLow * (unsigned __int64)bLow; #endif } }; template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int32 > { public: static bool RegMultiply( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ); #else unsigned __int32 aHigh, aLow; // Consider that a*b can be broken up into: // (aHigh * 2^32 + aLow) * b // => (aHigh * b * 2^32) + (aLow * b) aHigh = (unsigned __int32)(a >> 32); aLow = (unsigned __int32)a; *pRet = 0; if(aHigh != 0) { *pRet = (unsigned __int64)aHigh * (unsigned __int64)b; unsigned __int64 tmp; if((unsigned __int32)(*pRet >> 32) != 0) return false; *pRet <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)b; *pRet += tmp; if(*pRet < tmp) return false; return true; } *pRet = (unsigned __int64)aLow * (unsigned __int64)b; return true; #endif } template < typename E > static void RegMultiplyThrow( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) ) E::SafeIntOnOverflow(); #else unsigned __int32 aHigh, aLow; // Consider that a*b can be broken up into: // (aHigh * 2^32 + aLow) * b // => (aHigh * b * 2^32) + (aLow * b) aHigh = (unsigned __int32)(a >> 32); aLow = (unsigned __int32)a; *pRet = 0; if(aHigh != 0) { *pRet = (unsigned __int64)aHigh * (unsigned __int64)b; unsigned __int64 tmp; if((unsigned __int32)(*pRet >> 32) != 0) E::SafeIntOnOverflow(); *pRet <<= 32; tmp = (unsigned __int64)aLow * (unsigned __int64)b; *pRet += tmp; if(*pRet < tmp) E::SafeIntOnOverflow(); return; } *pRet = (unsigned __int64)aLow * (unsigned __int64)b; return; #endif } }; template<> class LargeIntRegMultiply< unsigned __int64, signed __int32 > { public: // Intrinsic not needed static bool RegMultiply( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW { if( b < 0 && a != 0 ) return false; #if SAFEINT_USE_INTRINSICS return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ); #else return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply(a, (unsigned __int32)b, pRet); #endif } template < typename E > static void RegMultiplyThrow( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW { if( b < 0 && a != 0 ) E::SafeIntOnOverflow(); #if SAFEINT_USE_INTRINSICS if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) ) E::SafeIntOnOverflow(); #else LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( a, (unsigned __int32)b, pRet ); #endif } }; template<> class LargeIntRegMultiply< unsigned __int64, signed __int64 > { public: static bool RegMultiply( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_NOTHROW { if( b < 0 && a != 0 ) return false; #if SAFEINT_USE_INTRINSICS return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ); #else return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply(a, (unsigned __int64)b, pRet); #endif } template < typename E > static void RegMultiplyThrow( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW { if( b < 0 && a != 0 ) E::SafeIntOnOverflow(); #if SAFEINT_USE_INTRINSICS if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) ) E::SafeIntOnOverflow(); #else LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet ); #endif } }; template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 > { public: // Devolves into ordinary 64-bit calculation static bool RegMultiply( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW { unsigned __int32 bHigh, bLow; bool fIsNegative = false; // Consider that a*b can be broken up into: // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) // aHigh == 0 implies: // ( aLow * bHigh * 2^32 ) + ( aLow + bLow ) // If the first part is != 0, fail bHigh = (unsigned __int32)(b >> 32); bLow = (unsigned __int32)b; *pRet = 0; if(bHigh != 0 && a != 0) return false; if( a < 0 ) { a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); fIsNegative = true; } unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow; if( !fIsNegative ) { if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt ) { *pRet = (signed __int32)tmp; return true; } } else { if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 ) { *pRet = SignedNegation< signed __int32 >::Value( tmp ); return true; } } return false; } template < typename E > static void RegMultiplyThrow( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW { unsigned __int32 bHigh, bLow; bool fIsNegative = false; // Consider that a*b can be broken up into: // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow) // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow) bHigh = (unsigned __int32)(b >> 32); bLow = (unsigned __int32)b; *pRet = 0; if(bHigh != 0 && a != 0) E::SafeIntOnOverflow(); if( a < 0 ) { a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); fIsNegative = true; } unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow; if( !fIsNegative ) { if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt ) { *pRet = (signed __int32)tmp; return; } } else { if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 ) { *pRet = SignedNegation< signed __int32 >::Value( tmp ); return; } } E::SafeIntOnOverflow(); } }; template<> class LargeIntRegMultiply< unsigned __int32, unsigned __int64 > { public: // Becomes ordinary 64-bit multiplication, intrinsic not needed static bool RegMultiply( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW { // Consider that a*b can be broken up into: // (bHigh * 2^32 + bLow) * a // => (bHigh * a * 2^32) + (bLow * a) // In this case, the result must fit into 32-bits // If bHigh != 0 && a != 0, immediate error. if( (unsigned __int32)(b >> 32) != 0 && a != 0 ) return false; unsigned __int64 tmp = b * (unsigned __int64)a; if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow return false; *pRet = (unsigned __int32)tmp; return true; } template < typename E > static void RegMultiplyThrow( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW { if( (unsigned __int32)(b >> 32) != 0 && a != 0 ) E::SafeIntOnOverflow(); unsigned __int64 tmp = b * (unsigned __int64)a; if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow E::SafeIntOnOverflow(); *pRet = (unsigned __int32)tmp; } }; template<> class LargeIntRegMultiply< unsigned __int32, signed __int64 > { public: static bool RegMultiply( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW { if( b < 0 && a != 0 ) return false; return LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( a, (unsigned __int64)b, pRet ); } template < typename E > static void RegMultiplyThrow( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW { if( b < 0 && a != 0 ) E::SafeIntOnOverflow(); LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet ); } }; template<> class LargeIntRegMultiply< signed __int64, signed __int64 > { public: static bool RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS return IntrinsicMultiplyInt64( a, b, pRet ); #else bool aNegative = false; bool bNegative = false; unsigned __int64 tmp; __int64 a1 = a; __int64 b1 = b; if( a1 < 0 ) { aNegative = true; a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); } if( b1 < 0 ) { bNegative = true; b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); } if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, &tmp ) ) { // The unsigned multiplication didn't overflow if( aNegative ^ bNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { *pRet = SignedNegation< signed __int64 >::Value( tmp ); return true; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { *pRet = (signed __int64)tmp; return true; } } } return false; #endif } template < typename E > static void RegMultiplyThrow( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS if( !IntrinsicMultiplyInt64( a, b, pRet ) ) E::SafeIntOnOverflow(); #else bool aNegative = false; bool bNegative = false; unsigned __int64 tmp; __int64 a1 = a; __int64 b1 = b; if( a1 < 0 ) { aNegative = true; a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); } if( b1 < 0 ) { bNegative = true; b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); } LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, (unsigned __int64)b1, &tmp ); // The unsigned multiplication didn't overflow or we'd be in the exception handler if( aNegative ^ bNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { *pRet = SignedNegation< signed __int64 >::Value( tmp ); return; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { *pRet = (signed __int64)tmp; return; } } E::SafeIntOnOverflow(); #endif } }; template<> class LargeIntRegMultiply< signed __int64, unsigned __int32 > { public: static bool RegMultiply( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ); #else bool aNegative = false; unsigned __int64 tmp; __int64 a1 = a; if( a1 < 0 ) { aNegative = true; a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); } if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, b, &tmp ) ) { // The unsigned multiplication didn't overflow if( aNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { *pRet = SignedNegation< signed __int64 >::Value( tmp ); return true; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { *pRet = (signed __int64)tmp; return true; } } } return false; #endif } template < typename E > static void RegMultiplyThrow( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) ) E::SafeIntOnOverflow(); #else bool aNegative = false; unsigned __int64 tmp; __int64 a1 = a; if( a1 < 0 ) { aNegative = true; a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); } LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, b, &tmp ); // The unsigned multiplication didn't overflow if( aNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { *pRet = SignedNegation< signed __int64 >::Value( tmp ); return; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { *pRet = (signed __int64)tmp; return; } } E::SafeIntOnOverflow(); #endif } }; template<> class LargeIntRegMultiply< signed __int64, signed __int32 > { public: static bool RegMultiply( const signed __int64& a, signed __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ); #else bool aNegative = false; bool bNegative = false; unsigned __int64 tmp; __int64 a1 = a; __int64 b1 = b; if( a1 < 0 ) { aNegative = true; a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); } if( b1 < 0 ) { bNegative = true; b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); } if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, (unsigned __int32)b1, &tmp ) ) { // The unsigned multiplication didn't overflow if( aNegative ^ bNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { *pRet = SignedNegation< signed __int64 >::Value( tmp ); return true; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { *pRet = (signed __int64)tmp; return true; } } } return false; #endif } template < typename E > static void RegMultiplyThrow( signed __int64 a, signed __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) ) E::SafeIntOnOverflow(); #else bool aNegative = false; bool bNegative = false; unsigned __int64 tmp; if( a < 0 ) { aNegative = true; a = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a); } if( b < 0 ) { bNegative = true; b = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(b); } LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a, (unsigned __int32)b, &tmp ); // The unsigned multiplication didn't overflow if( aNegative ^ bNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { *pRet = SignedNegation< signed __int64 >::Value( tmp ); return; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { *pRet = (signed __int64)tmp; return; } } E::SafeIntOnOverflow(); #endif } }; template<> class LargeIntRegMultiply< signed __int32, signed __int64 > { public: static bool RegMultiply( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW { #if SAFEINT_USE_INTRINSICS __int64 tmp; if( IntrinsicMultiplyInt64( a, b, &tmp ) ) { if( tmp > IntTraits< signed __int32 >::maxInt || tmp < IntTraits< signed __int32 >::minInt ) { return false; } *pRet = (__int32)tmp; return true; } return false; #else bool aNegative = false; bool bNegative = false; unsigned __int32 tmp; __int64 b1 = b; if( a < 0 ) { aNegative = true; a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); } if( b1 < 0 ) { bNegative = true; b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1); } if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( (unsigned __int32)a, (unsigned __int64)b1, &tmp ) ) { // The unsigned multiplication didn't overflow if( aNegative ^ bNegative ) { // Result must be negative if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt ) { *pRet = SignedNegation< signed __int32 >::Value( tmp ); return true; } } else { // Result must be positive if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt ) { *pRet = (signed __int32)tmp; return true; } } } return false; #endif } template < typename E > static void RegMultiplyThrow( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW { #if SAFEINT_USE_INTRINSICS __int64 tmp; if( IntrinsicMultiplyInt64( a, b, &tmp ) ) { if( tmp > IntTraits< signed __int32 >::maxInt || tmp < IntTraits< signed __int32 >::minInt ) { E::SafeIntOnOverflow(); } *pRet = (__int32)tmp; return; } E::SafeIntOnOverflow(); #else bool aNegative = false; bool bNegative = false; unsigned __int32 tmp; signed __int64 b2 = b; if( a < 0 ) { aNegative = true; a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a); } if( b < 0 ) { bNegative = true; b2 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b2); } LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)a, (unsigned __int64)b2, &tmp ); // The unsigned multiplication didn't overflow if( aNegative ^ bNegative ) { // Result must be negative if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt ) { *pRet = SignedNegation< signed __int32 >::Value( tmp ); return; } } else { // Result must be positive if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt ) { *pRet = (signed __int32)tmp; return; } } E::SafeIntOnOverflow(); #endif } }; template<> class LargeIntRegMultiply< signed __int64, unsigned __int64 > { public: // Leave this one as-is - will call unsigned intrinsic internally static bool RegMultiply( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW { bool aNegative = false; unsigned __int64 tmp; __int64 a1 = a; if( a1 < 0 ) { aNegative = true; a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); } if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) ) { // The unsigned multiplication didn't overflow if( aNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { *pRet = SignedNegation< signed __int64 >::Value( tmp ); return true; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { *pRet = (signed __int64)tmp; return true; } } } return false; } template < typename E > static void RegMultiplyThrow( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW { bool aNegative = false; unsigned __int64 tmp; __int64 a1 = a; if( a1 < 0 ) { aNegative = true; a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1); } if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) ) { // The unsigned multiplication didn't overflow if( aNegative ) { // Result must be negative if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt ) { *pRet = SignedNegation< signed __int64 >::Value( tmp ); return; } } else { // Result must be positive if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt ) { *pRet = (signed __int64)tmp; return; } } } E::SafeIntOnOverflow(); } }; // In all of the following functions where LargeIntRegMultiply methods are called, // we need to properly transition types. The methods need __int64, __int32, etc. // but the variables being passed to us could be long long, long int, or long, depending on // the compiler. Microsoft compiler knows that long long is the same type as __int64, but gcc doesn't template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint64 > { public: // T, U are unsigned __int64 static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isUint64 && IntTraits::isUint64 ); unsigned __int64 t1 = t; unsigned __int64 u1 = u; return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast(&ret) ); } template < typename E > static void MultiplyThrow(const unsigned __int64& t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isUint64 && IntTraits::isUint64 ); unsigned __int64 t1 = t; unsigned __int64 u1 = u; LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast(&ret) ); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint > { public: // T is unsigned __int64 // U is any unsigned int 32-bit or less static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isUint64 ); unsigned __int64 t1 = t; return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast(&ret) ); } template < typename E > static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isUint64 ); unsigned __int64 t1 = t; LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast(&ret) ); } }; // converse of the previous function template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintUint64 > { public: // T is any unsigned int up to 32-bit // U is unsigned __int64 static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isUint64 ); unsigned __int64 u1 = u; unsigned __int32 tmp; if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( t, u1, &tmp ) && SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) ) { return true; } return false; } template < typename E > static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isUint64 ); unsigned __int64 u1 = u; unsigned __int32 tmp; LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( t, u1, &tmp ); SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int > { public: // T is unsigned __int64 // U is any signed int, up to 64-bit static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isUint64 ); unsigned __int64 t1 = t; return LargeIntRegMultiply< unsigned __int64, signed __int32 >::RegMultiply(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret)); } template < typename E > static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isUint64 ); unsigned __int64 t1 = t; LargeIntRegMultiply< unsigned __int64, signed __int32 >::template RegMultiplyThrow< E >(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret)); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int64 > { public: // T is unsigned __int64 // U is __int64 static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isUint64 && IntTraits::isInt64 ); unsigned __int64 t1 = t; __int64 u1 = u; return LargeIntRegMultiply< unsigned __int64, __int64 >::RegMultiply(t1, u1, reinterpret_cast< unsigned __int64* >(&ret)); } template < typename E > static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isUint64 && IntTraits::isInt64 ); unsigned __int64 t1 = t; __int64 u1 = u; LargeIntRegMultiply< unsigned __int64, __int64 >::template RegMultiplyThrow< E >(t1, u1, reinterpret_cast< unsigned __int64* >(&ret)); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintInt64 > { public: // T is unsigned up to 32-bit // U is __int64 static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isInt64 ); __int64 u1 = u; unsigned __int32 tmp; if( LargeIntRegMultiply< unsigned __int32, __int64 >::RegMultiply( (unsigned __int32)t, u1, &tmp ) && SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) ) { return true; } return false; } template < typename E > static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isInt64 ); __int64 u1 = u; unsigned __int32 tmp; LargeIntRegMultiply< unsigned __int32, __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)t, u1, &tmp ); SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint > { public: // T is __int64 // U is unsigned up to 32-bit static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isInt64 ); __int64 t1 = t; return LargeIntRegMultiply< __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) ); } template < typename E > static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isInt64 ); __int64 t1 = t; LargeIntRegMultiply< __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) ); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int64 > { public: // T, U are __int64 static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isInt64 && IntTraits::isInt64 ); __int64 t1 = t; __int64 u1 = u; return LargeIntRegMultiply< __int64, __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) ); } template < typename E > static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isInt64 && IntTraits::isInt64 ); __int64 t1 = t; __int64 u1 = u; LargeIntRegMultiply< __int64, __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret)); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int > { public: // T is __int64 // U is signed up to 32-bit static bool Multiply( const T& t, U u, T& ret ) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isInt64 ); __int64 t1 = t; return LargeIntRegMultiply< __int64, __int32 >::RegMultiply( t1, (__int32)u, reinterpret_cast< __int64* >(&ret)); } template < typename E > static void MultiplyThrow( const __int64& t, U u, T& ret ) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isInt64 ); __int64 t1 = t; LargeIntRegMultiply< __int64, __int32 >::template RegMultiplyThrow< E >(t1, (__int32)u, reinterpret_cast< __int64* >(&ret)); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntUint64 > { public: // T is signed up to 32-bit // U is unsigned __int64 static bool Multiply(T t, const U& u, T& ret) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isUint64 ); unsigned __int64 u1 = u; __int32 tmp; if( LargeIntRegMultiply< __int32, unsigned __int64 >::RegMultiply( (__int32)t, u1, &tmp ) && SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) ) { return true; } return false; } template < typename E > static void MultiplyThrow(T t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isUint64 ); unsigned __int64 u1 = u; __int32 tmp; LargeIntRegMultiply< __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp ); SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret ); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint64> { public: // T is __int64 // U is unsigned __int64 static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isInt64 && IntTraits::isUint64 ); __int64 t1 = t; unsigned __int64 u1 = u; return LargeIntRegMultiply< __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) ); } template < typename E > static void MultiplyThrow( const __int64& t, const unsigned __int64& u, T& ret ) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isInt64 && IntTraits::isUint64 ); __int64 t1 = t; unsigned __int64 u1 = u; LargeIntRegMultiply< __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret) ); } }; template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntInt64> { public: // T is signed, up to 32-bit // U is __int64 static bool Multiply( T t, const U& u, T& ret ) SAFEINT_NOTHROW { C_ASSERT( IntTraits::isInt64 ); __int64 u1 = u; __int32 tmp; if( LargeIntRegMultiply< __int32, __int64 >::RegMultiply( (__int32)t, u1, &tmp ) && SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) ) { return true; } return false; } template < typename E > static void MultiplyThrow(T t, const U& u, T& ret) SAFEINT_CPP_THROW { C_ASSERT( IntTraits::isInt64 ); __int64 u1 = u; __int32 tmp; LargeIntRegMultiply< __int32, __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp ); SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret ); } }; enum DivisionState { DivisionState_OK, DivisionState_UnsignedSigned, DivisionState_SignedUnsigned32, DivisionState_SignedUnsigned64, DivisionState_SignedUnsigned, DivisionState_SignedSigned }; template < typename T, typename U > class DivisionMethod { public: enum { method = (SafeIntCompare< T, U >::isBothUnsigned ? DivisionState_OK : (!IntTraits< T >::isSigned && IntTraits< U >::isSigned) ? DivisionState_UnsignedSigned : (IntTraits< T >::isSigned && IntTraits< U >::isUint32 && IntTraits< T >::isLT64Bit) ? DivisionState_SignedUnsigned32 : (IntTraits< T >::isSigned && IntTraits< U >::isUint64) ? DivisionState_SignedUnsigned64 : (IntTraits< T >::isSigned && !IntTraits< U >::isSigned) ? DivisionState_SignedUnsigned : DivisionState_SignedSigned) }; }; template < typename T, typename U, int state > class DivisionHelper; template < typename T, typename U > class DivisionHelper< T, U, DivisionState_OK > { public: static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if( u == 0 ) return SafeIntDivideByZero; if( t == 0 ) { result = 0; return SafeIntNoError; } result = (T)( t/u ); return SafeIntNoError; } template < typename E > static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if( u == 0 ) E::SafeIntOnDivZero(); if( t == 0 ) { result = 0; return; } result = (T)( t/u ); } }; template < typename T, typename U > class DivisionHelper< T, U, DivisionState_UnsignedSigned> { public: static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if( u == 0 ) return SafeIntDivideByZero; if( t == 0 ) { result = 0; return SafeIntNoError; } if( u > 0 ) { result = (T)( t/u ); return SafeIntNoError; } // it is always an error to try and divide an unsigned number by a negative signed number // unless u is bigger than t if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t ) { result = 0; return SafeIntNoError; } return SafeIntArithmeticOverflow; } template < typename E > static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if( u == 0 ) E::SafeIntOnDivZero(); if( t == 0 ) { result = 0; return; } if( u > 0 ) { result = (T)( t/u ); return; } // it is always an error to try and divide an unsigned number by a negative signed number // unless u is bigger than t if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t ) { result = 0; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned32 > { public: static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if( u == 0 ) return SafeIntDivideByZero; if( t == 0 ) { result = 0; return SafeIntNoError; } // Test for t > 0 // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional if( t > 0 ) result = (T)( t/u ); else result = (T)( (__int64)t/(__int64)u ); return SafeIntNoError; } template < typename E > static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if( u == 0 ) { E::SafeIntOnDivZero(); } if( t == 0 ) { result = 0; return; } // Test for t > 0 // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional if( t > 0 ) result = (T)( t/u ); else result = (T)( (__int64)t/(__int64)u ); } }; template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned64 > { public: static SafeIntError Divide( const T& t, const unsigned __int64& u, T& result ) SAFEINT_NOTHROW { C_ASSERT( IntTraits< U >::isUint64 ); if( u == 0 ) { return SafeIntDivideByZero; } if( t == 0 ) { result = 0; return SafeIntNoError; } if( u <= (unsigned __int64)IntTraits< T >::maxInt ) { // Else u can safely be cast to T if( CompileConst< sizeof( T ) < sizeof( __int64 )>::Value() ) result = (T)( (int)t/(int)u ); else result = (T)((__int64)t/(__int64)u); } else // Corner case if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt ) { // Min int divided by it's own magnitude is -1 result = -1; } else { result = 0; } return SafeIntNoError; } template < typename E > static void DivideThrow( const T& t, const unsigned __int64& u, T& result ) SAFEINT_CPP_THROW { C_ASSERT( IntTraits< U >::isUint64 ); if( u == 0 ) { E::SafeIntOnDivZero(); } if( t == 0 ) { result = 0; return; } if( u <= (unsigned __int64)IntTraits< T >::maxInt ) { // Else u can safely be cast to T if( CompileConst< sizeof( T ) < sizeof( __int64 ) >::Value() ) result = (T)( (int)t/(int)u ); else result = (T)((__int64)t/(__int64)u); } else // Corner case if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt ) { // Min int divided by it's own magnitude is -1 result = -1; } else { result = 0; } } }; template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned> { public: // T is any signed, U is unsigned and smaller than 32-bit // In this case, standard operator casting is correct static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if( u == 0 ) { return SafeIntDivideByZero; } if( t == 0 ) { result = 0; return SafeIntNoError; } result = (T)( t/u ); return SafeIntNoError; } template < typename E > static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if( u == 0 ) { E::SafeIntOnDivZero(); } if( t == 0 ) { result = 0; return; } result = (T)( t/u ); } }; template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedSigned> { public: static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { if( u == 0 ) { return SafeIntDivideByZero; } if( t == 0 ) { result = 0; return SafeIntNoError; } // Must test for corner case if( t == IntTraits< T >::minInt && u == (U)-1 ) return SafeIntArithmeticOverflow; result = (T)( t/u ); return SafeIntNoError; } template < typename E > static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW { if(u == 0) { E::SafeIntOnDivZero(); } if( t == 0 ) { result = 0; return; } // Must test for corner case if( t == IntTraits< T >::minInt && u == (U)-1 ) E::SafeIntOnOverflow(); result = (T)( t/u ); } }; enum AdditionState { AdditionState_CastIntCheckMax, AdditionState_CastUintCheckOverflow, AdditionState_CastUintCheckOverflowMax, AdditionState_CastUint64CheckOverflow, AdditionState_CastUint64CheckOverflowMax, AdditionState_CastIntCheckSafeIntMinMax, AdditionState_CastInt64CheckSafeIntMinMax, AdditionState_CastInt64CheckMax, AdditionState_CastUint64CheckSafeIntMinMax, AdditionState_CastUint64CheckSafeIntMinMax2, AdditionState_CastInt64CheckOverflow, AdditionState_CastInt64CheckOverflowSafeIntMinMax, AdditionState_CastInt64CheckOverflowMax, AdditionState_ManualCheckInt64Uint64, AdditionState_ManualCheck, AdditionState_Error }; template< typename T, typename U > class AdditionMethod { public: enum { //unsigned-unsigned method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? AdditionState_CastIntCheckMax : (IntRegion< T,U >::IntZone_Uint32_UintLT64) ? AdditionState_CastUintCheckOverflow : (IntRegion< T,U >::IntZone_UintLT32_Uint32) ? AdditionState_CastUintCheckOverflowMax : (IntRegion< T,U >::IntZone_Uint64_Uint) ? AdditionState_CastUint64CheckOverflow : (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? AdditionState_CastUint64CheckOverflowMax : //unsigned-signed (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax : (IntRegion< T,U >::IntZone_Uint32_IntLT64 || IntRegion< T,U >::IntZone_UintLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax : (IntRegion< T,U >::IntZone_Uint64_Int || IntRegion< T,U >::IntZone_Uint64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax : (IntRegion< T,U >::IntZone_UintLT64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax2 : //signed-signed (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax : (IntRegion< T,U >::IntZone_Int32_IntLT64 || IntRegion< T,U >::IntZone_IntLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax : (IntRegion< T,U >::IntZone_Int64_Int || IntRegion< T,U >::IntZone_Int64_Int64) ? AdditionState_CastInt64CheckOverflow : (IntRegion< T,U >::IntZone_IntLT64_Int64) ? AdditionState_CastInt64CheckOverflowSafeIntMinMax : //signed-unsigned (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? AdditionState_CastIntCheckMax : (IntRegion< T,U >::IntZone_Int32_UintLT32 || IntRegion< T,U >::IntZone_IntLT64_Uint32) ? AdditionState_CastInt64CheckMax : (IntRegion< T,U >::IntZone_Int64_UintLT64) ? AdditionState_CastInt64CheckOverflowMax : (IntRegion< T,U >::IntZone_Int64_Uint64) ? AdditionState_ManualCheckInt64Uint64 : (IntRegion< T,U >::IntZone_Int_Uint64) ? AdditionState_ManualCheck : AdditionState_Error) }; }; template < typename T, typename U, int method > class AdditionHelper; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckMax > { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { //16-bit or less unsigned addition __int32 tmp = lhs + rhs; if( tmp <= (__int32)IntTraits< T >::maxInt ) { result = (T)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { //16-bit or less unsigned addition __int32 tmp = lhs + rhs; if( tmp <= (__int32)IntTraits< T >::maxInt ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflow > { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // 32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; //we added didn't get smaller if( tmp >= lhs ) { result = (T)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // 32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; //we added didn't get smaller if( tmp >= lhs ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflowMax> { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // 32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; // We added and it didn't get smaller or exceed maxInt if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { //32-bit or less - both are unsigned unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs; // We added and it didn't get smaller or exceed maxInt if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflow> { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it didn't get smaller if(tmp >= lhs) { result = (T)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it didn't get smaller if(tmp >= lhs) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflowMax > { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { //lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it didn't get smaller if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { //lhs unsigned __int64, rhs unsigned unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it didn't get smaller if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckSafeIntMinMax > { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // 16-bit or less - one or both are signed __int32 tmp = lhs + rhs; if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt ) { result = (T)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // 16-bit or less - one or both are signed __int32 tmp = lhs + rhs; if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckSafeIntMinMax > { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // 32-bit or less - one or both are signed __int64 tmp = (__int64)lhs + (__int64)rhs; if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt ) { result = (T)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // 32-bit or less - one or both are signed __int64 tmp = (__int64)lhs + (__int64)rhs; if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckMax > { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // 32-bit or less - lhs signed, rhs unsigned __int64 tmp = (__int64)lhs + (__int64)rhs; if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // 32-bit or less - lhs signed, rhs unsigned __int64 tmp = (__int64)lhs + (__int64)rhs; if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax > { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs is unsigned __int64, rhs signed unsigned __int64 tmp; if( rhs < 0 ) { // So we're effectively subtracting tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); if( tmp <= lhs ) { result = lhs - tmp; return true; } } else { // now we know that rhs can be safely cast into an unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it did not become smaller if( tmp >= lhs ) { result = (T)tmp; return true; } } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is unsigned __int64, rhs signed unsigned __int64 tmp; if( rhs < 0 ) { // So we're effectively subtracting tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); if( tmp <= lhs ) { result = lhs - tmp; return; } } else { // now we know that rhs can be safely cast into an unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // We added and it did not become smaller if( tmp >= lhs ) { result = (T)tmp; return; } } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax2> { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs is unsigned and < 64-bit, rhs signed __int64 if( rhs < 0 ) { if( lhs >= ~(unsigned __int64)( rhs ) + 1 )//negation is safe, since rhs is 64-bit { result = (T)( lhs + rhs ); return true; } } else { // now we know that rhs can be safely cast into an unsigned __int64 unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff // it is not possible for the operation above to overflow, so just check max if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return true; } } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is unsigned and < 64-bit, rhs signed __int64 if( rhs < 0 ) { if( lhs >= ~(unsigned __int64)( rhs ) + 1) //negation is safe, since rhs is 64-bit { result = (T)( lhs + rhs ); return; } } else { // now we know that rhs can be safely cast into an unsigned __int64 unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff // it is not possible for the operation above to overflow, so just check max if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return; } } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflow> { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs is signed __int64, rhs signed __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs); if( lhs >= 0 ) { // mixed sign cannot overflow if( rhs >= 0 && tmp < lhs ) return false; } else { // lhs negative if( rhs < 0 && tmp > lhs ) return false; } result = (T)tmp; return true; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is signed __int64, rhs signed __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs); if( lhs >= 0 ) { // mixed sign cannot overflow if( rhs >= 0 && tmp < lhs ) E::SafeIntOnOverflow(); } else { // lhs negative if( rhs < 0 && tmp > lhs ) E::SafeIntOnOverflow(); } result = (T)tmp; } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowSafeIntMinMax> { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { //rhs is signed __int64, lhs signed __int64 tmp; if( AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::Addition( (__int64)lhs, (__int64)rhs, tmp ) && tmp <= IntTraits< T >::maxInt && tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { //rhs is signed __int64, lhs signed __int64 tmp; AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::AdditionThrow< E >( (__int64)lhs, (__int64)rhs, tmp ); if( tmp <= IntTraits< T >::maxInt && tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowMax> { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { //lhs is signed __int64, rhs unsigned < 64-bit unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; if( (__int64)tmp >= lhs ) { result = (T)(__int64)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is signed __int64, rhs unsigned < 64-bit // Some compilers get optimization-happy, let's thwart them unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs; if( (__int64)tmp >= lhs ) { result = (T)(__int64)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheckInt64Uint64 > { public: static bool Addition( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW { C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); // rhs is unsigned __int64, lhs __int64 // cast everything to unsigned, perform addition, then // cast back for check - this is done to stop optimizers from removing the code unsigned __int64 tmp = (unsigned __int64)lhs + rhs; if( (__int64)tmp >= lhs ) { result = (__int64)tmp; return true; } return false; } template < typename E > static void AdditionThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW { C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); // rhs is unsigned __int64, lhs __int64 unsigned __int64 tmp = (unsigned __int64)lhs + rhs; if( (__int64)tmp >= lhs ) { result = (__int64)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheck> { public: static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // rhs is unsigned __int64, lhs signed, 32-bit or less if( (unsigned __int32)( rhs >> 32 ) == 0 ) { // Now it just happens to work out that the standard behavior does what we want // Adding explicit casts to show exactly what's happening here // Note - this is tweaked to keep optimizers from tossing out the code. unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs; if( (__int32)tmp >= lhs && SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( (__int32)tmp, result ) ) return true; } return false; } template < typename E > static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // rhs is unsigned __int64, lhs signed, 32-bit or less if( (unsigned __int32)( rhs >> 32 ) == 0 ) { // Now it just happens to work out that the standard behavior does what we want // Adding explicit casts to show exactly what's happening here unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs; if( (__int32)tmp >= lhs ) { SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( (__int32)tmp, result ); return; } } E::SafeIntOnOverflow(); } }; enum SubtractionState { SubtractionState_BothUnsigned, SubtractionState_CastIntCheckSafeIntMinMax, SubtractionState_CastIntCheckMin, SubtractionState_CastInt64CheckSafeIntMinMax, SubtractionState_CastInt64CheckMin, SubtractionState_Uint64Int, SubtractionState_UintInt64, SubtractionState_Int64Int, SubtractionState_IntInt64, SubtractionState_Int64Uint, SubtractionState_IntUint64, SubtractionState_Int64Uint64, // states for SubtractionMethod2 SubtractionState_BothUnsigned2, SubtractionState_CastIntCheckSafeIntMinMax2, SubtractionState_CastInt64CheckSafeIntMinMax2, SubtractionState_Uint64Int2, SubtractionState_UintInt642, SubtractionState_Int64Int2, SubtractionState_IntInt642, SubtractionState_Int64Uint2, SubtractionState_IntUint642, SubtractionState_Int64Uint642, SubtractionState_Error }; template < typename T, typename U > class SubtractionMethod { public: enum { // unsigned-unsigned method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || (IntRegion< T,U >::IntZone_Uint32_UintLT64) || (IntRegion< T,U >::IntZone_UintLT32_Uint32) || (IntRegion< T,U >::IntZone_Uint64_Uint) || (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned : // unsigned-signed (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax : (IntRegion< T,U >::IntZone_Uint32_IntLT64 || IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax : (IntRegion< T,U >::IntZone_Uint64_Int || IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int : (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 : // signed-signed (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax : (IntRegion< T,U >::IntZone_Int32_IntLT64 || IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax : (IntRegion< T,U >::IntZone_Int64_Int || IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int : (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt64 : // signed-unsigned (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMin : (IntRegion< T,U >::IntZone_Int32_UintLT32 || IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMin : (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint : (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint64 : (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint64 : SubtractionState_Error) }; }; // this is for the case of U - SafeInt< T, E > template < typename T, typename U > class SubtractionMethod2 { public: enum { // unsigned-unsigned method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 || (IntRegion< T,U >::IntZone_Uint32_UintLT64) || (IntRegion< T,U >::IntZone_UintLT32_Uint32) || (IntRegion< T,U >::IntZone_Uint64_Uint) || (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned2 : // unsigned-signed (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 : (IntRegion< T,U >::IntZone_Uint32_IntLT64 || IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 : (IntRegion< T,U >::IntZone_Uint64_Int || IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int2 : (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 : // signed-signed (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 : (IntRegion< T,U >::IntZone_Int32_IntLT64 || IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 : (IntRegion< T,U >::IntZone_Int64_Int || IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int2 : (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt642 : // signed-unsigned (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 : (IntRegion< T,U >::IntZone_Int32_UintLT32 || IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 : (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint2 : (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint642 : (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint642 : SubtractionState_Error) }; }; template < typename T, typename U, int method > class SubtractionHelper; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // both are unsigned - easy case if( rhs <= lhs ) { result = (T)( lhs - rhs ); return true; } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // both are unsigned - easy case if( rhs <= lhs ) { result = (T)( lhs - rhs ); return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned2 > { public: static bool Subtract( const T& lhs, const U& rhs, U& result ) SAFEINT_NOTHROW { // both are unsigned - easy case // Except we do have to check for overflow - lhs could be larger than result can hold if( rhs <= lhs ) { T tmp = (T)(lhs - rhs); return SafeCastHelper< U, T, GetCastMethod::method>::Cast( tmp, result); } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, U& result ) SAFEINT_CPP_THROW { // both are unsigned - easy case if( rhs <= lhs ) { T tmp = (T)(lhs - rhs); SafeCastHelper< U, T, GetCastMethod::method >::template CastThrow( tmp, result); return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckSafeIntMinMax > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs; if( SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result ) ) { result = (T)tmp; return true; } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs; SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result ); } }; template class SubtractionHelper< U, T, SubtractionState_CastIntCheckSafeIntMinMax2 > { public: static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs; return SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result ); } template < typename E > static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW { // both values are 16-bit or less // rhs is signed, so could end up increasing or decreasing __int32 tmp = lhs - rhs; SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result ); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckMin > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // both values are 16-bit or less // rhs is unsigned - check only minimum __int32 tmp = lhs - rhs; if( tmp >= (__int32)IntTraits< T >::minInt ) { result = (T)tmp; return true; } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // both values are 16-bit or less // rhs is unsigned - check only minimum __int32 tmp = lhs - rhs; if( tmp >= (__int32)IntTraits< T >::minInt ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckSafeIntMinMax > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs; return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result ); } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs; SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result ); } }; template class SubtractionHelper< U, T, SubtractionState_CastInt64CheckSafeIntMinMax2 > { public: static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs; return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result ); } template < typename E > static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW { // both values are 32-bit or less // rhs is signed, so could end up increasing or decreasing __int64 tmp = (__int64)lhs - (__int64)rhs; SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result ); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckMin > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // both values are 32-bit or less // rhs is unsigned - check only minimum __int64 tmp = (__int64)lhs - (__int64)rhs; if( tmp >= (__int64)IntTraits< T >::minInt ) { result = (T)tmp; return true; } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // both values are 32-bit or less // rhs is unsigned - check only minimum __int64 tmp = (__int64)lhs - (__int64)rhs; if( tmp >= (__int64)IntTraits< T >::minInt ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Uint64Int > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs is an unsigned __int64, rhs signed // must first see if rhs is positive or negative if( rhs >= 0 ) { if( (unsigned __int64)rhs <= lhs ) { result = (T)( lhs - (unsigned __int64)rhs ); return true; } } else { T tmp = lhs; // we're now effectively adding result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); if(result >= tmp) return true; } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is an unsigned __int64, rhs signed // must first see if rhs is positive or negative if( rhs >= 0 ) { if( (unsigned __int64)rhs <= lhs ) { result = (T)( lhs - (unsigned __int64)rhs ); return; } } else { T tmp = lhs; // we're now effectively adding result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs ); if(result >= tmp) return; } E::SafeIntOnOverflow(); } }; template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Uint64Int2 > { public: static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW { // U is unsigned __int64, T is signed if( rhs < 0 ) { // treat this as addition unsigned __int64 tmp; tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs ); // must check for addition overflow and max if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return true; } } else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works { // result is negative // implies that lhs must fit into T, and result cannot overflow // Also allows us to drop to 32-bit math, which is faster on a 32-bit system result = (T)lhs - (T)rhs; return true; } else { // result is positive unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return true; } } return false; } template < typename E > static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW { // U is unsigned __int64, T is signed if( rhs < 0 ) { // treat this as addition unsigned __int64 tmp; tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs ); // must check for addition overflow and max if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return; } } else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works { // result is negative // implies that lhs must fit into T, and result cannot overflow // Also allows us to drop to 32-bit math, which is faster on a 32-bit system result = (T)lhs - (T)rhs; return; } else { // result is positive unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return; } } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_UintInt64 > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs is an unsigned int32 or smaller, rhs signed __int64 // must first see if rhs is positive or negative if( rhs >= 0 ) { if( (unsigned __int64)rhs <= lhs ) { result = (T)( lhs - (T)rhs ); return true; } } else { // we're now effectively adding // since lhs is 32-bit, and rhs cannot exceed 2^63 // this addition cannot overflow unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe // but we could exceed MaxInt if(tmp <= IntTraits< T >::maxInt) { result = (T)tmp; return true; } } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is an unsigned int32 or smaller, rhs signed __int64 // must first see if rhs is positive or negative if( rhs >= 0 ) { if( (unsigned __int64)rhs <= lhs ) { result = (T)( lhs - (T)rhs ); return; } } else { // we're now effectively adding // since lhs is 32-bit, and rhs cannot exceed 2^63 // this addition cannot overflow unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe // but we could exceed MaxInt if(tmp <= IntTraits< T >::maxInt) { result = (T)tmp; return; } } E::SafeIntOnOverflow(); } }; template class SubtractionHelper< U, T, SubtractionState_UintInt642 > { public: static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW { // U unsigned 32-bit or less, T __int64 if( rhs >= 0 ) { // overflow not possible result = (T)( (__int64)lhs - rhs ); return true; } else { // we effectively have an addition // which cannot overflow internally unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs ); if( tmp <= (unsigned __int64)IntTraits< T >::maxInt ) { result = (T)tmp; return true; } } return false; } template < typename E > static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW { // U unsigned 32-bit or less, T __int64 if( rhs >= 0 ) { // overflow not possible result = (T)( (__int64)lhs - rhs ); return; } else { // we effectively have an addition // which cannot overflow internally unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs ); if( tmp <= (unsigned __int64)IntTraits< T >::maxInt ) { result = (T)tmp; return; } } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Int > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs is an __int64, rhs signed (up to 64-bit) // we have essentially 4 cases: // // 1) lhs positive, rhs positive - overflow not possible // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error // 3) lhs negative, rhs positive - check result <= lhs // 4) lhs negative, rhs negative - overflow not possible __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); // Note - ideally, we can order these so that true conditionals // lead to success, which enables better pipelining // It isn't practical here if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2 ( rhs >= 0 && tmp > lhs ) ) // condition 3 { return false; } result = (T)tmp; return true; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is an __int64, rhs signed (up to 64-bit) // we have essentially 4 cases: // // 1) lhs positive, rhs positive - overflow not possible // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error // 3) lhs negative, rhs positive - check result <= lhs // 4) lhs negative, rhs negative - overflow not possible __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); // Note - ideally, we can order these so that true conditionals // lead to success, which enables better pipelining // It isn't practical here if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2 ( rhs >= 0 && tmp > lhs ) ) // condition 3 { E::SafeIntOnOverflow(); } result = (T)tmp; } }; template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Int2 > { public: static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW { // lhs __int64, rhs any signed int (including __int64) __int64 tmp = lhs - rhs; // we have essentially 4 cases: // // 1) lhs positive, rhs positive - overflow not possible in tmp // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error // 3) lhs negative, rhs positive - check result <= lhs // 4) lhs negative, rhs negative - overflow not possible in tmp if( lhs >= 0 ) { // if both positive, overflow to negative not possible // which is why we'll explicitly check maxInt, and not call SafeCast if( ( IntTraits< T >::isLT64Bit && tmp > IntTraits< T >::maxInt ) || ( rhs < 0 && tmp < lhs ) ) { return false; } } else { // lhs negative if( ( IntTraits< T >::isLT64Bit && tmp < IntTraits< T >::minInt) || ( rhs >=0 && tmp > lhs ) ) { return false; } } result = (T)tmp; return true; } template < typename E > static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW { // lhs __int64, rhs any signed int (including __int64) __int64 tmp = lhs - rhs; // we have essentially 4 cases: // // 1) lhs positive, rhs positive - overflow not possible in tmp // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error // 3) lhs negative, rhs positive - check result <= lhs // 4) lhs negative, rhs negative - overflow not possible in tmp if( lhs >= 0 ) { // if both positive, overflow to negative not possible // which is why we'll explicitly check maxInt, and not call SafeCast if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp > IntTraits< T >::maxInt ) || ( rhs < 0 && tmp < lhs ) ) { E::SafeIntOnOverflow(); } } else { // lhs negative if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp < IntTraits< T >::minInt) || ( rhs >=0 && tmp > lhs ) ) { E::SafeIntOnOverflow(); } } result = (T)tmp; } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntInt64 > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs is a 32-bit int or less, rhs __int64 // we have essentially 4 cases: // // lhs positive, rhs positive - rhs could be larger than lhs can represent // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int // lhs negative, rhs positive - check tmp <= lhs and tmp < min int // lhs negative, rhs negative - addition cannot internally overflow, check against max __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); if( lhs >= 0 ) { // first case if( rhs >= 0 ) { if( tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return true; } } else { // second case if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return true; } } } else { // lhs < 0 // third case if( rhs >= 0 ) { if( tmp <= lhs && tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return true; } } else { // fourth case if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return true; } } } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is a 32-bit int or less, rhs __int64 // we have essentially 4 cases: // // lhs positive, rhs positive - rhs could be larger than lhs can represent // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int // lhs negative, rhs positive - check tmp <= lhs and tmp < min int // lhs negative, rhs negative - addition cannot internally overflow, check against max __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs); if( lhs >= 0 ) { // first case if( rhs >= 0 ) { if( tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return; } } else { // second case if( tmp >= lhs && tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return; } } } else { // lhs < 0 // third case if( rhs >= 0 ) { if( tmp <= lhs && tmp >= IntTraits< T >::minInt ) { result = (T)tmp; return; } } else { // fourth case if( tmp <= IntTraits< T >::maxInt ) { result = (T)tmp; return; } } } E::SafeIntOnOverflow(); } }; template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntInt642 > { public: static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW { // lhs is any signed int32 or smaller, rhs is int64 __int64 tmp = (__int64)lhs - rhs; if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || ( rhs > 0 && tmp > lhs ) ) { return false; //else OK } result = (T)tmp; return true; } template < typename E > static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is any signed int32 or smaller, rhs is int64 __int64 tmp = (__int64)lhs - rhs; if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || ( rhs > 0 && tmp > lhs ) ) { E::SafeIntOnOverflow(); //else OK } result = (T)tmp; } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs is a 64-bit int, rhs unsigned int32 or smaller // perform test as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; if( (__int64)tmp <= lhs ) { result = (T)(__int64)tmp; return true; } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is a 64-bit int, rhs unsigned int32 or smaller // perform test as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; if( (__int64)tmp <= lhs ) { result = (T)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint2 > { public: // lhs is __int64, rhs is unsigned 32-bit or smaller static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW { // Do this as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt ) { result = (T)(__int64)tmp; return true; } return false; } template < typename E > static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW { // Do this as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs; if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt ) { result = (T)(__int64)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntUint64 > { public: static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW { // lhs is any signed int, rhs unsigned int64 // check against available range // We need the absolute value of IntTraits< T >::minInt // This will give it to us without extraneous compiler warnings const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1; if( lhs < 0 ) { if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) ) { result = (T)( lhs - rhs ); return true; } } else { if( rhs <= AbsMinIntT + (unsigned __int64)lhs ) { result = (T)( lhs - rhs ); return true; } } return false; } template < typename E > static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW { // lhs is any signed int, rhs unsigned int64 // check against available range // We need the absolute value of IntTraits< T >::minInt // This will give it to us without extraneous compiler warnings const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1; if( lhs < 0 ) { if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) ) { result = (T)( lhs - rhs ); return; } } else { if( rhs <= AbsMinIntT + (unsigned __int64)lhs ) { result = (T)( lhs - rhs ); return; } } E::SafeIntOnOverflow(); } }; template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntUint642 > { public: static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW { // We run into upcasting problems on comparison - needs 2 checks if( lhs >= 0 && (T)lhs >= rhs ) { result = (T)((U)lhs - (U)rhs); return true; } return false; } template < typename E > static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW { // We run into upcasting problems on comparison - needs 2 checks if( lhs >= 0 && (T)lhs >= rhs ) { result = (T)((U)lhs - (U)rhs); return; } E::SafeIntOnOverflow(); } }; template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint64 > { public: static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW { C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); // if we subtract, and it gets larger, there's a problem // Perform test as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - rhs; if( (__int64)tmp <= lhs ) { result = (__int64)tmp; return true; } return false; } template < typename E > static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW { C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 ); // if we subtract, and it gets larger, there's a problem // Perform test as unsigned to prevent unwanted optimizations unsigned __int64 tmp = (unsigned __int64)lhs - rhs; if( (__int64)tmp <= lhs ) { result = (__int64)tmp; return; } E::SafeIntOnOverflow(); } }; template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint642 > { public: // If lhs is negative, immediate problem - return must be positive, and subtracting only makes it // get smaller. If rhs > lhs, then it would also go negative, which is the other case static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_NOTHROW { C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 ); if( lhs >= 0 && (unsigned __int64)lhs >= rhs ) { result = (unsigned __int64)lhs - rhs; return true; } return false; } template < typename E > static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW { C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 ); if( lhs >= 0 && (unsigned __int64)lhs >= rhs ) { result = (unsigned __int64)lhs - rhs; return; } E::SafeIntOnOverflow(); } }; enum BinaryState { BinaryState_OK, BinaryState_Int8, BinaryState_Int16, BinaryState_Int32 }; template < typename T, typename U > class BinaryMethod { public: enum { // If both operands are unsigned OR // return type is smaller than rhs OR // return type is larger and rhs is unsigned // Then binary operations won't produce unexpected results method = ( sizeof( T ) <= sizeof( U ) || SafeIntCompare< T, U >::isBothUnsigned || !IntTraits< U >::isSigned ) ? BinaryState_OK : IntTraits< U >::isInt8 ? BinaryState_Int8 : IntTraits< U >::isInt16 ? BinaryState_Int16 : BinaryState_Int32 }; }; #ifdef SAFEINT_DISABLE_BINARY_ASSERT #define BinaryAssert(x) #else #define BinaryAssert(x) SAFEINT_ASSERT(x) #endif template < typename T, typename U, int method > class BinaryAndHelper; template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK > { public: static T And( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs & rhs ); } }; template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 > { public: static T And( T lhs, U rhs ) SAFEINT_NOTHROW { // cast forces sign extension to be zeros BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int8)rhs ) ); return (T)( lhs & (unsigned __int8)rhs ); } }; template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 > { public: static T And( T lhs, U rhs ) SAFEINT_NOTHROW { //cast forces sign extension to be zeros BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int16)rhs ) ); return (T)( lhs & (unsigned __int16)rhs ); } }; template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 > { public: static T And( T lhs, U rhs ) SAFEINT_NOTHROW { //cast forces sign extension to be zeros BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int32)rhs ) ); return (T)( lhs & (unsigned __int32)rhs ); } }; template < typename T, typename U, int method > class BinaryOrHelper; template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK > { public: static T Or( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs | rhs ); } }; template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 > { public: static T Or( T lhs, U rhs ) SAFEINT_NOTHROW { //cast forces sign extension to be zeros BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int8)rhs ) ); return (T)( lhs | (unsigned __int8)rhs ); } }; template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 > { public: static T Or( T lhs, U rhs ) SAFEINT_NOTHROW { //cast forces sign extension to be zeros BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int16)rhs ) ); return (T)( lhs | (unsigned __int16)rhs ); } }; template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 > { public: static T Or( T lhs, U rhs ) SAFEINT_NOTHROW { //cast forces sign extension to be zeros BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int32)rhs ) ); return (T)( lhs | (unsigned __int32)rhs ); } }; template class BinaryXorHelper; template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK > { public: static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs ^ rhs ); } }; template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 > { public: static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW { // cast forces sign extension to be zeros BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int8)rhs ) ); return (T)( lhs ^ (unsigned __int8)rhs ); } }; template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 > { public: static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW { // cast forces sign extension to be zeros BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int16)rhs ) ); return (T)( lhs ^ (unsigned __int16)rhs ); } }; template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 > { public: static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW { // cast forces sign extension to be zeros BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int32)rhs ) ); return (T)( lhs ^ (unsigned __int32)rhs ); } }; /***************** External functions ****************************************/ // External functions that can be used where you only need to check one operation // non-class helper function so that you can check for a cast's validity // and handle errors how you like template < typename T, typename U > inline bool SafeCast( const T From, U& To ) SAFEINT_NOTHROW { return SafeCastHelper< U, T, GetCastMethod< U, T >::method >::Cast( From, To ); } template < typename T, typename U > inline bool SafeEquals( const T t, const U u ) SAFEINT_NOTHROW { return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u ); } template < typename T, typename U > inline bool SafeNotEquals( const T t, const U u ) SAFEINT_NOTHROW { return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u ); } template < typename T, typename U > inline bool SafeGreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u ); } template < typename T, typename U > inline bool SafeGreaterThanEquals( const T t, const U u ) SAFEINT_NOTHROW { return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t ); } template < typename T, typename U > inline bool SafeLessThan( const T t, const U u ) SAFEINT_NOTHROW { return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t ); } template < typename T, typename U > inline bool SafeLessThanEquals( const T t, const U u ) SAFEINT_NOTHROW { return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u ); } template < typename T, typename U > inline bool SafeModulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW { return ( ModulusHelper< T, U, ValidComparison< T, U >::method >::Modulus( t, u, result ) == SafeIntNoError ); } template < typename T, typename U > inline bool SafeMultiply( T t, U u, T& result ) SAFEINT_NOTHROW { return MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::Multiply( t, u, result ); } template < typename T, typename U > inline bool SafeDivide( T t, U u, T& result ) SAFEINT_NOTHROW { return ( DivisionHelper< T, U, DivisionMethod< T, U >::method >::Divide( t, u, result ) == SafeIntNoError ); } template < typename T, typename U > inline bool SafeAdd( T t, U u, T& result ) SAFEINT_NOTHROW { return AdditionHelper< T, U, AdditionMethod< T, U >::method >::Addition( t, u, result ); } template < typename T, typename U > inline bool SafeSubtract( T t, U u, T& result ) SAFEINT_NOTHROW { return SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::Subtract( t, u, result ); } /***************** end external functions ************************************/ // Main SafeInt class // Assumes exceptions can be thrown template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeInt { public: SafeInt() SAFEINT_NOTHROW { C_ASSERT( NumericType< T >::isInt ); m_int = 0; } // Having a constructor for every type of int // avoids having the compiler evade our checks when doing implicit casts - // e.g., SafeInt s = 0x7fffffff; SafeInt( const T& i ) SAFEINT_NOTHROW { C_ASSERT( NumericType< T >::isInt ); //always safe m_int = i; } // provide explicit boolean converter SafeInt( bool b ) SAFEINT_NOTHROW { C_ASSERT( NumericType< T >::isInt ); m_int = (T)( b ? 1 : 0 ); } template < typename U > SafeInt(const SafeInt< U, E >& u) SAFEINT_CPP_THROW { C_ASSERT( NumericType< T >::isInt ); *this = SafeInt< T, E >( (U)u ); } template < typename U > SafeInt( const U& i ) SAFEINT_CPP_THROW { C_ASSERT( NumericType< T >::isInt ); // SafeCast will throw exceptions if i won't fit in type T SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( i, m_int ); } // The destructor is intentionally commented out - no destructor // vs. a do-nothing destructor makes a huge difference in // inlining characteristics. It wasn't doing anything anyway. // ~SafeInt(){}; // now start overloading operators // assignment operator // constructors exist for all int types and will ensure safety template < typename U > SafeInt< T, E >& operator =( const U& rhs ) SAFEINT_CPP_THROW { // use constructor to test size // constructor is optimized to do minimal checking based // on whether T can contain U // note - do not change this *this = SafeInt< T, E >( rhs ); return *this; } SafeInt< T, E >& operator =( const T& rhs ) SAFEINT_NOTHROW { m_int = rhs; return *this; } template < typename U > SafeInt< T, E >& operator =( const SafeInt< U, E >& rhs ) SAFEINT_CPP_THROW { SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( rhs.Ref(), m_int ); return *this; } SafeInt< T, E >& operator =( const SafeInt< T, E >& rhs ) SAFEINT_NOTHROW { m_int = rhs.m_int; return *this; } // Casting operators operator bool() const SAFEINT_NOTHROW { return !!m_int; } operator char() const SAFEINT_CPP_THROW { char val; SafeCastHelper< char, T, GetCastMethod< char, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator signed char() const SAFEINT_CPP_THROW { signed char val; SafeCastHelper< signed char, T, GetCastMethod< signed char, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator unsigned char() const SAFEINT_CPP_THROW { unsigned char val; SafeCastHelper< unsigned char, T, GetCastMethod< unsigned char, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator __int16() const SAFEINT_CPP_THROW { __int16 val; SafeCastHelper< __int16, T, GetCastMethod< __int16, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator unsigned __int16() const SAFEINT_CPP_THROW { unsigned __int16 val; SafeCastHelper< unsigned __int16, T, GetCastMethod< unsigned __int16, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator __int32() const SAFEINT_CPP_THROW { __int32 val; SafeCastHelper< __int32, T, GetCastMethod< __int32, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator unsigned __int32() const SAFEINT_CPP_THROW { unsigned __int32 val; SafeCastHelper< unsigned __int32, T, GetCastMethod< unsigned __int32, T >::method >::template CastThrow< E >( m_int, val ); return val; } // The compiler knows that int == __int32 // but not that long == __int32 operator long() const SAFEINT_CPP_THROW { long val; SafeCastHelper< long, T, GetCastMethod< long, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator unsigned long() const SAFEINT_CPP_THROW { unsigned long val; SafeCastHelper< unsigned long, T, GetCastMethod< unsigned long, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator __int64() const SAFEINT_CPP_THROW { __int64 val; SafeCastHelper< __int64, T, GetCastMethod< __int64, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator unsigned __int64() const SAFEINT_CPP_THROW { unsigned __int64 val; SafeCastHelper< unsigned __int64, T, GetCastMethod< unsigned __int64, T >::method >::template CastThrow< E >( m_int, val ); return val; } #if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED operator wchar_t() const SAFEINT_CPP_THROW { wchar_t val; SafeCastHelper< wchar_t, T, GetCastMethod< wchar_t, T >::method >::template CastThrow< E >( m_int, val ); return val; } #endif #ifdef SIZE_T_CAST_NEEDED // We also need an explicit cast to size_t, or the compiler will complain // Apparently, only SOME compilers complain, and cl 14.00.50727.42 isn't one of them // Leave here in case we decide to backport this to an earlier compiler operator size_t() const SAFEINT_CPP_THROW { size_t val; SafeCastHelper< size_t, T, GetCastMethod< size_t, T >::method >::template CastThrow< E >( m_int, val ); return val; } #endif // Also provide a cast operator for floating point types operator float() const SAFEINT_CPP_THROW { float val; SafeCastHelper< float, T, GetCastMethod< float, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator double() const SAFEINT_CPP_THROW { double val; SafeCastHelper< double, T, GetCastMethod< double, T >::method >::template CastThrow< E >( m_int, val ); return val; } operator long double() const SAFEINT_CPP_THROW { long double val; SafeCastHelper< long double, T, GetCastMethod< long double, T >::method >::template CastThrow< E >( m_int, val ); return val; } // If you need a pointer to the data // this could be dangerous, but allows you to correctly pass // instances of this class to APIs that take a pointer to an integer // also see overloaded address-of operator below T* Ptr() SAFEINT_NOTHROW { return &m_int; } const T* Ptr() const SAFEINT_NOTHROW { return &m_int; } const T& Ref() const SAFEINT_NOTHROW { return m_int; } // Or if SafeInt< T, E >::Ptr() is inconvenient, use the overload // operator & // This allows you to do unsafe things! // It is meant to allow you to more easily // pass a SafeInt into things like ReadFile T* operator &() SAFEINT_NOTHROW { return &m_int; } const T* operator &() const SAFEINT_NOTHROW { return &m_int; } // Unary operators bool operator !() const SAFEINT_NOTHROW { return (!m_int) ? true : false; } // operator + (unary) // note - normally, the '+' and '-' operators will upcast to a signed int // for T < 32 bits. This class changes behavior to preserve type const SafeInt< T, E >& operator +() const SAFEINT_NOTHROW { return *this; } //unary - SafeInt< T, E > operator -() const SAFEINT_CPP_THROW { // Note - unsigned still performs the bitwise manipulation // will warn at level 2 or higher if the value is 32-bit or larger return SafeInt(NegationHelper::isSigned>::template NegativeThrow(m_int)); } // prefix increment operator SafeInt< T, E >& operator ++() SAFEINT_CPP_THROW { if( m_int != IntTraits< T >::maxInt ) { ++m_int; return *this; } E::SafeIntOnOverflow(); } // prefix decrement operator SafeInt< T, E >& operator --() SAFEINT_CPP_THROW { if( m_int != IntTraits< T >::minInt ) { --m_int; return *this; } E::SafeIntOnOverflow(); } // note that postfix operators have inherently worse perf // characteristics // postfix increment operator SafeInt< T, E > operator ++( int ) SAFEINT_CPP_THROW // dummy arg to comply with spec { if( m_int != IntTraits< T >::maxInt ) { SafeInt< T, E > tmp( m_int ); m_int++; return tmp; } E::SafeIntOnOverflow(); } // postfix decrement operator SafeInt< T, E > operator --( int ) SAFEINT_CPP_THROW // dummy arg to comply with spec { if( m_int != IntTraits< T >::minInt ) { SafeInt< T, E > tmp( m_int ); m_int--; return tmp; } E::SafeIntOnOverflow(); } // One's complement // Note - this operator will normally change size to an int // cast in return improves perf and maintains type SafeInt< T, E > operator ~() const SAFEINT_NOTHROW { return SafeInt< T, E >( (T)~m_int ); } // Binary operators // // arithmetic binary operators // % modulus // * multiplication // / division // + addition // - subtraction // // For each of the arithmetic operators, you will need to // use them as follows: // // SafeInt c = 2; // SafeInt i = 3; // // SafeInt i2 = i op (char)c; // OR // SafeInt i2 = (int)i op c; // // The base problem is that if the lhs and rhs inputs are different SafeInt types // it is not possible in this implementation to determine what type of SafeInt // should be returned. You have to let the class know which of the two inputs // need to be the return type by forcing the other value to the base integer type. // // Note - as per feedback from Scott Meyers, I'm exploring how to get around this. // 3.0 update - I'm still thinking about this. It can be done with template metaprogramming, // but it is tricky, and there's a perf vs. correctness tradeoff where the right answer // is situational. // // The case of: // // SafeInt< T, E > i, j, k; // i = j op k; // // works just fine and no unboxing is needed because the return type is not ambiguous. // Modulus // Modulus has some convenient properties - // first, the magnitude of the return can never be // larger than the lhs operand, and it must be the same sign // as well. It does, however, suffer from the same promotion // problems as comparisons, division and other operations template < typename U > SafeInt< T, E > operator %( U rhs ) const SAFEINT_CPP_THROW { T result; ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, result ); return SafeInt< T, E >( result ); } SafeInt< T, E > operator %( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW { T result; ModulusHelper< T, T, ValidComparison< T, T >::method >::template ModulusThrow< E >( m_int, rhs, result ); return SafeInt< T, E >( result ); } // Modulus assignment template < typename U > SafeInt< T, E >& operator %=( U rhs ) SAFEINT_CPP_THROW { ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, m_int ); return *this; } template < typename U > SafeInt< T, E >& operator %=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, (U)rhs, m_int ); return *this; } // Multiplication template < typename U > SafeInt< T, E > operator *( U rhs ) const SAFEINT_CPP_THROW { T ret( 0 ); MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, ret ); return SafeInt< T, E >( ret ); } SafeInt< T, E > operator *( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW { T ret( 0 ); MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, ret ); return SafeInt< T, E >( ret ); } // Multiplication assignment SafeInt< T, E >& operator *=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW { MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, m_int ); return *this; } template < typename U > SafeInt< T, E >& operator *=( U rhs ) SAFEINT_CPP_THROW { MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, m_int ); return *this; } template < typename U > SafeInt< T, E >& operator *=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs.Ref(), m_int ); return *this; } // Division template < typename U > SafeInt< T, E > operator /( U rhs ) const SAFEINT_CPP_THROW { T ret( 0 ); DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, rhs, ret ); return SafeInt< T, E >( ret ); } SafeInt< T, E > operator /( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW { T ret( 0 ); DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)rhs, ret ); return SafeInt< T, E >( ret ); } // Division assignment SafeInt< T, E >& operator /=( SafeInt< T, E > i ) SAFEINT_CPP_THROW { DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)i, m_int ); return *this; } template < typename U > SafeInt< T, E >& operator /=( U i ) SAFEINT_CPP_THROW { DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, i, m_int ); return *this; } template < typename U > SafeInt< T, E >& operator /=( SafeInt< U, E > i ) { DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, (U)i, m_int ); return *this; } // For addition and subtraction // Addition SafeInt< T, E > operator +( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW { T ret( 0 ); AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, ret ); return SafeInt< T, E >( ret ); } template < typename U > SafeInt< T, E > operator +( U rhs ) const SAFEINT_CPP_THROW { T ret( 0 ); AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, ret ); return SafeInt< T, E >( ret ); } //addition assignment SafeInt< T, E >& operator +=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW { AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, m_int ); return *this; } template < typename U > SafeInt< T, E >& operator +=( U rhs ) SAFEINT_CPP_THROW { AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, m_int ); return *this; } template < typename U > SafeInt< T, E >& operator +=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, (U)rhs, m_int ); return *this; } // Subtraction template < typename U > SafeInt< T, E > operator -( U rhs ) const SAFEINT_CPP_THROW { T ret( 0 ); SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, ret ); return SafeInt< T, E >( ret ); } SafeInt< T, E > operator -(SafeInt< T, E > rhs) const SAFEINT_CPP_THROW { T ret( 0 ); SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, ret ); return SafeInt< T, E >( ret ); } // Subtraction assignment SafeInt< T, E >& operator -=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW { SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, m_int ); return *this; } template < typename U > SafeInt< T, E >& operator -=( U rhs ) SAFEINT_CPP_THROW { SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, m_int ); return *this; } template < typename U > SafeInt< T, E >& operator -=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, (U)rhs, m_int ); return *this; } // Shift operators // Note - shift operators ALWAYS return the same type as the lhs // specific version for SafeInt< T, E > not needed - // code path is exactly the same as for SafeInt< U, E > as rhs // Left shift // Also, shifting > bitcount is undefined - trap in debug #ifdef SAFEINT_DISABLE_SHIFT_ASSERT #define ShiftAssert(x) #else #define ShiftAssert(x) SAFEINT_ASSERT(x) #endif template < typename U > SafeInt< T, E > operator <<( U bits ) const SAFEINT_NOTHROW { ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); ShiftAssert( bits < (int)IntTraits< T >::bitCount ); return SafeInt< T, E >( (T)( m_int << bits ) ); } template < typename U > SafeInt< T, E > operator <<( SafeInt< U, E > bits ) const SAFEINT_NOTHROW { ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount ); return SafeInt< T, E >( (T)( m_int << (U)bits ) ); } // Left shift assignment template < typename U > SafeInt< T, E >& operator <<=( U bits ) SAFEINT_NOTHROW { ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); ShiftAssert( bits < (int)IntTraits< T >::bitCount ); m_int <<= bits; return *this; } template < typename U > SafeInt< T, E >& operator <<=( SafeInt< U, E > bits ) SAFEINT_NOTHROW { ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount ); m_int <<= (U)bits; return *this; } // Right shift template < typename U > SafeInt< T, E > operator >>( U bits ) const SAFEINT_NOTHROW { ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); ShiftAssert( bits < (int)IntTraits< T >::bitCount ); return SafeInt< T, E >( (T)( m_int >> bits ) ); } template < typename U > SafeInt< T, E > operator >>( SafeInt< U, E > bits ) const SAFEINT_NOTHROW { ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); ShiftAssert( bits < (int)IntTraits< T >::bitCount ); return SafeInt< T, E >( (T)(m_int >> (U)bits) ); } // Right shift assignment template < typename U > SafeInt< T, E >& operator >>=( U bits ) SAFEINT_NOTHROW { ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 ); ShiftAssert( bits < (int)IntTraits< T >::bitCount ); m_int >>= bits; return *this; } template < typename U > SafeInt< T, E >& operator >>=( SafeInt< U, E > bits ) SAFEINT_NOTHROW { ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 ); ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount ); m_int >>= (U)bits; return *this; } // Bitwise operators // This only makes sense if we're dealing with the same type and size // demand a type T, or something that fits into a type T // Bitwise & SafeInt< T, E > operator &( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW { return SafeInt< T, E >( m_int & (T)rhs ); } template < typename U > SafeInt< T, E > operator &( U rhs ) const SAFEINT_NOTHROW { // we want to avoid setting bits by surprise // consider the case of lhs = int, value = 0xffffffff // rhs = char, value = 0xff // // programmer intent is to get only the lower 8 bits // normal behavior is to upcast both sides to an int // which then sign extends rhs, setting all the bits // If you land in the assert, this is because the bitwise operator // was causing unexpected behavior. Fix is to properly cast your inputs // so that it works like you meant, not unexpectedly return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs ) ); } // Bitwise & assignment SafeInt< T, E >& operator &=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW { m_int &= (T)rhs; return *this; } template < typename U > SafeInt< T, E >& operator &=( U rhs ) SAFEINT_NOTHROW { m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs ); return *this; } template < typename U > SafeInt< T, E >& operator &=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW { m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, (U)rhs ); return *this; } // XOR SafeInt< T, E > operator ^( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW { return SafeInt< T, E >( (T)( m_int ^ (T)rhs ) ); } template < typename U > SafeInt< T, E > operator ^( U rhs ) const SAFEINT_NOTHROW { // If you land in the assert, this is because the bitwise operator // was causing unexpected behavior. Fix is to properly cast your inputs // so that it works like you meant, not unexpectedly return SafeInt< T, E >( BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs ) ); } // XOR assignment SafeInt< T, E >& operator ^=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW { m_int ^= (T)rhs; return *this; } template < typename U > SafeInt< T, E >& operator ^=( U rhs ) SAFEINT_NOTHROW { m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs ); return *this; } template < typename U > SafeInt< T, E >& operator ^=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW { m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, (U)rhs ); return *this; } // bitwise OR SafeInt< T, E > operator |( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW { return SafeInt< T, E >( (T)( m_int | (T)rhs ) ); } template < typename U > SafeInt< T, E > operator |( U rhs ) const SAFEINT_NOTHROW { return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs ) ); } // bitwise OR assignment SafeInt< T, E >& operator |=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW { m_int |= (T)rhs; return *this; } template < typename U > SafeInt< T, E >& operator |=( U rhs ) SAFEINT_NOTHROW { m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs ); return *this; } template < typename U > SafeInt< T, E >& operator |=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW { m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, (U)rhs ); return *this; } // Miscellaneous helper functions SafeInt< T, E > Min( SafeInt< T, E > test, const T floor = IntTraits< T >::minInt ) const SAFEINT_NOTHROW { T tmp = test < m_int ? (T)test : m_int; return tmp < floor ? floor : tmp; } SafeInt< T, E > Max( SafeInt< T, E > test, const T upper = IntTraits< T >::maxInt ) const SAFEINT_NOTHROW { T tmp = test > m_int ? (T)test : m_int; return tmp > upper ? upper : tmp; } void Swap( SafeInt< T, E >& with ) SAFEINT_NOTHROW { T temp( m_int ); m_int = with.m_int; with.m_int = temp; } static SafeInt< T, E > SafeAtoI( const char* input ) SAFEINT_CPP_THROW { return SafeTtoI( input ); } static SafeInt< T, E > SafeWtoI( const wchar_t* input ) { return SafeTtoI( input ); } enum alignBits { align2 = 1, align4 = 2, align8 = 3, align16 = 4, align32 = 5, align64 = 6, align128 = 7, align256 = 8 }; template < alignBits bits > const SafeInt< T, E >& Align() SAFEINT_CPP_THROW { // Zero is always aligned if( m_int == 0 ) return *this; // We don't support aligning negative numbers at this time // Can't align unsigned numbers on bitCount (e.g., 8 bits = 256, unsigned char max = 255) // or signed numbers on bitCount-1 (e.g., 7 bits = 128, signed char max = 127). // Also makes no sense to try to align on negative or no bits. ShiftAssert( ( ( IntTraits::isSigned && bits < (int)IntTraits< T >::bitCount - 1 ) || ( !IntTraits::isSigned && bits < (int)IntTraits< T >::bitCount ) ) && bits >= 0 && ( !IntTraits::isSigned || m_int > 0 ) ); const T AlignValue = ( (T)1 << bits ) - 1; m_int = (T)( ( m_int + AlignValue ) & ~AlignValue ); if( m_int <= 0 ) E::SafeIntOnOverflow(); return *this; } // Commonly needed alignments: const SafeInt< T, E >& Align2() { return Align< align2 >(); } const SafeInt< T, E >& Align4() { return Align< align4 >(); } const SafeInt< T, E >& Align8() { return Align< align8 >(); } const SafeInt< T, E >& Align16() { return Align< align16 >(); } const SafeInt< T, E >& Align32() { return Align< align32 >(); } const SafeInt< T, E >& Align64() { return Align< align64 >(); } private: // This is almost certainly not the best optimized version of atoi, // but it does not display a typical bug where it isn't possible to set MinInt // and it won't allow you to overflow your integer. // This is here because it is useful, and it is an example of what // can be done easily with SafeInt. template < typename U > static SafeInt< T, E > SafeTtoI( U* input ) SAFEINT_CPP_THROW { U* tmp = input; SafeInt< T, E > s; bool negative = false; // Bad input, or empty string if( input == nullptr || input[0] == 0 ) E::SafeIntOnOverflow(); switch( *tmp ) { case '-': tmp++; negative = true; break; case '+': tmp++; break; } while( *tmp != 0 ) { if( *tmp < '0' || *tmp > '9' ) break; if( (T)s != 0 ) s *= (T)10; if( !negative ) s += (T)( *tmp - '0' ); else s -= (T)( *tmp - '0' ); tmp++; } return s; } T m_int; }; // Helper function used to subtract pointers. // Used to squelch warnings template SafeInt SafePtrDiff(const P* p1, const P* p2) SAFEINT_CPP_THROW { return SafeInt( p1 - p2 ); } // Comparison operators //Less than template < typename T, typename U, typename E > bool operator <( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs ); } template < typename T, typename U, typename E > bool operator <( SafeInt lhs, U rhs ) SAFEINT_NOTHROW { return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs ); } template < typename T, typename U, typename E > bool operator <( SafeInt< U, E > lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, (U)lhs ); } // Greater than template < typename T, typename U, typename E > bool operator >( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs ); } template < typename T, typename U, typename E > bool operator >( SafeInt lhs, U rhs ) SAFEINT_NOTHROW { return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs ); } template < typename T, typename U, typename E > bool operator >( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs ); } // Greater than or equal template < typename T, typename U, typename E > bool operator >=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs ); } template < typename T, typename U, typename E > bool operator >=( SafeInt lhs, U rhs ) SAFEINT_NOTHROW { return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs ); } template < typename T, typename U, typename E > bool operator >=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( (U)rhs, (T)lhs ); } // Less than or equal template < typename T, typename U, typename E > bool operator <=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs ); } template < typename T, typename U, typename E > bool operator <=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW { return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs ); } template < typename T, typename U, typename E > bool operator <=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs ); } // equality // explicit overload for bool template < typename T, typename E > bool operator ==( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return lhs == ( (T)rhs == 0 ? false : true ); } template < typename T, typename E > bool operator ==( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW { return rhs == ( (T)lhs == 0 ? false : true ); } template < typename T, typename U, typename E > bool operator ==( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals((T)rhs, lhs); } template < typename T, typename U, typename E > bool operator ==( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW { return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs ); } template < typename T, typename U, typename E > bool operator ==( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, (U)rhs ); } //not equals template < typename T, typename U, typename E > bool operator !=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)rhs, lhs ); } template < typename T, typename U, typename E > bool operator !=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW { return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs ); } template < typename T, typename U, typename E > bool operator !=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( lhs, rhs ); } template < typename T, typename E > bool operator !=( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return ( (T)rhs == 0 ? false : true ) != lhs; } template < typename T, typename E > bool operator !=( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW { return ( (T)lhs == 0 ? false : true ) != rhs; } template < typename T, typename U, typename E, int method > class ModulusSimpleCaseHelper; template < typename T, typename E, int method > class ModulusSignedCaseHelper; template < typename T, typename E > class ModulusSignedCaseHelper < T, E, true > { public: static bool SignedCase( SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_NOTHROW { if( (T)rhs == (T)-1 ) { result = 0; return true; } return false; } }; template < typename T, typename E > class ModulusSignedCaseHelper < T, E, false > { public: static bool SignedCase( SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW { return false; } }; template < typename T, typename U, typename E > class ModulusSimpleCaseHelper < T, U, E, true > { public: static bool ModulusSimpleCase( U lhs, SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_CPP_THROW { if( rhs != 0 ) { if( ModulusSignedCaseHelper< T, E, IntTraits< T >::isSigned >::SignedCase( rhs, result ) ) return true; result = SafeInt< T, E >( (T)( lhs % (T)rhs ) ); return true; } E::SafeIntOnDivZero(); } }; template< typename T, typename U, typename E > class ModulusSimpleCaseHelper < T, U, E, false > { public: static bool ModulusSimpleCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW { return false; } }; // Modulus template < typename T, typename U, typename E > SafeInt< T, E > operator %( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW { // Value of return depends on sign of lhs // This one may not be safe - bounds check in constructor // if lhs is negative and rhs is unsigned, this will throw an exception. // Fast-track the simple case // same size and same sign SafeInt< T, E > result; if( ModulusSimpleCaseHelper< T, U, E, sizeof(T) == sizeof(U) && (bool)IntTraits< T >::isSigned == (bool)IntTraits< U >::isSigned >::ModulusSimpleCase( lhs, rhs, result ) ) return result; return SafeInt< T, E >( ( SafeInt< U, E >( lhs ) % (T)rhs ) ); } // Multiplication template < typename T, typename U, typename E > SafeInt< T, E > operator *( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW { T ret( 0 ); MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( (T)rhs, lhs, ret ); return SafeInt< T, E >(ret); } template < typename T, typename U, typename E, int method > class DivisionNegativeCornerCaseHelper; template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, true > { public: static bool NegativeCornerCase( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW { // Problem case - normal casting behavior changes meaning // flip rhs to positive // any operator casts now do the right thing U tmp; if( CompileConst< sizeof(T) == 4 >::Value() ) tmp = lhs/(U)( ~(unsigned __int32)(T)rhs + 1 ); else tmp = lhs/(U)( ~(unsigned __int64)(T)rhs + 1 ); if( tmp <= (U)IntTraits< T >::maxInt ) { result = SafeInt< T, E >( (T)(~(unsigned __int64)tmp + 1) ); return true; } // Corner case T maxT = IntTraits< T >::maxInt; if( tmp == (U)maxT + 1 ) { T minT = IntTraits< T >::minInt; result = SafeInt< T, E >( minT ); return true; } E::SafeIntOnOverflow(); } }; template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, false > { public: static bool NegativeCornerCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW { return false; } }; template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper; template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, true > { public: static bool DivisionCornerCase1( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW { if( (T)rhs > 0 ) { result = SafeInt< T, E >( lhs/(T)rhs ); return true; } // Now rhs is either negative, or zero if( (T)rhs != 0 ) { if( DivisionNegativeCornerCaseHelper< T, U, E, sizeof( U ) >= 4 && sizeof( T ) <= sizeof( U ) >::NegativeCornerCase( lhs, rhs, result ) ) return true; result = SafeInt< T, E >(lhs/(T)rhs); return true; } E::SafeIntOnDivZero(); } }; template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, false > { public: static bool DivisionCornerCase1( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW { return false; } }; template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper2; template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, true > { public: static bool DivisionCornerCase2( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW { if( lhs == IntTraits< U >::minInt && (T)rhs == -1 ) { // corner case of a corner case - lhs = min int, rhs = -1, // but rhs is the return type, so in essence, we can return -lhs // if rhs is a larger type than lhs // If types are wrong, throws #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER #pragma warning(push) //cast truncates constant value #pragma warning(disable:4310) #endif if( CompileConst::Value() ) result = SafeInt< T, E >( (T)( -(T)IntTraits< U >::minInt ) ); else E::SafeIntOnOverflow(); #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER #pragma warning(pop) #endif return true; } return false; } }; template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, false > { public: static bool DivisionCornerCase2( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW { return false; } }; // Division template < typename T, typename U, typename E > SafeInt< T, E > operator /( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW { // Corner case - has to be handled seperately SafeInt< T, E > result; if( DivisionCornerCaseHelper< T, U, E, (int)DivisionMethod< U, T >::method == (int)DivisionState_UnsignedSigned >::DivisionCornerCase1( lhs, rhs, result ) ) return result; if( DivisionCornerCaseHelper2< T, U, E, SafeIntCompare< T, U >::isBothSigned >::DivisionCornerCase2( lhs, rhs, result ) ) return result; // Otherwise normal logic works with addition of bounds check when casting from U->T U ret; DivisionHelper< U, T, DivisionMethod< U, T >::method >::template DivideThrow< E >( lhs, (T)rhs, ret ); return SafeInt< T, E >( ret ); } // Addition template < typename T, typename U, typename E > SafeInt< T, E > operator +( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW { T ret( 0 ); AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( (T)rhs, lhs, ret ); return SafeInt< T, E >( ret ); } // Subtraction template < typename T, typename U, typename E > SafeInt< T, E > operator -( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW { T ret( 0 ); SubtractionHelper< U, T, SubtractionMethod2< U, T >::method >::template SubtractThrow< E >( lhs, rhs.Ref(), ret ); return SafeInt< T, E >( ret ); } // Overrides designed to deal with cases where a SafeInt is assigned out // to a normal int - this at least makes the last operation safe // += template < typename T, typename U, typename E > T& operator +=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { T ret( 0 ); AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( lhs, (U)rhs, ret ); lhs = ret; return lhs; } template < typename T, typename U, typename E > T& operator -=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { T ret( 0 ); SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( lhs, (U)rhs, ret ); lhs = ret; return lhs; } template < typename T, typename U, typename E > T& operator *=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { T ret( 0 ); MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( lhs, (U)rhs, ret ); lhs = ret; return lhs; } template < typename T, typename U, typename E > T& operator /=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { T ret( 0 ); DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( lhs, (U)rhs, ret ); lhs = ret; return lhs; } template < typename T, typename U, typename E > T& operator %=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { T ret( 0 ); ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( lhs, (U)rhs, ret ); lhs = ret; return lhs; } template < typename T, typename U, typename E > T& operator &=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { lhs = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( lhs, (U)rhs ); return lhs; } template < typename T, typename U, typename E > T& operator ^=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { lhs = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( lhs, (U)rhs ); return lhs; } template < typename T, typename U, typename E > T& operator |=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { lhs = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( lhs, (U)rhs ); return lhs; } template < typename T, typename U, typename E > T& operator <<=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { lhs = (T)( SafeInt< T, E >( lhs ) << (U)rhs ); return lhs; } template < typename T, typename U, typename E > T& operator >>=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW { lhs = (T)( SafeInt< T, E >( lhs ) >> (U)rhs ); return lhs; } // Specific pointer overrides // Note - this function makes no attempt to ensure // that the resulting pointer is still in the buffer, only // that no int overflows happened on the way to getting the new pointer template < typename T, typename U, typename E > T*& operator +=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { // Cast the pointer to a number so we can do arithmetic SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs ); // Check first that rhs is valid for the type of ptrdiff_t // and that multiplying by sizeof( T ) doesn't overflow a ptrdiff_t // Next, we need to add 2 SafeInts of different types, so unbox the ptr_diff // Finally, cast the number back to a pointer of the correct type lhs = reinterpret_cast< T* >( (size_t)( ptr_val + (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) ); return lhs; } template < typename T, typename U, typename E > T*& operator -=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW { // Cast the pointer to a number so we can do arithmetic SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs ); // See above for comments lhs = reinterpret_cast< T* >( (size_t)( ptr_val - (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) ); return lhs; } template < typename T, typename U, typename E > T*& operator *=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW { // This operator explicitly not supported C_ASSERT( sizeof(T) == 0 ); return (lhs = NULL); } template < typename T, typename U, typename E > T*& operator /=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW { // This operator explicitly not supported C_ASSERT( sizeof(T) == 0 ); return (lhs = NULL); } template < typename T, typename U, typename E > T*& operator %=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW { // This operator explicitly not supported C_ASSERT( sizeof(T) == 0 ); return (lhs = NULL); } template < typename T, typename U, typename E > T*& operator &=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW { // This operator explicitly not supported C_ASSERT( sizeof(T) == 0 ); return (lhs = NULL); } template < typename T, typename U, typename E > T*& operator ^=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW { // This operator explicitly not supported C_ASSERT( sizeof(T) == 0 ); return (lhs = NULL); } template < typename T, typename U, typename E > T*& operator |=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW { // This operator explicitly not supported C_ASSERT( sizeof(T) == 0 ); return (lhs = NULL); } template < typename T, typename U, typename E > T*& operator <<=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW { // This operator explicitly not supported C_ASSERT( sizeof(T) == 0 ); return (lhs = NULL); } template < typename T, typename U, typename E > T*& operator >>=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW { // This operator explicitly not supported C_ASSERT( sizeof(T) == 0 ); return (lhs = NULL); } // Shift operators // NOTE - shift operators always return the type of the lhs argument // Left shift template < typename T, typename U, typename E > SafeInt< U, E > operator <<( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW { ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 ); ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount ); return SafeInt< U, E >( (U)( lhs << (T)bits ) ); } // Right shift template < typename T, typename U, typename E > SafeInt< U, E > operator >>( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW { ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 ); ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount ); return SafeInt< U, E >( (U)( lhs >> (T)bits ) ); } // Bitwise operators // This only makes sense if we're dealing with the same type and size // demand a type T, or something that fits into a type T. // Bitwise & template < typename T, typename U, typename E > SafeInt< T, E > operator &( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( (T)rhs, lhs ) ); } // Bitwise XOR template < typename T, typename U, typename E > SafeInt< T, E > operator ^( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return SafeInt< T, E >(BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( (T)rhs, lhs ) ); } // Bitwise OR template < typename T, typename U, typename E > SafeInt< T, E > operator |( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW { return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( (T)rhs, lhs ) ); } #if SAFEINT_COMPILER == GCC_COMPILER #pragma GCC diagnostic pop #endif #if SAFEINT_COMPILER == CLANG_COMPILER #pragma clang diagnostic pop #endif #endif //SAFEINT_HPP #if defined VISUAL_STUDIO_SAFEINT_COMPAT } // utilities } // msl #endif libminizinc-2.0.11/include/minizinc/type.hh0000644000175000017500000002220012646030173017303 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_TYPE_HH__ #define __MINIZINC_TYPE_HH__ #include #include namespace MiniZinc { /// Type of a MiniZinc expression class Type { public: /// Type-inst enum TypeInst { TI_PAR, TI_VAR }; /// Basic type enum BaseType { BT_TOP, BT_BOOL, BT_INT, BT_FLOAT, BT_STRING, BT_ANN, BT_BOT, BT_UNKNOWN }; /// Whether the expression is plain or set enum SetType { ST_PLAIN, ST_SET }; /// Whether the expression is normal or optional enum OptType { OT_PRESENT, OT_OPTIONAL }; /// Whether the par expression contains a var argument enum ContainsVarType { CV_NO, CV_YES }; private: unsigned int _ti : 1; unsigned int _bt : 4; unsigned int _st : 1; unsigned int _ot : 1; unsigned int _cv : 1; /// Number of array dimensions int _dim : 19; public: /// Default constructor Type(void) : _ti(TI_PAR), _bt(BT_UNKNOWN), _st(ST_PLAIN), _ot(OT_PRESENT), _cv(CV_NO), _dim(0) {} /// Access type-inst TypeInst ti(void) const { return static_cast(_ti); } /// Set type-inst void ti(const TypeInst& t) { _ti = t; if (t==TI_VAR) _cv=CV_YES; } /// Access basic type BaseType bt(void) const { return static_cast(_bt); } /// Set basic type void bt(const BaseType& b) { _bt = b; } /// Access set type SetType st(void) const { return static_cast(_st); } /// Set set type void st(const SetType& s) { _st = s; } /// Access opt type OptType ot(void) const { return static_cast(_ot); } /// Set opt type void ot(const OptType& o) { _ot = o; } /// Access var-in-par type bool cv(void) const { return static_cast(_cv) == CV_YES; } /// Set var-in-par type void cv(bool b) { _cv = b ? CV_YES : CV_NO; } /// Access dimensions int dim(void) const { return _dim; } /// Set dimensions void dim(int d) { _dim = d; } protected: /// Constructor Type(const TypeInst& ti, const BaseType& bt, const SetType& st, int dim) : _ti(ti), _bt(bt), _st(st), _ot(OT_PRESENT), _cv(ti==TI_VAR ? CV_YES : CV_NO), _dim(dim) {} public: static Type parint(int dim=0) { return Type(TI_PAR,BT_INT,ST_PLAIN,dim); } static Type parbool(int dim=0) { return Type(TI_PAR,BT_BOOL,ST_PLAIN,dim); } static Type parfloat(int dim=0) { return Type(TI_PAR,BT_FLOAT,ST_PLAIN,dim); } static Type parstring(int dim=0) { return Type(TI_PAR,BT_STRING,ST_PLAIN,dim); } static Type ann(int dim=0) { return Type(TI_PAR,BT_ANN,ST_PLAIN,dim); } static Type parsetint(int dim=0) { return Type(TI_PAR,BT_INT,ST_SET,dim); } static Type parsetbool(int dim=0) { return Type(TI_PAR,BT_BOOL,ST_SET,dim); } static Type parsetfloat(int dim=0) { return Type(TI_PAR,BT_FLOAT,ST_SET,dim); } static Type parsetstring(int dim=0) { return Type(TI_PAR,BT_STRING,ST_SET,dim); } static Type varint(int dim=0) { return Type(TI_VAR,BT_INT,ST_PLAIN,dim); } static Type varbool(int dim=0) { return Type(TI_VAR,BT_BOOL,ST_PLAIN,dim); } static Type varfloat(int dim=0) { return Type(TI_VAR,BT_FLOAT,ST_PLAIN,dim); } static Type varsetint(int dim=0) { return Type(TI_VAR,BT_INT,ST_SET,dim); } static Type varbot(int dim=0) { return Type(TI_VAR,BT_BOT,ST_PLAIN,dim); } static Type bot(int dim=0) { return Type(TI_PAR,BT_BOT,ST_PLAIN,dim); } static Type top(int dim=0) { return Type(TI_PAR,BT_TOP,ST_PLAIN,dim); } static Type vartop(int dim=0) { return Type(TI_VAR,BT_TOP,ST_PLAIN,dim); } static Type optvartop(int dim=0) { Type t(TI_VAR,BT_TOP,ST_PLAIN,dim); t._ot = OT_OPTIONAL; return t; } bool isunknown(void) const { return _bt==BT_UNKNOWN; } bool isplain(void) const { return _dim==0 && _st==ST_PLAIN && _ot==OT_PRESENT; } bool isint(void) const { return _dim==0 && _st==ST_PLAIN && _bt==BT_INT; } bool isbot(void) const { return _bt==BT_BOT; } bool isfloat(void) const { return _dim==0 && _st==ST_PLAIN && _bt==BT_FLOAT; } bool isbool(void) const { return _dim==0 && _st==ST_PLAIN && _bt==BT_BOOL; } bool isstring(void) const { return isplain() && _bt==BT_STRING; } bool isvar(void) const { return _ti!=TI_PAR; } bool isvarbool(void) const { return _ti==TI_VAR && _dim==0 && _st==ST_PLAIN && _bt==BT_BOOL && _ot==OT_PRESENT; } bool isvarfloat(void) const { return _ti==TI_VAR && _dim==0 && _st==ST_PLAIN && _bt==BT_FLOAT && _ot==OT_PRESENT; } bool isvarint(void) const { return _ti==TI_VAR && _dim==0 && _st==ST_PLAIN && _bt==BT_INT && _ot==OT_PRESENT; } bool ispar(void) const { return _ti==TI_PAR; } bool isopt(void) const { return _ot==OT_OPTIONAL; } bool ispresent(void) const { return _ot==OT_PRESENT; } bool is_set(void) const { return _dim==0 && _st==ST_SET; } bool isintset(void) const { return is_set() && (_bt==BT_INT || _bt==BT_BOT); } bool isboolset(void) const { return is_set() && (_bt==BT_BOOL || _bt==BT_BOT); } bool isann(void) const { return isplain() && _bt==BT_ANN; } bool isintarray(void) const { return _dim==1 && _st==ST_PLAIN && _ot==OT_PRESENT && _bt==BT_INT; } bool isboolarray(void) const { return _dim==1 && _st==ST_PLAIN && _ot==OT_PRESENT && _bt==BT_BOOL; } bool isintsetarray(void) const { return _dim==1 && _st==ST_SET && _bt==BT_INT; } bool operator== (const Type& t) const { return _ti==t._ti && _bt==t._bt && _st==t._st && _ot==t._ot && _dim==t._dim; } bool operator!= (const Type& t) const { return !this->operator==(t); } // protected: int toInt(void) const { return + ((1-static_cast(_st))<<28) + (static_cast(_bt)<<24) + (static_cast(_ti)<<21) + (static_cast(_ot)<<20) + (_dim == -1 ? 1 : (_dim == 0 ? 0 : _dim+1)); } static Type fromInt(int i) { Type t; t._st = 1-static_cast((i >> 28) & 0x1); t._bt = static_cast((i >> 24) & 0xF); t._ti = static_cast((i >> 21) & 0x7); t._ot = static_cast((i >> 20) & 0x1); int dim = (i & 0xFFFFF); t._dim = (dim == 0 ? 0 : (dim==1 ? -1 : dim-1)); return t; } std::string toString(void) const { std::ostringstream oss; if (_dim>0) { oss<<"array[int"; for (int i=1; i<_dim; i++) oss << ",int"; oss<<"] of "; } if (_dim<0) oss<<"array[$_] of "; switch (_ti) { case TI_PAR: break; case TI_VAR: oss<<"var "; break; } if (_ot==OT_OPTIONAL) oss<<"opt "; if (_st==ST_SET) oss<<"set of "; switch (_bt) { case BT_INT: oss<<"int"; break; case BT_BOOL: oss<<"bool"; break; case BT_FLOAT: oss<<"float"; break; case BT_STRING: oss<<"string"; break; case BT_ANN: oss<<"ann"; break; case BT_BOT: oss<<"bot"; break; case BT_TOP: oss<<"top"; break; case BT_UNKNOWN: oss<<"??? "; break; } return oss.str(); } public: /// Check if \a bt0 is a subtype of \a bt1 static bool bt_subtype(const BaseType& bt0, const BaseType& bt1) { if (bt0==bt1) return true; switch (bt0) { case BT_BOOL: return (bt1==BT_INT || bt1==BT_FLOAT); case BT_INT: return bt1==BT_FLOAT; default: return false; } } /// Check if this type is a subtype of \a t bool isSubtypeOf(const Type& t) const { if (_dim==0 && t._dim!=0 && _st==ST_SET && t._st==ST_PLAIN && ( bt()==BT_BOT || bt_subtype(bt(), t.bt()) || t.bt()==BT_TOP) && _ti==TI_PAR && (_ot==OT_PRESENT || _ot==t._ot) ) return true; // either same dimension or t has variable dimension if (_dim!=t._dim && (_dim==0 || t._dim!=-1)) return false; // same type, this is present or both optional if (_ti==t._ti && bt_subtype(bt(),t.bt()) && _st==t._st) return _ot==OT_PRESENT || _ot==t._ot; // this is par other than that same type as t if (_ti==TI_PAR && bt_subtype(bt(),t.bt()) && _st==t._st) return _ot==OT_PRESENT || _ot==t._ot; if ( _ti==TI_PAR && t._bt==BT_BOT) return true; if ((_ti==t._ti || _ti==TI_PAR) && _bt==BT_BOT && (_st==t._st || _st==ST_PLAIN)) return _ot==OT_PRESENT || _ot==t._ot; if (t._bt==BT_TOP && (_ot==OT_PRESENT || _ot==t._ot) && (t._st==ST_PLAIN || _st==t._st) && (_ti==TI_PAR || t._ti==TI_VAR)) return true; return false; } /// Compare types int cmp(const Type& t) const { return toInt()t.toInt() ? 1 : 0); } }; }; #endif libminizinc-2.0.11/include/minizinc/astiterator.hh0000644000175000017500000002636712646030173020705 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_ASTITERATOR_HH__ #define __MINIZINC_ASTITERATOR_HH__ #include #include namespace MiniZinc { /** * \brief Bottom-up iterator for expressions */ template class BottomUpIterator { protected: /// The visitor to call back during iteration T& _t; /// Stack item struct C { /// Expression on the stack Expression* _e; /// Whether this expression has been visited before bool _done; /// If part of a generator expression, which one it is int _gen_i; /// Constructor C(Expression* e) : _e(e), _done(false), _gen_i(-1) {} /// Constructor for generator expression C(Expression* e, int gen_i) : _e(e), _done(true), _gen_i(gen_i) {} }; /// Push all elements of \a v onto \a stack template void pushVec(std::vector& stack, ASTExprVec v) { for (unsigned int i=0; i void bottomUp(T& t, Expression* e) { BottomUpIterator(t).run(e); } /** * \brief Leaf iterator for expressions */ template class TopDownIterator { protected: /// The visitor to call back during iteration T& _t; /// Push all elements of \a v onto \a stack template static void pushVec(std::vector& stack, ASTExprVec v) { for (unsigned int i=0; i void topDown(T& t, Expression* e) { TopDownIterator(t).run(e); } /* IMPLEMENTATION */ template void BottomUpIterator::run(Expression* root) { std::vector stack; if (_t.enter(root)) stack.push_back(C(root)); while (!stack.empty()) { C& c = stack.back(); if (c._e==NULL) { stack.pop_back(); continue; } if (c._done) { switch (c._e->eid()) { case Expression::E_INTLIT: _t.vIntLit(*c._e->template cast()); break; case Expression::E_FLOATLIT: _t.vFloatLit(*c._e->template cast()); break; case Expression::E_SETLIT: _t.vSetLit(*c._e->template cast()); break; case Expression::E_BOOLLIT: _t.vBoolLit(*c._e->template cast()); break; case Expression::E_STRINGLIT: _t.vStringLit(*c._e->template cast()); break; case Expression::E_ID: _t.vId(*c._e->template cast()); break; case Expression::E_ANON: _t.vAnonVar(*c._e->template cast()); break; case Expression::E_ARRAYLIT: _t.vArrayLit(*c._e->template cast()); break; case Expression::E_ARRAYACCESS: _t.vArrayAccess(*c._e->template cast()); break; case Expression::E_COMP: if (c._gen_i >= 0) { _t.vComprehensionGenerator(*c._e->template cast(), c._gen_i); } else { _t.vComprehension(*c._e->template cast()); } break; case Expression::E_ITE: _t.vITE(*c._e->template cast()); break; case Expression::E_BINOP: _t.vBinOp(*c._e->template cast()); break; case Expression::E_UNOP: _t.vUnOp(*c._e->template cast()); break; case Expression::E_CALL: _t.vCall(*c._e->template cast()); break; case Expression::E_VARDECL: _t.vVarDecl(*c._e->template cast()); break; case Expression::E_LET: _t.vLet(*c._e->template cast()); break; case Expression::E_TI: _t.vTypeInst(*c._e->template cast()); break; case Expression::E_TIID: _t.vTIId(*c._e->template cast()); break; } _t.exit(c._e); stack.pop_back(); } else { c._done=true; Expression* ce = c._e; for (ExpressionSetIter it = ce->ann().begin(); it != ce->ann().end(); ++it) { if (_t.enter(*it)) stack.push_back(C(*it)); } if (_t.enter(ce)) { switch (ce->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_ID: case Expression::E_TIID: break; case Expression::E_SETLIT: pushVec(stack, ce->template cast()->v()); break; case Expression::E_ARRAYLIT: pushVec(stack, ce->template cast()->v()); break; case Expression::E_ARRAYACCESS: pushVec(stack, ce->template cast()->idx()); stack.push_back(C(ce->template cast()->v())); break; case Expression::E_COMP: { Comprehension* comp = ce->template cast(); stack.push_back(C(comp->e())); stack.push_back(C(comp->where())); for (unsigned int i=comp->n_generators(); i--; ) { for (unsigned int j=comp->n_decls(i); j--; ) { stack.push_back(C(comp->decl(i, j))); } stack.push_back(C(comp,i)); stack.push_back(C(comp->in(i))); } } break; case Expression::E_ITE: { ITE* ite = ce->template cast(); stack.push_back(C(ite->e_else())); for (int i=0; isize(); i++) { stack.push_back(C(ite->e_if(i))); stack.push_back(C(ite->e_then(i))); } } break; case Expression::E_BINOP: stack.push_back(C(ce->template cast()->rhs())); stack.push_back(C(ce->template cast()->lhs())); break; case Expression::E_UNOP: stack.push_back(C(ce->template cast()->e())); break; case Expression::E_CALL: pushVec(stack, ce->template cast()->args()); break; case Expression::E_VARDECL: stack.push_back(C(ce->template cast()->e())); stack.push_back(C(ce->template cast()->ti())); break; case Expression::E_LET: stack.push_back(C(ce->template cast()->in())); pushVec(stack, ce->template cast()->let()); break; case Expression::E_TI: stack.push_back(C(ce->template cast()->domain())); pushVec(stack,ce->template cast()->ranges()); break; } } else { c._e = NULL; } } } } template void TopDownIterator::run(Expression* root) { std::vector stack; if (_t.enter(root)) stack.push_back(root); while (!stack.empty()) { Expression* e = stack.back(); stack.pop_back(); if (e==NULL) { continue; } if (!_t.enter(e)) continue; for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { stack.push_back(*it); } switch (e->eid()) { case Expression::E_INTLIT: _t.vIntLit(*e->template cast()); break; case Expression::E_FLOATLIT: _t.vFloatLit(*e->template cast()); break; case Expression::E_SETLIT: _t.vSetLit(*e->template cast()); pushVec(stack, e->template cast()->v()); break; case Expression::E_BOOLLIT: _t.vBoolLit(*e->template cast()); break; case Expression::E_STRINGLIT: _t.vStringLit(*e->template cast()); break; case Expression::E_ID: _t.vId(*e->template cast()); break; case Expression::E_ANON: _t.vAnonVar(*e->template cast()); break; case Expression::E_ARRAYLIT: _t.vArrayLit(*e->template cast()); pushVec(stack, e->template cast()->v()); break; case Expression::E_ARRAYACCESS: _t.vArrayAccess(*e->template cast()); pushVec(stack, e->template cast()->idx()); stack.push_back(e->template cast()->v()); break; case Expression::E_COMP: _t.vComprehension(*e->template cast()); { Comprehension* comp = e->template cast(); stack.push_back(comp->where()); for (unsigned int i=comp->n_generators(); i--; ) { stack.push_back(comp->in(i)); for (unsigned int j=comp->n_decls(i); j--; ) { stack.push_back(comp->decl(i, j)); } } stack.push_back(comp->e()); } break; case Expression::E_ITE: _t.vITE(*e->template cast()); { ITE* ite = e->template cast(); stack.push_back(ite->e_else()); for (int i=0; isize(); i++) { stack.push_back(ite->e_if(i)); stack.push_back(ite->e_then(i)); } } break; case Expression::E_BINOP: _t.vBinOp(*e->template cast()); stack.push_back(e->template cast()->rhs()); stack.push_back(e->template cast()->lhs()); break; case Expression::E_UNOP: _t.vUnOp(*e->template cast()); stack.push_back(e->template cast()->e()); break; case Expression::E_CALL: _t.vCall(*e->template cast()); pushVec(stack, e->template cast()->args()); break; case Expression::E_VARDECL: _t.vVarDecl(*e->template cast()); stack.push_back(e->template cast()->e()); stack.push_back(e->template cast()->ti()); break; case Expression::E_LET: _t.vLet(*e->template cast()); stack.push_back(e->template cast()->in()); pushVec(stack, e->template cast()->let()); break; case Expression::E_TI: _t.vTypeInst(*e->template cast()); stack.push_back(e->template cast()->domain()); pushVec(stack,e->template cast()->ranges()); break; case Expression::E_TIID: _t.vTIId(*e->template cast()); break; } } } } #endif libminizinc-2.0.11/include/minizinc/astvec.hh0000644000175000017500000001412612646030173017617 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_ASTVEC_HH__ #define __MINIZINC_ASTVEC_HH__ #include #include namespace MiniZinc { class ASTIntVecO; /** * \brief Handler for ASTIntVecO objects */ class ASTIntVec { protected: /// Vector ASTIntVecO* _v; public: /// Default constructor ASTIntVec(void) : _v(NULL) {} /// Constructor ASTIntVec(ASTIntVecO* v) : _v(v) {} /// Constructor ASTIntVec(const std::vector& v); /// Copy constructor ASTIntVec(const ASTIntVec& s); /// Assignment operator ASTIntVec& operator= (const ASTIntVec& s); /// Size of vector unsigned int size(void) const; /// Element access int& operator[](unsigned int i); /// Element access int operator[](unsigned int i) const; /// Iterator begin int* begin(void); /// Iterator end int* end(void); /// Mark as alive for garbage collection void mark(void) const; }; template class ASTExprVecO; /** * \brief Handler for ASTExprVecO objects */ template class ASTExprVec { protected: /// Vector ASTExprVecO* _v; public: /// Default constructor ASTExprVec(void) : _v(NULL) {} /// Constructor ASTExprVec(ASTExprVecO* v) : _v(v) {} /// Constructor ASTExprVec(const std::vector& v); /// Copy constructor ASTExprVec(const ASTExprVec& v); /// Assignment operator ASTExprVec& operator= (const ASTExprVec& v); /// Size of vector unsigned int size(void) const; /// Element access T*& operator[](unsigned int i); /// Element access const T* operator[](unsigned int i) const; /// Iterator begin T** begin(void); /// Iterator end T** end(void); /// Return vector object ASTExprVecO* vec(void); /// Mark as alive for garbage collection void mark(void) const; }; /// Garbage collected integer vector class ASTIntVecO : public ASTChunk { protected: /// Constructor ASTIntVecO(const std::vector& v); public: /// Allocate and initialise from \a v static ASTIntVecO* a(const std::vector& v); /// Return size unsigned int size(void) const { return _size/sizeof(int); } /// Return element at position \a i int& operator[](unsigned int i) { assert(i(_data)[i]; } /// Return element at position \a i int operator[](unsigned int i) const { assert(i(_data)[i]; } /// Iterator begin int* begin(void) { return reinterpret_cast(_data); } /// Iterator end int* end(void) { return begin()+size(); } /// Mark as alive for garbage collection void mark(void) const { _gc_mark = 1; } }; /// Garbage collected vector of expressions template class ASTExprVecO : public ASTVec { protected: /// Constructor ASTExprVecO(const std::vector& v); public: /// Allocate and initialise from \a v static ASTExprVecO* a(const std::vector& v); unsigned int size(void) const { return _size; } bool empty(void) const { return size()==0; } T& operator[] (int i) { assert(i(size())); return reinterpret_cast(_data[i]); } const T operator[] (int i) const { assert(i(size())); return reinterpret_cast(_data[i]); } /// Iterator begin T* begin(void) { return reinterpret_cast(_data); } /// Iterator end T* end(void) { return begin()+size(); } /// Mark as alive for garbage collection void mark(void) const { _gc_mark = 1; } }; template ASTExprVecO::ASTExprVecO(const std::vector& v) : ASTVec(v.size()) { for (unsigned int i=v.size(); i--;) (*this)[i] = v[i]; } template ASTExprVecO* ASTExprVecO::a(const std::vector& v) { ASTExprVecO* ao = static_cast*>(alloc(v.size())); new (ao) ASTExprVecO(v); return ao; } inline ASTIntVec::ASTIntVec(const std::vector& v) : _v(ASTIntVecO::a(v)) {} inline ASTIntVec::ASTIntVec(const ASTIntVec& v) : _v(v._v) {} inline ASTIntVec& ASTIntVec::operator= (const ASTIntVec& v) { _v = v._v; return *this; } inline unsigned int ASTIntVec::size(void) const { return _v ? _v->size() : 0; } inline int& ASTIntVec::operator[](unsigned int i) { return (*_v)[i]; } inline int ASTIntVec::operator[](unsigned int i) const { return (*_v)[i]; } inline int* ASTIntVec::begin(void) { return _v ? _v->begin() : NULL; } inline int* ASTIntVec::end(void) { return _v ? _v->end() : NULL; } inline void ASTIntVec::mark(void) const { if (_v) _v->mark(); } template ASTExprVec::ASTExprVec(const std::vector& v) : _v(ASTExprVecO::a(v)) {} template inline ASTExprVec::ASTExprVec(const ASTExprVec& v) : _v(v._v) {} template inline ASTExprVec& ASTExprVec::operator =(const ASTExprVec& v) { _v = v._v; return *this; } template inline unsigned int ASTExprVec::size(void) const { return _v ? _v->size() : 0; } template inline T*& ASTExprVec::operator[](unsigned int i) { return (*_v)[i]; } template inline const T* ASTExprVec::operator[](unsigned int i) const { return (*_v)[i]; } template inline T** ASTExprVec::begin(void) { return _v ? _v->begin() : NULL; } template inline T** ASTExprVec::end(void) { return _v ? _v->end() : NULL; } template inline ASTExprVecO* ASTExprVec::vec(void) { return _v; } template inline void ASTExprVec::mark(void) const { if (_v) _v->mark(); } } #endif libminizinc-2.0.11/include/minizinc/optimize.hh0000644000175000017500000000570012646030173020170 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_OPTIMIZE_HH__ #define __MINIZINC_OPTIMIZE_HH__ #include #include #include namespace MiniZinc { class VarOccurrences { public: typedef UNORDERED_NAMESPACE::unordered_set Items; IdMap _m; IdMap idx; /// Add \a to the index void add(VarDeclI* i, int idx_i); /// Add \a to the index void add(VarDecl* e, int idx_i); /// Find index of \a vd int find(VarDecl* vd); /// Remove index of \a vd void remove(VarDecl* vd); /// Add \a i to the dependencies of \a v void add(VarDecl* v, Item* i); /// Remove \a i from map and return new number of occurrences int remove(VarDecl* v, Item* i); /// Return number of occurrences of \a v int occurrences(VarDecl* v); /// Unify \a v0 and \a v1 (removing \a v0) void unify(EnvI& env, Model* m, Id* id0, Id* id1); /// Clear all entries void clear(void); }; class CollectOccurrencesE : public EVisitor { public: VarOccurrences& vo; Item* ci; CollectOccurrencesE(VarOccurrences& vo0, Item* ci0) : vo(vo0), ci(ci0) {} void vId(const Id& id) { if(id.decl()) vo.add(id.decl(),ci); } }; class CollectOccurrencesI : public ItemVisitor { public: VarOccurrences& vo; CollectOccurrencesI(VarOccurrences& vo0) : vo(vo0) {} void vVarDeclI(VarDeclI* v); void vConstraintI(ConstraintI* ci); void vSolveI(SolveI* si); }; class CollectDecls : public EVisitor { public: VarOccurrences& vo; std::vector& vd; Item* item; CollectDecls(VarOccurrences& vo0, std::vector& vd0, Item* item0) : vo(vo0), vd(vd0), item(item0) {} void vId(Id& id) { if (id.decl() && vo.remove(id.decl(),item) == 0) { if (id.decl()->e()==NULL || id.decl()->ti()->domain()==NULL || id.decl()->ti()->computedDomain()) { vd.push_back(id.decl()); } else { /// TODO: test if id's domain is a superset of the right hand side /// this currently only tests for equality, and for Boolean domains if (Id* ident = id.decl()->e()->dyn_cast()) { if (Expression::equal(ident->decl()->ti()->domain(), id.decl()->ti()->domain())) { vd.push_back(id.decl()); } } else if (id.decl()->e()==id.decl()->ti()->domain()) { vd.push_back(id.decl()); } } } } }; bool isOutput(VarDecl* vd); /// Simplyfy models in \a env void optimize(Env& env); } #endif libminizinc-2.0.11/include/minizinc/hash.hh0000644000175000017500000001343112646030173017253 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_HASH_HH__ #define __MINIZINC_HASH_HH__ #include #include namespace MiniZinc { /// Hash class for expressions struct ExpressionHash { size_t operator() (const Expression* e) const { return Expression::hash(e); } }; /// Equality test for expressions struct ExpressionEq { bool operator() (const Expression* e0, const Expression* e1) const { return Expression::equal(e0,e1); } }; /// Hash map from expression to \a T template class ExpressionMap { protected: /// The underlying map implementation UNORDERED_NAMESPACE::unordered_map _m; public: /// Iterator type typedef typename UNORDERED_NAMESPACE::unordered_map::iterator iterator; /// Insert mapping from \a e to \a t iterator insert(Expression* e, const T& t) { assert(e != NULL); return _m.insert(std::pair(e,t)).first; } /// Find \a e in map iterator find(Expression* e) { return _m.find(e); } /// Begin of iterator iterator begin(void) { return _m.begin(); } /// End of iterator iterator end(void) { return _m.end(); } /// Remove binding of \a e from map void remove(Expression* e) { _m.erase(e); } /// Remove all elements from the map void clear(void) { _m.clear(); } }; /// Equality test for identifiers struct IdEq { bool operator() (const Id* e0, const Id* e1) const { if (e0->idn() == e1->idn()) { if (e0->idn() == -1) return e0->v() == e1->v(); return true; } return false; } }; /// Hash map from identifier to \a T template class IdMap { protected: /// The underlying map implementation UNORDERED_NAMESPACE::unordered_map _m; public: /// Iterator type typedef typename UNORDERED_NAMESPACE::unordered_map::iterator iterator; /// Insert mapping from \a e to \a t void insert(Id* e, const T& t) { assert(e != NULL); _m.insert(std::pair(e,t)); } /// Find \a e in map iterator find(Id* e) { return _m.find(e); } /// Begin of iterator iterator begin(void) { return _m.begin(); } /// End of iterator iterator end(void) { return _m.end(); } /// Remove binding of \a e from map void remove(Id* e) { _m.erase(e); } /// Remove all elements from the map void clear(void) { _m.clear(); } }; /// Hash class for KeepAlive objects struct KAHash { size_t operator() (const KeepAlive& e) const { return Expression::hash(e()); } }; /// Equality test for KeepAlive objects struct KAEq { bool operator() (const KeepAlive& e0, const KeepAlive& e1) const { return Expression::equal(e0(),e1()); } }; /// Hash map from KeepAlive to \a T template class KeepAliveMap { protected: /// The underlying map implementation UNORDERED_NAMESPACE::unordered_map _m; public: /// Iterator type typedef typename UNORDERED_NAMESPACE::unordered_map::iterator iterator; /// Insert mapping from \a e to \a t void insert(KeepAlive& e, const T& t) { assert(e() != NULL); _m.insert(std::pair(e,t)); } /// Find \a e in map iterator find(KeepAlive& e) { return _m.find(e); } /// Begin of iterator iterator begin(void) { return _m.begin(); } /// End of iterator iterator end(void) { return _m.end(); } /// Remove binding of \a e from map void remove(KeepAlive& e) { _m.erase(e); } template void dump(void) { for (iterator i = _m.begin(); i != _m.end(); ++i) { std::cerr << i->first() << ": " << D::d(i->second) << std::endl; } } }; class ExpressionSetIter : public UNORDERED_NAMESPACE::unordered_set::iterator { protected: bool _empty; typedef UNORDERED_NAMESPACE::unordered_set::iterator Iter; public: ExpressionSetIter(void) : _empty(false) {} ExpressionSetIter(bool) : _empty(true) {} ExpressionSetIter(const Iter& i) : Iter(i), _empty(false) {} bool operator ==(const ExpressionSetIter& i) const { return (_empty && i._empty) || static_cast(*this)==static_cast(i); } bool operator !=(const ExpressionSetIter& i) const { return !operator ==(i); } }; /// Hash set for expressions class ExpressionSet { protected: /// The underlying set implementation UNORDERED_NAMESPACE::unordered_set _s; public: /// Insert \a e void insert(Expression* e) { assert(e != NULL); _s.insert(e); } /// Find \a e in map ExpressionSetIter find(Expression* e) { return _s.find(e); } /// Begin of iterator ExpressionSetIter begin(void) { return _s.begin(); } /// End of iterator ExpressionSetIter end(void) { return _s.end(); } /// Remove binding of \a e from map void remove(Expression* e) { _s.erase(e); } bool contains(Expression* e) { return find(e) != end(); } /// Remove all elements from the map void clear(void) { _s.clear(); } bool isEmpty(void) const { return _s.begin() == _s.end(); } }; } #endif libminizinc-2.0.11/include/minizinc/prettyprinter.hh0000644000175000017500000000357112646030173021267 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Pierre Wilke * Guido Tack */ /* 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 __MINIZINC_PRETTYPRINTER_HH__ #define __MINIZINC_PRETTYPRINTER_HH__ #include #include namespace MiniZinc { class Document; class ItemDocumentMapper; class PrettyPrinter; class Printer { private: ItemDocumentMapper* ism; PrettyPrinter* printer; std::ostream& _os; int _width; bool _flatZinc; void init(void); void p(Document* d); void p(const Item* i); public: Printer(std::ostream& os, int width=80, bool flatZinc=true); ~Printer(void); void print(const Expression* e); void print(const Item* i); void print(const Model* m); static std::string escapeStringLit(const ASTString& s); }; /// Output operator for expressions template std::basic_ostream& operator <<(std::basic_ostream& os, const Expression& e) { std::basic_ostringstream s; s.copyfmt(os); s.width(0); Printer p(s,0); p.print(&e); return os << s.str(); } /// Output operator for items template std::basic_ostream& operator <<(std::basic_ostream& os, const Item& i) { std::basic_ostringstream s; s.copyfmt(os); s.width(0); Printer p(s); p.print(&i); return os << s.str(); } } void debugprint(MiniZinc::Expression* e); void debugprint(MiniZinc::Item* i); void debugprint(MiniZinc::Model* m); void debugprint(const MiniZinc::Location& l); #endif libminizinc-2.0.11/include/minizinc/astexception.hh0000644000175000017500000000307412646030173021040 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_ASTEXCEPTION_HH__ #define __MINIZINC_ASTEXCEPTION_HH__ #include #include #include #include namespace MiniZinc { class LocationException : public Exception { protected: Location _loc; public: LocationException(EnvI& env, const Location& loc, const std::string& msg); virtual ~LocationException(void) throw() {} const Location& loc(void) const { return _loc; } }; class TypeError : public LocationException { public: TypeError(EnvI& env, const Location& loc, const std::string& msg) : LocationException(env,loc,msg) {} ~TypeError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: type error"; } }; class EvalError : public LocationException { public: EvalError(EnvI& env, const Location& loc, const std::string& msg) : LocationException(env,loc,msg) {} EvalError(EnvI& env, const Location& loc, const std::string& msg, const ASTString& name) : LocationException(env,loc,msg+" '"+name.str()+"'") {} ~EvalError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: evaluation error"; } }; } #endif libminizinc-2.0.11/include/minizinc/parser.hh0000644000175000017500000000703312646030173017625 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_PARSER_HH__ #define __MINIZINC_PARSER_HH__ // This is a workaround for a bug in flex that only shows up // with the Microsoft C++ compiler #if defined(_MSC_VER) #define YY_NO_UNISTD_H #ifdef __cplusplus extern "C" int isatty(int); #endif #endif // The Microsoft C++ compiler marks certain functions as deprecated, // so let's take the alternative definitions #if defined(_MSC_VER) #define strdup _strdup #define fileno _fileno #endif #if defined(_MSC_VER) #pragma warning(disable:4065) #endif #include #include #include #include #include #include #include #include #include namespace MiniZinc { /// %State of the %MiniZinc parser class ParserState { public: ParserState(const std::string& f, const std::string& b, std::ostream& err0, std::vector >& files0, std::map& seenModels0, MiniZinc::Model* model0, bool isDatafile0, bool isFlatZinc0, bool parseDocComments0) : filename(f.c_str()), buf(b.c_str()), pos(0), length(b.size()), lineno(1), lineStartPos(0), nTokenNextStart(1), files(files0), seenModels(seenModels0), model(model0), isDatafile(isDatafile0), isFlatZinc(isFlatZinc0), parseDocComments(parseDocComments0), hadError(false), err(err0) {} const char* filename; void* yyscanner; const char* buf; unsigned int pos, length; int lineno; int lineStartPos; int nTokenNextStart; std::vector >& files; std::map& seenModels; MiniZinc::Model* model; bool isDatafile; bool isFlatZinc; bool parseDocComments; bool hadError; std::ostream& err; std::string stringBuffer; void printCurrentLine(void) { const char* eol_c = strchr(buf+lineStartPos,'\n'); if (eol_c) { err << std::string(buf+lineStartPos,eol_c-(buf+lineStartPos)); } else { err << buf+lineStartPos; } err << std::endl; } 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; } }; Model* parse(const std::string& filename, const std::vector& datafiles, const std::vector& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, std::ostream& err); Model* parseFromString(const std::string& model, const std::string& filename, const std::vector& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, std::ostream& err); Model* parseData(Model* m, const std::vector& datafiles, const std::vector& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, std::ostream& err); } #endif libminizinc-2.0.11/include/minizinc/htmlprinter.hh0000644000175000017500000000222712646030173020701 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_HTMLPRINTER_HH #define __MINIZINC_HTMLPRINTER_HH #include #include namespace MiniZinc { class Model; class HtmlDocument { protected: std::string _filename; std::string _title; std::string _doc; public: HtmlDocument(const std::string& filename, const std::string& title, const std::string& document) : _filename(filename), _title(title), _doc(document) {} std::string filename(void) const { return _filename; } std::string title(void) const { return _title; } std::string document(void) const { return _doc; } }; class HtmlPrinter { public: static std::vector printHtml(EnvI& env, Model* m, const std::string& basename, int splitLevel, bool includeStdLib); }; } #endif libminizinc-2.0.11/include/minizinc/aststring.hh0000644000175000017500000001337212646030173020352 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_ASTSTRING_HH__ #define __MINIZINC_ASTSTRING_HH__ #include #include #include #include #include #include namespace MiniZinc { class ASTStringO; /** * \brief Handler for ASTStringO objects */ class ASTString { protected: /// String ASTStringO* _s; public: /// Default constructor ASTString(void) : _s(NULL) {} /// Constructor ASTString(ASTStringO* s) : _s(s) {} /// Constructor ASTString(const std::string& s); /// Copy constructor ASTString(const ASTString& s); /// Assignment operator ASTString& operator= (const ASTString& s); /// Size of the string unsigned int size(void) const; /// Underlying C string object const char* c_str(void) const; /// Conversion to STL string std::string str(void) const; /// Underlying string implementation ASTStringO* aststr(void) const { return _s; } /// Return if string is equal to \a s bool operator== (const ASTString& s) const; /// Return if string is not equal to \a s bool operator!= (const ASTString& s) const; /// Return if string is equal to \a s bool operator== (const std::string& s) const; /// Return if string is not equal to \a s bool operator!= (const std::string& s) const; /// Return if string ends with \a s bool endsWith(const std::string& s) const; /// Return if string begins with \a s bool beginsWith(const std::string& s) const; /// Compute hash value of string size_t hash(void) const; /// Mark string during garbage collection void mark(void) const; }; /// Hash map from strings to \a T template struct ASTStringMap { /// The map type specialised for ASTString typedef UNORDERED_NAMESPACE::unordered_map t; }; /** * \brief Print integer set \a s * \relates Gecode::IntSet */ template std::basic_ostream& operator <<(std::basic_ostream& os, const ASTString& s) { return s.size()==0 ? os : (os << s.c_str()); } } OPEN_HASH_NAMESPACE { template<> struct hash { public: size_t operator()(const MiniZinc::ASTString& s) const; }; CLOSE_HASH_NAMESPACE } namespace std { template<> struct equal_to { public: bool operator()(const MiniZinc::ASTString& s0, const MiniZinc::ASTString& s1) const; }; } namespace MiniZinc { /** * \brief Garbage collected string */ class ASTStringO : public ASTChunk { protected: /// Constructor ASTStringO(const std::string& s); public: /// Allocate and initialise as \a s static ASTStringO* a(const std::string& s); /// Return underlying C-style string const char* c_str(void) const { return _data+sizeof(size_t); } /// Conversion to STL string std::string str(void) const { return std::string(c_str()); } /// Return size of string unsigned int size(void) const { return _size-sizeof(size_t)-1; } /// Access character at position \a i char operator[](unsigned int i) { assert(i(_data)[0]; } /// Mark for garbage collection void mark(void) const { _gc_mark = 1; } }; inline ASTString::ASTString(const std::string& s) : _s(ASTStringO::a(s)) {} inline ASTString::ASTString(const ASTString& s) : _s(s._s) {} inline ASTString& ASTString::operator= (const ASTString& s) { _s = s._s; return *this; } inline unsigned int ASTString::size(void) const { return _s ? _s->size() : 0; } inline const char* ASTString::c_str(void) const { return _s ? _s->c_str() : NULL; } inline std::string ASTString::str(void) const { return _s ? _s->str() : std::string(""); } inline void ASTString::mark(void) const { if (_s) _s->mark(); } inline bool ASTString::operator== (const ASTString& s) const { return size()==s.size() && (size()==0 || strncmp(_s->c_str(),s._s->c_str(),size())==0); } inline bool ASTString::operator!= (const ASTString& s) const { return !(*this == s); } inline bool ASTString::operator== (const std::string& s) const { return size()==s.size() && (size()==0 || strncmp(_s->c_str(),s.c_str(),size())==0); } inline bool ASTString::operator!= (const std::string& s) const { return !(*this == s); } inline bool ASTString::endsWith(const std::string &s) const { return size() >= s.size() && (size() == 0 || strncmp(_s->c_str()+size()-s.size(), s.c_str(), s.size())==0); } inline bool ASTString::beginsWith(const std::string &s) const { return size() >= s.size() && (size() == 0 || strncmp(_s->c_str(), s.c_str(), s.size())==0); } inline size_t ASTString::hash(void) const { return _s ? _s->hash() : 0; } } OPEN_HASH_NAMESPACE { inline size_t hash::operator()( const MiniZinc::ASTString& s) const { return s.hash(); } CLOSE_HASH_NAMESPACE } namespace std { inline bool equal_to::operator()(const MiniZinc::ASTString& s0, const MiniZinc::ASTString& s1) const { return s0==s1; } } #endif libminizinc-2.0.11/include/minizinc/builtins.hh0000644000175000017500000000107412646030173020161 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_BUILTINS_HH__ #define __MINIZINC_BUILTINS_HH__ #include namespace MiniZinc { /// Add builtins to the functions defined in \a m void registerBuiltins(Env& env, Model* m); } #endif libminizinc-2.0.11/include/minizinc/values.hh0000644000175000017500000003231212646030173017626 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_VALUES_HH__ #define __MINIZINC_VALUES_HH__ #include #include #include #include #include #include #include #include #include namespace MiniZinc { class IntVal; } namespace std { MiniZinc::IntVal abs(const MiniZinc::IntVal& x); } #ifdef _MSC_VER #define MZN_NORETURN __declspec(noreturn) #define MZN_NORETURN_ATTR #else #define MZN_NORETURN #define MZN_NORETURN_ATTR __attribute__((__noreturn__)) #endif namespace MiniZinc { class MiniZincSafeIntExceptionHandler { public: static MZN_NORETURN void SafeIntOnOverflow() MZN_NORETURN_ATTR { throw ArithmeticError( "integer overflow" ); } static MZN_NORETURN void SafeIntOnDivZero() MZN_NORETURN_ATTR { throw ArithmeticError( "integer division by zero" ); } }; } #undef MZN_NORETURN namespace MiniZinc { class IntVal { friend IntVal operator +(const IntVal& x, const IntVal& y); friend IntVal operator -(const IntVal& x, const IntVal& y); friend IntVal operator *(const IntVal& x, const IntVal& y); friend IntVal operator /(const IntVal& x, const IntVal& y); friend IntVal operator %(const IntVal& x, const IntVal& y); friend IntVal std::abs(const MiniZinc::IntVal& x); friend bool operator ==(const IntVal& x, const IntVal& y); private: long long int _v; bool _infinity; IntVal(long long int v, bool infinity) : _v(v), _infinity(infinity) {} typedef SafeInt SI; SI toSafeInt(void) const { return _v; } IntVal(SI v) : _v(v), _infinity(false) {} public: IntVal(void) : _v(0), _infinity(false) {} IntVal(long long int v) : _v(v), _infinity(false) {} long long int toInt(void) const { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); return _v; } bool isFinite(void) const { return !_infinity; } bool isPlusInfinity(void) const { return _infinity && _v==1; } bool isMinusInfinity(void) const { return _infinity && _v==-1; } IntVal& operator +=(const IntVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v = toSafeInt() + x.toSafeInt(); return *this; } IntVal& operator -=(const IntVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v = toSafeInt() - x.toSafeInt(); return *this; } IntVal& operator *=(const IntVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v = toSafeInt() * x.toSafeInt(); return *this; } IntVal& operator /=(const IntVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v = toSafeInt() / x.toSafeInt(); return *this; } IntVal operator -() const { IntVal r = *this; r._v = -r.toSafeInt(); return r; } IntVal& operator ++() { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); _v = toSafeInt() + 1; return *this; } IntVal operator ++(int) { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); IntVal ret = *this; _v = toSafeInt() + 1; return ret; } IntVal& operator --() { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); _v = toSafeInt() - 1; return *this; } IntVal operator --(int) { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); IntVal ret = *this; _v = toSafeInt() - 1; return ret; } static const IntVal minint(void); static const IntVal maxint(void); static const IntVal infinity(void); /// Infinity-safe addition IntVal plus(int x) { if (isFinite()) return toSafeInt()+x; else return *this; } /// Infinity-safe subtraction IntVal minus(int x) { if (isFinite()) return toSafeInt()-x; else return *this; } size_t hash(void) const { HASH_NAMESPACE::hash longhash; return longhash(_v); } }; inline bool operator ==(const IntVal& x, const IntVal& y) { return x._infinity==y._infinity && x._v == y._v; } inline bool operator <=(const IntVal& x, const IntVal& y) { return y.isPlusInfinity() || x.isMinusInfinity() || (x.isFinite() && y.isFinite() && x.toInt() <= y.toInt()); } inline bool operator <(const IntVal& x, const IntVal& y) { return (y.isPlusInfinity() && !x.isPlusInfinity()) || (x.isMinusInfinity() && !y.isMinusInfinity()) || (x.isFinite() && y.isFinite() && x.toInt() < y.toInt()); } inline bool operator >=(const IntVal& x, const IntVal& y) { return y <= x; } inline bool operator >(const IntVal& x, const IntVal& y) { return y < x; } inline bool operator !=(const IntVal& x, const IntVal& y) { return !(x==y); } inline IntVal operator +(const IntVal& x, const IntVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return x.toSafeInt()+y.toSafeInt(); } inline IntVal operator -(const IntVal& x, const IntVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return x.toSafeInt()-y.toSafeInt(); } inline IntVal operator *(const IntVal& x, const IntVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return x.toSafeInt()*y.toSafeInt(); } inline IntVal operator /(const IntVal& x, const IntVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return x.toInt()/y.toInt(); } inline IntVal operator %(const IntVal& x, const IntVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return x.toInt()%y.toInt(); } template std::basic_ostream& operator <<(std::basic_ostream& os, const IntVal& s) { if (s.isMinusInfinity()) return os << "-infinity"; else if (s.isPlusInfinity()) return os << "infinity"; else return os << s.toInt(); } } namespace std { inline MiniZinc::IntVal abs(const MiniZinc::IntVal& x) { if (!x.isFinite()) return MiniZinc::IntVal::infinity(); MiniZinc::IntVal::SI y(x.toInt()); return y < 0 ? MiniZinc::IntVal(static_cast(-y)) : x; } inline MiniZinc::IntVal min(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) { return x <= y ? x : y; } inline MiniZinc::IntVal max(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) { return x >= y ? x : y; } template<> struct equal_to { public: bool operator()(const MiniZinc::IntVal& s0, const MiniZinc::IntVal& s1) const { return s0==s1; } }; } OPEN_HASH_NAMESPACE { template<> struct hash { public: size_t operator()(const MiniZinc::IntVal& s) const { return s.hash(); } }; CLOSE_HASH_NAMESPACE } namespace MiniZinc { typedef unsigned long long int UIntVal; typedef double FloatVal; /// An integer set value class IntSetVal : public ASTChunk { public: /// Contiguous range struct Range { /// Range minimum IntVal min; /// Range maximum IntVal max; /// Construct range from \a m to \a n Range(IntVal m, IntVal n) : min(m), max(n) {} /// Default constructor Range(void) {} }; private: /// Return range at position \a i Range& get(int i) { return reinterpret_cast(_data)[i]; } /// Return range at position \a i const Range& get(int i) const { return reinterpret_cast(_data)[i]; } /// Construct empty set IntSetVal(void) : ASTChunk(0) {} /// Construct set of single range IntSetVal(IntVal m, IntVal n); /// Construct set from \a s IntSetVal(const std::vector& s) : ASTChunk(sizeof(Range)*s.size()) { for (unsigned int i=s.size(); i--;) get(i) = s[i]; } /// Disabled IntSetVal(const IntSetVal& r); /// Disabled IntSetVal& operator =(const IntSetVal& r); public: /// Return number of ranges int size(void) const { return _size / sizeof(Range); } /// Return minimum, or infinity if set is empty IntVal min(void) const { return size()==0 ? IntVal::infinity() : get(0).min; } /// Return maximum, or minus infinity if set is empty IntVal max(void) const { return size()==0 ? -IntVal::infinity() : get(size()-1).max; } /// Return minimum of range \a i IntVal min(int i) const { assert(i(ASTChunk::alloc(0)); new (r) IntSetVal(); return r; } /// Allocate set \f$\{m,n\}\f$ from context static IntSetVal* a(IntVal m, IntVal n) { if (m>n) { return a(); } else { IntSetVal* r = static_cast(ASTChunk::alloc(sizeof(Range))); new (r) IntSetVal(m,n); return r; } } /// Allocate set using iterator \a i template static IntSetVal* ai(I& i) { std::vector s; for (; i(); ++i) s.push_back(Range(i.min(),i.max())); IntSetVal* r = static_cast( ASTChunk::alloc(sizeof(Range)*s.size())); new (r) IntSetVal(s); return r; } /// Allocate set from vector \a s0 (may contain duplicates) static IntSetVal* a(const std::vector& s0) { if (s0.size()==0) return a(); std::vector s=s0; std::sort(s.begin(),s.end()); std::vector ranges; IntVal min=s[0]; IntVal max=min; for (unsigned int i=1; imax+1) { ranges.push_back(Range(min,max)); min=s[i]; max=min; } else { max=s[i]; } } ranges.push_back(Range(min,max)); IntSetVal* r = static_cast( ASTChunk::alloc(sizeof(Range)*ranges.size())); new (r) IntSetVal(ranges); return r; } static IntSetVal* a(const std::vector& ranges) { IntSetVal* r = static_cast(ASTChunk::alloc(sizeof(Range)*ranges.size())); new (r) IntSetVal(ranges); return r; } /// Check if set contains \a v bool contains(const IntVal& v) { for (int i=0; isize()) return false; for (int i=0; imin(i) || max(i)!=s->max(i)) return false; return true; } /// Mark for garbage collection void mark(void) { _gc_mark = 1; } }; /// Iterator over an IntSetVal class IntSetRanges { /// The set value const IntSetVal* rs; /// The current range int n; public: /// Constructor IntSetRanges(const IntSetVal* r) : rs(r), n(0) {} /// Check if iterator is still valid bool operator()(void) const { return nsize(); } /// Move to next range void operator++(void) { ++n; } /// Return minimum of current range IntVal min(void) const { return rs->min(n); } /// Return maximum of current range IntVal max(void) const { return rs->max(n); } /// Return width of current range IntVal width(void) const { return rs->width(n); } }; template std::basic_ostream& operator <<(std::basic_ostream& os, const IntSetVal& s) { for (IntSetRanges isr(&s); isr(); ++isr) os << isr.min() << ".." << isr.max() << " "; return os; } } #endif libminizinc-2.0.11/include/minizinc/exception.hh0000644000175000017500000000244212646030173020326 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_EXCEPTION_HH__ #define __MINIZINC_EXCEPTION_HH__ #include #include namespace MiniZinc { class Exception : public std::exception { protected: std::string _msg; public: Exception(const std::string& msg) : _msg(msg) {} virtual ~Exception(void) throw() {} virtual const char* what(void) const throw() = 0; const std::string& msg(void) const { return _msg; } }; class InternalError : public Exception { public: InternalError(const std::string& msg) : Exception(msg) {} ~InternalError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: internal error"; } }; class ArithmeticError : public Exception { public: ArithmeticError(const std::string& msg) : Exception(msg) {} virtual ~ArithmeticError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: arithmetic error"; } }; } #endif libminizinc-2.0.11/include/minizinc/ast.hh0000644000175000017500000012202012646030173017112 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_AST_HH__ #define __MINIZINC_AST_HH__ #include #include #include #include #include #include #include #include #include namespace MiniZinc { class IntLit; class FloatLit; class SetLit; class BoolLit; class StringLit; class Id; class AnonVar; class ArrayLit; class ArrayAccess; class Comprehension; class ITE; class BinOp; class UnOp; class Call; class VarDecl; class Let; class TypeInst; class Item; class FunctionI; class ExpressionSet; class ExpressionSetIter; /// %Location of an expression in the source code class Location { public: /// Source code file name ASTString filename; /// Line where expression starts unsigned int first_line; /// Column where expression starts unsigned int first_column; /// Line where expression ends unsigned int last_line; /// Column where expression ends unsigned int last_column : 30; /// Whether the location was introduced during compilation unsigned int is_introduced : 1; /// Construct empty location Location(void); /// Return string representation std::string toString(void) const; /// Mark as alive for garbage collection void mark(void) const; /// Return location with introduced flag set Location introduce(void) const; }; /// Output operator for locations template std::basic_ostream& operator <<(std::basic_ostream& os, const Location& loc) { std::basic_ostringstream s; s.copyfmt(os); s.width(0); if (loc.filename=="") { s << "unknown file"; } else { s << loc.filename << ":" << loc.first_line; } return os << s.str(); } /** * \brief Annotations */ class Annotation { private: ExpressionSet* _s; /// Delete Annotation(const Annotation&); /// Delete Annotation& operator =(const Annotation&); public: Annotation(void) : _s(NULL) {} ~Annotation(void); bool contains(Expression* e) const; bool isEmpty(void) const; ExpressionSetIter begin(void) const; ExpressionSetIter end(void) const; void add(Expression* e); void add(std::vector e); void remove(Expression* e); void removeCall(const ASTString& id); void clear(void); void merge(const Annotation& ann); }; /// returns the Annotation specified by the string; returns NULL if not exists Expression* getAnnotation(const Annotation& ann, std::string str); /// returns the Annotation specified by the string; returns NULL if not exists Expression* getAnnotation(const Annotation& ann, const ASTString& str); /** * \brief Base class for expressions */ class Expression : public ASTNode { protected: /// The annotations Annotation _ann; /// The location of the expression Location _loc; /// The %MiniZinc type of the expression Type _type; /// The hash value of the expression size_t _hash; public: /// Identifier of the concrere expression type enum ExpressionId { E_INTLIT = ASTNode::NID_END+1, E_FLOATLIT, E_SETLIT, E_BOOLLIT, E_STRINGLIT, E_ID, E_ANON, E_ARRAYLIT, E_ARRAYACCESS, E_COMP, E_ITE, E_BINOP, E_UNOP, E_CALL, E_VARDECL, E_LET, E_TI, E_TIID, EID_END = E_TIID }; ExpressionId eid(void) const { return static_cast(_id); } const Location& loc(void) const { return _loc; } void loc(const Location& l) { _loc = l; } const Type& type(void) const { return _type; } void type(const Type& t); size_t hash(void) const { return _hash; } protected: /// Combination function for hash values void cmb_hash(size_t h) { _hash ^= h + 0x9e3779b9 + (_hash << 6) + (_hash >> 2); } /// Combination function for hash values size_t cmb_hash(size_t seed, size_t h) { seed ^= h + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } /// Compute base hash value void init_hash(void) { _hash = cmb_hash(0,_id); } /// Check if \a e0 and \a e1 are equal static bool equal_internal(const Expression* e0, const Expression* e1); /// Constructor Expression(const Location& loc, const ExpressionId& eid, const Type& t) : ASTNode(eid), _loc(loc), _type(t) {} public: /// Test if expression is of type \a T template bool isa(void) const { return _id==T::eid; } /// Cast expression to type \a T* template T* cast(void) { assert(isa()); return static_cast(this); } /// Cast expression to type \a const T* template const T* cast(void) const { assert(isa()); return static_cast(this); } /// Cast expression to type \a T* or NULL if types do not match template T* dyn_cast(void) { return isa() ? static_cast(this) : NULL; } /// Cast expression to type \a const T* or NULL if types do not match template const T* dyn_cast(void) const { return isa() ? static_cast(this) : NULL; } /// Cast expression to type \a T* template static T* cast(Expression* e) { return e==NULL ? NULL : e->cast(); } /// Cast expression to type \a const T* template static const T* cast(const Expression* e) { return e==NULL ? NULL : e->cast(); } /// Cast expression to type \a T* or NULL if types do not match template static T* dyn_cast(Expression* e) { return e==NULL ? NULL : e->dyn_cast(); } /// Cast expression to type \a const T* or NULL if types do not match template static const T* dyn_cast(const Expression* e) { return e==NULL ? NULL : e->dyn_cast(); } /// Add annotation \a ann to the expression void addAnnotation(Expression* ann); /// Add annotation \a ann to the expression void addAnnotations(std::vector ann); const Annotation& ann(void) const { return _ann; } Annotation& ann(void) { return _ann; } /// Return hash value of \a e static size_t hash(const Expression* e) { return e==NULL ? 0 : e->_hash; } /// Check if \a e0 and \a e1 are equal static bool equal(const Expression* e0, const Expression* e1); /// Mark \a e as alive for garbage collection static void mark(Expression* e); }; /// \brief Integer literal expression class IntLit : public Expression { protected: /// The value of this expression IntVal _v; public: /// The identifier of this expression type static const ExpressionId eid = E_INTLIT; /// Constructor IntLit(const Location& loc, IntVal v); /// Access value IntVal v(void) const { return _v; } /// Set value void v(IntVal val) { _v = val; } /// Recompute hash value void rehash(void); /// Allocate new temporary literal (tries to avoid allocation) static IntLit* a(IntVal v); }; /// \brief Float literal expression class FloatLit : public Expression { protected: /// The value of this expression FloatVal _v; public: /// The identifier of this expression type static const ExpressionId eid = E_FLOATLIT; /// Constructor FloatLit(const Location& loc, FloatVal v); /// Access value FloatVal v(void) const { return _v; } /// Set value void v(FloatVal val) { _v = val; } /// Recompute hash value void rehash(void); /// Allocate new temporary literal (tries to avoid allocation) static FloatLit* a(FloatVal v); }; /// \brief Set literal expression class SetLit : public Expression { protected: /// The value of this expression ASTExprVec _v; /// A range-list based representation for an integer set, or NULL IntSetVal* _isv; public: /// The identifier of this expression type static const ExpressionId eid = E_SETLIT; /// Construct set \$f\{v1,\dots,vn\}\$f SetLit(const Location& loc, const std::vector& v); /// Construct set \$f\{v1,\dots,vn\}\$f SetLit(const Location& loc, ASTExprVec v); /// Construct set SetLit(const Location& loc, IntSetVal* isv); /// Access value ASTExprVec v(void) const { return _v; } /// Set value void v(const ASTExprVec& val) { _v = val; } /// Access value IntSetVal* isv(void) const { return _isv; } /// Set value void isv(IntSetVal* val) { _isv = val; } /// Recompute hash value void rehash(void); }; /// \brief Boolean literal expression class BoolLit : public Expression { protected: /// The value of this expression bool _v; public: /// The identifier of this expression type static const ExpressionId eid = E_BOOLLIT; /// Constructor BoolLit(const Location& loc, bool v); /// Access value bool v(void) const { return _v; } /// Recompute hash value void rehash(void); }; /// \brief String literal expression class StringLit : public Expression { protected: /// The value of this expression ASTString _v; public: /// The identifier of this expression type static const ExpressionId eid = E_STRINGLIT; /// Constructor StringLit(const Location& loc, const std::string& v); /// Constructor StringLit(const Location& loc, const ASTString& v); /// Access value ASTString v(void) const { return _v; } /// Set value void v(const ASTString& val) { _v = val; } /// Recompute hash value void rehash(void); }; /// \brief Identifier expression class Id : public Expression { protected: /// The string identifier void* _v_or_idn; /// The declaration corresponding to this identifier (may be NULL) Expression* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_ID; /// Constructor (\a decl may be NULL) Id(const Location& loc, const std::string& v, VarDecl* decl); /// Constructor (\a decl may be NULL) Id(const Location& loc, const ASTString& v, VarDecl* decl); /// Constructor (\a decl may be NULL) Id(const Location& loc, long long int idn, VarDecl* decl); /// Access identifier ASTString v(void) const; /// Set identifier void v(const ASTString& val) { _v_or_idn = val.aststr(); } /// Access identifier number long long int idn(void) const; /// Set identifier number void idn(long long int n) { _v_or_idn = reinterpret_cast((static_cast(n) << 1) | static_cast(1)); rehash(); } /// Return identifier or X_INTRODUCED plus identifier number ASTString str(void) const; /// Access declaration VarDecl* decl(void) const { Expression* d = _decl; while (d && d->isa()) d = d->cast()->_decl; return Expression::cast(d); } /// Set declaration void decl(VarDecl* d); /// Redirect to another Id \a id void redirect(Id* id) { assert(_decl==NULL || _decl->isa()); _decl = id; } /// Recompute hash value void rehash(void); }; /// \brief Type-inst identifier expression class TIId : public Expression { protected: /// The string identifier ASTString _v; public: /// The identifier of this expression type static const ExpressionId eid = E_TIID; /// Constructor TIId(const Location& loc, const std::string& v); /// Access identifier ASTString v(void) const { return _v; } /// Set identifier void v(const ASTString& val) { _v = val; } /// Recompute hash value void rehash(void); }; /// \brief Anonymous variable expression class AnonVar : public Expression { public: /// The identifier of this expression type static const ExpressionId eid = E_ANON; /// Constructor AnonVar(const Location& loc); /// Recompute hash value void rehash(void); }; /// \brief Array literal expression class ArrayLit : public Expression { friend class Expression; protected: /// The array ASTExprVec _v; /// The declared array dimensions ASTIntVec _dims; public: /// The identifier of this expression type static const ExpressionId eid = E_ARRAYLIT; /// Constructor ArrayLit(const Location& loc, const std::vector& v, const std::vector >& dims); /// Constructor (existing content) ArrayLit(const Location& loc, ASTExprVec v, const std::vector >& dims); /// Constructor (one-dimensional, existing content) ArrayLit(const Location& loc, ASTExprVec v); /// Constructor (one-dimensional) ArrayLit(const Location& loc, const std::vector& v); /// Constructor (two-dimensional) ArrayLit(const Location& loc, const std::vector >& v); /// Recompute hash value void rehash(void); /// Access value ASTExprVec v(void) const { return _v; } /// Set value void v(const ASTExprVec& val) { _v = val; } /// Return number of dimensions int dims(void) const; /// Return minimum index of dimension \a i int min(int i) const; /// Return maximum index of dimension \a i int max(int i) const; /// Return the length of the array int length(void) const; /// Set dimension vector void setDims(ASTIntVec dims) { _dims = dims; } /// Check if this array was produced by flattening bool flat(void) const { return _flag_1; } /// Set whether this array was produced by flattening void flat(bool b) { _flag_1 = b; } }; /// \brief Array access expression class ArrayAccess : public Expression { protected: /// The array to access Expression* _v; /// The indexes (for all array dimensions) ASTExprVec _idx; public: /// The identifier of this expression type static const ExpressionId eid = E_ARRAYACCESS; /// Constructor ArrayAccess(const Location& loc, Expression* v, const std::vector& idx); /// Constructor ArrayAccess(const Location& loc, Expression* v, ASTExprVec idx); /// Access value Expression* v(void) const { return _v; } /// Set value void v(Expression* val) { _v = val; } /// Access index sets ASTExprVec idx(void) const { return _idx; } /// Set index sets void idx(const ASTExprVec& idx) { _idx = idx; } /// Recompute hash value void rehash(void); }; /** * \brief Generators for comprehensions * * A generator consists of a list of variable declarations, one for * each generated variable, and the expression to generate. E.g., * the Zinc expression [ x[i,j,k] | i,j in 1..10, k in 1..5] contains * two generators. The first one has variable declarations for i and j * and the expression 1..10, and the second one has a variable declaration * for k and the expression 1..5. * */ class Generator { friend class Comprehension; protected: /// Variable declarations std::vector _v; /// in-expression Expression* _in; public: /// Allocate Generator(const std::vector& v, Expression* in); /// Allocate Generator(const std::vector& v, Expression* in); /// Allocate Generator(const std::vector& v, Expression* in); }; /// \brief A list of generators with one where-expression struct Generators { /// %Generators std::vector _g; /// where-expression Expression* _w; /// Constructor Generators(void) : _w(NULL) {} }; /// \brief An expression representing an array- or set-comprehension class Comprehension : public Expression { friend class Expression; protected: /// The expression to generate Expression* _e; /// A list of generator expressions ASTExprVec _g; /// A list of indices where generators start ASTIntVec _g_idx; /// The where-clause (or NULL) Expression* _where; public: /// The identifier of this expression type static const ExpressionId eid = E_COMP; /// Constructor Comprehension(const Location& loc, Expression* e, Generators& g, bool set); /// Recompute hash value void rehash(void); /// Whether comprehension is a set bool set(void) const; /// Return number of generators int n_generators(void) const; /// Return "in" expression for generator \a i Expression* in(int i); /// Return "in" expression for generator \a i const Expression* in(int i) const; /// Return number of declarations for generator \a i int n_decls(int i) const; /// Return declaration \a i for generator \a gen VarDecl* decl(int gen, int i); /// Return declaration \a i for generator \a gen const VarDecl* decl(int gen, int i) const; /// Return where clause Expression* where(void) const { return _where; } /// Return generator body Expression* e(void) const { return _e; } /// Re-construct (used for copying) void init(Expression* e, Generators& g); }; /// \brief If-then-else expression class ITE : public Expression { friend class Expression; protected: /// List of if-then-pairs ASTExprVec _e_if_then; /// Else-expression Expression* _e_else; public: /// The identifier of this expression type static const ExpressionId eid = E_ITE; /// Constructor ITE(const Location& loc, const std::vector& e_if_then, Expression* e_else); int size(void) const { return _e_if_then.size()/2; } Expression* e_if(int i) { return _e_if_then[2*i]; } Expression* e_then(int i) { return _e_if_then[2*i+1]; } Expression* e_else(void) { return _e_else; } const Expression* e_if(int i) const { return _e_if_then[2*i]; } const Expression* e_then(int i) const { return _e_if_then[2*i+1]; } const Expression* e_else(void) const { return _e_else; } void e_then(int i, Expression* e) { _e_if_then[2*i+1] = e; } void e_else(Expression* e) { _e_else = e; } /// Recompute hash value void rehash(void); /// Re-construct (used for copying) void init(const std::vector& e_if_then, Expression* e_else); }; /// Type of binary operators enum BinOpType { BOT_PLUS, BOT_MINUS, BOT_MULT, BOT_DIV, BOT_IDIV, BOT_MOD, BOT_LE, BOT_LQ, BOT_GR, BOT_GQ, BOT_EQ, BOT_NQ, BOT_IN, BOT_SUBSET, BOT_SUPERSET, BOT_UNION, BOT_DIFF, BOT_SYMDIFF, BOT_INTERSECT, BOT_PLUSPLUS, BOT_EQUIV, BOT_IMPL, BOT_RIMPL, BOT_OR, BOT_AND, BOT_XOR, BOT_DOTDOT }; /// \brief Binary-operator expression class BinOp : public Expression { protected: /// Left hand side expression Expression* _e0; /// Right hand side expression Expression* _e1; /// The predicate or function declaration (or NULL) FunctionI* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_BINOP; /// Constructor BinOp(const Location& loc, Expression* e0, BinOpType op, Expression* e1); /// Access left hand side Expression* lhs(void) const { return _e0; } /// Set left hand side void lhs(Expression* e) { _e0 = e; } /// Access right hand side Expression* rhs(void) const { return _e1; } /// Set right hand side void rhs(Expression* e) { _e1 = e; } /// Access declaration FunctionI* decl(void) const { return _decl; } /// Set declaration void decl(FunctionI* f) { _decl = f; } /// Return string representation of the operator ASTString opToString(void) const; /// Recompute hash value void rehash(void); /// Return operator type BinOpType op(void) const; }; /// Type of unary operators enum UnOpType { UOT_NOT, UOT_PLUS, UOT_MINUS }; /// \brief Unary-operator expressions class UnOp : public Expression { protected: /// %Expression Expression* _e0; /// The predicate or function declaration (or NULL) FunctionI* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_UNOP; /// Constructor UnOp(const Location& loc, UnOpType op, Expression* e); /// Access expression Expression* e(void) const { return _e0; } /// Set expression void e(Expression* e0) { _e0 = e0; } /// Access declaration FunctionI* decl(void) const { return _decl; } /// Set declaration void decl(FunctionI* f) { _decl = f; } ASTString opToString(void) const; /// Recompute hash value void rehash(void); /// Return operator type UnOpType op(void) const; }; /// \brief A predicate or function call expression class Call : public Expression { friend class Expression; protected: /// Identifier of called predicate or function ASTString _id; /// Arguments to the call ASTExprVec _args; /// The predicate or function declaration (or NULL) FunctionI* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_CALL; /// Constructor Call(const Location& loc, const std::string& id, const std::vector& args, FunctionI* decl=NULL); /// Constructor Call(const Location& loc, const ASTString& id, const std::vector& args, FunctionI* decl=NULL); /// Access identifier ASTString id(void) const { return _id; } /// Set identifier void id(const ASTString& i) { _id = i; } /// Access arguments ASTExprVec args(void) const { return _args; } /// Set arguments void args(const ASTExprVec& a) { _args = a; } /// Access declaration FunctionI* decl(void) const { return _decl; } /// Set declaration void decl(FunctionI* f) { _decl = f; } /// Recompute hash value void rehash(void); }; /// \brief A variable declaration expression class VarDecl : public Expression { friend class Let; protected: /// Type-inst of the declared variable TypeInst* _ti; /// Identifier Id* _id; /// Initialisation expression (can be NULL) Expression* _e; /// Flattened version of the VarDecl WeakRef _flat; /// Integer payload int _payload; public: /// The identifier of this expression type static const ExpressionId eid = E_VARDECL; /// Constructor VarDecl(const Location& loc, TypeInst* ti, const std::string& id, Expression* e=NULL); /// Constructor VarDecl(const Location& loc, TypeInst* ti, const ASTString& id, Expression* e=NULL); /// Constructor VarDecl(const Location& loc, TypeInst* ti, long long int idn, Expression* e=NULL); /// Constructor VarDecl(const Location& loc, TypeInst* ti, Id* id, Expression* e=NULL); /// Access TypeInst TypeInst* ti(void) const { return _ti; } /// Set TypeInst void ti(TypeInst* t) { _ti=t; } /// Access identifier Id* id(void) const { return _id; } /// Access initialisation expression Expression* e(void) const; /// Set initialisation expression void e(Expression* rhs); /// Access flattened version VarDecl* flat(void) { return _flat() ? _flat()->cast() : NULL; } /// Set flattened version void flat(VarDecl* vd); /// Recompute hash value void rehash(void); /// Whether variable is toplevel bool toplevel(void) const; /// Whether variable is toplevel void toplevel(bool t); /// Whether variable is introduced bool introduced(void) const; /// Whether variable is introduced void introduced(bool t); /// Whether variable has been evaluated bool evaluated(void) const; /// Whether variable has been evaluated void evaluated(bool t); /// Access payload int payload(void) const { return _payload; } /// Set payload void payload(int i) { _payload = i; } }; class EnvI; class CopyMap; /// \brief %Let expression class Let : public Expression { friend Expression* copy(EnvI& env, CopyMap& m, Expression* e, bool followIds, bool copyFundecls, bool isFlatModel); friend class Expression; protected: /// List of local declarations ASTExprVec _let; /// Copy of original local declarations ASTExprVec _let_orig; /// Body of the let Expression* _in; public: /// The identifier of this expression type static const ExpressionId eid = E_LET; /// Constructor Let(const Location& loc, const std::vector& let, Expression* in); /// Recompute hash value void rehash(void); /// Access local declarations ASTExprVec let(void) const { return _let; } /// Access local declarations ASTExprVec let_orig(void) const { return _let_orig; } /// Access body Expression* in(void) const { return _in; } /// Remember current let bindings void pushbindings(void); /// Restore previous let bindings void popbindings(void); }; /// \brief Type-inst expression class TypeInst : public Expression { protected: /// Ranges of an array expression ASTExprVec _ranges; /// Declared domain (or NULL) Expression* _domain; public: /// The identifier of this expression type static const ExpressionId eid = E_TI; /// Constructor TypeInst(const Location& loc, const Type& t, ASTExprVec ranges, Expression* domain=NULL); /// Constructor TypeInst(const Location& loc, const Type& t, Expression* domain=NULL); /// Access ranges ASTExprVec ranges(void) const { return _ranges; } /// Access domain Expression* domain(void) const { return _domain; } //// Set domain void domain(Expression* d) { _domain = d; } /// Set ranges to \a ranges void setRanges(const std::vector& ranges); bool isarray(void) const { return _ranges.size()>0; } bool hasTiVariable(void) const; /// Recompute hash value void rehash(void); /// Check if domain is computed from right hand side of variable bool computedDomain(void) const { return _flag_1; } /// Set if domain is computed from right hand side of variable void setComputedDomain(bool b) { _flag_1=b; } }; /** * \brief Base-class for items */ class Item : public ASTNode { protected: /// Location of the item Location _loc; public: /// Identifier of the concrete item type enum ItemId { II_INC = Expression::EID_END+1, II_VD, II_ASN, II_CON, II_SOL, II_OUT, II_FUN, II_END = II_FUN }; ItemId iid(void) const { return static_cast(_id); } const Location& loc(void) const { return _loc; } protected: /// Constructor Item(const Location& loc, const ItemId& iid) : ASTNode(iid), _loc(loc) { _flag_1 = false; } public: /// Test if item is of type \a T template bool isa(void) const { return _id==T::iid; } /// Cast item to type \a T* template T* cast(void) { assert(isa()); return static_cast(this); } /// Cast expression to type \a const T* template const T* cast(void) const { assert(isa()); return static_cast(this); } /// Cast item to type \a T* or NULL if types do not match template T* dyn_cast(void) { return isa() ? static_cast(this) : NULL; } /// Cast item to type \a const T* or NULL if types do not match template const T* dyn_cast(void) const { return isa() ? static_cast(this) : NULL; } /// Cast item to type \a T* template static T* cast(Item* i) { return i==NULL ? NULL : i->cast(); } /// Cast item to type \a const T* template static const T* cast(const Item* i) { return i==NULL ? NULL : i->cast(); } /// Cast item to type \a T* or NULL if types do not match template static T* dyn_cast(Item* i) { return i==NULL ? NULL : i->dyn_cast(); } /// Cast item to type \a const T* or NULL if types do not match template static const T* dyn_cast(const Item* i) { return i==NULL ? NULL : i->dyn_cast(); } /// Check if item should be removed bool removed(void) const { return _flag_1; } /// Set flag to remove item void remove(void) { _flag_1 = true; } }; class Model; /// \brief Include item class IncludeI : public Item { protected: /// Filename to include ASTString _f; /// Model for that file Model* _m; public: /// The identifier of this item type static const ItemId iid = II_INC; /// Constructor IncludeI(const Location& loc, const ASTString& f); /// Access filename ASTString f(void) const { return _f; } /// Set filename void f(const ASTString& nf) { _f = nf; } /// Access model Model* m(void) const { return _m; } /// Set the model void m(Model* m0, bool own=true) { assert(_m==NULL || m0==NULL); _m = m0; _flag_2 = own; } bool own(void) const { return _flag_2; } }; /// \brief Variable declaration item class VarDeclI : public Item { protected: /// The declaration expression VarDecl* _e; public: /// The identifier of this item type static const ItemId iid = II_VD; /// Constructor VarDeclI(const Location& loc, VarDecl* e); /// Access expression VarDecl* e(void) const { return _e; } /// Set expression void e(VarDecl* vd) { _e = vd; } /// Flag used during compilation bool flag(void) const { return _flag_2; } /// Set flag used during compilation void flag(bool b) { _flag_2 = b; } }; /// \brief Assign item class AssignI : public Item { protected: /// Identifier of variable to assign to ASTString _id; /// Expression to assign to the variable Expression* _e; /// Declaration of the variable to assign to VarDecl* _decl; public: /// The identifier of this item type static const ItemId iid = II_ASN; /// Constructor AssignI(const Location& loc, const std::string& id, Expression* e); /// Access identifier ASTString id(void) const { return _id; } /// Access expression Expression* e(void) const { return _e; } /// Set expression void e(Expression* e0) { _e = e0; } /// Access declaration VarDecl* decl(void) const { return _decl; } /// Set declaration void decl(VarDecl* d) { _decl = d; } }; /// \brief Constraint item class ConstraintI : public Item { protected: /// Constraint expression Expression* _e; public: /// The identifier of this item type static const ItemId iid = II_CON; /// Constructor ConstraintI(const Location& loc, Expression* e); /// Access expression Expression* e(void) const { return _e; } /// Set expression void e(Expression* e0) { _e = e0; } /// Flag used during compilation bool flag(void) const { return _flag_2; } /// Set flag used during compilation void flag(bool b) { _flag_2 = b; } }; /// \brief Solve item class SolveI : public Item { protected: /// Solve item annotation Annotation _ann; /// Expression for minimisation/maximisation (or NULL) Expression* _e; /// Constructor SolveI(const Location& loc, Expression* e); public: /// The identifier of this item type static const ItemId iid = II_SOL; /// Type of solving enum SolveType { ST_SAT, ST_MIN, ST_MAX }; /// Allocate solve satisfy item static SolveI* sat(const Location& loc); /// Allocate solve minimize item static SolveI* min(const Location& loc, Expression* e); /// Allocate solve maximize item static SolveI* max(const Location& loc, Expression* e); /// Access solve annotation const Annotation& ann(void) const { return _ann; } /// Access solve annotation Annotation& ann(void) { return _ann; } /// Access expression for optimisation Expression* e(void) const { return _e; } /// Set expression for optimisation void e(Expression* e0) { _e=e0; } /// Return type of solving SolveType st(void) const; /// Set type of solving void st(SolveType s); }; /// \brief Output item class OutputI : public Item { protected: /// Expression to output Expression* _e; public: /// The identifier of this item type static const ItemId iid = II_OUT; /// Constructor OutputI(const Location& loc, Expression* e); /// Access expression Expression* e(void) const { return _e; } }; class EnvI; /// \brief Function declaration item class FunctionI : public Item { protected: /// Identifier of this function ASTString _id; /// Type-inst of the return value TypeInst* _ti; /// List of parameter declarations ASTExprVec _params; /// Annotation Annotation _ann; /// Function body (or NULL) Expression* _e; public: /// The identifier of this item type static const ItemId iid = II_FUN; /// Type of builtin expression-valued functions typedef Expression* (*builtin_e) (EnvI&, Call*); /// Type of builtin int-valued functions typedef IntVal (*builtin_i) (EnvI&, Call*); /// Type of builtin bool-valued functions typedef bool (*builtin_b) (EnvI&, Call*); /// Type of builtin float-valued functions typedef FloatVal (*builtin_f) (EnvI&, Call*); /// Type of builtin set-valued functions typedef IntSetVal* (*builtin_s) (EnvI&, Call*); /// Type of builtin string-valued functions typedef std::string (*builtin_str) (EnvI&, Call*); /// Builtin functions (or NULL) struct { builtin_e e; builtin_i i; builtin_f f; builtin_b b; builtin_s s; builtin_str str; } _builtins; /// Constructor FunctionI(const Location& loc, const std::string& id, TypeInst* ti, const std::vector& params, Expression* e = NULL); /// Access identifier ASTString id(void) const { return _id; } /// Access TypeInst TypeInst* ti(void) const { return _ti; } /// Access parameters ASTExprVec params(void) const { return _params; } /// Access annotation const Annotation& ann(void) const { return _ann; } /// Access annotation Annotation& ann(void) { return _ann; } /// Access body Expression* e(void) const { return _e; } /// Set body void e(Expression* b) { _e = b; } /** \brief Compute return type given argument types \a ta */ Type rtype(EnvI& env, const std::vector& ta); /** \brief Compute return type given argument types \a ta */ Type rtype(EnvI& env, const std::vector& ta); /** \brief Compute expected type of argument \a n given argument types \a ta */ Type argtype(const std::vector& ta, int n); /// Mark for GC void mark(void) { _gc_mark = 1; loc().mark(); } }; /** * \brief Visitor for expressions * * This class implements no-ops for all expression types. * Override the methods to implement custom behaviour. */ class EVisitor { public: /// Visit integer literal void vIntLit(const IntLit&) {} /// Visit floating point literal void vFloatLit(const FloatLit&) {} /// Visit Boolean literal void vBoolLit(const BoolLit&) {} /// Visit set literal void vSetLit(const SetLit&) {} /// Visit string literal void vStringLit(const StringLit&) {} /// Visit identifier void vId(const Id&) {} /// Visit anonymous variable void vAnonVar(const AnonVar&) {} /// Visit array literal void vArrayLit(const ArrayLit&) {} /// Visit array access void vArrayAccess(const ArrayAccess&) {} /// Visit array comprehension void vComprehension(const Comprehension&) {} /// Visit array comprehension (only generator \a gen_i) void vComprehensionGenerator(const Comprehension&, int gen_i) { (void) gen_i; } /// Visit if-then-else void vITE(const ITE&) {} /// Visit binary operator void vBinOp(const BinOp&) {} /// Visit unary operator void vUnOp(const UnOp&) {} /// Visit call void vCall(const Call&) {} /// Visit let void vLet(const Let&) {} /// Visit variable declaration void vVarDecl(const VarDecl&) {} /// Visit type inst void vTypeInst(const TypeInst&) {} /// Visit TIId void vTIId(const TIId&) {} /// Determine whether to enter node bool enter(Expression* e) { return true; } /// Exit node after processing has finished void exit(Expression* e) {} }; /// Statically allocated constants class Constants { private: /// Garbage collection root set for constants Model* m; public: /// Literal true BoolLit* lit_true; /// Variable bound to true VarDecl* var_true; /// Literal false BoolLit* lit_false; /// Variable bound to false VarDecl* var_false; /// Infinite set SetLit* infinity; /// Function item used to keep track of redefined variables FunctionI* var_redef; /// Literal absent value Expression* absent; /// Identifiers for builtins struct { ASTString forall; ASTString forall_reif; ASTString exists; ASTString clause; ASTString bool2int; ASTString int2float; ASTString bool2float; ASTString assert; ASTString trace; ASTString sum; ASTString lin_exp; ASTString element; ASTString show; ASTString fix; ASTString output; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; } int_; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; } int_reif; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_lt; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; } float_; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_lt; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; } float_reif; ASTString bool_eq; ASTString bool_eq_reif; ASTString array_bool_or; ASTString array_bool_and; ASTString bool_clause; ASTString bool_clause_reif; ASTString bool_xor; ASTString set_eq; ASTString set_in; ASTString set_card; ASTString introduced_var; } ids; /// Identifiers for Boolean contexts struct { Id* root; Id* pos; Id* neg; Id* mix; } ctx; /// Common annotations struct { Id* output_var; ASTString output_array; Id* is_defined_var; ASTString defines_var; Id* is_reverse_map; Id* promise_total; ASTString doc_comment; ASTString is_introduced; } ann; /// Keep track of allocated integer literals UNORDERED_NAMESPACE::unordered_map integerMap; /// Keep track of allocated float literals UNORDERED_NAMESPACE::unordered_map floatMap; /// Constructor Constants(void); /// Return shared BoolLit BoolLit* boollit(bool b) { return b ? lit_true : lit_false; } static const int max_array_size = INT_MAX / 2; }; /// Return static instance Constants& constants(void); } #include #endif libminizinc-2.0.11/include/minizinc/ast.hpp0000644000175000017500000003345612646030173017320 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ namespace MiniZinc { inline bool Expression::equal(const Expression* e0, const Expression* e1) { if (e0==e1) return true; if (e0 == NULL || e1 == NULL) return false; if (e0->_id != e1->_id) return false; if (e0->type() != e1->type()) return false; if (e0->hash() != e1->hash()) return false; return equal_internal(e0, e1); } inline void Expression::type(const Type& t) { if (eid()==E_VARDECL) { this->cast()->id()->_type = t; } else if (eid()==E_ID && this->cast()->decl()) { assert(_type.bt() == Type::BT_UNKNOWN || _type.dim()==t.dim() || t.dim() != -1); this->cast()->decl()->_type = t; } _type = t; } inline IntLit::IntLit(const Location& loc, IntVal v) : Expression(loc,E_INTLIT,Type::parint()), _v(v) { rehash(); } inline IntLit* IntLit::a(MiniZinc::IntVal v) { UNORDERED_NAMESPACE::unordered_map::iterator it = constants().integerMap.find(v); if (it==constants().integerMap.end() || it->second()==NULL) { IntLit* il = new IntLit(Location().introduce(), v); constants().integerMap.insert(std::make_pair(v, il)); return il; } else { return it->second()->cast(); } } inline FloatLit::FloatLit(const Location& loc, FloatVal v) : Expression(loc,E_FLOATLIT,Type::parfloat()), _v(v) { rehash(); } inline FloatLit* FloatLit::a(MiniZinc::FloatVal v) { UNORDERED_NAMESPACE::unordered_map::iterator it = constants().floatMap.find(v); if (it==constants().floatMap.end() || it->second()==NULL) { FloatLit* fl = new FloatLit(Location().introduce(), v); constants().floatMap.insert(std::make_pair(v, fl)); return fl; } else { return it->second()->cast(); } } inline SetLit::SetLit(const Location& loc, const std::vector& v) : Expression(loc,E_SETLIT,Type()), _v(ASTExprVec(v)), _isv(NULL) { rehash(); } inline SetLit::SetLit(const Location& loc, ASTExprVec v) : Expression(loc,E_SETLIT,Type()), _v(v), _isv(NULL) { rehash(); } inline SetLit::SetLit(const Location& loc, IntSetVal* isv) : Expression(loc,E_SETLIT,Type()), _isv(isv) { _type = Type::parsetint(); rehash(); } inline BoolLit::BoolLit(const Location& loc, bool v) : Expression(loc,E_BOOLLIT,Type::parbool()), _v(v) { rehash(); } inline StringLit::StringLit(const Location& loc, const std::string& v) : Expression(loc,E_STRINGLIT,Type::parstring()), _v(ASTString(v)) { rehash(); } inline StringLit::StringLit(const Location& loc, const ASTString& v) : Expression(loc,E_STRINGLIT,Type::parstring()), _v(v) { rehash(); } inline Id::Id(const Location& loc, const std::string& v0, VarDecl* decl) : Expression(loc,E_ID,Type()), _decl(decl) { v(v0); rehash(); } inline Id::Id(const Location& loc, const ASTString& v0, VarDecl* decl) : Expression(loc,E_ID,Type()), _decl(decl) { v(v0); rehash(); } inline Id::Id(const Location& loc, long long int idn0, VarDecl* decl) : Expression(loc,E_ID,Type()), _decl(decl) { idn(idn0); rehash(); } inline void Id::decl(VarDecl* d) { _decl = d; } inline ASTString Id::v(void) const { if (_decl && _decl->isa()) { Expression* d = _decl; while (d && d->isa()) { d = d->cast()->_decl; } return d->cast()->id()->v(); } else { assert((reinterpret_cast(_v_or_idn) & static_cast(1)) == 0); return ASTString(reinterpret_cast(_v_or_idn)); } } inline long long int Id::idn(void) const { if (_decl && _decl->isa()) { Expression* d = _decl; while (d && d->isa()) { d = d->cast()->_decl; } return d->cast()->id()->idn(); } else { if ((reinterpret_cast(_v_or_idn) & static_cast(1)) == 0) return -1; long long int i = reinterpret_cast(_v_or_idn) & ~static_cast(1); return i >> 1; } } inline TIId::TIId(const Location& loc, const std::string& v) : Expression(loc,E_TIID,Type()), _v(ASTString(v)) { rehash(); } inline AnonVar::AnonVar(const Location& loc) : Expression(loc,E_ANON,Type()) { rehash(); } inline ArrayLit::ArrayLit(const Location& loc, const std::vector& v, const std::vector >& dims) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; std::vector d(dims.size()*2); for (unsigned int i=dims.size(); i--;) { d[i*2] = dims[i].first; d[i*2+1] = dims[i].second; } _v = ASTExprVec(v); _dims = ASTIntVec(d); rehash(); } inline ArrayLit::ArrayLit(const Location& loc, ASTExprVec v, const std::vector >& dims) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; std::vector d(dims.size()*2); for (unsigned int i=dims.size(); i--;) { d[i*2] = dims[i].first; d[i*2+1] = dims[i].second; } _v = v; _dims = ASTIntVec(d); rehash(); } inline ArrayLit::ArrayLit(const Location& loc, ASTExprVec v) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; std::vector dims(2); dims[0]=1; dims[1]=v.size(); _v = v; _dims = ASTIntVec(dims); rehash(); } inline ArrayLit::ArrayLit(const Location& loc, const std::vector& v) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; std::vector dims(2); dims[0]=1; dims[1]=v.size(); _v = ASTExprVec(v); _dims = ASTIntVec(dims); rehash(); } inline ArrayLit::ArrayLit(const Location& loc, const std::vector >& v) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; std::vector dims(4); dims[0]=1; dims[1]=v.size(); dims[2]=1; dims[3]=v.size() > 0 ? v[0].size() : 0; std::vector vv; for (unsigned int i=0; i(vv); _dims = ASTIntVec(dims); rehash(); } inline ArrayAccess::ArrayAccess(const Location& loc, Expression* v, const std::vector& idx) : Expression(loc,E_ARRAYACCESS,Type()) { _v = v; _idx = ASTExprVec(idx); rehash(); } inline ArrayAccess::ArrayAccess(const Location& loc, Expression* v, ASTExprVec idx) : Expression(loc,E_ARRAYACCESS,Type()) { _v = v; _idx = idx; rehash(); } inline void Comprehension::init(Expression *e, Generators &g) { _e = e; std::vector es; std::vector idx; for (unsigned int i=0; i(es); _g_idx = ASTIntVec(idx); _where = g._w; rehash(); } inline Comprehension::Comprehension(const Location& loc, Expression* e, Generators& g, bool set) : Expression(loc,E_COMP,Type()) { init(e,g); _flag_1 = set; } inline void ITE::init(const std::vector& e_if_then, Expression* e_else) { _e_if_then = ASTExprVec(e_if_then); _e_else = e_else; rehash(); } inline ITE::ITE(const Location& loc, const std::vector& e_if_then, Expression* e_else) : Expression(loc,E_ITE,Type()) { init(e_if_then,e_else); } inline BinOp::BinOp(const Location& loc, Expression* e0, BinOpType op, Expression* e1) : Expression(loc,E_BINOP,Type()), _e0(e0), _e1(e1), _decl(NULL) { _sec_id = op; rehash(); } inline UnOp::UnOp(const Location& loc, UnOpType op, Expression* e) : Expression(loc,E_UNOP,Type()), _e0(e), _decl(NULL) { _sec_id = op; rehash(); } inline Call::Call(const Location& loc, const std::string& id, const std::vector& args, FunctionI* decl) : Expression(loc, E_CALL,Type()) { _id = ASTString(id); _args = ASTExprVec(args); _decl = decl; rehash(); } inline Call::Call(const Location& loc, const ASTString& id, const std::vector& args, FunctionI* decl) : Expression(loc, E_CALL,Type()) { _id = id; _args = ASTExprVec(args); _decl = decl; rehash(); } inline VarDecl::VarDecl(const Location& loc, TypeInst* ti, const ASTString& id, Expression* e) : Expression(loc,E_VARDECL,ti ? ti->type() : Type()), _id(NULL), _flat(NULL) { _id = new Id(loc,id,this); _flag_1 = true; _flag_2 = false; _ti = ti; _e = e; _id->type(type()); _payload = 0; rehash(); } inline VarDecl::VarDecl(const Location& loc, TypeInst* ti, long long int idn, Expression* e) : Expression(loc,E_VARDECL,ti ? ti->type() : Type()), _id(NULL), _flat(NULL) { _id = new Id(loc,idn,this); _flag_1 = true; _flag_2 = false; _ti = ti; _e = e; _id->type(type()); _payload = 0; rehash(); } inline VarDecl::VarDecl(const Location& loc, TypeInst* ti, const std::string& id, Expression* e) : Expression(loc,E_VARDECL,ti->type()), _id(NULL), _flat(NULL) { _id = new Id(loc,ASTString(id),this); _flag_1 = true; _flag_2 = false; _ti = ti; _e = e; _id->type(type()); _payload = 0; rehash(); } inline VarDecl::VarDecl(const Location& loc, TypeInst* ti, Id* id, Expression* e) : Expression(loc,E_VARDECL,ti->type()), _id(NULL), _flat(NULL) { if (id->idn()==-1) _id = new Id(loc,id->v(),this); else _id = new Id(loc,id->idn(),this); _flag_1 = true; _flag_2 = false; _ti = ti; _e = e; _id->type(type()); _payload = 0; rehash(); } inline Expression* VarDecl::e(void) const { return reinterpret_cast(reinterpret_cast(_e) & ~ static_cast(1)); } inline void VarDecl::e(Expression* rhs) { _e = rhs; } inline bool VarDecl::toplevel(void) const { return _flag_1; } inline void VarDecl::toplevel(bool t) { _flag_1 = t; } inline bool VarDecl::introduced(void) const { return _flag_2; } inline void VarDecl::introduced(bool t) { _flag_2 = t; } inline bool VarDecl::evaluated(void) const { return reinterpret_cast(_e) & 1; } inline void VarDecl::evaluated(bool t) { if (t) _e = reinterpret_cast(reinterpret_cast(_e) | 1); else _e = reinterpret_cast(reinterpret_cast(_e) & ~static_cast(1)); } inline void VarDecl::flat(VarDecl* vd) { _flat = WeakRef(vd); } inline TypeInst::TypeInst(const Location& loc, const Type& type, ASTExprVec ranges, Expression* domain) : Expression(loc,E_TI,type), _ranges(ranges), _domain(domain) { _flag_1 = false; rehash(); } inline TypeInst::TypeInst(const Location& loc, const Type& type, Expression* domain) : Expression(loc,E_TI,type), _domain(domain) { _flag_1 = false; rehash(); } inline IncludeI::IncludeI(const Location& loc, const ASTString& f) : Item(loc, II_INC), _f(f), _m(NULL) {} inline VarDeclI::VarDeclI(const Location& loc, VarDecl* e) : Item(loc, II_VD), _e(e) {} inline AssignI::AssignI(const Location& loc, const std::string& id, Expression* e) : Item(loc, II_ASN), _id(ASTString(id)), _e(e), _decl(NULL) {} inline ConstraintI::ConstraintI(const Location& loc, Expression* e) : Item(loc, II_CON), _e(e) {} inline SolveI::SolveI(const Location& loc, Expression* e) : Item(loc, II_SOL), _e(e) {} inline SolveI* SolveI::sat(const Location& loc) { SolveI* si = new SolveI(loc,NULL); si->_sec_id = ST_SAT; return si; } inline SolveI* SolveI::min(const Location& loc, Expression* e) { SolveI* si = new SolveI(loc,e); si->_sec_id = ST_MIN; return si; } inline SolveI* SolveI::max(const Location& loc, Expression* e) { SolveI* si = new SolveI(loc,e); si->_sec_id = ST_MAX; return si; } inline SolveI::SolveType SolveI::st(void) const { return static_cast(_sec_id); } inline void SolveI::st(SolveI::SolveType s) { _sec_id = s; } inline OutputI::OutputI(const Location& loc, Expression* e) : Item(loc, II_OUT), _e(e) {} inline FunctionI::FunctionI(const Location& loc, const std::string& id, TypeInst* ti, const std::vector& params, Expression* e) : Item(loc, II_FUN), _id(ASTString(id)), _ti(ti), _params(ASTExprVec(params)), _e(e) { _builtins.e = NULL; _builtins.b = NULL; _builtins.f = NULL; _builtins.i = NULL; _builtins.s = NULL; _builtins.str = NULL; } }libminizinc-2.0.11/include/minizinc/config.hh.in0000644000175000017500000000060512646030173020201 0ustar kaolkaol#define MZN_VERSION_MAJOR "${libminizinc_VERSION_MAJOR}" #define MZN_VERSION_MINOR "${libminizinc_VERSION_MINOR}" #define MZN_VERSION_PATCH "${libminizinc_VERSION_PATCH}" #cmakedefine HAS_DECLSPEC_THREAD #cmakedefine HAS_ATTR_THREAD #cmakedefine MZN_NEED_TR1 #cmakedefine HAS_PIDPATH #cmakedefine HAS_GETMODULEFILENAME #cmakedefine HAS_GETFILEATTRIBUTES #cmakedefine HAS_MEMCPY_S libminizinc-2.0.11/include/minizinc/flatten.hh0000644000175000017500000000374112646030173017770 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_FLATTEN_HH__ #define __MINIZINC_FLATTEN_HH__ #include #include namespace MiniZinc { /// Exception thrown for errors during flattening class FlatteningError : public LocationException { public: FlatteningError(EnvI& env, const Location& loc, const std::string& msg); ~FlatteningError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: flattening error"; } }; /// Options for the flattener struct FlatteningOptions { /// Keep output in resulting flat model bool keepOutputInFzn; /// Default constructor FlatteningOptions(void) : keepOutputInFzn(false) {} }; /// Flatten model \a m void flatten(Env& m, FlatteningOptions opt = FlatteningOptions()); /// Translate \a m into old FlatZinc syntax void oldflatzinc(Env& m); /// Statistics on flat models struct FlatModelStatistics { /// Number of integer variables int n_int_vars; /// Number of bool variables int n_bool_vars; /// Number of float variables int n_float_vars; /// Number of set variables int n_set_vars; /// Number of bool constraints int n_bool_ct; /// Number of integer constraints int n_int_ct; /// Number of float constraints int n_float_ct; /// Number of set constraints int n_set_ct; /// Constructor FlatModelStatistics(void) : n_int_vars(0), n_bool_vars(0), n_float_vars(0), n_set_vars(0), n_bool_ct(0), n_int_ct(0), n_float_ct(0), n_set_ct(0) {} }; /// Compute statistics for flat model in \a m FlatModelStatistics statistics(Env& m); } #endif libminizinc-2.0.11/include/minizinc/flatten_internal.hh0000644000175000017500000003344312646030173021666 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_FLATTEN_INTERNAL_HH__ #define __MINIZINC_FLATTEN_INTERNAL_HH__ #include #include #include #include namespace MiniZinc { /// Result of evaluation class EE { public: /// The result value KeepAlive r; /// Boolean expression representing whether result is defined KeepAlive b; /// Constructor explicit EE(Expression* r0=NULL, Expression* b0=NULL) : r(r0), b(b0) {} }; /// Boolean evaluation context enum BCtx { C_ROOT, C_POS, C_NEG, C_MIX }; /// Evaluation context struct Ctx { /// Boolean context BCtx b; /// Integer context BCtx i; /// Boolen negation flag bool neg; /// Default constructor (root context) Ctx(void) : b(C_ROOT), i(C_POS), neg(false) {} /// Copy constructor Ctx(const Ctx& ctx) : b(ctx.b), i(ctx.i), neg(ctx.neg) {} /// Assignment operator Ctx& operator =(const Ctx& ctx) { if (this!=&ctx) { b = ctx.b; i = ctx.i; neg = ctx.neg; } return *this; } }; /// Turn \a c into positive context BCtx operator +(const BCtx& c); /// Negate context \a c BCtx operator -(const BCtx& c); class EnvI { public: Model* orig; Model* output; VarOccurrences vo; VarOccurrences output_vo; CopyMap cmap; IdMap reverseMappers; struct WW { WeakRef r; WeakRef b; WW(WeakRef r0, WeakRef b0) : r(r0), b(b0) {} }; typedef KeepAliveMap Map; bool ignorePartial; std::vector callStack; std::vector errorStack; std::vector idStack; unsigned int maxCallStack; std::vector warnings; bool collect_vardecls; std::vector modifiedVarDecls; int in_redundant_constraint; protected: Map map; Model* _flat; unsigned int ids; ASTStringMap::t reifyMap; public: EnvI(Model* orig0); ~EnvI(void); long long int genId(void); void map_insert(Expression* e, const EE& ee); Map::iterator map_find(Expression* e); void map_remove(Expression* e); Map::iterator map_end(void); void dump(void); void flat_addItem(Item* i); void flat_removeItem(int i); void flat_removeItem(Item* i); void vo_add_exp(VarDecl* vd); Model* flat(void); ASTString reifyId(const ASTString& id); std::ostream& dumpStack(std::ostream& os, bool errStack); void addWarning(const std::string& msg); void collectVarDecls(bool b); void createErrorStack(void); }; Expression* follow_id(Expression* e); Expression* follow_id_to_decl(Expression* e); Expression* follow_id_to_value(Expression* e); EE flat_exp(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); class CmpExpIdx { public: std::vector& x; CmpExpIdx(std::vector& x0) : x(x0) {} bool operator ()(int i, int j) const { if (Expression::equal(x[i](),x[j]())) return false; if (x[i]()->isa() && x[j]()->isa() && x[i]()->cast()->idn() != -1 && x[j]()->cast()->idn() != -1) return x[i]()->cast()->idn() < x[j]()->cast()->idn(); return x[i]() class LinearTraits { }; template<> class LinearTraits { public: typedef IntVal Val; static Val eval(EnvI& env, Expression* e) { return eval_int(env,e); } static void constructLinBuiltin(BinOpType bot, ASTString& callid, int& coeff_sign, Val& d) { switch (bot) { case BOT_LE: callid = constants().ids.int_.lin_le; coeff_sign = 1; d += 1; break; case BOT_LQ: callid = constants().ids.int_.lin_le; coeff_sign = 1; break; case BOT_GR: callid = constants().ids.int_.lin_le; coeff_sign = -1; d = -d+1; break; case BOT_GQ: callid = constants().ids.int_.lin_le; coeff_sign = -1; d = -d; break; case BOT_EQ: callid = constants().ids.int_.lin_eq; coeff_sign = 1; break; case BOT_NQ: callid = constants().ids.int_.lin_ne; coeff_sign = 1; break; default: assert(false); break; } } static ASTString id_eq(void) { return constants().ids.int_.eq; } typedef IntBounds Bounds; static bool finite(const IntBounds& ib) { return ib.l.isFinite() && ib.u.isFinite(); } static bool finite(const IntVal& v) { return v.isFinite(); } static Bounds compute_bounds(EnvI& env, Expression* e) { return compute_int_bounds(env,e); } typedef IntSetVal* Domain; static Domain eval_domain(EnvI& env, Expression* e) { return eval_intset(env, e); } static Expression* new_domain(Val v) { return new SetLit(Location().introduce(),IntSetVal::a(v,v)); } static Expression* new_domain(Val v0, Val v1) { return new SetLit(Location().introduce(),IntSetVal::a(v0,v1)); } static Expression* new_domain(Domain d) { return new SetLit(Location().introduce(),d); } static bool domain_contains(Domain dom, Val v) { return dom->contains(v); } static bool domain_equals(Domain dom, Val v) { return dom->size()==1 && dom->min(0)==v && dom->max(0)==v; } static bool domain_equals(Domain dom1, Domain dom2) { IntSetRanges d1(dom1); IntSetRanges d2(dom2); return Ranges::equal(d1,d2); } static bool domain_intersects(Domain dom, Val v0, Val v1) { return (v0 > v1) || (dom->size() > 0 && dom->min(0) <= v1 && v0 <= dom->max(dom->size()-1)); } static bool domain_empty(Domain dom) { return dom->size()==0; } static Domain limit_domain(BinOpType bot, Domain dom, Val v) { IntSetRanges dr(dom); IntSetVal* ndomain; switch (bot) { case BOT_LE: v -= 1; // fall through case BOT_LQ: { Ranges::Bounded b = Ranges::Bounded::maxiter(dr,v); ndomain = IntSetVal::ai(b); } break; case BOT_GR: v += 1; // fall through case BOT_GQ: { Ranges::Bounded b = Ranges::Bounded::miniter(dr,v); ndomain = IntSetVal::ai(b); } break; case BOT_NQ: { Ranges::Const c(v,v); Ranges::Diff d(dr,c); ndomain = IntSetVal::ai(d); } break; default: assert(false); return NULL; } return ndomain; } static Domain intersect_domain(Domain dom, Val v0, Val v1) { IntSetRanges dr(dom); Ranges::Const c(v0,v1); Ranges::Inter inter(dr,c); return IntSetVal::ai(inter); } static Val floor_div(Val v0, Val v1) { return static_cast(floor(static_cast(v0.toInt()) / static_cast(v1.toInt()))); } static Val ceil_div(Val v0, Val v1) { return static_cast(ceil(static_cast(v0.toInt()) / v1.toInt())); } static IntLit* newLit(Val v) { return IntLit::a(v); } }; template<> class LinearTraits { public: typedef FloatVal Val; static Val eval(EnvI& env, Expression* e) { return eval_float(env,e); } static void constructLinBuiltin(BinOpType bot, ASTString& callid, int& coeff_sign, Val& d) { switch (bot) { case BOT_LE: callid = constants().ids.float_.lin_lt; coeff_sign = 1; break; case BOT_LQ: callid = constants().ids.float_.lin_le; coeff_sign = 1; break; case BOT_GR: callid = constants().ids.float_.lin_lt; coeff_sign = -1; d = -d; break; case BOT_GQ: callid = constants().ids.float_.lin_le; coeff_sign = -1; d = -d; break; case BOT_EQ: callid = constants().ids.float_.lin_eq; coeff_sign = 1; break; case BOT_NQ: callid = constants().ids.float_.lin_ne; coeff_sign = 1; break; default: assert(false); break; } } static ASTString id_eq(void) { return constants().ids.float_.eq; } typedef FloatBounds Bounds; static bool finite(const FloatBounds& ib) { return true; } static bool finite(const FloatVal&) { return true; } static Bounds compute_bounds(EnvI& env, Expression* e) { return compute_float_bounds(env,e); } typedef BinOp* Domain; static Domain eval_domain(EnvI& env, Expression* e) { BinOp* bo = e->cast(); assert(bo->op() == BOT_DOTDOT); if (bo->lhs()->isa() && bo->rhs()->isa()) return bo; BinOp* ret = new BinOp(bo->loc(),eval_par(env,bo->lhs()),BOT_DOTDOT,eval_par(env,bo->rhs())); ret->type(bo->type()); return ret; } static Expression* new_domain(Val v) { BinOp* ret = new BinOp(Location().introduce(),FloatLit::a(v),BOT_DOTDOT,FloatLit::a(v)); ret->type(Type::parsetfloat()); return ret; } static Expression* new_domain(Val v0, Val v1) { BinOp* ret = new BinOp(Location().introduce(),FloatLit::a(v0),BOT_DOTDOT,FloatLit::a(v1)); ret->type(Type::parsetfloat()); return ret; } static Expression* new_domain(Domain d) { return d; } static bool domain_contains(Domain dom, Val v) { return dom==NULL || (dom->lhs()->cast()->v() <= v && dom->rhs()->cast()->v() >= v); } static bool domain_intersects(Domain dom, Val v0, Val v1) { return dom==NULL || (dom->lhs()->cast()->v() <= v1 && dom->rhs()->cast()->v() >= v0); } static bool domain_equals(Domain dom, Val v) { return dom != NULL && dom->lhs()->cast()->v() == v && dom->rhs()->cast()->v() == v; } static bool domain_equals(Domain dom1, Domain dom2) { if (dom1==dom2) return true; if (dom1==NULL || dom2==NULL) return false; return dom1->lhs()->cast()->v() == dom2->lhs()->cast()->v() && dom1->rhs()->cast()->v() == dom2->rhs()->cast()->v(); } static bool domain_empty(Domain dom) { return dom != NULL && dom->lhs()->cast()->v() > dom->rhs()->cast()->v(); } static Domain intersect_domain(Domain dom, Val v0, Val v1) { if (dom) { Val lb = dom->lhs()->cast()->v(); Val ub = dom->rhs()->cast()->v(); Val nlb = std::max(lb,v0); Val nub = std::min(ub,v1); if (nlb==lb && nub==ub) return dom; Domain d = new BinOp(Location().introduce(), FloatLit::a(nlb), BOT_DOTDOT, FloatLit::a(nub)); d->type(Type::parsetfloat()); return d; } else { Domain d = new BinOp(Location().introduce(), FloatLit::a(v0), BOT_DOTDOT, FloatLit::a(v1)); d->type(Type::parsetfloat()); return d; } } static Domain limit_domain(BinOpType bot, Domain dom, Val v) { if (dom) { Val lb = dom->lhs()->cast()->v(); Val ub = dom->rhs()->cast()->v(); Domain ndomain; switch (bot) { case BOT_LE: return NULL; case BOT_LQ: if (v < ub) { Domain d = new BinOp(dom->loc(),dom->lhs(),BOT_DOTDOT,FloatLit::a(v)); d->type(Type::parsetfloat()); return d; } else { return dom; } case BOT_GR: return NULL; case BOT_GQ: if (v > lb) { Domain d = new BinOp(dom->loc(),FloatLit::a(v),BOT_DOTDOT,dom->rhs()); d->type(Type::parsetfloat()); return d; } else { return dom; } case BOT_NQ: return NULL; default: assert(false); return NULL; } return ndomain; } return NULL; } static Val floor_div(Val v0, Val v1) { return v0 / v1; } static Val ceil_div(Val v0, Val v1) { return v0 / v1; } static FloatLit* newLit(Val v) { return FloatLit::a(v); } }; template void simplify_lin(std::vector::Val>& c, std::vector& x, typename LinearTraits::Val& d) { std::vector idx(c.size()); for (unsigned int i=idx.size(); i--;) { idx[i]=i; Expression* e = follow_id_to_decl(x[i]()); if (VarDecl* vd = e->dyn_cast()) { if (vd->e() && vd->e()->isa()) { x[i] = vd->e(); } else { x[i] = e->cast()->id(); } } else { x[i] = e; } } std::sort(idx.begin(),idx.end(),CmpExpIdx(x)); unsigned int ci = 0; for (; cidyn_cast()) { d += c[idx[ci]]*il->v(); c[idx[ci]] = 0; } else { break; } } for (unsigned int i=ci+1; idyn_cast()) { d += c[idx[i]]*il->v(); c[idx[i]] = 0; } else { ci=i; } } ci = 0; for (unsigned int i=0; i */ /* 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 __MINIZINC_EVAL_PAR_HH__ #define __MINIZINC_EVAL_PAR_HH__ #include #include #include namespace MiniZinc { /// Evaluate par int expression \a e IntVal eval_int(EnvI& env, Expression* e); /// Evaluate par bool expression \a e bool eval_bool(EnvI& env, Expression* e); /// Evaluate par float expression \a e FloatVal eval_float(EnvI& env, Expression* e); /// Evaluate an array expression \a e into an array literal ArrayLit* eval_array_lit(EnvI& env, Expression* e); /// Evaluate an access to array \a with indices \a idx and return whether /// access succeeded in \a success Expression* eval_arrayaccess(EnvI& env, ArrayLit* a, const std::vector& idx, bool& success); /// Evaluate an array access \a e and return whether access succeeded in \a success Expression* eval_arrayaccess(EnvI& env, ArrayAccess* e, bool& success); /// Evaluate a par integer set \a e IntSetVal* eval_intset(EnvI& env, Expression* e); /// Evaluate a par bool set \a e IntSetVal* eval_boolset(EnvI& env, Expression* e); /// Evaluate a par string \a e std::string eval_string(EnvI& env, Expression* e); /// Evaluate a par expression \a e and return it wrapped in a literal Expression* eval_par(EnvI& env, Expression* e); /// Representation for bounds of an integer expression struct IntBounds { /// Lower bound IntVal l; /// Upper bound IntVal u; /// Whether the bounds are valid bool valid; /// Constructor IntBounds(IntVal l0, IntVal u0, bool valid0) : l(l0), u(u0), valid(valid0) {} }; /// Compute bounds of an integer expression IntBounds compute_int_bounds(EnvI& env, Expression* e); /// Representation for bounds of a float expression struct FloatBounds { /// Lower bound FloatVal l; /// Upper bound FloatVal u; /// Whether the bounds are valid bool valid; /// Constructor FloatBounds(FloatVal l0, FloatVal u0, bool valid0) : l(l0), u(u0), valid(valid0) {} }; /// Compute bounds of an integer expression FloatBounds compute_float_bounds(EnvI& env, Expression* e); /** * \brief Compute bounds of a set of int expression * * Returns NULL if bounds cannot be determined */ IntSetVal* compute_intset_bounds(EnvI& env, Expression* e); template void eval_comp_array(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, KeepAlive in, std::vector& a); template void eval_comp_set(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, KeepAlive in, std::vector& a); template void eval_comp_set(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, IntVal i, KeepAlive in, std::vector& a) { e->decl(gen,id)->e()->cast()->v(i); CallStackItem csi(env, e->decl(gen,id)->id(), i); if (id == e->n_decls(gen)-1) { if (gen == e->n_generators()-1) { bool where = true; if (e->where() != NULL && !e->where()->type().isvar()) { GCLock lock; where = eval_bool(env, e->where()); } if (where) { a.push_back(eval.e(env,e->e())); } } else { KeepAlive nextin; { if (e->in(gen+1)->type().dim()==0) { GCLock lock; nextin = new SetLit(Location(),eval_intset(env, e->in(gen+1))); } else { GCLock lock; nextin = eval_array_lit(env, e->in(gen+1)); } } if (e->in(gen+1)->type().dim()==0) { eval_comp_set(env, eval,e,gen+1,0,nextin,a); } else { eval_comp_array(env, eval,e,gen+1,0,nextin,a); } } } else { eval_comp_set(env, eval,e,gen,id+1,in,a); } } template void eval_comp_array(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, IntVal i, KeepAlive in, std::vector& a) { ArrayLit* al = in()->cast(); CallStackItem csi(env, e->decl(gen,id)->id(), i); e->decl(gen,id)->e(al->v()[i.toInt()]); e->rehash(); if (id == e->n_decls(gen)-1) { if (gen == e->n_generators()-1) { bool where = true; if (e->where() != NULL) { GCLock lock; where = eval_bool(env, e->where()); } if (where) { a.push_back(eval.e(env,e->e())); } } else { KeepAlive nextin; { if (e->in(gen+1)->type().dim()==0) { GCLock lock; nextin = new SetLit(Location(),eval_intset(env,e->in(gen+1))); } else { GCLock lock; nextin = eval_array_lit(env, e->in(gen+1)); } } if (e->in(gen+1)->type().dim()==0) { eval_comp_set(env, eval,e,gen+1,0,nextin,a); } else { eval_comp_array(env, eval,e,gen+1,0,nextin,a); } } } else { eval_comp_array(env, eval,e,gen,id+1,in,a); } e->decl(gen,id)->e(NULL); e->decl(gen,id)->flat(NULL); } /** * \brief Evaluate comprehension expression * * Calls \a eval.e for every element of the comprehension \a e, * where \a gen is the current generator, \a id is the current identifier * in that generator, \a in is the expression of that generator, and * \a a is the array in which to place the result. */ template void eval_comp_set(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, KeepAlive in, std::vector& a) { IntSetVal* isv = eval_intset(env, in()); IntSetRanges rsi(isv); Ranges::ToValues rsv(rsi); for (; rsv(); ++rsv) { eval_comp_set(env, eval,e,gen,id,rsv.val(),in,a); } } /** * \brief Evaluate comprehension expression * * Calls \a eval.e for every element of the comprehension \a e, * where \a gen is the current generator, \a id is the current identifier * in that generator, \a in is the expression of that generator, and * \a a is the array in which to place the result. */ template void eval_comp_array(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, KeepAlive in, std::vector& a) { ArrayLit* al = in()->cast(); for (unsigned int i=0; iv().size(); i++) { eval_comp_array(env, eval,e,gen,id,i,in,a); } } /** * \brief Evaluate comprehension expression * * Calls \a eval.e for every element of the comprehension \a e and * returns a vector with all the evaluated results. */ template std::vector eval_comp(EnvI& env, Eval& eval, Comprehension* e) { std::vector a; KeepAlive in; { GCLock lock; if (e->in(0)->type().dim()==0) { if (e->in(0)->type().isvar()) { in = new SetLit(Location(),compute_intset_bounds(env, e->in(0))); } else { in = new SetLit(Location(),eval_intset(env, e->in(0))); } } else { in = eval_array_lit(env, e->in(0)); } } if (e->in(0)->type().dim()==0) { eval_comp_set(env, eval,e,0,0,in,a); } else { eval_comp_array(env, eval,e,0,0,in,a); } return a; } /** * \brief Evaluate comprehension expression * * Calls \a Eval::e for every element of the comprehension \a e and * returns a vector with all the evaluated results. */ template std::vector eval_comp(EnvI& env, Comprehension* e) { Eval eval; return eval_comp(env, eval,e); } } #endif libminizinc-2.0.11/include/minizinc/typecheck.hh0000644000175000017500000000344312646030173020311 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_TYPECHECK_HH__ #define __MINIZINC_TYPECHECK_HH__ #include #include #include namespace MiniZinc { /// Topological sorting of items class TopoSorter { public: typedef std::vector Decls; typedef IdMap DeclMap; typedef UNORDERED_NAMESPACE::unordered_map PosMap; /// List of all declarations Decls decls; /// Map from identifiers to declarations DeclMap idmap; /// Map from declarations to positions PosMap pos; /// Add a variable declaration void add(EnvI& env, VarDecl* vd, bool unique); /// Remove a variable declaration void remove(EnvI& env, VarDecl* vd); /// Get variable declaration from identifier \a id VarDecl* get(EnvI& env, const ASTString& id, const Location& loc); VarDecl* checkId(EnvI& env, const ASTString& id, const Location& loc); VarDecl* checkId(EnvI& env, Id* id, const Location& loc); /// Run the topological sorting for expression \a e void run(EnvI& env, Expression* e); }; /// Type check the model \a m void typecheck(Env& env, Model* m, std::vector& typeErrors, bool ignoreUndefinedParameters = false); /// Type check new assign item \a ai in model \a m void typecheck(Env& env, Model* m, AssignI* ai); /// Typecheck FlatZinc variable declarations void typecheck_fzn(Env& env, Model* m); } #endif libminizinc-2.0.11/include/minizinc/file_utils.hh0000644000175000017500000000150012646030173020461 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_FILE_UTILS_HH__ #define __MINIZINC_FILE_UTILS_HH__ #include namespace MiniZinc { namespace FileUtils { /// Return full path to current executable std::string progpath(void); /// Test if \a filename exists bool file_exists(const std::string& filename); /// Test if \a dirname exists and is a directory bool directory_exists(const std::string& dirname); /// Return full path to file std::string file_path(const std::string& filename); }} #endif libminizinc-2.0.11/include/minizinc/copy.hh0000644000175000017500000000416212646030173017303 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_COPY_HH__ #define __MINIZINC_COPY_HH__ #include namespace MiniZinc { class CopyMap { protected: typedef UNORDERED_NAMESPACE::unordered_map MyMap; MyMap m; public: void insert(Expression* e0, Expression* e1); Expression* find(Expression* e); void insert(Item* e0, Item* e1); Item* find(Item* e); void insert(Model* e0, Model* e1); Model* find(Model* e); void insert(const ASTString& e0, const ASTString& e1); ASTStringO* find(const ASTString& e); void insert(IntSetVal* e0, IntSetVal* e1); IntSetVal* find(IntSetVal* e); template void insert(ASTExprVec e0, ASTExprVec e1) { m.insert(std::pair(e0.vec(),e1.vec())); } template ASTExprVecO* find(ASTExprVec e) { MyMap::iterator it = m.find(e.vec()); if (it==m.end()) return NULL; return static_cast*>(it->second); } }; /// Create a deep copy of expression \a e Expression* copy(EnvI& env, Expression* e, bool followIds=false, bool copyFundecls=false, bool isFlatModel=false); /// Create a deep copy of item \a i Item* copy(EnvI& env, Item* i, bool followIds=false, bool copyFundecls=false, bool isFlatModel=false); /// Create a deep copy of model \a m Model* copy(EnvI& env, Model* m); /// Create a deep copy of expression \a e Expression* copy(EnvI& env, CopyMap& map, Expression* e, bool followIds=false, bool copyFundecls=false, bool isFlatModel=false); /// Create a deep copy of item \a i Item* copy(EnvI& env, CopyMap& map, Item* i, bool followIds=false, bool copyFundecls=false, bool isFlatModel=false); /// Create a deep copy of model \a m Model* copy(EnvI& env, CopyMap& map, Model* m, bool isFlatModel=false); } #endif libminizinc-2.0.11/include/minizinc/gc.hh0000644000175000017500000001174412646030173016726 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_GC_HH__ #define __MINIZINC_GC_HH__ #include #include #include namespace MiniZinc { /** * \brief Base class for abstract syntax tree nodes */ class ASTNode { friend class GC; protected: /// Mark for garbage collection mutable unsigned int _gc_mark : 1; /// Id of the node unsigned int _id : 7; /// Secondary id unsigned int _sec_id : 7; /// Flag unsigned int _flag_1 : 1; /// Flag unsigned int _flag_2 : 1; enum BaseNodes { NID_FL, NID_CHUNK, NID_VEC, NID_END = NID_VEC }; /// Constructor ASTNode(unsigned int id) : _gc_mark(0), _id(id) {} public: /// Allocate node void* operator new(size_t size); /// Placement-new void* operator new(size_t, void* n) throw() { return n; } /// Delete node (no-op) void operator delete(void*, size_t) throw() { } /// Delete node (no-op) void operator delete(void*, void*) throw() { } /// Delete node (no-op) void operator delete(void*) throw() {} }; /** * \brief Base class for unstructured garbage collected data */ class ASTChunk : public ASTNode { friend class GC; protected: /// Allocated size size_t _size; /// Storage char _data[4]; /// Constructor ASTChunk(size_t size); /// Actual size of object in memory size_t memsize(void) const { size_t s = sizeof(ASTChunk)+(_size<=4?0:_size-4)*sizeof(char); s += ((8 - (s & 7)) & 7); return s; } /// Allocate raw memory static void* alloc(size_t size); }; /** * \brief Base class for structured garbage collected data */ class ASTVec : public ASTNode { friend class GC; protected: /// Allocated size size_t _size; /// Storage void* _data[2]; /// Constructor ASTVec(size_t size); /// Actual size of object in memory size_t memsize(void) const { size_t s = sizeof(ASTVec)+(_size<=2?0:_size-2)*sizeof(void*); s += ((8 - (s & 7)) & 7); return s; } /// Allocate raw memory static void* alloc(size_t size); }; class Model; class Expression; class KeepAlive; class WeakRef; /// Garbage collector class GC { friend class ASTNode; friend class ASTVec; friend class ASTChunk; friend class KeepAlive; friend class WeakRef; private: class Heap; /// The memory controlled by the collector Heap* _heap; /// Count how many locks are currently active unsigned int _lock_count; /// Return thread-local GC object static GC*& gc(void); /// Constructor GC(void); /// Allocate garbage collected memory void* alloc(size_t size); static void addKeepAlive(KeepAlive* e); static void removeKeepAlive(KeepAlive* e); static void addWeakRef(WeakRef* e); static void removeWeakRef(WeakRef* e); public: /// Acquire garbage collector lock for this thread static void lock(void); /// Release garbage collector lock for this thread static void unlock(void); /// Test if garbage collector is locked static bool locked(void); /// Add model \a m to root set static void add(Model* m); /// Remove model \a m from root set static void remove(Model* m); /// Put a mark on the trail static void mark(void); /// Add a trail entry static void trail(Expression**,Expression*); /// Untrail to previous mark static void untrail(void); /// Return maximum allocated memory (high water mark) static size_t maxMem(void); }; /// Automatic garbage collection lock class GCLock { public: /// Acquire lock GCLock(void); /// Release lock upon destruction ~GCLock(void); }; /// Expression wrapper that is a member of the root set class KeepAlive { friend class GC; private: Expression* _e; KeepAlive* _p; KeepAlive* _n; public: KeepAlive(Expression* e = NULL); ~KeepAlive(void); KeepAlive(const KeepAlive& e); KeepAlive& operator =(const KeepAlive& e); Expression* operator ()(void) { return _e; } Expression* operator ()(void) const { return _e; } KeepAlive* next(void) const { return _n; } }; /// Expression wrapper that is a member of the root set class WeakRef { friend class GC; private: Expression* _e; WeakRef* _p; WeakRef* _n; bool _valid; public: WeakRef(Expression* e = NULL); ~WeakRef(void); WeakRef(const WeakRef& e); WeakRef& operator =(const WeakRef& e); Expression* operator ()(void) { return _valid ? _e : NULL; } Expression* operator ()(void) const { return _valid ? _e : NULL; } WeakRef* next(void) const { return _n; } }; } #endif libminizinc-2.0.11/include/minizinc/optimize_constraints.hh0000644000175000017500000000175012646030173022620 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_OPTIMIZE_CONSTRAINTS_HH__ #define __MINIZINC_OPTIMIZE_CONSTRAINTS_HH__ #include #include namespace MiniZinc { class OptimizeRegistry { public: enum ConstraintStatus { CS_NONE, CS_OK, CS_FAILED, CS_ENTAILED, CS_REWRITE }; typedef ConstraintStatus (*optimizer) (EnvI& env, Item* i, Call* c, Expression*& rewrite); protected: ASTStringMap::t _m; public: void reg(const ASTString& call, optimizer); ConstraintStatus process(EnvI& env, Item* i, Call* c, Expression*& rewrite); static OptimizeRegistry& registry(void); }; } #endif libminizinc-2.0.11/include/minizinc/iter.hh0000644000175000017500000003731712646030173017304 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_ITER_HH__ #define __MINIZINC_ITER_HH__ #include namespace MiniZinc { namespace Ranges { /** * \brief Base for range iterators with explicit min and max * * The iterator provides members \a mi and \a ma for storing the * limits of the currently iterated range. The iterator * continues until \a mi becomes greater than \a ma. The member function * finish does exactly that. * * \ingroup FuncIterRanges */ class MinMax { protected: /// Minimum of current range IntVal mi; /// Maximum of current range IntVal ma; /// %Set range such that iteration stops void finish(void); public: /// \name Constructors and initialization //@{ /// Default constructor MinMax(void); /// Initialize with range \a min to \a max MinMax(IntVal min, IntVal max); //@} /// \name Iteration control //@{ /// Test whether iterator is still at a range or done bool operator ()(void) const; //@} /// \name Range access //@{ /// Return smallest value of range IntVal min(void) const; /// Return largest value of range IntVal max(void) const; /// Return width of range (distance between minimum and maximum) IntVal width(void) const; //@} }; inline void MinMax::finish(void) { mi = 1; ma = 0; } inline MinMax::MinMax(void) {} inline MinMax::MinMax(IntVal min, IntVal max) : mi(min), ma(max) {} inline bool MinMax::operator ()(void) const { return mi <= ma; } inline IntVal MinMax::min(void) const { return mi; } inline IntVal MinMax::max(void) const { return ma; } inline IntVal MinMax::width(void) const { if (mi > ma) return 0; if (mi.isFinite() && ma.isFinite()) return ma-mi+1; return IntVal::infinity(); } template class Bounded { protected: I i; IntVal _min; bool use_min; IntVal _max; bool use_max; Bounded(I& i, IntVal min0, bool umin0, IntVal max0, bool umax0); public: static Bounded miniter(I& i, IntVal min); static Bounded maxiter(I& i, IntVal max); static Bounded minmaxiter(I& i, IntVal min, IntVal max); /// \name Iteration control //@{ /// Test whether iterator is still at a range or done bool operator ()(void) const; /// Move iterator to next range (if possible) void operator ++(void); //@} /// \name Range access //@{ /// Return smallest value of range IntVal min(void) const; /// Return largest value of range IntVal max(void) const; /// Return width of range (distance between minimum and maximum) IntVal width(void) const; //@} }; template inline Bounded::Bounded(I& i0, IntVal min0, bool umin0, IntVal max0, bool umax0) : i(i0), _min(min0), use_min(umin0), _max(max0), use_max(umax0) { while (i() && use_min && i.max() < _min) ++i; } template inline Bounded Bounded::miniter(I& i, IntVal min) { return Bounded(i,min,true,0,false); } template inline Bounded Bounded::maxiter(I& i, IntVal max) { return Bounded(i,0,false,max,true); } template inline Bounded Bounded::minmaxiter(I& i, IntVal min, IntVal max) { return Bounded(i,min,true,max,true); } template inline bool Bounded::operator ()(void) const { return i() && (!use_max || i.min() <= _max); } template inline void Bounded::operator ++(void) { ++i; while (i() && use_min && i.max() < _min) ++i; } template inline IntVal Bounded::min(void) const { return use_min ? std::max(_min,i.min()) : i.min(); } template inline IntVal Bounded::max(void) const { return use_max ? std::min(_max,i.max()) : i.max(); } template inline IntVal Bounded::width(void) const { if (min() > max()) return 0; if (min().isFinite() && max().isFinite()) return max()-min()+1; return IntVal::infinity(); } class Const { protected: IntVal _min; IntVal _max; bool done; public: Const(IntVal min0, IntVal max0); /// \name Iteration control //@{ /// Test whether iterator is still at a range or done bool operator ()(void) const; /// Move iterator to next range (if possible) void operator ++(void); //@} /// \name Range access //@{ /// Return smallest value of range IntVal min(void) const; /// Return largest value of range IntVal max(void) const; /// Return width of range (distance between minimum and maximum) IntVal width(void) const; //@} }; inline Const::Const(IntVal min0, IntVal max0) : _min(min0), _max(max0), done(min0>max0) {} inline bool Const::operator ()(void) const { return !done; } inline void Const::operator ++(void) { done = true; } inline IntVal Const::min(void) const { return _min; } inline IntVal Const::max(void) const { return _max; } inline IntVal Const::width(void) const { if (min() > max()) return 0; if (min().isFinite() && max().isFinite()) return max()-min()+1; return IntVal::infinity(); } /** * \brief Range iterator for computing union (binary) * * \ingroup FuncIterRanges */ template class Union : public MinMax { protected: /// First iterator I i; /// Second iterator J j; public: /// \name Constructors and initialization //@{ /// Default constructor Union(void); /// Initialize with iterator \a i and \a j Union(I& i, J& j); /// Initialize with iterator \a i and \a j void init(I& i, J& j); //@} /// \name Iteration control //@{ /// Move iterator to next range (if possible) void operator ++(void); //@} }; /* * Binary union * */ template inline void Union::operator ++(void) { if (!i() && !j()) { finish(); return; } if (!i() || (j() && (j.max().plus(1) < i.min()))) { mi = j.min(); ma = j.max(); ++j; return; } if (!j() || (i() && (i.max().plus(1) < j.min()))) { mi = i.min(); ma = i.max(); ++i; return; } mi = std::min(i.min(),j.min()); ma = std::max(i.max(),j.max()); ++i; ++j; next: if (i() && (i.min() <= ma.plus(1))) { ma = std::max(ma,i.max()); ++i; goto next; } if (j() && (j.min() <= ma.plus(1))) { ma = std::max(ma,j.max()); ++j; goto next; } } template inline Union::Union(void) {} template inline Union::Union(I& i0, J& j0) : i(i0), j(j0) { operator ++(); } template inline void Union::init(I& i0, J& j0) { i = i0; j = j0; operator ++(); } /** * \brief Range iterator for computing intersection (binary) * * \ingroup FuncIterRanges */ template class Inter : public MinMax { protected: /// First iterator I i; /// Second iterator J j; public: /// \name Constructors and initialization //@{ /// Default constructor Inter(void); /// Initialize with iterator \a i and \a j Inter(I& i, J& j); /// Initialize with iterator \a i and \a j void init(I& i, J& j); //@} /// \name Iteration control //@{ /// Move iterator to next range (if possible) void operator ++(void); //@} }; /* * Binary intersection * */ template inline void Inter::operator ++(void) { if (!i() || !j()) goto done; do { while (i() && (i.max() < j.min())) ++i; if (!i()) goto done; while (j() && (j.max() < i.min())) ++j; if (!j()) goto done; } while (i.max() < j.min()); // Now the intervals overlap: consume the smaller interval ma = std::min(i.max(),j.max()); mi = std::max(i.min(),j.min()); if (i.max() < j.max()) ++i; else ++j; return; done: finish(); } template inline Inter::Inter(void) {} template inline Inter::Inter(I& i0, J& j0) : i(i0), j(j0) { operator ++(); } template inline void Inter::init(I& i0, J& j0) { i = i0; j = j0; operator ++(); } /** * \brief Range iterator for computing set difference * * \ingroup FuncIterRanges */ template class Diff : public MinMax { protected: /// Iterator from which to subtract I i; /// Iterator to be subtracted J j; public: /// \name Constructors and initialization //@{ /// Default constructor Diff(void); /// Initialize with iterator \a i and \a j Diff(I& i, J& j); /// Initialize with iterator \a i and \a j void init(I& i, J& j); //@} /// \name Iteration control //@{ /// Move iterator to next range (if possible) void operator ++(void); //@} }; template inline void Diff::operator ++(void) { // Precondition: mi <= ma // Task: find next mi greater than ma while (true) { if (!i()) break; mi = ma.plus(1); ma = i.max(); if (mi > i.max()) { ++i; if (!i()) break; mi = i.min(); ma = i.max(); } while (j() && (j.max() < mi)) ++j; if (j() && (j.min() <= ma)) { // Now the interval [mi ... ma] must be shrunken // Is [mi ... ma] completely consumed? if ((mi >= j.min()) && (ma <= j.max())) continue; // Does [mi ... ma] overlap on the left? if (j.min() <= mi) { mi = j.max().plus(1); // Search for max! ++j; if (j() && (j.min() <= ma)) ma = j.min().minus(1); } else { ma = j.min().minus(1); } } return; } finish(); } template inline Diff::Diff(void) {} template inline Diff::Diff(I& i0, J& j0) : i(i0), j(j0) { if (!i()) { finish(); } else { mi = i.min().minus(1); ma = mi; operator ++(); } } template inline void Diff::init(I& i0, J& j0) { i = i0; j = j0; if (!i()) { finish(); } else { mi = i.min().minus(1); ma = mi; operator ++(); } } /** * \brief Value iterator from range iterator * * \ingroup FuncIterValues */ template class ToValues { protected: /// Range iterator used I i; /// Current value IntVal cur; /// End of current range IntVal max; /// Initialize iterator void start(void); public: /// \name Constructors and initialization //@{ /// Default constructor ToValues(void); /// Initialize with values from range iterator \a i ToValues(I& i); /// Initialize with values from range iterator \a i void init(I& i); //@} /// \name Iteration control //@{ /// Test whether iterator is still at a value or done bool operator ()(void) const; /// Move iterator to next value (if possible) void operator ++(void); //@} /// \name Value access //@{ /// Return current value IntVal val(void) const; //@} }; template inline ToValues::ToValues(void) {} template inline void ToValues::start(void) { if (i()) { cur = i.min(); max = i.max(); } else { cur = 1; max = 0; } } template inline ToValues::ToValues(I& i0) : i(i0) { start(); } template inline void ToValues::init(I& i0) { i = i0; start(); } template inline bool ToValues::operator ()(void) const { return (cur <= max); } template inline void ToValues::operator ++(void) { ++cur; if (cur > max) { ++i; if (i()) { cur = i.min(); max = i.max(); } } } template inline IntVal ToValues::val(void) const { return cur; } /** * \defgroup FuncIterRangesOp Operations on range iterators * * \ingroup FuncIterRanges */ //@{ /// Size of all ranges of range iterator \a i template IntVal size(I& i); /// Check whether range iterators \a i and \a j are equal template bool equal(I& i, J& j); /// Check whether range iterator \a i is subset of range iterator \a j template bool subset(I& i, J& j); /// Check whether range iterators \a i and \a j are disjoint template bool disjoint(I& i, J& j); /// Comapre two iterators with each other enum CompareStatus { CS_SUBSET, ///< First is subset of second iterator CS_DISJOINT, ///< Intersection is empty CS_NONE ///< Neither of the above }; /// Check whether range iterator \a i is a subset of \a j, or whether they are disjoint template CompareStatus compare(I& i, J& j); //@} template inline IntVal size(I& i) { IntVal s = 0; while (i()) { if (i.width().isFinite()) { s += i.width(); ++i; } else { return IntVal::infinity(); } } return s; } template inline bool equal(I& i, J& j) { // Are i and j equal? while (i() && j()) if ((i.min() == j.min()) && (i.max() == j.max())) { ++i; ++j; } else { return false; } return !i() && !j(); } template inline bool subset(I& i, J& j) { // Is i subset of j? while (i() && j()) if (j.max() < i.min()) { ++j; } else if ((i.min() >= j.min()) && (i.max() <= j.max())) { ++i; } else { return false; } return !i(); } template inline bool disjoint(I& i, J& j) { // Are i and j disjoint? while (i() && j()) if (j.max() < i.min()) { ++j; } else if (i.max() < j.min()) { ++i; } else { return false; } return true; } template inline CompareStatus compare(I& i, J& j) { bool subset = true; bool disjoint = true; while (i() && j()) { if (j.max() < i.min()) { ++j; } else if (i.max() < j.min()) { ++i; subset = false; } else if ((i.min() >= j.min()) && (i.max() <= j.max())) { ++i; disjoint = false; } else if (i.max() <= j.max()) { ++i; disjoint = false; subset = false; } else if (j.max() <= i.max()) { ++j; disjoint = false; subset = false; } } if (i()) subset = false; if (subset) return CS_SUBSET; return disjoint ? CS_DISJOINT : CS_NONE; } template inline bool less(I& i, J& j) { while (i()) { if (!j()) return false; if (i.min() < j.min()) return true; if (i.min() > j.min()) return false; if (i.max() < j.max()) return true; if (i.max() > j.max()) return false; ++i; ++j; } if (j()) return true; return false; } template inline bool lessEq(I& i, J& j) { while (i()) { if (!j()) return false; if (i.min() < j.min()) return true; if (i.min() > j.min()) return false; if (i.max() < j.max()) return true; if (i.max() > j.max()) return false; ++i; ++j; } return true; } }} #endif libminizinc-2.0.11/include/minizinc/stl_map_set.hh0000644000175000017500000000144712646030173020646 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #include #ifdef MZN_NEED_TR1 #include #include #define HASH_NAMESPACE std::tr1 #define OPEN_HASH_NAMESPACE namespace std { namespace tr1 #define CLOSE_HASH_NAMESPACE } #define UNORDERED_NAMESPACE std::tr1 #else #include #include #define HASH_NAMESPACE std #define OPEN_HASH_NAMESPACE namespace std #define CLOSE_HASH_NAMESPACE #define UNORDERED_NAMESPACE std #endif libminizinc-2.0.11/include/minizinc/timer.hh0000644000175000017500000000310712646030173017447 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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 __MINIZINC_TIMER_HH__ #define __MINIZINC_TIMER_HH__ #ifdef _WIN32 #include #else #include #endif namespace MiniZinc { class Timer { protected: #ifdef _WIN32 LARGE_INTEGER time; LARGE_INTEGER freq; #else timeval time; #endif public: /// Construct timer Timer(void) { #ifdef _WIN32 QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&time); #else gettimeofday(&time, NULL); #endif } /// Reset timer void reset(void) { #ifdef _WIN32 QueryPerformanceCounter(&time); #else gettimeofday(&time, NULL); #endif } /// Return milliseconds since timer was last reset double ms(void) const { #ifdef _WIN32 LARGE_INTEGER now; QueryPerformanceCounter(&now); return (static_cast(now.QuadPart-time.QuadPart) / freq.QuadPart) * 1000.0; #else timeval now; gettimeofday(&now, NULL); timeval diff; diff.tv_sec = now.tv_sec - time.tv_sec; diff.tv_usec = now.tv_usec - time.tv_usec; if (diff.tv_usec < 0) { diff.tv_sec--; diff.tv_usec += 1000000; } return static_cast(diff.tv_sec) * 1000.0 + static_cast(diff.tv_usec) / 1000.0; #endif } }; } #endiflibminizinc-2.0.11/solns2out.cpp0000644000175000017500000003302212646030173015216 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace MiniZinc; using namespace std; std::string stoptime(Timer& timer) { std::ostringstream oss; oss << std::setprecision(0) << std::fixed << timer.ms() << " ms"; return oss.str(); } int main(int argc, char** argv) { Timer starttime; string filename; string flag_output_file; bool flag_output_comments = true; bool flag_output_flush = true; bool flag_output_time = false; string solfile; int flag_ignore_lines = 0; istream& solstream = cin; string solution_separator = "----------"; string solution_comma = ""; string unsatisfiable_msg = "=====UNSATISFIABLE====="; string unbounded_msg = "=====UNBOUNDED====="; string unknown_msg = "=====UNKNOWN====="; string search_complete_msg= "=========="; vector includePaths; string std_lib_dir; if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) { std_lib_dir = string(MZNSTDLIBDIR); } if (argc < 2) goto error; for (int i=1; i(), includePaths, false, false, false, std::cerr)) { try { std::vector typeErrors; Env env(outputm); MiniZinc::typecheck(env,outputm,typeErrors); MiniZinc::registerBuiltins(env,outputm); typedef pair DE; ASTStringMap::t declmap; Expression* outputExpr = NULL; for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*outputm)[i]->dyn_cast()) { declmap.insert(pair(vdi->e()->id()->v(),DE(vdi->e(),vdi->e()->e()))); } else if (OutputI* oi = (*outputm)[i]->dyn_cast()) { outputExpr = oi->e(); } } //ostream& fout(flag_output_file.empty() ? std::cout : new fstream(flag_output_file)); fstream file_ostream; if (!flag_output_file.empty()) file_ostream.open(flag_output_file.c_str(), std::fstream::out); ostream& fout = flag_output_file.empty() ? std::cout : file_ostream; int solutions_found = 0; string solution; string comments; for (;;) { if (solstream.good()) { string line; getline(solstream, line); if (flag_ignore_lines > 0) { flag_ignore_lines--; continue; } if (line=="----------") { ++solutions_found; if (flag_output_time) fout << "% time elapsed: " << stoptime(starttime) << "\n"; // Put the "solution comma" before the solution itself, // but only for solutions after the first one. if (solutions_found > 1 && !solution_comma.empty()) fout << solution_comma << std::endl; if (outputExpr != NULL) { for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*outputm)[i]->dyn_cast()) { ASTStringMap::t::iterator it = declmap.find(vdi->e()->id()->v()); vdi->e()->e(it->second.second); vdi->e()->evaluated(false); } } Model* sm = parseFromString(solution, "solution.szn", includePaths, true, false, false, cerr); for (unsigned int i=0; isize(); i++) { if (AssignI* ai = (*sm)[i]->dyn_cast()) { ASTStringMap::t::iterator it = declmap.find(ai->id()); if (it==declmap.end()) { cerr << "Error: unexpected identifier " << ai->id() << " in output\n"; exit(EXIT_FAILURE); } ai->e()->type(it->second.first->type()); ai->decl(it->second.first); typecheck(env,outputm, ai); if (Call* c = ai->e()->dyn_cast()) { // This is an arrayXd call, make sure we get the right builtin assert(c->args()[c->args().size()-1]->isa()); for (unsigned int i=0; iargs().size(); i++) c->args()[i]->type(Type::parsetint()); c->args()[c->args().size()-1]->type(it->second.first->type()); c->decl(outputm->matchFn(env.envi(),c)); } it->second.first->e(ai->e()); } } delete sm; GCLock lock; ArrayLit* al = eval_array_lit(env.envi(),outputExpr); std::string os; for (unsigned int i=0; iv().size(); i++) { std::string s = eval_string(env.envi(),al->v()[i]); if (!s.empty()) { os = s; fout << os; if (flag_output_flush) fout.flush(); } } if (!os.empty() && os[os.size()-1] != '\n') fout << std::endl; if (flag_output_flush) fout.flush(); } fout << comments; fout << solution_separator << std::endl; if (flag_output_flush) fout.flush(); solution = ""; comments = ""; } else if (line=="==========") { if (flag_output_time) fout << "% time elapsed: " << stoptime(starttime) << "\n"; fout << search_complete_msg << std::endl; if (flag_output_flush) fout.flush(); } else if(line=="=====UNSATISFIABLE=====") { if (flag_output_time) fout << "% time elapsed: " << stoptime(starttime) << "\n"; fout << unsatisfiable_msg << std::endl; if (flag_output_flush) fout.flush(); } else if(line=="=====UNBOUNDED=====") { if (flag_output_time) fout << "% time elapsed: " << stoptime(starttime) << "\n"; fout << unbounded_msg << std::endl; if (flag_output_flush) fout.flush(); } else if(line=="=====UNKNOWN=====") { if (flag_output_time) fout << "% time elapsed: " << stoptime(starttime) << "\n"; fout << unknown_msg << std::endl; if (flag_output_flush) fout.flush(); } else { solution += line+"\n"; size_t comment_pos = line.find('%'); if (comment_pos != string::npos) { comments += line.substr(comment_pos); comments += "\n"; } } } else { break; } } fout << comments; if (flag_output_flush) fout.flush(); } catch (LocationException& e) { std::cerr << e.what() << ": " << e.msg() << std::endl; std::cerr << e.loc() << std::endl; exit(EXIT_FAILURE); } catch (Exception& e) { std::cerr << e.what() << ": " << e.msg() << std::endl; exit(EXIT_FAILURE); } delete outputm; } } return 0; error: std::cerr << "Usage: "<< argv[0] << " [] .ozn" << std::endl << std::endl << "Options:" << std::endl << " --help, -h\n Print this help message." << std::endl << " --version\n Print version information." << std::endl << " -o , --output-to-file \n Filename for generated output." << std::endl << " --stdlib-dir \n Path to MiniZinc standard library directory." << std::endl << " --no-output-comments\n Do not print comments in the FlatZinc solution stream." << std::endl << " --output-time\n Print timing information in the FlatZinc solution stream." << std::endl << " --no-flush-output\n Don't flush output stream after every line." << std::endl << " -i , --ignore-lines , --ignore-leading-lines \n Ignore the first lines in the FlatZinc solution stream." << std::endl << " --soln-sep , --soln-separator , --solution-separator \n Specify the string printed after each solution.\n The default is to use the same as FlatZinc,\n \"----------\"." << std::endl << " --soln-comma , --solution-comma \n Specify the string used to separate solutions.\n The default is the empty string." << std::endl << " --unsat-msg , --unsatisfiable-msg \n Specify the message to print if the model instance is\n unsatisfiable.\n The default is to print \"=====UNSATISFIABLE=====\"." << std::endl << " --unbounded-msg \n Specify the message to print if the objective of the\n model instance is unbounded.\n The default is to print \"=====UNBOUNDED=====\"." << std::endl << " --unknown-msg \n Specify the message to print if search terminates without\n the entire search space having been explored and no\n solution has been found.\n The default is to print \"=====UNKNOWN=====\"." << std::endl << " --search-complete-msg \n Specify the message to print if search terminates having\n explored the entire search space.\n The default is to print \"==========\"." << std::endl ; exit(EXIT_FAILURE); } libminizinc-2.0.11/LICENSE.txt0000644000175000017500000004131312646030173014367 0ustar kaolkaolIf not noted otherwise in individual file headers, all files that make up the libminizinc distribution are released under the Mozilla Public License Version 2.0, a copy of which can be found below. A notable exception is the file include/minizinc/thirdparty/SafeInt3.hpp which is distributed under the Microsoft Public License (Ms-PL), see the file header for details. Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- 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/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. libminizinc-2.0.11/doc/0000755000175000017500000000000012646732517013322 5ustar kaolkaollibminizinc-2.0.11/doc/spec/0000755000175000017500000000000012646030173014241 5ustar kaolkaollibminizinc-2.0.11/doc/spec/minizinc-spec.tex0000644000175000017500000055133512646030173017547 0ustar kaolkaol\documentclass[10pt]{scrartcl} \usepackage[paper=a4paper,margin=1.2cm]{geometry} \usepackage[colorlinks=true,linkcolor=black]{hyperref} \usepackage{fancyvrb} %---------------------------------------------------------------------------% % \comment{} provides a mechanism for people to make comments about this % document. For comments that have been resolved, but we want to keep a % record of the reasoning behind the decision, we have \resolvedcomment{}. % % Set these macros to 'true' or 'false' to control whether (a) unresolved % comments are shown, and (b) resolved-but-kept comments are shown. % \newcommand{\pjs}[1]{\textcolor{blue}{PJS:#1}} \newcommand{\gt}[1]{\textcolor{green}{GT:#1}} \newcommand{\showcomments}{true} \newcommand{\showresolvedcomments}{false} %\newcommand{\showcomments}{false} %\newcommand{\showcomments}{true} \newcommand{\ignore}[1]{} %---------------------------------------------------------------------------% \input{common-spec.tex} \input{version.tex} %-----------------------------------------------------------------------------% \newcommand{\underscore}{\texttt{\n{}}} %-----------------------------------------------------------------------------% \newcommand{\TyThing}[1]{\vspace{1.2mm}\noindent\emph{#1} } \newcommand{\TyOverview}{\TyThing{Overview.}} \newcommand{\TyInsts}{\TyThing{Allowed Insts.}} \newcommand{\TySyntax}{\TyThing{Syntax.}} \newcommand{\TyFiniteType}{\TyThing{Finite?}} \newcommand{\TyVarifiable}{\TyThing{Varifiable?}} \newcommand{\TyOrdering}{\TyThing{Ordering.}} \newcommand{\TyInit}{\TyThing{Initialisation.}} \newcommand{\TyCoercions}{\TyThing{Coercions.}} \newcommand{\coerce}[2]{#1 $\stackrel{c}{\rightarrow}$ #2} \newcommand{\varify}[2]{#1 $\stackrel{v}{\rightarrow}$ #2} \newcommand{\vblabel}[1] {\large\textbf{#1}} \newcommand{\vbcmd} {>} \newcommand{\vbout} {\slshape} \DefineVerbatimEnvironment{Zinc}{Verbatim} {samepage,frame=single,framesep=0.25em,xleftmargin=0.15em,xrightmargin=0.15em} \DefineVerbatimEnvironment{Shell}{Verbatim} {xleftmargin=0.15em,commandchars=\\\{\}} \title{\textbf{Specification of MiniZinc}} \author{The MiniZinc Team\\[2ex] NICTA, Victoria Research Lab, Melbourne, Australia} % Original authors: % Nicholas Nethercote, Kim Marriott, Reza Rafeh, Mark Wallace % and Maria Garcia de la Banda \date{November 2015\\ {\small (MiniZinc version \mznversion)}} \sloppy \pagestyle{plain} \begin{document} \maketitle \thispagestyle{empty} %---------------------------------------------------------------------------% % The grammar %---------------------------------------------------------------------------% % We define the productions here so they can appear twice in the text -- % once in the appropriate section, and again when the whole grammar is % presented in the appendix. They're listed here in the same order as in % the appendix. %---------------------------------------------------------------------------% % Items %---------------------------------------------------------------------------% \newcommand{\RuleModel}{ \production{model} \maybe{\semicolons{\nt{item}}} } \newcommand{\RuleItem}{ \production{item} % \nt{type-inst-syn-item} %\alt\nt{enum-item} %\alt \nt{include-item} \alt\nt{var-decl-item} \alt\nt{assign-item} \alt\nt{constraint-item} \alt\nt{solve-item} \alt\nt{output-item} \alt\nt{predicate-item} \alt\nt{test-item} \alt\nt{function-item} \alt\nt{annotation-item} } \newcommand{\RuleTypeInstSynItem}{ \production{type-inst-syn-item} \term{type} \nt{ident} \nt{annotations} \term{=} \nt{ti-expr} % Undefined types are currently not implemented. % \term{type} \nt{ident} \maybe{\term{=} \nt{ti-expr}} } \newcommand{\RuleEnumItem}{ \production{enum-item} \term{enum} \nt{ident} \nt{annotations} \maybe{\term{=} \nt{enum-cases}} } \newcommand{\RuleEnumCases}{ \production{enum-cases} \curlies{\commas{\nt{enum-case}}} } \newcommand{\RuleEnumCase}{ \production{enum-case} \nt{ident} \maybe{\parens{\commas{\nt{ti-expr-and-id}}}} } \newcommand{\RuleIncludeItem}{ \production{include-item} \term{include} \nt{string-literal} } \newcommand{\RuleVarDeclItem}{ \production{var-decl-item} \nt{ti-expr-and-id} \nt{annotations} \maybe{\term{=} \nt{expr}} } \newcommand{\RuleAssignItem}{ \production{assign-item} \nt{ident} \term{=} \nt{expr} } \newcommand{\RuleConstraintItem}{ \production{constraint-item} \term{constraint} \nt{expr} } \newcommand{\RuleSolveItem}{ \production{solve-item} \term{solve} \nt{annotations} \term{satisfy} \alt\term{solve} \nt{annotations} \term{minimize} \nt{expr} \alt\term{solve} \nt{annotations} \term{maximize} \nt{expr} } \newcommand{\RuleOutputItem}{ \production{output-item} \term{output} \nt{expr} } \newcommand{\RuleAnnotationItem}{ \production{annotation-item} \term{annotation} \nt{ident} \nt{params} } \newcommand{\RulePredicateItem}{ \production{predicate-item} \term{predicate} \nt{operation-item-tail} } \newcommand{\RuleTestItem}{ \production{test-item} \term{test} \nt{operation-item-tail} } \newcommand{\RuleFunctionItem}{ \production{function-item} \term{function} \nt{ti-expr} \term{:} \nt{operation-item-tail} } \newcommand{\RuleOperationItemTail}{ \production{operation-item-tail} \nt{ident} \nt{params} \nt{annotations} \maybe{\term{=} \nt{expr}} } \newcommand{\RuleParams}{ \production{params} \maybe{\parens{\commas{\nt{ti-expr-and-id}}}} } \newcommand{\RuleTIExprAndId}{ \production{ti-expr-and-id} \nt{ti-expr} \term{:} \nt{ident} } %---------------------------------------------------------------------------% % Type-insts %---------------------------------------------------------------------------% \newcommand{\RuleTIExpr}{ \production{ti-expr} % \parens{\nt{ti-expr} \term{:} \nt{ident} \term{where} \nt{expr}} %\alt \nt{base-ti-expr} } \newcommand{\RuleVarPar}{ \production{var-par} \term{var} \altB \term{par} \altB \ensuremath{\epsilon} } \newcommand{\RuleBaseTIExpr}{ \production{base-ti-expr} \nt{var-par} \nt{base-ti-expr-tail} } \newcommand{\RuleBaseTIExprTail}{ \production{base-ti-expr-tail} \nt{ident} \alt\term{bool} \alt\term{int} \alt\term{float} \alt\term{string} \alt\nt{set-ti-expr-tail} \alt\nt{array-ti-expr-tail} %\alt\nt{tuple-ti-expr-tail} %\alt\nt{record-ti-expr-tail} %\alt\nt{ti-variable-expr-tail} \alt\term{ann} \alt\term{opt} \nt{base-ti-expr-tail} %\alt\nt{op-ti-expr-tail} \alt\curlies{\commas{\nt{expr}}} \alt\dotdotXX{\nt{num-expr}} } \newcommand{\RuleTIVariableExprTail}{ \production{ti-variable-expr-tail} %\maybe{\term{any}} \regexp{\$[A-Za-z][A-Za-z0-9\n{}]*} } \newcommand{\RuleSetTIExprTail}{ \production{set-ti-expr-tail} \term{set} \term{of} \nt{base-type} } \newcommand{\RuleArrayTIExprTail}{ \production{array-ti-expr-tail} \term{array} \squares{\commas{\nt{ti-expr}}} \term{of} \nt{ti-expr} \alt\term{list} \term{of} \nt{ti-expr} } \newcommand{\RuleTupleTIExprTail}{ \production{tuple-ti-expr-tail} \term{tuple} \parens{\commas{\nt{ti-expr}}} } \newcommand{\RuleRecordTIExprTail}{ \production{record-ti-expr-tail} \term{record} \parens{\commas{\nt{ti-expr-and-id}}} } \newcommand{\RuleOpTIExprTail}{ \production{op-ti-expr-tail} \term{op} \parens{\nt{ti-expr} \term{:} \parens{\commas{\nt{ti-expr}}}} } %---------------------------------------------------------------------------% % Expressions %---------------------------------------------------------------------------% \newcommand{\RuleExpr}{ \production{expr} \nt{expr-atom} \nt{expr-binop-tail} } \newcommand{\RuleNumExpr}{ \production{num-expr} \nt{num-expr-atom} \nt{num-expr-binop-tail} } \newcommand{\RuleExprAtom}{ \production{expr-atom} \nt{expr-atom-head} \nt{expr-atom-tail} \nt{annotations} } \newcommand{\RuleNumExprAtom}{ \production{num-expr-atom} \nt{num-expr-atom-head} \nt{expr-atom-tail} \nt{annotations} } \newcommand{\RuleExprBinopTail}{ \production{expr-binop-tail} \maybe{\nt{bin-op} \nt{expr}} } \newcommand{\RuleNumExprBinopTail}{ \production{num-expr-binop-tail} \maybe{\nt{num-bin-op} \nt{num-expr}} } \newcommand{\RuleExprAtomHead}{ \production{expr-atom-head} \nt{builtin-un-op} \nt{expr-atom} \alt\parens{\nt{expr}} \alt\nt{ident-or-quoted-op} \alt\term{\underscore} \alt\nt{bool-literal} \alt\nt{int-literal} \alt\nt{float-literal} \alt\nt{string-literal} \alt\nt{set-literal} \alt\nt{set-comp} \alt\nt{simple-array-literal} \alt\nt{simple-array-literal-2d} \alt\nt{indexed-array-literal} \alt\nt{simple-array-comp} \alt\nt{indexed-array-comp} %\alt\nt{tuple-literal} %\alt\nt{record-literal} %\alt\nt{enum-literal} \alt\nt{ann-literal} \alt\nt{if-then-else-expr} %\alt\nt{case-expr} \alt\nt{let-expr} \alt\nt{call-expr} \alt\nt{gen-call-expr} } \newcommand{\RuleNumExprAtomHead}{ \production{num-expr-atom-head} \nt{builtin-num-un-op} \nt{num-expr-atom} \alt\parens{\nt{num-expr}} \alt\nt{ident-or-quoted-op} \alt\nt{int-literal} \alt\nt{float-literal} \alt\nt{if-then-else-expr} \alt\nt{case-expr} \alt\nt{let-expr} \alt\nt{call-expr} \alt\nt{gen-call-expr} } \newcommand{\RuleExprAtomTail}{ \production{expr-atom-tail} \ensuremath{\epsilon} \alt\nt{array-access-tail} \nt{expr-atom-tail} %\alt\nt{tuple-access-tail} \nt{expr-atom-tail} %\alt\nt{record-access-tail} \nt{expr-atom-tail} } \newcommand{\RuleBuiltinOp}{ \production{builtin-op} \nt{builtin-bin-op} \alt\nt{builtin-un-op} } \newcommand{\RuleBinOp}{ \production{bin-op} \nt{builtin-bin-op} \alt\term{`}\nt{ident}\term{`} } \newcommand{\RuleNumBinOp}{ \production{num-bin-op} \nt{builtin-num-bin-op} \alt\term{`}\nt{ident}\term{`} } \newcommand{\RuleBuiltinBinOp}{ \production{builtin-bin-op} \term{<->} \altB\term{->} \altB\term{<-} \altB \term{\backsl{}/} \altB\term{xor} \altB\term{/\backsl{}} \alt\term{<} \altB \term{>} \altB \term{<=} \altB \term{>=} \altB \term{==} \altB \term{=} \altB \term{!=} \alt\term{in} \altB \term{subset} \altB \term{superset} \altB \term{union} \altB \term{diff} \altB \term{symdiff} \alt\term{..} \altB \term{intersect}\altB \term{++} \altB \nt{builtin-num-bin-op} } \newcommand{\RuleBuiltinNumBinOp}{ \production{builtin-num-bin-op} \term{+} \altB \term{-} \altB \term{*} \altB \term{/} \altB \term{div} \altB \term{mod} } \newcommand{\RuleBuiltinUnOp}{ \production{builtin-un-op} \term{not} \altB \nt{builtin-num-un-op} } \newcommand{\RuleBuiltinNumUnOp}{ \production{builtin-num-un-op} \term{+} \altB \term{-} } \newcommand{\RuleBoolLiteral}{ \production{bool-literal} \term{false} \altB \term{true} } \newcommand{\RuleIntLiteral}{ \production{int-literal} \regexp{[0-9]+} \alt\regexp{0x[0-9A-Fa-f]+} \alt\regexp{0o[0-7]+} } \newcommand{\RuleFloatLiteral}{ \production{float-literal} \regexp{[0-9]+.[0-9]+} \alt\regexp{[0-9]+.[0-9]+[Ee][-+]?[0-9]+} \alt\regexp{[0-9]+[Ee][-+]?[0-9]+} } \newcommand{\RuleStringLiteral}{ \production{string-contents} \regexp{([\carat{}"\backsl{}n\term{\backsl{}}] | \term{\backsl{}}[\carat{}\backsl{}n\term{(}])*}\\\\ \production{string-literal} \regexp{"}\nt{string-contents}\regexp{"} \alt\regexp{"}\nt{string-contents}\regexp{\term{\backsl{}}\term{(}} \nt{string-interpolate-tail}\\\\ \production{string-interpolate-tail} \nt{expr} \regexp{\term{)}}\nt{string-contents}\regexp{"} \alt\nt{expr} \regexp{\term{)}}\nt{string-contents}\regexp{\term{\backsl{}}\term{(}} \nt{string-interpolate-tail} } \newcommand{\RuleSetLiteral}{ \production{set-literal} \curlies{\maybe{\commas{\nt{expr}}}} } \newcommand{\RuleSetComp}{ \production{set-comp} \curlies{\nt{expr} \term{\bar} \nt{comp-tail}} } \newcommand{\RuleCompTail}{ \production{comp-tail} \commas{\nt{generator}} \maybe{\term{where} \nt{expr}} } \newcommand{\RuleGenerator}{ \production{generator} \commas{\nt{ident}} \term{in} \nt{expr} } \newcommand{\RuleSimpleArrayLiteral}{ \production{array-literal} \squares{\maybe{\commas{\nt{expr}}}} } \newcommand{\RuleSimpleArrayLiteralTwoD}{ \production{array-literal-2d} \squaresPipes{\maybe{\pipes{(\commas{\nt{expr}})}}} } \newcommand{\RuleSimpleArrayComp}{ \production{array-comp} \squares{\nt{expr} \term{\bar} \nt{comp-tail}} } \newcommand{\RuleIndexedArrayLiteral}{ \production{indexed-array-literal} \squares{\maybe{\commas{\nt{index-expr}}}} } \newcommand{\RuleIndexExpr}{ \production{index-expr} \nt{expr} \term{:} \nt{expr} } \newcommand{\RuleIndexedArrayComp}{ \production{indexed-array-comp} \squares{\nt{index-expr} \term{\bar} \nt{comp-tail}} } \newcommand{\RuleArrayAccessTail}{ \production{array-access-tail} \squares{\commas{\nt{expr}}} } \newcommand{\RuleTupleLiteral}{ \production{tuple-literal} \parens{\commas{\nt{expr}}} } \newcommand{\RuleTupleAccessTail}{ \production{tuple-access-tail} \term{.} \nt{int-literal} } \newcommand{\RuleRecordLiteral}{ \production{record-literal} \parens{\commas{\nt{named-expr}}} } \newcommand{\RuleNamedExpr}{ \production{named-expr} \nt{ident} \term{:} \nt{expr} } \newcommand{\RuleRecordAccessTail}{ \production{record-access-tail} \term{.} \nt{ident} } \newcommand{\RuleEnumLiteral}{ \production{enum-literal} \nt{ident} \parens{\commas{\nt{named-expr}}} \alt\nt{ident} \parens{\commas{\nt{expr}}} \alt\nt{ident} } \newcommand{\RuleAnnLiteral}{ \production{ann-literal} \nt{ident} \maybe{\parens{\commas{\nt{expr}}}} } \newcommand{\RuleIfThenElseExpr}{ \production{if-then-else-expr} \term{if} \nt{expr} \term{then} \nt{expr} \spl \zeroOrMore{\term{elseif} \nt{expr} \term{then} \nt{expr}} \spl \term{else} \nt{expr} \term{endif} } \newcommand{\RuleCaseExpr}{ \production{case-expr} \term{case} \nt{expr} \curlies{\commas{\nt{case-expr-case}}} } \newcommand{\RuleCaseExprCase}{ \production{case-expr-case} \nt{ident} \term{-->} \nt{expr} } \newcommand{\RuleCallExpr}{ \production{call-expr} \nt{ident-or-quoted-op} \maybe{\parens{\commas{\nt{expr}}}} } \newcommand{\RuleLetExpr}{ \production{let-expr} \term{let} \curlies{\semicolons{\nt{let-item}}} \term{in} \nt{expr} } \newcommand{\RuleLetItem}{ \production{let-item} \nt{var-decl-item} \alt\nt{constraint-item} } \newcommand{\RuleGenCallExpr}{ \production{gen-call-expr} \nt{ident-or-quoted-op} \parens{\nt{comp-tail}} \parens{\nt{expr}} } %---------------------------------------------------------------------------% % Repeated elements %---------------------------------------------------------------------------% \newcommand{\RuleIdent}{ \production{ident} \regexp{[A-Za-z][A-Za-z0-9\n{}]*} \quad\% excluding keywords } \newcommand{\RuleIdentOrQuotedOp}{ \production{ident-or-quoted-op} \nt{ident} \alt\term{'}\nt{builtin-op}\term{'} } \newcommand{\RuleAnnotations}{ \production{annotations} \zeroOrMore{\term{::} \nt{annotation}} } \newcommand{\RuleAnnotation}{ \production{annotation} \nt{expr-atom-head} \nt{expr-atom-tail} } %---------------------------------------------------------------------------% % Output format %---------------------------------------------------------------------------% \newcommand{\RuleOutput}{ \production{output} \nt{no-solutions} \maybe{\nt{warnings}} \nt{free-text} \alt \zeroOrMore{\nt{solution}} \maybe{\nt{complete}} \maybe{\nt{warnings}} \nt{free-text} } %\newcommand{\RuleOutcome}{ %\production{outcome} % \nt{no-solutions} \alt % \nt{no-more-solutions} \alt % \nt{no-better-solutions} %} %\newcommand{\RuleCompleteness}{ %\production{completeness} % \nt{complete} \altB \nt{incomplete} %} \newcommand{\RuleSolution}{ \production{solution} \nt{solution-text} \maybe{\nl} \term{----------} ~\nl } \newcommand{\RuleOutcomeStrings}{ \production{no-solutions} ~\texttt{=====UNSATISFIABLE=====} ~\nl } \newcommand{\RuleComplete}{ \production{complete} \texttt{==========} ~\nl } %\newcommand{\RuleIncomplete}{ %\production{incomplete} % \texttt{Search incomplete:} ~\nl~ \oneOrMore{\nt{message}} %} \newcommand{\RuleWarnings}{ \production{warnings} \oneOrMore{\nt{message}} } \newcommand{\RuleMessage}{ \production{message} \oneOrMore{\nt{line}} \\ \production{line} \texttt{\%} \regexp{[\carat{}\backsl{}n]*} ~\nl } \setcounter{tocdepth}{2} \pagebreak \tableofcontents \pagebreak %===========================================================================% \section{Introduction} %===========================================================================% This document defines MiniZinc, a language for modelling constraint satisfaction and optimisation problems. MiniZinc is a high-level, typed, mostly first-order, functional, modelling language. It provides: \begin{itemize} \item mathematical notation-like syntax (automatic coercions, overloading, iteration, sets, arrays); \item expressive constraints (finite domain, set, linear arithmetic, integer); \item support for different kinds of problems (satisfaction, explicit optimisation); \item separation of data from model; %\item high-level data structures and data encapsulation (sets, % arrays, tuples, records, enumerated types, constrained type-insts); \item extensibility (user-defined functions and predicates); \item reliability (type checking, instantiation checking, assertions); \item solver-independent modelling; \item simple, declarative semantics. \end{itemize} MiniZinc is similar to OPL and moves closer to CLP languages such as ECLiPSe. This document has the following structure. Section~\ref{Syntax Notation} introduces the syntax notation used throughout the specification. Section~\ref{Overview} provides a high-level overview of MiniZinc models. Section~\ref{Syntax Overview} covers syntax basics. Section~\ref{High-level Model Structure} covers high-level structure: items, multi-file models, namespaces, and scopes. Section~\ref{Types} introduces types and type-insts. Section~\ref{Expressions} covers expressions. Section~\ref{Items} describes the top-level items in detail. Section~\ref{Annotations} describes annotations. Section~\ref{Partiality} describes how partiality is handled in various cases. Appendix~\ref{builtins} describes the language built-ins. % The following two appendices are commented out. %Appendix~\ref{Libraries} describes some language libraries. %Appendix~\ref{Standard Annotations} describes the standard language annotations. Appendix~\ref{Grammar} gives the MiniZinc grammar. %Appendix~\ref{MiniZinc} gives the definition of MiniZinc. Appendix~\ref{Content-types} defines content-types used in this specification. This document also provides some explanation of why certain design decisions were made. Such explanations are marked by the word ``Rationale'' and written in italics, and do not constitute part of the specification as such. \Rationale{These explanations are present because they are useful to both the designers and the users of MiniZinc.} \paragraph{Original authors.} The original version of this document was prepared by Nicholas Nethercote, Kim Marriott, Reza Rafeh, Mark Wallace and Mar\'{\i}a Garc\'{\i}a de la Banda. MiniZinc is evolving, however, and so is this document. For a formally published paper on the MiniZinc language and the superset Zinc language , please see: \ N.~Nethercote, P.J. Stuckey, R.~Becket, S.~Brand, G.J. Duck, and G.~Tack. Minizinc: Towards a standard {CP} modelling language. In C.~Bessiere, editor, {\em Proceedings of the 13th International Conference on Principles and Practice of Constraint Programming}, volume 4741 of {\em LNCS}, pages 529--543. Springer-Verlag, 2007. K.~Marriott, N.~Nethercote, R.~Rafeh, P.J.~Stuckey, M.~Garc\'{\i}a de la Banda, and M.~Wallace. The Design of the Zinc Modelling Language. \emph{Constraints}, 13(3):229-267, 2008. %===========================================================================% \section{Notation} \label{Syntax Notation} %===========================================================================% The basics of the EBNF used in this specification are as follows. \CommonEBNFBasics{sep/term} MiniZinc's grammar is presented piece-by-piece throughout this document. It is also available as a whole in Appendix~\ref{Grammar}. The output grammar also includes some details of the use of whitespace. The following conventions are used: \begin{itemize} \item A newline character or CRLF sequence is written \nl. \item A sequence of space characters of length $n$ is written \spc{$n$}, e.g., \spc{2}. \end{itemize} %===========================================================================% \section{Overview of a Model} \label{Overview} %===========================================================================% %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% \CommonTwoConceptualParts{MiniZinc} {The model and data may be separated, or the data may be ``hard-wired'' into the model.} There are two broad classes of problems: satisfaction and optimisation. In satisfaction problems all solutions are considered equally good, whereas in optimisation problems the solutions are ordered according to an objective and the aim is to find a solution whose objective is optimal. Section~\ref{Solve Items} specifies how the class of problem is chosen. %---------------------------------------------------------------------------% \subsection{Evaluation Phases} %---------------------------------------------------------------------------% %\pjs{Remove the 3 evaluation phases, make it two!} A MiniZinc model instance is evaluated in two distinct phases. \begin{enumerate} \item Instance-time: static checking of the model instance. \item Run-time: evaluation of the instance (i.e.~constraint solving). \end{enumerate} % The model instance may not compile due to a problem with the model and/or data, detected at instance-time. This could be caused by a syntax error, a type-inst error, the use of an unsupported feature or operation, etc. In this case the outcome of evaluation is a static error; this must be reported prior to run-time. The form of output for static errors is implementation-dependent, although such output should be easily recognisable as a static error. An implementation may produce warnings during all evaluation phases. For example, an implementation may be able to determine that unsatisfiable constraints exist prior to run-time, and the resulting warning given to the user may be more helpful than if the unsatisfiability is detected at run-time. An implementation must produce a warning if the objective for an optimisation problem is unbounded. %---------------------------------------------------------------------------% \subsection{Run-time Outcomes} \label{Run-time Outcomes} %---------------------------------------------------------------------------% Assuming there are no static errors, the output from the run-time phase has the following abstract form: \begin{productions} \RuleOutput \end{productions} If a solution occurs in the output then it must be feasible. For optimisation problems, each solution must be strictly better than any preceding solution. If there are no solutions in the output, the outcome must indicate that there are no solutions. If the search is complete the output may state this after the solutions. The absence of the completness message indicates that the search is incomplete. Any warnings produced during run-time must be summarised after the statement of completeness. In particular, if there were any warnings at all during run-time then the summary must indicate this fact. The implementation may produce text in any format after the warnings. For example, it may print a summary of benchmarking statistics or resources used. %---------------------------------------------------------------------------% \subsection{Output} \label{Output} %---------------------------------------------------------------------------% % \pjs{Needs a total reworking for MiniZinc!} Implementations must be capable of producing output of content type `application/x-zinc-output', which is described below and also in Appendix~\ref{Content-types}. Implementations may also produce output in alternative formats. Any output should conform to the abstract format from the previous section and must have the semantics described there. Content type `application/x-zinc-output' extends the syntax from the previous section as follows: \begin{productions} \RuleSolution \end{productions} \noindent The solution text for each solution must be as described in Section~\ref{Output Items}. A newline must be appended if the solution text does not end with a newline. \Rationale{This allows solutions to be extracted from output without necessarily knowing how the solutions are formatted.} Solutions end with a sequence of ten dashes followed by a newline. \begin{productions} \RuleOutcomeStrings \end{productions} \noindent The completness result is printed on a separate line. \Rationale{The strings are designed to clearly indicate the end of the solutions.} \begin{productions} \RuleComplete \end{productions} \noindent If the search is complete, a statement corresponding to the outcome is printed. For an outcome of no solutions the statement is that the model instance is unsatisfiable, for an outcome of no more solutions the statement is that the solution set is complete, and for an outcome of no better solutions the statement is that the last solution is optimal. \Rationale{These are the logical implications of a search being complete.} \begin{productions} \RuleWarnings \\ \\ \RuleMessage \end{productions} \noindent If the search is incomplete, one or more messages describing reasons for incompleteness may be printed. Likewise, if any warnings occurred during search they are repeated after the completeness message. Both kinds of message should have lines that start with \texttt{\%} so they are recognized as comments by post-processing. \Rationale{This allows individual messages to be easily recognised.} For example, the following may be output for an optimisation problem: \begin{verbatim} =====UNSATISFIABLE===== % trentin.fzn:4: warning: model inconsistency detected before search. \end{verbatim} \noindent Note that, as in this case, an unbounded objective is not regarded as a source of incompleteness. %===========================================================================% \section{Syntax Overview} \label{Syntax Overview} %===========================================================================% \CommonCharacterSetAndComments{MiniZinc} %---------------------------------------------------------------------------% \subsection{Identifiers} \label{Identifiers} %---------------------------------------------------------------------------% Identifiers have the following syntax: \begin{productions} \RuleIdent \end{productions} For example: \begin{verbatim} my_name_2 MyName2 \end{verbatim} A number of keywords are reserved and cannot be used as identifiers. The keywords are: \reservedKeywords{} A number of identifiers are used for built-ins; see Section~\ref{builtins} for details. %===========================================================================% \section{High-level Model Structure} \label{High-level Model Structure} %===========================================================================% %---------------------------------------------------------------------------% \subsection{Items} %---------------------------------------------------------------------------% A MiniZinc model consists of multiple \emph{items}: \begin{productions} \RuleModel \end{productions} Items can occur in any order; identifiers need not be declared before they are used. Items have the following top-level syntax: \begin{productions} \RuleItem \end{productions} %Type-inst synonym items and enumerated type items define new types. Include items provide a way of combining multiple files into a single instance. This allows a model to be split into multiple files (Section~\ref{Include Items}). Variable declaration items introduce new global variables and possibly bind them to a value (Section~\ref{Declarations}). Assignment items bind values to global variables (Section~\ref{Assignments}). Constraint items describe model constraints (Section~\ref{Constraint Items}). Solve items are the ``starting point'' of a model, and specify exactly what kind of solution is being looked for: plain satisfaction, or the minimization/maximization of an expression. Each model must have exactly one solve item (Section~\ref{Solve Items}). Output items are used for nicely presenting the result of a model execution (Section~\ref{Output Items}). %\emph{Note:} models to be converted to FlatZinc should use the built-in %{\tt is\_output} annotation on variables rather than an output item. %If an output item is provided, then the corresponding FlatZinc model %should have output annotations placed on the variables appearing in the %original output item. Predicate items, test items (which are just a special type of predicate) and function items introduce new user-defined predicates and functions which can be called in expressions (Section~\ref{preds and fns}). Predicates, functions, and built-in operators are described collectively as \emph{operations}. Annotation items augment the \texttt{ann} type, values of which can specify non-declarative and/or solver-specific information in a model. %---------------------------------------------------------------------------% \subsection{Model Instance Files} \label{Model Instance Files} %---------------------------------------------------------------------------% MiniZinc models can be constructed from multiple files using include items (see Section~\ref{Include Items}). MiniZinc has no module system as such; all the included files are simply concatenated and processed as a whole, exactly as if they had all been part of a single file. \Rationale{We have not found much need for one so far. If bigger models become common and the single global namespace becomes a problem, this should be reconsidered.} Each model may be paired with one or more data files. Data files are more restricted than model files. They may only contain variable assignments (see Section~\ref{Assignments}). Data files may not include calls to user-defined operations. Models do not contain the names of data files; doing so would fix the data file used by the model and defeat the purpose of allowing separate data files. Instead, an implementation must allow one or more data files to be combined with a model for evaluation via a mechanism such as the command-line. %An implementation should allow a model to be checked with and without its %instance data. When checking a model without data, all global variables %with fixed type-insts need not be assigned. When checking a model with data, all global variables with fixed type-insts must be assigned, unless they are not used (in which case they can be removed from the model without effect). A data file can only be checked for static errors in conjunction with a model, since the model contains the declarations that include the types of the variables assigned in the data file. A single data file may be shared between multiple models, so long as the definitions are compatible with all the models. %---------------------------------------------------------------------------% \subsection{Namespaces} \label{Namespaces} %---------------------------------------------------------------------------% All names declared at the top-level belong to a single namespace. It includes the following names. \begin{enumerate} \item All global variable names. \item All function and predicate names, both built-in and user-defined. %\item All user-defined type and type-inst names (type-inst synonyms and % enumerated types). %\item All enum case names. \item All annotation names. \end{enumerate} Because multi-file MiniZinc models are composed via concatenation (Section~\ref{Model Instance Files}), all files share this top-level namespace. Therefore a variable \texttt{v} declared in one model file could not be declared with a different type in a different file, for example. MiniZinc supports overloading of built-in and user-defined operations. %MiniZinc has two kinds of local namespace: each record and (non-flat) enum %has its own local namespace for field names. This means distinct %records and (non-flat) enums can use the same field names. All names %in these local namespaces co-exist without conflict with identical names in %the top-level namespace---in any situation, which namespace applies can %always be determined from context. %---------------------------------------------------------------------------% \subsection{Scopes} \label{Scopes} %---------------------------------------------------------------------------% Within the top-level namespace, there are several kinds of local scope that introduce local names: \begin{itemize} \item Comprehension expressions (Section~\ref{Set Comprehensions}). \item Let expressions (Section~\ref{Let Expressions}). \item Function and predicate argument lists and bodies (Section~\ref{preds and fns}). %\item Type-inst constraints (Section~\ref{Arbitrarily Constrained % Type-insts}). \end{itemize} The listed sections specify these scopes in more detail. In each case, any names declared in the local scope overshadow identical global names. %===========================================================================% \section{Types and Type-insts} \label{Types} %===========================================================================% MiniZinc provides four scalar built-in types: Booleans, integers, floats, and strings; several compound built-in types: sets, multi-dimensional arrays; %with arbitrary index types, tuples, and records; and three kinds of %user-defined annotation types: type-inst synonyms, enumerated types, and \texttt{ann}, %a user-extensible type that represents annotations. and the user extensible annotation type \texttt{ann}. %Zinc also allows %type-inst variables in certain places, and has some very limited %higher-order types. \CommonInstantiationTypeInstDescription{} %Zinc also supports \emph{constrained type-insts}, which are type-insts %with an additional expression that constrains their possible values. We begin by discussing some properties that apply to every type. We then introduce instantiations in more detail. We then cover each type individually, giving: an overview of the type and its possible instantiations, the syntax for its type-insts, whether it is a finite type (and if so, its domain), whether it is varifiable, the ordering and equality operations, whether its variables must be initialised at instance-time, and whether it can be involved in automatic coercions. %We conclude by describing Zinc's constrained type-insts. %-----------------------------------------------------------------------------% \subsection{Properties of Types} %-----------------------------------------------------------------------------% The following list introduces some general properties of MiniZinc types. \begin{itemize} \item Currently all types are monotypes. % Recursive types are not allowed. In the future we may allow types which are polymorphic in other types and also the associated constraints. \item We distinguish types which are \emph{finite types}. In MiniZinc, finite types include Booleans, %flat enums, types defined via set expression type-insts such as range types (see Section~\ref{Set Expression Type-insts}), as well as sets and arrays, %tuples, records and non-flat enums composed of finite types. Types that are not finite types are unconstrained integers, unconstrained floats, unconstrained strings, and \texttt{ann}. Finite types are relevant to sets (Section~\ref{Sets}) and array indices (Section~\ref{Arrays}). Every finite type has a \emph{domain}, which is a set value that holds all the possible values represented by the type. \item Every first-order type (this excludes \texttt{ann}) has a built-in total order and a built-in equality; \texttt{>}, \texttt{<}, \texttt{==}/\texttt{=}, \texttt{!=}, \texttt{<=} and \texttt{>=} comparison operators can be applied to any pair of values of the same type. \Rationale{This facilitates the specification of symmetry breaking and of polymorphic predicates and functions.} Note that, as in most languages, using equality on floats or types that contain floats is generally not reliable due to their inexact representation. An implementation may choose to warn about the use of equality with floats or types that contain floats. %\item Higher-order types are used in very limited ways. They % can only be used with the built-in functions \texttt{foldl} and % \texttt{foldr}, which both take a function as their first argument. \end{itemize} %---------------------------------------------------------------------------% \subsection{Instantiations} \label{Instantiations} %---------------------------------------------------------------------------% \CommonInstantiationsDescription{MiniZinc} %% %There are also intermediate instantiations for some compound types---they %can have a fixed size but may contain unfixed elements. In MiniZinc decision variables can have the following types: Booleans, integers, floats, and sets of integers. %, and flat enums. %Tuples, arrays, records, non-flat %enums Arrays and \texttt{ann} can contain decision variables. %---------------------------------------------------------------------------% \subsection{Type-insts} \label{Type-insts} %---------------------------------------------------------------------------% \CommonTypeInstDescription{} MiniZinc allows coercions between some types as well. Some type-insts can be \emph{varified}, i.e.~made unfixed at the top-level. For example, \texttt{par int} is varified to \texttt{var int}. We write this \varify{\texttt{par int}}{\texttt{var int}}. Type-insts that are varifiable include the type-insts of the types that can be decision variables (Booleans, integers, floats, sets). %, enumerated types), and also tuples and records, %if their constituent elements can be varified. Varification is relevant to %type-inst synonyms and array accesses. %---------------------------------------------------------------------------% \subsection{Type-inst Expressions Overview} \label{Type-inst Expressions Overview} %---------------------------------------------------------------------------% This section partly describes how to write type-insts in MiniZinc models. Further details are given for each type as they are described in the following sections. A type-inst expression specifies a type-inst. \resolvedcomment{zs}{ I think the debacle with declaration syntax in C has shown that putting non-type things in type expressions is a bad idea. }{ Since they're now type-inst declarations, hopefully that will avoid the problems seen with C. } Type-inst expressions may include type-inst constraints. Type-inst expressions appear in variable declarations (Section~\ref{Declarations}), user-defined operation items (Section~\ref{preds and fns}).%, and type-inst synonyms %(Section~\ref{Type-inst Synonym Items}). Type-inst expressions have this syntax: \begin{productions} \RuleTIExpr \\ \RuleBaseTIExpr \\ \RuleVarPar \\ \RuleBaseTIExprTail \end{productions} %The first alternative is for arbitrarily constrained type-insts, which are %described in Section~\ref{Arbitrarily Constrained Type-insts}. % Base type-inst expressions have the % following syntax: % \begin{productions} % \RuleBaseTIExpr \\ % \RuleVarPar \\ % \RuleBaseTIExprTail % \end{productions} (The final alternative, for range types, uses the numeric-specific \nt{num-expr} non-terminal, defined in Section~\ref{Expressions Overview}, rather than the \nt{expr} non-terminal. If this were not the case, the rule would never match because the `\texttt{..}' operator would always be matched by the first \nt{expr}.) This fully covers the type-inst expressions for scalar types. The compound type-inst expression syntax is covered in more detail in Section~\ref{Built-in Compound Types}. %Type-inst variable syntax is %described in more detail in Section~\ref{Type-inst Variables}. %The constrained type-inst expressions are covered in more %detail in Section~\ref{Constrained Type-insts}. The \texttt{par} and \texttt{var} keywords (or lack of them) determine the instantiation. The \texttt{par} annotation can be omitted; the following two type-inst expressions are equivalent: \begin{verbatim} par int int \end{verbatim} \Rationale{The use of the explicit \texttt{var} keyword allows an implementation to check that all parameters are initialised in the model or the instance. It also clearly documents which variables are parameters, and allows more precise type-inst checking.} A type-inst is fixed if it does not contain \texttt{var} or \texttt{any}, with the exception of \texttt{ann}. Note that several type-inst expressions that are syntactically expressible represent illegal type-insts. For example, although the grammar allows \texttt{var} in front of all these base type-inst expression tails, it is a type-inst error to have \texttt{var} in the front of a string or array %, tuple, record, or type-inst variable type-inst expression. %-----------------------------------------------------------------------------% \subsection{Built-in Scalar Types and Type-insts} \label{Built-in Scalar Types} %-----------------------------------------------------------------------------% %---------------------------------------------------------------------------% \subsubsection{Booleans} %---------------------------------------------------------------------------% \TyOverview Booleans represent truthhood or falsity. \Rationale{Boolean values are not represented by integers. Booleans can be explicit converted to integers with the \texttt{bool2int} function, which makes the user's intent clear.} \TyInsts Booleans can be fixed or unfixed. \TySyntax Fixed Booleans are written \texttt{bool} or \texttt{par bool}. Unfixed Booleans are written as \texttt{var bool}. \TyFiniteType Yes. The domain of a Boolean is \texttt{\{false, true\}}. \TyVarifiable \varify{\texttt{par bool}}{\texttt{var bool}}, \varify{\texttt{var bool}}{\texttt{var bool}}. \TyOrdering The value \texttt{false} is considered smaller than \texttt{true}. \TyInit A fixed Boolean variable must be initialised at instance-time; an unfixed Boolean variable need not be. \TyCoercions \coerce{\texttt{par bool}}{\texttt{var bool}}. Also Booleans can be automatically coerced to integers; see Section~\ref{Integers}. % [this was relevant when operators like '<' were treated as % left-associative. Now that they are treated as non-associative, "0 < x < 10" % is a syntax error] %Booleans are not automatically coercible to 0-1 integers. %\begin{RationaleEnv} %This could be useful, but it is also dangerous. In particular, a user might %mean to write this: %\begin{verbatim} % constraint 0 < x /\ x < 10; %\end{verbatim} %but instead write this: %\begin{verbatim} % constraint 0 < x < 10; %\end{verbatim} %This would be parsed and implicitly coerced like this: %\begin{verbatim} % constraint coerce(bool, int, 0 < x) < 10; %\end{verbatim} %which always succeeds. Given that Zinc is quite high-level and %mathematical, it would be very easy for a user to assume that they can write %\texttt{0 < x < 10} and end up with a very subtle defect in their model. %Furthermore, the \texttt{bool2int} built-in function lets a user explicitly %coerce Booleans to integers easily. %\end{RationaleEnv} %---------------------------------------------------------------------------% \subsubsection{Integers} \label{Integers} %---------------------------------------------------------------------------% \TyOverview \CommonIntegersOverview{} \TyInsts Integers can be fixed or unfixed. \TySyntax Fixed integers are written \texttt{int} or \texttt{par int}. Unfixed integers are written as \texttt{var int}. \TyFiniteType Not unless constrained by a set expression (see Section~\ref{Set Expression Type-insts}). \TyVarifiable \varify{\texttt{par int}}{\texttt{var int}}, \varify{\texttt{var int}}{\texttt{var int}}. \TyOrdering The ordering on integers is the standard one. \TyInit A fixed integer variable must be initialised at instance-time; an unfixed integer variable need not be. \TyCoercions \coerce{\texttt{par int}}{\texttt{var int}}, \coerce{\texttt{par bool}}{\texttt{par int}}, \coerce{\texttt{par bool}}{\texttt{var int}}, \coerce{\texttt{var bool}}{\texttt{var int}}. Also, integers can be automatically coerced to floats; see Section~\ref{Floats}. %---------------------------------------------------------------------------% \subsubsection{Floats} \label{Floats} %---------------------------------------------------------------------------% \TyOverview \CommonFloatsOverview{} \TyInsts Floats can be fixed or unfixed. \TySyntax Fixed floats are written \texttt{float} or \texttt{par float}. Unfixed floats are written as \texttt{var float}. \TyFiniteType Not unless constrained by a set expression (see Section~\ref{Set Expression Type-insts}). \TyVarifiable \varify{\texttt{par float}}{\texttt{var float}}, \varify{\texttt{var float}}{\texttt{var float}}. \TyOrdering The ordering on floats is the standard one. \TyInit A fixed float variable must be initialised at instance-time; an unfixed float variable need not be. \TyCoercions \coerce{\texttt{par int}}{\texttt{par float}}, \coerce{\texttt{par int}}{\texttt{var float}}, \coerce{\texttt{var int}}{\texttt{var float}}, \coerce{\texttt{par float}}{\texttt{var float}}. %---------------------------------------------------------------------------% \subsubsection{Strings} %---------------------------------------------------------------------------% \TyOverview Strings are primitive, i.e.~they are not lists of characters. String expressions are used in assertions, output items and annotations, and string literals are used in include items. \TyInsts Strings must be fixed. \TySyntax Fixed strings are written \texttt{string} or \texttt{par string}. \TyFiniteType Not unless constrained by a set expression (see Section~\ref{Set Expression Type-insts}). \TyVarifiable No. \TyOrdering Strings are ordered lexicographically using the underlying character codes. \TyInit A string variable (which can only be fixed) must be initialised at instance-time. \TyCoercions None automatic. However, any non-string value can be manually converted to a string using the built-in \texttt{show} function or using string interpolation (see Section~\ref{String Interpolation Expressions}). %---------------------------------------------------------------------------% \subsection{Built-in Compound Types and Type-insts} \label{Built-in Compound Types} %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% \subsubsection{Sets} \label{Sets} %---------------------------------------------------------------------------% \TyOverview A set is a collection with no duplicates. \TyInsts The type-inst of a set's elements must be fixed. \Rationale{This is because current solvers are not powerful enough to handle sets containing decision variables.} Sets may contain any type, and may be fixed or unfixed. If a set is unfixed, its elements must be finite, unless it occurs in one of the following contexts: \begin{itemize} \item the argument of a predicate, function or annotation. \item the declaration of a variable or let local variable with an assigned value. \end{itemize} \TySyntax A set base type-inst expression tail has this syntax: \begin{productions} \RuleSetTIExprTail \end{productions} Some example set type-inst expressions: \begin{verbatim} set of int var set of bool \end{verbatim} \TyFiniteType Yes, if the set elements are finite types. Otherwise, no. The domain of a set type that is a finite type is the powerset of the domain of its element type. For example, the domain of \texttt{set of 1..2} is \texttt{powerset(1..2)}, which is \verb+{{}, {1}, {1,2}, {2}}+. \TyVarifiable \varify{\texttt{par set of TI}}{\texttt{var set of TI}}, \varify{\texttt{var set of TI}}{\texttt{var set of TI}}, \TyOrdering %The pre-defined ordering on sets is the lexicographic ordering on the %corresponding \emph{characteristic arrays}. For example, %\begin{verbatim} % {} < {2} < {1,3} %\end{verbatim} %since %\begin{verbatim} % [0,0,0] < [0,1,0] < [1,0,1]. %\end{verbatim} % %MiniZinc: % \pjs{Better check that this is what we actually want!} The pre-defined ordering on sets is a lexicographic ordering of the \emph{sorted set form}, where \{1,2\} is in sorted set form, for example, but \{2,1\} is not. This means, for instance, \verb'{} < {1,3} < {2}'. %\Rationale{The order based on the characteristic array %seems easier to propagate well (as it reduces to the array case) %than the perhaps more natural one based on the sorted set form.} \TyInit A fixed set variable must be initialised at instance-time; an unfixed set variable need not be. \TyCoercions \coerce{\texttt{par set of TI}}{\texttt{par set of UI}} and \coerce{\texttt{par set of TI}}{\texttt{var set of UI}} and \coerce{\texttt{var set of TI}}{\texttt{var set of UI}}, if \coerce{\texttt{TI}}{\texttt{UI}}. %\pjs{Is this true for MiniZinc?} %Fixed sets can be automatically coerced to arrays; see %section~\ref{Arrays}. This means that array accesses can be used on fixed %sets; \texttt{S[1]} is the smallest element in a fixed set \texttt{S} while %\texttt{S[card(S)]} is the largest. %---------------------------------------------------------------------------% \subsubsection{Arrays} \label{Arrays} %---------------------------------------------------------------------------% \TyOverview MiniZinc arrays are maps from fixed integers to values. Values can be of any type. %When used with integer keys, Zinc arrays %can be used like arrays in languages like Java, but with other types of key %they act like associative arrays. Using floats or types containing floats %as keys can be dangerous because of their imprecise equality comparison, and %an implementation may give a warning in this case. The values can have only have base type-insts. Arrays-of-arrays are not allowed. All arrays are one-dimensional. However, multi-dimensional arrays can be simulated using a tuple as the index, and there is some syntactic sugar to make this easier (see below and in Section~\ref{Array Access Expressions}). MiniZinc arrays can be declared in two different ways. \begin{enumerate} \item \emph{Explicitly-indexed} arrays have index types in the declaration that are finite types. For example: \begin{verbatim} array[0..3] of int: a1; \end{verbatim} For such arrays, the index type specifies exactly the indices that will be in the array---the array's index set is the \emph{domain} of the index type---and if the indices of the value assigned do not match then it is a run-time error. For example, the following assignments cause run-time errors: \begin{verbatim} a1 = [4,6,4,3,2]; % too many elements array[1..5, 1..10] of var float: a5 = []; % too few elements \end{verbatim} \item \emph{Implicitly-indexed} arrays have index types in the declaration that are not finite types. For example: \begin{verbatim} array[int] of int: a6; \end{verbatim} No checking of indices occurs when these variables are assigned. \end{enumerate} The initialisation of an array can be done in a separate assignment statement, which may be present in the model or a separate data file. Arrays can be accessed. See Section~\ref{Array Access Expressions} for details. \TyInsts An array's size must be fixed. Its indices must also have fixed type-insts. Its elements may be fixed or unfixed. \TySyntax An array base type-inst expression tail has this syntax: \begin{productions} \RuleArrayTIExprTail \end{productions} Some example array type-inst expressions: \begin{verbatim} array[1..10] of int list of var int \end{verbatim} Note that \texttt{list of } is just syntactic sugar for \texttt{array[int] of }. \Rationale{Integer-indexed arrays of this form are very common, and so worthy of special support to make things easier for modellers. Implementing it using syntactic sugar avoids adding an extra type to the language, which keeps things simple for implementers.} Because arrays must be fixed-size it is a type-inst error to precede an array type-inst expression with \texttt{var}. % \pjs{Introduce the $index:value$ as a notation to explain arrays?} % Syntactic sugar exists for declaring tuple-indexed arrays. For example, % the second of the following two declarations is syntactic sugar for the % first. % \begin{verbatim} % array[tuple(1..5, 1..4)] of int: a5; % array[1..5, 1..4] of int: a5; % \end{verbatim} \TyFiniteType Yes, if the index types and element type are all finite types. Otherwise, no. The domain of an array type that is a finite array is the set of all distinct arrays whose index set equals the domain of the index type and whose elements are of the array element type. % For example, the domain of % \texttt{array[5..6] of 1..2} is % \verb+{[5:1,6:1], [5:1,6:2], [5:2,6:1], [5:2,6:2]}+. \TyVarifiable No. \TyOrdering Arrays are ordered lexicographically, taking absence of a value for a given key to be before any value for that key. For example, \texttt{[1, 1]} is less than \texttt{[1, 2]}, which is less than \texttt{[1, 2, 3]} and \texttt{array1d(2..4,[0, 0, 0])} is less than \texttt{[1, 2, 3]}. \TyInit An explicitly-indexed array variable must be initialised at instance-time only if its elements must be initialised at instance time. An implicitly-indexed array variable must be initialised at instance-time so that its length and index set is known. \TyCoercions %\coerce{\texttt{set of TI}}{\texttt{array[1..n] of UI}} if %\coerce{\texttt{TI}}{\texttt{UI}}, where %\texttt{n} is the number of elements in the set. The elements of the %resulting array will be in sorted order. %This is handy for initialisation but seems a bit dangerous. %This means that elements of fixed sets can be accessed like array elements, %using square brackets. \coerce{\texttt{array[TI0] of TI}}{\texttt{array[TI0] of UI}} if \coerce{\texttt{TI}}{\texttt{UI}} (i.e.\ coercion of the element type but not the index type). \ignore{ %---------------------------------------------------------------------------% \subsubsection{Tuples} %---------------------------------------------------------------------------% \TyOverview Tuples are fixed-size, heterogeneous collections. They must contain at least two elements; unary tuples are not allowed. \TyInsts Tuples may contain unfixed elements. \TySyntax A tuple base type-inst expression tail has this syntax: \begin{productions} \RuleTupleTIExprTail \end{productions} An example tuple type-inst expression: \begin{verbatim} tuple(int, var float) \end{verbatim} It is a type-inst error to precede a tuple type-inst expression with \texttt{var}. \TyFiniteType Yes, if all its constituent elements are finite types. Otherwise, no. The domain of a tuple type that is a finite type is the Cartesian product of the domains of the element types. For example, the domain of \texttt{tuple(1..2, \{3,5\})} is \verb+{(1,3), (1,5), (2,3), (2,5)}+. \TyVarifiable Yes, if all its constituent elements are varifiable. A tuple is varified by varifying its constituent elements. \TyOrdering Tuples are ordered lexicographically. \TyInit A tuple variable must be initialised at instance-time if any of its constituent elements must be initialised at instance-time. \TyCoercions \coerce{\texttt{tuple(TI1,...,TIn)}}{\texttt{tuple(UI1,...UIn)}}, if \coerce{\texttt{TI1}}{\texttt{UI1}},\ldots,\coerce{\texttt{TIn}}{\texttt{UIn}}. Also, tuples can be automatically coerced to records; see Section~\ref{Records} for details. %---------------------------------------------------------------------------% \subsubsection{Records} \label{Records} %---------------------------------------------------------------------------% \TyOverview Records are fixed-size, heterogeneous collections. They are similar to tuples, but have named fields. Field names in different records can be identical, because each record's field names belong to a different namespace (Section~\ref{Namespaces}). Record field order is significant; the following two record type-insts are distinct and do not match: \begin{verbatim} record(var int: x, var int: y) record(var int: y, var int: x) \end{verbatim} \begin{RationaleEnv} This is necessary to avoid ambiguity when tuples are coerced to records. If field ordering did not matter, we could have this array: \begin{small} \begin{verbatim} [(x:3, y:4), (y:2, x:5), (7,8)] \end{verbatim} \end{small} in which the \texttt{(7,8)} must be coerced to a record, but it is unclear if it should become \texttt{(x:7, y:8)} or \texttt{(y:7, x:8)}. \end{RationaleEnv} \TyInsts Records may contain unfixed elements. \TySyntax A record base type-inst expression tail has this syntax: \begin{productions} \RuleRecordTIExprTail \\ \RuleTIExprAndId \end{productions} An example record type-inst expression: \begin{verbatim} record(int: x, int: y) \end{verbatim} It is a type-inst error to precede a record type-inst expression with \texttt{var}. \TyFiniteType Yes, if all its constituent elements are finite types. Otherwise, no. The domain of a record type that is a finite type is the same as that of a tuple type, but with the fields included. For example, the domain of \texttt{record(1..2:x, \{3,5\}:y)} is \verb+{(x:1,y:3), (x:1,y:5), (x:2,y:3), (x:2,y:5)}+. \TyVarifiable Yes, if all its constituent elements are varifiable. A record is varified by varifying its constituent elements. \TyOrdering Records are ordered lexicographically according to the values of the fields. The field names are irrelevant for comparisons because in order for two records to be compared they must have the same type-inst, in which case the field names and order must be the same. \TyInit A record variable must be initialised at instance-time if any of its constituent elements must be initialised at instance-time. \TyCoercions \coerce{\texttt{tuple(TI1,...,TIn)}}{\texttt{record(UI1:x1,...UIn:xn)}}, if \coerce{\texttt{TI1}}{\texttt{UI1}},\ldots,\coerce{\texttt{TIn}}{\texttt{UIn}}. This is useful for record initialisation. For example, we can initialise a record of type \emph{Task} (defined in Section~\ref{Arbitrarily Constrained Type-insts}) using: \begin{verbatim} Task: T = (10,_,_); \end{verbatim} which initialises \texttt{duration} field with 10 and the variable fields \texttt{start} and \texttt{finish} with `\underscore'. Also, \coerce{\texttt{record(TI1:x1,...,TIn:xn)}} {\texttt{record(UI1:x1,...UIn:xn)}}, if \coerce{\texttt{TI1}}{\texttt{UI1}},\ldots,\coerce{\texttt{TIn}}{\texttt{UIn}}. %---------------------------------------------------------------------------% \subsection{User-defined Types and Type-insts} \label{User-defined Types} %---------------------------------------------------------------------------% This section introduces the properties of the user-defined types and type-insts. The syntax and details of the items that are used to declare these new types are in Section~\ref{Items}. Because these user-defined types have names, their type-inst expressions are simple identifiers. Syntactically, any identifier may be used as a base type-inst expression. However, in a valid model any identifier within a base type-inst expression must be one of: \begin{itemize} %\item the name of a user-defined type or type-inst (type-inst synonym % or enumerated type); \item the name of a fixed set value (Section~\ref{Set Expression Type-insts}). \end{itemize} %---------------------------------------------------------------------------% \subsubsection{Type-inst Synonyms} \label{Type-inst Synonyms} %---------------------------------------------------------------------------% \TyOverview A type-inst synonym is an alternative name for a pre-existing type-inst which can be used interchangeably with the pre-existing type-inst. For example, if \texttt{MyFixedInt} is a synonym for \texttt{par int} then \texttt{MyFixedInt} can be used anywhere \texttt{par int} can, and vice versa. \TyInsts Preceding a type-inst synonym with \texttt{var} varifies it, unless the type-inst is not varifiable, in which case it is a type-inst error. Preceding a type-inst synonym with \texttt{par} has no effect---the \texttt{par} is ignored. \TySyntax A type-inst synonym named ``X'' is represented by the term \texttt{X}. \TyFiniteType As for the pre-existing type-inst. \TyVarifiable Yes, if the pre-existing type-inst is varifiable. \TyOrdering As for the pre-existing type-inst. \TyInit As for the pre-existing type-inst. \TyCoercions As for the pre-existing type-inst. %---------------------------------------------------------------------------% \subsubsection{Enumerated Types} \label{Enumerated Types} %---------------------------------------------------------------------------% \TyOverview Enumerated types (or \emph{enums} for short) provide a set of named alternatives. Unlike many languages, Zinc's enumerated types can have arguments, and each argument has a field name, so they are more like discriminated unions. However, they cannot be recursive. \Rationale{This restriction naturally follows from the decision to disallow recursive functions and predicates (see Section~\ref{Basic Properties}). Without such capabilities, recursive data structures are of little use as there is no general way to traverse them.} We distinguish between \emph{flat} enums, in which all the alternatives have no arguments, and \emph{non-flat} enums, in which some or all alternatives have arguments. Each alternative is identified by its \emph{case name}. \TyInsts Flat enums can be fixed or unfixed. Non-flat enums cannot be preceded by \texttt{var}, but they may contain unfixed elements. \TySyntax Variables of an enumerated type named ``X'' are represented by the term \texttt{X} or \texttt{par X} if fixed, and (flat enums only) \texttt{var X} if unfixed. \TyFiniteType If flat, yes. If non-flat, only if all its constituent elements (in all alternatives) are finite types; otherwise, no. The domain of a flat enum is the set containing all of its case names. The domain of a non-flat enum is the set containing all the possible values of that enum. For example, these two enums: \begin{verbatim} enum C = { R, G, B }; enum X = { a(1..3:x), b(bool:y), c }; \end{verbatim} have these domains: \begin{verbatim} { R, G, B } { a(x:1), a(x:2), a(x:3), b(y:false), b(y:true), c } \end{verbatim} \TyVarifiable For flat enums: \varify{\texttt{par X}}{\texttt{var X}}, \varify{\texttt{var X}}{\texttt{var X}}. For non-flat enums: no. \TyOrdering When two enum values with different case names are compared, the value with the case name that is declared first is considered smaller than the value with the case name that is declared second. If the case names are the same, the ordering is lexicographic on the case arguments (if there are any). \TyInit A fixed flat enum variable must be initialised at instance-time; an unfixed flat enum variable need not be. A non-flat enum variable must be initialised at instance-time. \TyCoercions For flat enums: \coerce{\texttt{par X}}{\texttt{var X}}. For non-flat enums: none. } %---------------------------------------------------------------------------% \subsubsection{Option Types} \label{option types} %---------------------------------------------------------------------------% \TyOverview Option types defined using the \texttt{opt} type constructor, define types that may or may not be there. They are similar to \texttt{Maybe} types of Haskell implicity adding a new value \texttt{<>} to the type. \TyInsts The argument of an option type must be one of the base types \texttt{bool}, \texttt{int} or \texttt{float}. \TySyntax The annotation type is written \texttt{opt } where \texttt{} if one of the three base types, or one of their constrained instances. \TyFiniteType Yes if the underlying type is finite, otherwise no. \TyVarifiable Yes. \TyOrdering \texttt{<>} is always less than any other value in the type. But beware that overloading of operators like \texttt{<} is different for option types. \TyInit A fixed \texttt{opt} type variable must be initialised at instance-time, a variable \texttt{opt} type variable need not be. \TyCoercions None. %---------------------------------------------------------------------------% \subsubsection{The Annotation Type \texttt{ann}} \label{the annotation type} %---------------------------------------------------------------------------% \TyOverview The annotation type, \texttt{ann}, can be used to represent arbitrary term structures. It is augmented by annotation items (\ref{Annotation Items}). \TyInsts \texttt{ann} is always considered unfixed, because it may contain unfixed elements. It cannot be preceded by \texttt{var}. \TySyntax The annotation type is written \texttt{ann}. \TyFiniteType No. \TyVarifiable No. \TyOrdering N/A. Annotation types do not have an ordering defined on them. \TyInit An \texttt{ann} variable must be initialised at instance-time. \TyCoercions None. \ignore{ %---------------------------------------------------------------------------% \subsection{Other Types and Type-insts} \label{Other Types} %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% \subsubsection{Type-inst Variables} \label{Type-inst Variables} %---------------------------------------------------------------------------% \TyOverview Type-inst variables allow parametric polymorphism. They can appear in MiniZinc predicate and function arguments and return type-insts, in let expressions within predicate and function bodies, and in annotation declarations; if one is used outside a function or predicate or annotation declaration it is a type-inst error. \TyInsts A type-inst variable expression consists of a type-inst variable and an optional prefix. Type-inst variables can be prefixed by \texttt{par}, in which case they match any fixed type-inst; the same is true if they lack a prefix. %Type-inst variables can also be prefixed by \texttt{any}, in which case they %match any first-order type-inst. The meanings of the prefixes are discussed in further detail in Section~\ref{Parametric Polymorphism}. \TySyntax A type-inst variable expression tail has this syntax: \begin{productions} \RuleTIVariableExprTail \end{productions} Some example type-inst variable expressions: \begin{verbatim} $T par $U3 \end{verbatim} \TyFiniteType No. This is because they can be bound to any type-inst, and not all type-insts are finite. \TyVarifiable No. This is because they can be bound to any type-inst, and not all type-insts can be varified. \TyOrdering Values of equal type-inst variables can be compared. The comparison used will be the comparison of the underlying type-insts. This is possible because all type-insts have a built-in ordering. \TyInit A variable with a type-inst variable as its type-inst (which can only appear inside predicate and function bodies) must be initialised. \TyCoercions None. %\coerce{\texttt{par \$T}}{\texttt{any \$T}}. } \ignore{ %---------------------------------------------------------------------------% \subsubsection{Higher-order Types} \label{Higher-order Types} %---------------------------------------------------------------------------% \TyOverview Operations (e.g.~predicates) have higher-order types. Operations can be used as values when passed as the first argument to \texttt{foldl} or \texttt{foldr}. They can also be used as arguments to annotations; annotation declarations are the only place where operation type-inst expressions are permitted. \TyInsts The type-inst of a higher-order type is determined by the type-insts it can take as its arguments, and its return type-inst. A higher-order type value is never considered fixed, and so cannot be used as the element of a set, for example. \TySyntax An operation type-inst expression tail has this syntax: \begin{productions} \RuleOpTIExprTail \end{productions} Some example type-inst variable expressions: \begin{verbatim} op(int:(int)); op(var bool:(float, any $T)); \end{verbatim} Note that operation type-inst expressions cannot be written for nullary operations (i.e.~those lacking arguments). \Rationale{This is because it is difficult to distinguish the name of a nullary operation from a call to it, and so passing nullary operations is difficult. Furthermore, they are little to no use, so they are unlikely to be missed.} \TyFiniteType No. \TyVarifiable No. \TyOrdering N/A. Higher-order types cannot be used in comparisons; it is a run-time error if they are. \TyInit N/A. Variables cannot have higher-order types. \TyCoercions None. } %---------------------------------------------------------------------------% \subsection{Constrained Type-insts} \label{Constrained Type-insts} %---------------------------------------------------------------------------% One powerful feature of MiniZinc is \emph{constrained type-insts}. A constrained type-inst is a restricted version of a \emph{base} type-inst, i.e.~a type-inst with fewer values in its domain. %---------------------------------------------------------------------------% \subsubsection{Set Expression Type-insts} \label{Set Expression Type-insts} %---------------------------------------------------------------------------% Three kinds of expressions can be used in type-insts. \begin{enumerate} \item Integer ranges: e.g.~\texttt{1..3}. \item Set literals: e.g.~\texttt{var \{1,3,5\}}. \item Identifiers: the name of a set parameter (which can be global, let-local, the argument of a predicate or function, or a generator value) can serve as a type-inst. \end{enumerate} In each case the base type is that of the set's elements, and the values within the set serve as the domain. For example, whereas a variable with type-inst \texttt{var int} can take any integer value, a variable with type-inst \texttt{var 1..3} can only take the value 1, 2 or 3. All set expression type-insts are finite types. Their domain is equal to the set itself. %---------------------------------------------------------------------------% \subsubsection{Float Range Type-insts} %---------------------------------------------------------------------------% Float ranges can be used as type-insts, e.g.~\verb+1.0 .. 3.0+. These are treated similarly to integer range type-insts, although \verb+1.0 .. 3.0+ is not a valid expression whereas \verb+1 .. 3+ is. Float ranges are not finite types. \ignore{ %---------------------------------------------------------------------------% \subsubsection{Arbitrarily Constrained Type-insts} \label{Arbitrarily Constrained Type-insts} %---------------------------------------------------------------------------% A more general form of constrained type-inst allows an arbitrary Boolean \emph{type-inst constraint} expression to be applied to a \emph{base} type-inst. Here are two examples of arbitrarily constrained type-inst expressions. The first is a fixed integer in the range 1--3, and the second is an unfixed non-negative float. \begin{verbatim} (par int: i where i in 1..3): dom; (var float: f where f >= 0) : fplus; \end{verbatim} The base type-inst appears before the `:'. The identifiers \texttt{i} and \texttt{f} are local identifiers used in the Boolean expression after the \texttt{where} keyword. The scope of the local identifiers \texttt{i} and \texttt{f} extends to the end of the Boolean expression after the \texttt{where}. An arbitrarily constrained type-inst is finite only if its base type-inst is finite. Its domain is that of its base type-inst, minus those elements that do not satisfy its constraint. Finiteness is thus the main difference between set expression type-insts (Section~\ref{Set Expression Type-insts}) and arbitrarily constrained type-insts. For example, in the following three lines, the first type-inst is equivalent to the second, with one exception. \begin{verbatim} par 1..3 (par int: i where i in 1..3) var {1,2,3} (var int: i where i in {1,2,3}) MySet ( int: i where i in MySet) \end{verbatim} The exception is that the type-insts on the left-hand side are finite, whereas those on the right are non-finite. Every float range type-inst has an equivalent arbitrarily constrained type-inst. For example, the following two type-insts are equivalent: \begin{verbatim} 1.0 .. 3.0 (float: f where 1.0 <= f /\ f <= 3.0) \end{verbatim} An unconstrained type-inst can be viewed as an arbitrarily constrained type-inst with a \textit{true} constraint. For example, the following two type-insts are equivalent: \begin{verbatim} par int (par int: i where true) \end{verbatim} The Boolean expression associated with a variable declared to have an arbitrarily constrained type-inst is either tested at instance-time if the variable is a parameter or else generates a constraint if it is a decision variable. An arbitrarily constrained type-inst is varified by varifying its base type-inst. Records can use type-inst constraints like other type-insts, for example: \begin{verbatim} type Task = (record(int: duration, var int: start, var int: finish ): t where t.finish = t.start + t.duration); \end{verbatim} Non-flat enums can also involve type-inst constraints; see Section~\ref{Enum Items} for details. } %===========================================================================% \section{Expressions} \label{Expressions} %===========================================================================% %---------------------------------------------------------------------------% \subsection{Expressions Overview} \label{Expressions Overview} %---------------------------------------------------------------------------% Expressions represent values. They occur in various kinds of items. They have the following syntax: \resolvedcomment{rafe}{ I'd like to have an `\texttt{expr where \{...\}}' construct, a la Haskell, where the ... could contain definitions and constraints sections. }{ Perhaps a good idea, but we won't do it for now because it's extra complexity and it's unclear how useful it will be. Plus we have let expressions, which are similar. } \begin{productions} \RuleExpr \\ \RuleExprAtom \\ \RuleExprBinopTail \\ \RuleExprAtomHead \\ \RuleExprAtomTail \end{productions} Expressions can be composed from sub-expressions combined with operators. All operators (binary and unary) are described in Section~\ref{Operators}, including the precedences of the binary operators. All unary operators bind more tightly than all binary operators. Expressions can have one or more annotations. Annotations bind more tightly than unary and binary operator applications, but less tightly than access operations and non-operator applications. In some cases this binding is non-intuitive. For example, in the first three of the following lines, the annotation \texttt{a} binds to the identifier expression \texttt{x} rather than the operator application. However, the fourth line features a non-operator application (due to the single quotes around the \texttt{not}) and so the annotation binds to the whole application. \begin{verbatim} not x::a; not (x)::a; not(x)::a; 'not'(x)::a; \end{verbatim} Section~\ref{Annotations} has more on annotations. Expressions can be contained within parentheses. The array access operations all bind more tightly than unary and binary operators and annotations. %The %access operations can be chained and they associate to the left. For %example, these two access operations are equivalent: %\begin{verbatim} % x = a[1].field.1; % x = ((a[1]).field).1; %\end{verbatim} They are described in more detail in Sections~\ref{Array Access Expressions}. %, \ref{Tuple Access Expressions}, \ref{Record Access %Expressions} and \ref{Non-flat Enum Access Expressions}. The remaining kinds of expression atoms (from \nt{ident} to \nt{gen-call-expr}) are described in Sections~\ref{Identifier Expressions and Quoted Operator Expressions}--\ref{Generator Call Expressions}. We also distinguish syntactically valid numeric expressions. This allows range types to be parsed correctly. \begin{productions} \RuleNumExpr \\ \RuleNumExprAtom \\ \RuleNumExprBinopTail \\ \RuleNumExprAtomHead \\ \end{productions} %---------------------------------------------------------------------------% \subsection{Operators} \label{Operators} %---------------------------------------------------------------------------% Operators are functions that are distinguished by their syntax in one or two ways. First, some of them contain non-alphanumeric characters that normal functions do not (e.g.~`\texttt{+}'). Second, their application is written in a manner different to normal functions. We distinguish between binary operators, which can be applied in an infix manner (e.g.~\texttt{3 + 4}), and unary operators, which can be applied in a prefix manner without parentheses (e.g.~\texttt{not x}). We also distinguish between built-in operators and user-defined operators. The syntax is the following: \begin{productions} \RuleBuiltinOp \\ \RuleBinOp \\ \RuleBuiltinBinOp \\ \RuleBuiltinUnOp \end{productions} Again, we syntactically distinguish numeric operators. \begin{productions} \RuleNumBinOp \\ \RuleBuiltinNumBinOp \\ \RuleBuiltinNumUnOp \end{productions} % \pjs{Where do we seay something about the unicode versions of these?} Some operators can be written using their unicode symbols, which are listed in Table~\ref{bin-ops-unicode} (recall that MiniZinc input is UTF-8). \begin{table}[t] \centering \begin{tabular}{lcl} \hline Operator & Unicode symbol & UTF-8 code \\ \hline \texttt{<->} & $\leftrightarrow$ & E2~86~94\\ \texttt{->} & $\rightarrow$ & E2~86~92\\ \texttt{<-} & $\leftarrow$ & E2~86~90\\ \texttt{not} & $\lnot$ & C2~AC\\ \verb+\/+ & $\lor$ & E2~88~A8\\ \verb+/\+ & $\land$ & E2~88~A7\\ \texttt{!=} & $\neq$ & E2~89~A0\\ \texttt{<=} & $\leq$ & E2~89~A4\\ \texttt{>=} & $\geq$ & E2~89~A5\\ \texttt{in} & $\in$ & E2~88~88\\ \texttt{subset} & $\subseteq$ & E2~8A~86\\ \texttt{superset} & $\supseteq$ & E2~8A~87\\ \texttt{union} & $\cup$ & E2~88~AA\\ \texttt{intersect} & $\cap$ & E2~88~A9\\ \end{tabular} \caption{Unicode equivalents of binary operators.} \label{bin-ops-unicode} \end{table} The binary operators are listed in Table~\ref{bin-ops}. %-----------------------------------------------------------------------------% \begin{table}[t] \centering \begin{tabular}{lll} \hline Symbol(s) & Assoc.& Prec. \\ \hline \texttt{<->} & left & 1200 \\ \texttt{->} & left & 1100 \\ \texttt{<-} & left & 1100 \\ \verb+\/+ & left & 1000 \\ \texttt{xor} & left & 1000 \\ \verb+/\+ & left & 900 \\ \texttt{<} & none & 800 \\ \texttt{>} & none & 800 \\ \texttt{<=} & none & 800 \\ \texttt{>=} & none & 800 \\ \texttt{==}, \texttt{=} & none & 800 \\ \texttt{!=} & none & 800 \\ \texttt{in} & none & 700 \\ \texttt{subset} & none & 700 \\ \texttt{superset} & none & 700 \\ \texttt{union} & left & 600 \\ \texttt{diff} & left & 600 \\ \texttt{symdiff} & left & 600 \\ \texttt{..} & none & 500 \\ \texttt{+} & left & 400 \\ \texttt{-} & left & 400 \\ \texttt{*} & left & 300 \\ \texttt{div} & left & 300 \\ \texttt{mod} & left & 300 \\ \texttt{/} & left & 300 \\ \texttt{intersect} & left & 300 \\ \texttt{++} & right & 200 \\ \texttt{`}\nt{ident}\texttt{`} & left & 100 \\ \hline \end{tabular} \caption{Binary infix operators. A lower precedence number means tighter binding; for example, \texttt{1+2*3} is parsed as \texttt{1+(2*3)} because `\texttt{*}' binds tighter than `\texttt{+}'. Associativity indicates how chains of operators with equal precedences are handled; for example, \texttt{1+2+3} is parsed as \texttt{(1+2)+3} because `\texttt{+}' is left-associative, \texttt{a++b++c} is parsed as \texttt{a++(b++c)} because `\texttt{++}' is right-associative, and \texttt{1 0 then 1 else 0 endif \end{verbatim} The presence of the \texttt{endif} avoids possible ambiguity when an if-then-else expression is part of a larger expression. The type-inst of the ``if'' expression must be \texttt{par bool} or \texttt{var bool}. % In the future we may allow it to also be \texttt{var bool}. The ``then'' and ``else'' expressions must have the same type-inst, or be coercible to the same type-inst, which is also the type-inst of the whole expression. If the ``if'' expression is \texttt{var bool} then the type-inst of the ``then'' and ``else'' expressions must be varifiable. If the ``if'' expression is \texttt{par bool} then evaluation of if-then-else expressions is lazy---the condition is evaluated, and then only one of the ``then'' and ``else'' branches are evaluated, depending on whether the condition succeeded or failed. This is not the case if it is \texttt{var bool}. \ignore{ %---------------------------------------------------------------------------% \subsubsection{Case Expressions} \label{Case Expressions} %---------------------------------------------------------------------------% Zinc provides case expressions for handling the different cases in an enum. Case expressions have this syntax: \resolvedcomment{pjs}{ I THINK WE NEED PROPER CASE EXPRESSIONS!\\ \indent\texttt{multi\_point: r;}\\ \indent\texttt{int M: case r \{ intp(a,\_) --> a , floatp(u,v) --> ceil(u+v) \};}}{ Decided to keep as is for the moment, for simplicity. } \begin{productions} \RuleCaseExpr \\ \RuleCaseExprCase \end{productions} For example, we can use the \texttt{multi\n{}point} record in Section~\ref{multipoint} with the following code: \begin{verbatim} multi_point: r; int: M = case r { int_point --> r.ix, float_point --> 0, }; \end{verbatim} The comma after the final case is optional. The type-inst of the case selection expression must be a fixed flat enum or a non-flat enum. The type-inst of every result expression must be the same, or be coercible to the same type-inst, which is also the type-inst of the whole expression. It is a static error if any case name is not covered by the case statement. Currently MiniZinc does not support pattern matching. This may be supported in the future. } %---------------------------------------------------------------------------% \subsubsection{Let Expressions} \label{Let Expressions} %---------------------------------------------------------------------------% Let expressions provide a way of introducing local names for one or more expressions and local constraints that can be used within another expression. They are particularly useful in user-defined operations. Let expressions have this syntax: \begin{productions} \RuleLetExpr \\ \RuleLetItem \end{productions} For example: \begin{verbatim} let { int: x = 3, int: y = 4; } in x + y; let { var int: x; constraint x >= y /\ x >= -y /\ (x = y \/ x = -y); } in x \end{verbatim} The scope of a let local variable covers: \begin{itemize} \item The type-inst and initialisation expressions of any subsequent variables within the let expression (but not the variable's own initialisation expression). \item The expression after the \texttt{in}, which is parsed as greedily as possible. \end{itemize} A variable can only be declared once in a let expression. Thus in the following examples the first is acceptable but the rest are not: \begin{verbatim} let { int: x = 3; int: y = x; } in x + y; % ok let { int: y = x; int: x = 3; } in x + y; % x not visible in y's defn. let { int: x = x; } in x; % x not visible in x's defn. let { int: x = 3; int: x = 4; } in x; % x declared twice \end{verbatim} The type-inst expressions can include type-inst variables if the let is within a function or predicate body in which the same type-inst variables were present in the function or predicate signature. The initialiser for a let local variable can be omitted only if the variable is a decision variable. For example: \begin{verbatim} let { var int: x; } in ...; % ok let { int: x; } in ...; % illegal \end{verbatim} The type-inst of the entire let expression is the type-inst of the expression after the \texttt{in} keyword. There is a complication involving let expressions in negative contexts. A let expression occurs in a negative context if it occurs in an expression of the form \texttt{not X}, \texttt{X <-> Y}, or in the sub-expression \texttt{X} in \texttt{X -> Y} or \texttt{Y <- X}, or in a subexpression \texttt{bool2int(X)}. If a let expression is used in a negative context, then any let-local decision variables must be defined only in terms of non-local variables and parameters. This is because local variables are implicitly existentially quantified, and if the let expression occurred in a negative context then the local variables would be effectively universally quantified which is not supported by MiniZinc. Constraints in let expressions float to the nearest enclosing Boolean context. For example \begin{verbatim} constraint b -> x + let { var 0..2: y; constraint y != -1;} in y >= 4; \end{verbatim} is equivalent to \begin{verbatim} var 0..2: y; constraint b -> (x + y >= 4 /\ y != 1); \end{verbatim} %---------------------------------------------------------------------------% \subsubsection{Call Expressions} %---------------------------------------------------------------------------% Call expressions are used to call predicates and functions. Call expressions have this syntax: \begin{productions} \RuleCallExpr \end{productions} For example: \begin{verbatim} x = min(3, 5); \end{verbatim} The type-insts of the expressions passed as arguments must match the argument types of the called predicate/function. The return type of the predicate/function must also be appropriate for the calling context. Note that a call to a function or predicate with no arguments is syntactically indistinguishable from the use of a variable, and so must be determined during type-inst checking. Evaluation of the arguments in call expressions is strict---all arguments are evaluated before the call itself is evaluated. Note that this includes Boolean operations such as \verb+/\+, \verb+\/+, \texttt{->} and \texttt{<-} which could be lazy in one argument. The one exception is \texttt{assert}, which is lazy in its third argument (Section~\ref{Other Operations}). \Rationale{Boolean operations are strict because: (a) this minimises exceptional cases; (b) in an expression like \texttt{A -> B}, where \texttt{A} is not fixed and \texttt{B} causes an abort, the appropriate behaviour is unclear if laziness is present; and (c) if a user needs laziness, an if-then-else can be used.} The order of argument evaluation is not specified. \Rationale{Because MiniZinc is declarative, there is no obvious need to specify an evaluation order, and leaving it unspecified gives implementors some freedom.} %---------------------------------------------------------------------------% \subsubsection{Generator Call Expressions} \label{Generator Call Expressions} %---------------------------------------------------------------------------% MiniZinc has special syntax for certain kinds of call expressions which makes models much more readable. Generator call expressions have this syntax: \begin{productions} \RuleGenCallExpr \end{productions} % A generator call expression \texttt{P(Gs)(E)} is equivalent to the call expression \texttt{P([E | Gs])}. For example, the expression: \begin{verbatim} forall(i,j in Domain where i= 0); type Domain = 1..n; \end{verbatim} It is a type-inst error if a type-inst synonym is declared and/or defined more than once in a model. Type-inst synonym items can be annotated. Section~\ref{Annotations} has more details on annotations. All type-inst synonyms must be defined at model-time. %---------------------------------------------------------------------------% \subsection{Enum Items} \label{Enum Items} %---------------------------------------------------------------------------% Enumerated type items have this syntax: \begin{productions} \RuleEnumItem \\ \RuleEnumCases \\ \RuleEnumCase \end{productions} An example of a flat enum: \begin{verbatim} enum country = {Australia, Canada, China, England, USA}; \end{verbatim} An example of a non-flat enum: \label{multipoint} \begin{verbatim} enum multi_point = { int_point(int: ix, int: iy), float_point(float: fx, float: fy) }; \end{verbatim} Each alternative is called an \emph{enum case}. The identifier used to name each case (e.g.~\texttt{Australia} and \texttt{float\n{}point}) is called the \emph{enum case name}. Enums can be constrained by using a type-inst synonym (Section~\ref{Type-inst Synonym Items}) and a case expression (Section~\ref{Case Expressions}). For example: \begin{verbatim} type multi_point2 = (multi_point: p where case p { int_point --> p.ix > p.iy, float_point --> p.fx > p.fy }); \end{verbatim} Because enum case names all reside in the top-level namespace (Section~\ref{Namespaces}), case names in different enums must be distinct. As for field names in non-flat enums, all field names in a single enum must be distinct to avoid possible ambiguities. An enum can be declared but not defined, in which case it must be defined elsewhere. For non-flat enums, ``elsewhere'' must be within the model. For flat enums, ``elsewhere'' must be within the model, or in a data file. For example, a model file could contain this: \begin{verbatim} enum Workers; enum Shifts; \end{verbatim} and the data file could contain this: \begin{verbatim} enum Workers = { welder, driller, stamper }; enum Shifts = { idle, day, night }; \end{verbatim} Sometimes it is useful to be able to refer to one of the enum case names within the model. This can be achieved by using a variable. The model would read: \begin{verbatim} enum Shifts; Shifts idle; % Variable representing the idle constant. \end{verbatim} and the data file: \begin{verbatim} enum Shifts = { idle_const, day, night }; idle = idle_const; % Assignment to the variable. \end{verbatim} Although the constant \texttt{idle\n{}const} cannot be mentioned in the model, the variable \texttt{idle} can be. All enums must be defined at instance-time. Enum items can be annotated. Section~\ref{Annotations} has more details on annotations. % For each enumerated type $T$ MiniZinc automatically creates the function % \begin{verbatim} % toInt(T):int % \end{verbatim} % which maps elements to their index in $T$. } %---------------------------------------------------------------------------% \subsection{Include Items} \label{Include Items} %---------------------------------------------------------------------------% Include items allow a model to be split across multiple files. They have this syntax: \begin{productions} \RuleIncludeItem \end{productions} %% For example: \begin{verbatim} include "foo.zinc"; \end{verbatim} includes the file \texttt{foo.zinc}. Include items are particularly useful for accessing libraries or breaking up large models into small pieces. They are not, as Section~\ref{Model Instance Files} explains, used for specifying data files. If the given name is not a complete path then the file is searched for in an implementation-defined set of directories. The search directories must be able to be altered with a command line option. %---------------------------------------------------------------------------% \subsection{Variable Declaration Items} \label{Declarations} %---------------------------------------------------------------------------% Variable declarations have this syntax: \begin{productions} \RuleVarDeclItem \end{productions} For example: \begin{verbatim} int: A = 10; \end{verbatim} It is a type-inst error if a variable is declared and/or defined more than once in a model. A variable whose declaration does not include an assignment can be initialised by a separate assignment item (Section~\ref{Assignments}). For example, the above item can be separated into the following two items: \begin{verbatim} int: A; ... A = 10; \end{verbatim} All variables that contain a parameter component must be defined at instance-time. Variables can have one or more annotations. Section~\ref{Annotations} has more on annotations. %---------------------------------------------------------------------------% \subsection{Assignment Items} \label{Assignments} %---------------------------------------------------------------------------% Assignments have this syntax: \begin{productions} \RuleAssignItem \end{productions} %% For example: \begin{verbatim} A = 10; \end{verbatim} % \pjs{Add something about automatic coercion of index sets?} %---------------------------------------------------------------------------% \subsection{Constraint Items} \label{Constraint Items} %---------------------------------------------------------------------------% Constraint items form the heart of a model. Any solutions found for a model will satisfy all of its constraints. Constraint items have this syntax: \begin{productions} \RuleConstraintItem \end{productions} %% For example: \begin{verbatim} constraint a*x < b; \end{verbatim} The expression in a constraint item must have type-inst \texttt{par bool} or \texttt{var bool}; note however that constraints with fixed expressions are not very useful. %---------------------------------------------------------------------------% \subsection{Solve Items} \label{Solve Items} %---------------------------------------------------------------------------% \resolvedcomment{njn} {Nb: the annotation cannot go after the satisfy/maximize/minimize keyword, because in "solve maximize :: foo(bar)..." you can't tell if the "(bar)" is an argument list for the 'foo', or a parenthesised expression. This screws up the grammar when expressed with yacc.}{} Every model must have exactly one solve item. Solve items have the following syntax: \begin{productions} \RuleSolveItem \end{productions} Example solve items: \begin{verbatim} solve satisfy; solve maximize a*x + y - 3*z; \end{verbatim} The solve item determines whether the model represents a constraint satisfaction problem or an optimisation problem. In the latter case the given expression is the one to be minimized/maximized. The expression in a minimize/maximize solve item can have integer or float type. \Rationale{This is possible because all type-insts have a defined order.} Note that having an expression with a fixed type-inst in a solve item is not very useful as it means that the model requires no optimisation. Solve items can be annotated. Section~\ref{Annotations} has more details on annotations. %---------------------------------------------------------------------------% \subsection{Output Items} \label{Output Items} %---------------------------------------------------------------------------% Output items are used to present the solutions of a model instance. They have the following syntax: \begin{productions} \RuleOutputItem \end{productions} For example: \begin{verbatim} output ["The value of x is ", show(x), "!\n"]; \end{verbatim} The expression must have type-inst \texttt{array[int] of par string}. It can be composed using the built-in operator \texttt{++} and the built-in functions \texttt{show}, \texttt{show\_int}, and \texttt{show\_float} (Appendix~\ref{builtins}). The output is the concatenation of the elements of the array. If no output item is present, the implementation should print all the global variables and their values in a readable format. %---------------------------------------------------------------------------% \subsection{Annotation Items} \label{Annotation Items} %---------------------------------------------------------------------------% Annotation items are used to augment the \texttt{ann} type. They have the following syntax: \begin{productions} \RuleAnnotationItem \end{productions} For example: \begin{verbatim} annotation solver(int: kind); \end{verbatim} It is a type-inst error if an annotation is declared and/or defined more than once in a model. The use of annotations is described in Section~\ref{Annotations}. %---------------------------------------------------------------------------% \subsection{User-defined Operations} \label{preds and fns} %---------------------------------------------------------------------------% % XXX: not saying if operations need to be defined. Implementation % currently requires functions and tests to be defined if used, but % predicates can be bodyless even if used. Should perhaps require functions % to be defined even if they're not used (like parameters), and make tests % like predicates? MiniZinc models can contain user-defined operations. They have this syntax: \begin{productions} \RulePredicateItem \\ \RuleTestItem \\ \RuleFunctionItem \\ \RuleOperationItemTail \\ \RuleParams \\ \end{productions} The type-inst expressions can include type-inst variables in the function and predicate declaration. For example, predicate \texttt{even} checks that its argument is an even number. \begin{verbatim} predicate even(var int: x) = x mod 2 = 0; \end{verbatim} %Predicate \texttt{serial} constrains the resistor \texttt{z} to be %equivalent to connecting the two resistors \texttt{x} and \texttt{y} in %series (the fields \texttt{r} and \texttt{i} represent resistance and %current respectively). %\begin{verbatim} % type Resistor = record(var int: r, var int: i); % predicate serial(Resistor: x, Resistor: y, Resistor: z) = % z.r = x.r + y.r /\ % z.i = x.i /\ % z.i = y.i; %\end{verbatim} A predicate supported natively by the target solver can be declared as follows: \begin{verbatim} predicate alldifferent(array [int] of var int: xs); \end{verbatim} Predicate declarations that are natively supported in MiniZinc are restricted to using FlatZinc types (for instance, multi-dimensional and non-1-based arrays are forbidden). % \pjs{need to fix this if we allow2d arrays in FlatZinc!} Declarations for user-defined operations can be annotated. Section~\ref{Annotations} has more details on annotations. \subsubsection{Basic Properties} \label{Basic Properties} The term ``predicate'' is generally used to refer to both test items and predicate items. When the two kinds must be distinguished, the terms ``test item'' and ``predicate item'' can be used. The return type-inst of a test item is implicitly \texttt{par bool}. The return type-inst of a predicate item is implicitly \texttt{var bool}. % \pjs{Can predicates and functionsbe recursive now?} Predicates and functions are allowed to be recursive. Termination of a recursive function call depends solely on its fixed arguments, i.e., recursive functions and predicates cannot be used to define recursively constrained variables. % \Rationale{This ensures that the satisfiability of models is decidable.} Predicates and functions introduce their own local names, being those of the formal arguments. The scope of these names covers the predicate/function body. Argument names cannot be repeated within a predicate/function declaration. %MiniZinc is mostly a first-order language, so operations cannot, in %general, be used as values. The only exception to this is that they may be %given as the first argument to \texttt{foldl} or \texttt{foldr}, and as %arguments in annotation literals (see Section~\ref{Higher-order Types}). \subsubsection{Ad-hoc polymorphism} MiniZinc supports ad-hoc polymorphism via overloading. Functions and predicates (both built-in and user-defined) can be overloaded. A name can be overloaded as both a function and a predicate. It is a type-inst error if a single version of an overloaded operation with a particular type-inst signature is declared and/or defined more than once in a model. For example: \begin{verbatim} predicate p(1..5: x); predicate p(1..5: x) = true; % error: repeated declaration \end{verbatim} The combination of overloading and coercions can cause problems. Two overloadings of an operation are said to ``overlap'' if they could match the same arguments. For example, the following overloadings of \texttt{p} overlap, as they both match the call \texttt{p(3)}. \begin{verbatim} predicate p(par int: x); predicate p(var int: x); \end{verbatim} However, the following two predicates do not overlap because they cannot match the same argument: \begin{verbatim} predicate q(int: x); predicate q(set of int: x); \end{verbatim} We avoid two potential overloading problems by placing some restrictions on overlapping overloadings of operations. \begin{enumerate} \item The first problem is ambiguity. Different placement of coercions in operation arguments may allow different choices for the overloaded function. For instance, if a MiniZinc function \texttt{f} is overloaded like this: \begin{verbatim} function int: f(int: x, float: y) = 0; function int: f(float: x, int: y) = 1; \end{verbatim} then \texttt{f(3,3)} could be either 0 or 1 depending on coercion/overloading choices. To avoid this problem, any overlapping overloadings of an operation must be semantically equivalent with respect to coercion. For example, the two overloadings of the predicate \texttt{p} above must have bodies that are semantically equivalent with respect to overloading. Currently, this requirement is not checked and the modeller must satisfy it manually. In the future, we may require the sharing of bodies among different versions of overloaded operations, which would provide automatic satisfaction of this requirement. \item The second problem is that certain combinations of overloadings could require a MiniZinc implementation to perform combinatorial search in order to explore different choices of coercions and overloading. For example, if function \texttt{g} is overloaded like this: \begin{verbatim} function float: g(int: t1, float: t2) = t2; function int : g(float: t1, int: t2) = t1; \end{verbatim} then how the overloading of \texttt{g(3,4)} is resolved depends upon its context: \begin{verbatim} float: s = g(3,4); int: t = g(3,4); \end{verbatim} In the definition of \texttt{s} the first overloaded definition must be used while in the definition of \texttt{t} the second must be used. To avoid this problem, all overlapping overloadings of an operation must be closed under intersection of their input type-insts. That is, if overloaded versions have input type-inst $(S_1,....,S_n)$ and $(T_1,...,T_n)$ then there must be another overloaded version with input type-inst $(R_1,...,R_n)$ where each $R_i$ is the greatest lower bound (\emph{glb}) of $S_i$ and $T_i$. Also, all overlapping overloadings of an operation must be monotonic. That is, if there are overloaded versions with input type-insts $(S_1,....,S_n)$ and $(T_1,...,T_n)$ and output type-inst $S$ and $T$, respectively, then $S_i \preceq T_i$ for all $i$, implies $S \preceq T$. At call sites, the matching overloading that is lowest on the type-inst lattice is always used. For \texttt{g} above, the type-inst intersection (or \emph{glb}) of \texttt{(float,int)} and \texttt{(float,int)} is \texttt{(int,int)}. Thus, the overloaded versions are not closed under intersection and the user needs to provide another overloading for \texttt{g} with input type-inst \texttt{(int,int)}. The natural definition is: \begin{verbatim} function int: g(int: t1, int: t2) = t1; \end{verbatim} Once \texttt{g} has been augmented with the third overloading, it satisfies the monotonicity requirement because the output type-inst of the third overloading is \texttt{int} which is less than the output type-inst of the original overloadings. Monotonicity and closure under type-inst conjunction ensure that whenever an overloaded function or predicate is reached during type-inst checking, there is always a unique and safe ``minimal'' version to choose, and so the complexity of type-inst checking remains linear. Thus in our example \texttt{g(3,4)} is always resolved by choosing the new overloaded definition. \end{enumerate} \ignore{ \subsubsection{Parametric Polymorphism} \label{Parametric Polymorphism} \pjs{Better check what it actually does!} MiniZinc supports parametric polymorphism of functions and predicates via type-inst variables. For example, function \texttt{min\n{}of\n{}two} takes two parameters and gives their minimum. \begin{verbatim} function $T:min_of_two($T: x, $T: y) = if x <= y then x else y endif; \end{verbatim} This function is possible because every type has a built-in ordering. Section~\ref{Type-inst Variables} explained that type-inst variables can have no prefix (or, equivalently, a \texttt{par} prefix). The prefixes are necessary for precise type-inst signatures of some user-defined operations. For example, consider the following two definitions of a function \texttt{between}: \begin{verbatim} par bool: function between(par $T: x, par $T: y, par $T: z) = (x <= y /\ y <= z) \/ (z <= y /\ y <= x); var bool: function between($T: x, $T: y, $T: z) = (x <= y /\ y <= z) \/ (z <= y /\ y <= x); \end{verbatim} The first version has a more precise return type-inst. The \texttt{par} prefixes is needed to express the difference between these two versions. \pjs{The example above is causes an error "function defined for this type already!} Note that although \texttt{par \$T} (and also \texttt{\$T}) only \emph{matches} fixed type-insts, it does not mean that the type-inst variable \texttt{\$T} must be \emph{bound} to a fixed type-inst. For example, with these variables and predicate: \begin{verbatim} par int: pi; var int: vi; predicate p(par $T: x, $T: y); \end{verbatim} the first two of the following are acceptable, but the last two are errors: \begin{verbatim} constraint p(pi, pi); % ok: $T bound to 'par int' constraint p(pi, vi); % ok: $T bound to 'var int' constraint p(vi, pi); % error constraint p(vi, vi); % error \end{verbatim} } \subsubsection{Local Variables} Local variables in operation bodies are introduced using let expressions. For example, the predicate \texttt{have\n{}common\n{}divisor} takes two integer values and checks whether they have a common divisor greater than one: \begin{verbatim} predicate have_common_divisor(int: A, int: B) = let { var 2..min(A,B): C; } in A mod C = 0 /\ B mod C = 0; \end{verbatim} However, as Section~\ref{Let Expressions} explained, because \texttt{C} is not defined, this predicate cannot be called in a negative context. The following is a version that could be called in a negative context: \begin{verbatim} predicate have_common_divisor(int: A, int: B) = exists(C in 2..min(A,B)) (A mod C = 0 /\ B mod C = 0); \end{verbatim} %===========================================================================% \section{Annotations} \label{Annotations} %===========================================================================% Annotations---values of the \texttt{ann} type---allow a modeller to specify non-declarative and solver-specific information that is beyond the core language. Annotations do not change the meaning of a model, however, only how it is solved. Annotations can be attached to variables (on their declarations), expresssions, type-inst synonyms, enum items, solve items and on user defined operations. They have the following syntax: %\comment{pjs}{ %What exactly do they mean? In:\\ % \indent\texttt{strength(24.0) :: forall(i in 1..n) x[i] >= 0}\\ %do I get the penalty of 24 if at least one \texttt{x[i] >= 0} is not satisfied, %do I get a penalty of 24 for each one that is not satisfied?\\ %} \begin{productions} \RuleAnnotations \\ \RuleAnnotation \end{productions} For example: \begin{verbatim} int: x::foo; x = (3 + 4)::bar("a", 9)::baz("b"); solve :: blah(4) minimize x; \end{verbatim} The types of the argument expressions must match the argument types of the declared annotation. Unlike user-defined predicates and functions, annotations cannot be overloaded. \Rationale{There is no particular strong reason for this, it just seemed to make things simpler.} Annotation signatures can contain type-inst variables. The order and nesting of annotations do not matter. For the expression case it can be helpful to view the annotation connector \texttt{'::'} as an overloaded operator: \begin{verbatim} ann: '::'(any $T: e, ann: a); % associative ann: '::'(ann: a, ann: b); % associative + commutative \end{verbatim} Both operators are associative, the second is commutative. This means that the following expressions are all equivalent: \begin{verbatim} e :: a :: b e :: b :: a (e :: a) :: b (e :: b) :: a e :: (a :: b) e :: (b :: a) \end{verbatim} This property also applies to annotations on solve items and variable declaration items. \Rationale{This property make things simple, as it allows all nested combinations of annotations to be treated as if they are flat, thus avoiding the need to determine what is the meaning of an annotated annotation. It also makes the MiniZinc abstract syntax tree simpler by avoiding the need to represent nesting.} % The Standard Annotations bit is currently commented out. %Zinc's built-in annotations are listed in Appendix~\ref{Standard %Annotations}. Moreover, an implementation is likely to define a number of %its own annotations for a variety of purposes. %===========================================================================% \section{Partiality} \label{Partiality} %===========================================================================% The presence of constrained type-insts in MiniZinc means that various operations are potentially \emph{partial}, i.e.~not clearly defined for all possible inputs. For example, what happens if a function expecting a positive argument is passed a negative argument? What happens if a variable is assigned a value that does not satisfy its type-inst constraints? What happens if an array index is out of bounds? This section describes what happens in all these cases. % \pjs{This is not what seems to happen in the current MiniZinc!} In general, cases involving fixed values that do not satisfy constraints lead to run-time aborts. \Rationale{Our experience shows that if a fixed value fails a constraint, it is almost certainly due to a programming error. Furthermore, these cases are easy for an implementation to check.} But cases involving unfixed values vary, as we will see. \Rationale{The best thing to do for unfixed values varies from case to case. Also, it is difficult to check constraints on unfixed values, particularly because during search a decision variable might become fixed and then backtracking will cause this value to be reverted, in which case aborting is a bad idea.} % XXX PARTIAL: as described, this static matching turned out to be a bad idea -- % it was not smart enough, and so clearly valid models were rejected, and % making it smarter is a slippery slope -- there are lots of cases, handling % all of them is difficult, and ones that aren't handled lead to very % confusing error messages for users. See additional "XXX PARTIAL" marks % below also. % %%-----------------------------------------------------------------------------% %\subsection{Static Matching} %%-----------------------------------------------------------------------------% %Before describing the cases, we need to define the notion of %\emph{static matching}. % %A type-inst expression \emph{statically matches} another iff one of the %following is true. %\begin{itemize} %\item % They are identical identifiers (ignoring \texttt{par} and \texttt{var} % prefixes). For example, if we have these: %\begin{verbatim} % type Pos = (int: x where x > 0); % type Pos2 = Pos; % set of int: s135 = {1, 3, 5}; % enum C = {R, G, B}; %\end{verbatim} % then we have the following matches and non-matches. %\begin{verbatim} % Pos Pos % match % par s135 var s135 % match % C par C % match % Pos Pos2 % no match: not synt. identical %\end{verbatim} % %\item % They are both range type-insts that contain only scalar literals and % function calls, and they are syntactically identical (ignoring % differences in whitespace, parentheses, annotations, and \texttt{par} % and \texttt{var} prefixes). For example: %\begin{verbatim} % var 1..5 1..5 % match % par m..n+1 m..(n + 1)::foo % match % 1..5 1..4+1 % no match: not synt. identical % 1..f([1,2]) 1..f([1,2]) % no match: '[1,2]' is not scalar %\end{verbatim} % %\item % They are both set expression type-insts that involve only scalar % literals and function calls, and they are syntactically identical % (ignoring differences in whitespace, parentheses, annotations, and % \texttt{par} and \texttt{var} prefixes). For example: %\begin{verbatim} % {1,3,5} par {1,3,5} % match % {1,f(2::a),5} {1,f(2::a)} % match % {1,3,5} {5,3,1} % no match: not synt. identical %\end{verbatim} %\end{itemize} % %We now extend this notion to cover expressions. An expression, \texttt{E}, %\emph{statically matches} a type-inst expression, \texttt{TIE}, iff it has an %\emph{inferred type-inst expression}, \texttt{InfTIE}, and \texttt{InfTIE} %statically matches \texttt{TIE}. The following expressions have inferred %type-inst expressions. % %\begin{itemize} %\item % If \texttt{E} is an identifier expression, and the identifier is that of a % variable, the inferred type-inst expression is the one from the variable's % declaration. For example, if we have this: %\begin{verbatim} % var Pos: p; %\end{verbatim} % then the inferred type-inst expression of the expression \texttt{p} is % \texttt{var Pos}. % %\item % If \texttt{E} is an array access expression where the array expression has % an inferred type-inst expression \texttt{array[IndexTIE] of ElemTIE}, the % inferred type-inst expression is \texttt{ElemTIE}. For example, if we have % this: %\begin{verbatim} % array[1..3] of var Pos: a; %\end{verbatim} % then the expression \texttt{a[1]} has the inferred type-inst expression % \texttt{var Pos}. % %\item % If \texttt{E} is a tuple access expression where the tuple expression has % an inferred type-inst expression \texttt{tuple(TIE1, TIE2, ...)}, the % inferred type-inst expression is \texttt{TIEn} for the selected \texttt{n}. % For example, if we have this: %\begin{verbatim} % tuple(Pos, var int): t; %\end{verbatim} % then the expression \texttt{t.1} has the inferred type-inst expression % \texttt{Pos}. % %\item % If \texttt{E} is a record access expression where the record expression has % an inferred type-inst expression \texttt{record(TIE1:x1, TIE2:x2, ...)}, % the inferred type-inst expression is \texttt{TIEn} for the selected % \texttt{n}. %\end{itemize} % %Note that all variables are declared using a type-inst expression, with one %exception: generator variables. For those, we determine a declaration %type-inst expression from the generator expression, \texttt{GE}, (ignoring any %surrounding set-to-array coercion) using the following rules. %\begin{itemize} %\item % If \texttt{GE} is an identifier of a type-inst expression (e.g.~the name % of a flat enum), the inferred type-inst expression is that same % identifier. %\begin{verbatim} % type t135 = {1,3,5}; % { i | i in t135 } % i's type-inst expression: t135 % enum C = {R, G, B}; % { i | i in C } % i's type-inst expression: C %\end{verbatim} % %\item % If \texttt{GE} is a set identifier, set literal or range expression, the % inferred type-inst expression is the corresponding set expression % type-inst expression. %\begin{verbatim} % set of int: s135 = {1,3,5}; % { i | i in s135 } % i's type-inst expression: s135 % { i | i in 1..5 } % i's type-inst expression: 1..5 % { i | i in {1,3,5::a} } % i's type-inst expression: {1,3,5::a} %\end{verbatim} % %\item % Otherwise, the inferred type-inst expression is the appropriate % unconstrained one. For example: %\begin{verbatim} % { i | i in [1,3,5] } % i's type-inst expression: int %\end{verbatim} %\end{itemize} % %An expression that statically matches a type-inst expression is guaranteed %to satisfy its constraints at run-time. The following sections will show %that static matching is used to guarantee that some potentially partial %cases are actually total. This guarantee is conservative---there are many %expressions that do not statically match a type-inst expression, but would %satisfy its constraint at run-time. % %\Rationale{The static matching rules provide a balance between %ease-of-implementation and ease-of-use. As described, static matching is %easy to implement; in particular, it does not require any compile-time %expression evaluation, which would be required if sub-ranges had to be %detected, for example. But they also cover most cases that occur in %practice; we have seen that modellers almost always use type-inst synonyms %for complex constrained type-insts, and range type-insts are the other %common case. For the cases that static matching does not cover, simple %workarounds usually exist, such as introducing an intermediate variable with %an appropriate type-inst expression.} % %The matching rules may be expanded in the future to make them less %conservative if they are too restrictive. %-----------------------------------------------------------------------------% \subsection{Partial Assignments} %-----------------------------------------------------------------------------% The first operation involving partiality is assignment. There are four distinct cases for assignments. \begin{itemize} \item A value assigned to a fixed, constrained global variable is checked at run-time; if the assigned value does not satisfy its constraints, it is a run-time error. In other words, this: \begin{verbatim} 1..5: x = 3; \end{verbatim} is equivalent to this: \begin{verbatim} int: x = 3; constraint assert(x in 1..5, "assignment to global parameter 'x' failed") \end{verbatim} \item A value assigned to an unfixed, constrained global variable makes the assignment act like a constraint; if the assigned value does not satisfy the variable's constraints, it causes a run-time model failure. In other words, this: \begin{verbatim} var 1..5: x = 3; \end{verbatim} is equivalent to this: \begin{verbatim} var int: x = 3; constraint x in 1..5; \end{verbatim} \Rationale{This behaviour is easy to understand and easy to implement.} \item A value assigned to a fixed, constrained let-local variable is checked at run-time; if the assigned value does not satisfy its constraints, it is a run-time error. In other words, this: \begin{verbatim} let { 1..5: x = 3; } in x+1 \end{verbatim} is equivalent to this: \begin{verbatim} let { int: x = 3; } in assert(x in 1..5, "assignment to let parameter 'x' failed", x+1) \end{verbatim} % XXX PARTIAL: this was specified when syntactic matching looked like a good % idea. For the moment, allowing them to fail seems like a better idea. % %\item % A value assigned to an unfixed, constrained let-local variable is % checked at compile-time; if the assigned value does not statically % match the variable's constraint, it is a compile-time error. In other % words, something like this is not allowed: %\begin{verbatim} % let { var 1..5: x = 3 } in x+1 %\end{verbatim} % because \texttt{3} does not statically match \texttt{var 1..5}. % \Rationale{This is because this case is very uncommon, and implementing % ``failure'' sensibly is not easy. This is also the case that is most % likely to cause a modeller problems, as it can be difficult to introduce % an intermediate variable with the appropriate type-inst expression, % especially if the let is inside a predicate/function.} \item A value assigned to an unfixed, constrained let-local variable makes the assignment act like a constraint; if the assigned value does not statically match the variable's constraint at run-time it fails, and the failure ``bubbles up'' to the nearest enclosing Boolean scope, where it is interpreted as \texttt{false}. \Rationale{This behaviour is consistent with assignments to global variables.} \end{itemize} Note that in cases where a value is partly fixed and partly unfixed, e.g.~some tuples, the different elements are checked according to the different cases, and fixed elements are checked before unfixed elements. For example: \begin{verbatim} u = [ let { var 1..5: x = 6} in x, let { par 1..5: y = 6; } in y) ]; \end{verbatim} This causes a run-time abort, because the second, fixed element is checked before the first, unfixed element. This ordering is true for the cases in the following sections as well. \Rationale{This ensures that failures cannot mask aborts, which seems desirable.} %-----------------------------------------------------------------------------% \subsection{Partial Predicate/Function and Annotation Arguments} %-----------------------------------------------------------------------------% The second kind of operation involving partiality is calls and annotations. % The behaviour for these operations is simple: constraints on arguments are % ignored. % % \Rationale{This is easy to implement and easy to understand. It is also % justifiable in the sense that predicate/function/annotation arguments are % values that are passed in from elsewhere; if those values are to be % constrained, that could be done earlier. (In comparison, when a variable % with a constrained type-inst is declared, any assigned value must clearly % respect that constraint.)} The semantics is similar to assignments: fixed arguments that fail their constraints will cause aborts, and unfixed arguments that fail their constraints will cause failure, which bubbles up to the nearest enclosing Boolean scope. % XXX PARTIAL: this text is from when syntactic checking seemed like a good % idea. Now just ignoring the argument constraints seems better. % %There are two distinct cases. % %\begin{itemize} %\item % Each actual argument in a predicate/function call or annotation that % corresponds to a fixed, constrained formal argument is checked at % run-time; if the actual argument value does not satisfy the formal % argument's constraints, it is a run-time error. % % Similarly, the return value of a function with a constrained return % type-inst expression is checked at run-time; if the return value does % not satisfy the return constraints, it is a run-time error. % % In other words, this: %\begin{verbatim} % function 2..6: f(1..5: x) = x+1; %\end{verbatim} % is equivalent to this: %\begin{verbatim} % predicate f(int: x) = % assert(x in 1..5, "argument 'x' of 'f' failed", % assert(x+1 in 2..6, "return value of 'f' failed", x+1)); %\end{verbatim} % %\item % Each actual argument in a predicate/function call or annotation that % corresponds to an unfixed, formal argument is checked at compile-time; % if the actual argument value does not statically match the formal % argument's type-inst expression, it is a compile-time error. For % example: %\begin{verbatim} % predicate q(var 1..5: x) = x > 0; % var 1..5: i = 3; % constraint q(3); % compile-time error % constraint q(i); % ok %\end{verbatim} % \Rationale{This fits with the way modellers tend to use partial % arguments, which is in a sub-type style rather than a constraining % style. Furthermore, implementing failure in this case is difficult.} %\end{itemize} %-----------------------------------------------------------------------------% \subsection{Partial Array Accesses} %-----------------------------------------------------------------------------% The third kind of operation involving partiality is array access. There are two distinct cases. \begin{itemize} \item A fixed value used as an array index is checked at run-time; if the index value is not in the index set of the array, it is a run-time error. \item An unfixed value used as an array index makes the access act like a constraint; if the access fails at run-time, the failure ``bubbles up'' to the nearest enclosing Boolean scope, where it is interpreted as \texttt{false}. For example: \begin{verbatim} array[1..3] of int: a = [1,2,3]; var int: i; constraint (a[i] + 3) > 10 \/ i = 99; \end{verbatim} Here the array access fails, so the failure bubbles up to the disjunction, and \texttt{i} is constrained to be 99. \Rationale{Unlike predicate/function calls, modellers in practice sometimes do use array accesses that can fail. In such cases, the ``bubbling up'' behaviour is a reasonable one.} \end{itemize} \appendix %=============================================================================% \clearpage \section{Built-in Operations} \label{builtins} %=============================================================================% This appendix lists built-in operators, functions and predicates. They may be implemented as true built-ins, or in libraries that are automatically imported for all models. Many of them are overloaded. Operator names are written within single quotes when used in type signatures, e.g.~\verb+bool: '\/'(bool, bool)+. We use the syntax \texttt{TI: f(TI1,...,TIn)} to represent an operation named \texttt{f} that takes arguments with type-insts \texttt{TI,...,TIn} and returns a value with type-inst \texttt{TI}. This is slightly more compact than the usual MiniZinc syntax, in that it omits argument names. %\newcommand{\builtin}{\hspace{-8mm}$\bullet$} \newcommand{\builtin}{\noindent} %---------------------------------------------------------------------------% \subsection{Comparison Operations} %---------------------------------------------------------------------------% \builtin{} Less than. Other comparisons are similar: greater than (\texttt{>}), less than or equal (\texttt{<=}), greater than or equal (\texttt{>=}), equality (\texttt{==}, \texttt{=}), and disequality (\texttt{!=}). % \pjs{Check use of any here!} \begin{verbatim} bool: '<'( $T, $T) var bool: '<'(var $T, var $T) \end{verbatim} %---------------------------------------------------------------------------% \subsection{Arithmetic Operations} %---------------------------------------------------------------------------% \builtin{} Addition. Other numeric operations are similar: subtraction (\texttt{-}), and multiplication (\texttt{*}). \begin{verbatim} int: '+'( int, int) var int: '+'(var int, var int) float: '+'( float, float) var float: '+'(var float, var float) \end{verbatim} \builtin{} Unary minus. Unary plus (\texttt{+}) is similar. \begin{verbatim} int: '-'( int) var int: '-'(var int) float: '-'( float) var float: '-'(var float) \end{verbatim} \builtin{} Integer and floating-point division and modulo. \begin{verbatim} int: 'div'( int, int) var int: 'div'(var int, var int) int: 'mod'( int, int) var int: 'mod'(var int, var int) float: '/' ( float, float) var float: '/' (var float, var float) \end{verbatim} The result of the modulo operation, if non-zero, always has the same sign as its first operand. The integer division and modulo operations are connected by the following identity: \begin{verbatim} x = (x div y) * y + (x mod y) \end{verbatim} Some illustrative examples: \begin{verbatim} 7 div 4 = 1 7 mod 4 = 3 -7 div 4 = -1 -7 mod 4 = -3 7 div -4 = -1 7 mod -4 = 3 -7 div -4 = 1 -7 mod -4 = -3 \end{verbatim} \builtin{} Sum multiple numbers. % Unrolled using \texttt{+}. Product (\texttt{product}) is similar. Note that the sum of an empty array is 0, and the product of an empty array is 1. \begin{verbatim} int: sum(array[$T] of int ) var int: sum(array[$T] of var int ) float: sum(array[$T] of float) var float: sum(array[$T] of var float) \end{verbatim} \builtin{} Minimum of two values; maximum (\texttt{max}) is similar. \begin{verbatim} any $T: min(any $T, any $T ) \end{verbatim} \builtin{} Minimum of an array of values; maximum (\texttt{max}) is similar. Aborts if the array is empty. \begin{verbatim} any $U: min(array[$T] of any $U) \end{verbatim} \builtin{} Minimum of a fixed set; maximum (\texttt{max}) is similar. Aborts if the set is empty. \begin{verbatim} $T: min(set of $T) \end{verbatim} \builtin{} Absolute value of a number. \begin{verbatim} int: abs( int) var int: abs(var int) float: abs( float) var float: abs(var float) \end{verbatim} \builtin{} Square root of a float. Aborts if argument is negative. \begin{verbatim} float: sqrt( float) var float: sqrt(var float) \end{verbatim} \builtin{} Power operator. E.g.~\texttt{pow(2, 5)} gives \texttt{32}. \begin{verbatim} int: pow(int, int) float: pow(float, float) \end{verbatim} % We should also have: % var float: pow(var float, int) \builtin{} Natural exponent. \begin{verbatim} float: exp(float) var float: exp(var float) \end{verbatim} \builtin{} Natural logarithm. Logarithm to base 10 (\texttt{log10}) and logarithm to base 2 (\texttt{log2}) are similar. \begin{verbatim} float: ln(float) var float: ln(var float) \end{verbatim} \builtin{} General logarithm; the first argument is the base. \begin{verbatim} float: log(float, float) \end{verbatim} \builtin{} Sine. Cosine (\texttt{cos}), tangent (\texttt{tan}), inverse sine (\texttt{asin}), inverse cosine (\texttt{acos}), inverse tangent (\texttt{atan}), hyperbolic sine (\texttt{sinh}), hyperbolic cosine (\texttt{cosh}), hyperbolic tangent (\texttt{tanh}), inverse hyperbolic sine (\texttt{asinh}), inverse hyperbolic cosine (\texttt{acosh}) and inverse hyperbolic tangent (\texttt{atanh}) are similar. \begin{verbatim} float: sin(float) var float: sin(var float) \end{verbatim} %---------------------------------------------------------------------------% \subsection{Logical Operations} %---------------------------------------------------------------------------% \builtin{} Conjunction. Other logical operations are similar: disjunction (\verb+\/+) reverse implication (\texttt{<-}), forward implication (\texttt{->}), bi-implication (\texttt{<->}), exclusive disjunction (\texttt{xor}), logical negation (\texttt{not}). Note that the implication operators are not written using \texttt{=>}, \texttt{<=} and \texttt{<=>} as is the case in some languages. This allows \texttt{<=} to instead represent ``less than or equal''. \begin{verbatim} bool: '/\'( bool, bool) var bool: '/\'(var bool, var bool) \end{verbatim} \builtin{} Universal quantification. Existential quantification (\texttt{exists}) is similar. Note that, when applied to an empty list, \texttt{forall} returns \texttt{true}, and \texttt{exists} returns \texttt{false}. \begin{verbatim} bool: forall(array[$T] of bool) var bool: forall(array[$T] of var bool) \end{verbatim} \builtin{} N-ary exclusive disjunction. N-ary bi-implication (\texttt{iffall}) is similar, with \texttt{true} instead of \texttt{false}. \begin{verbatim} bool: xorall(array[$T] of bool: bs) = foldl('xor', false, bs) var bool: xorall(array[$T] of var bool: bs) = foldl('xor', false, bs) \end{verbatim} %---------------------------------------------------------------------------% \subsection{Set Operations} %---------------------------------------------------------------------------% \builtin{} Set membership. \begin{verbatim} bool: 'in'( $T, set of $T ) var bool: 'in'(var int, var set of int) \end{verbatim} \builtin{} Non-strict subset. Non-strict superset (\texttt{superset}) is similar. \begin{verbatim} bool: 'subset'( set of $T , set of $T ) var bool: 'subset'(var set of int, var set of int) \end{verbatim} \builtin{} Set union. Other set operations are similar: intersection (\texttt{intersect}), difference (\texttt{diff}), symmetric difference (\texttt{symdiff}). \begin{verbatim} set of $T: 'union'( set of $T, set of $T ) var set of int: 'union'(var set of int, var set of int ) \end{verbatim} \builtin{} Set range. If the first argument is larger than the second (e.g.~\texttt{1..0}), it returns the empty set. \begin{verbatim} set of int: '..'(int, int) \end{verbatim} \builtin{} Cardinality of a set. \begin{verbatim} int: card( set of $T) var int: card(var set of int) \end{verbatim} \builtin{} Union of an array of sets. %Unrolled with \texttt{union}. Intersection of multiple sets (\texttt{array\n{}intersect}) is similar. \begin{verbatim} set of $U: array_union(array[$T] of set of $U) var set of int: array_union(array[$T] of var set of int) \end{verbatim} \ignore{ \builtin{} Power set. \begin{verbatim} set of set of $T: powerset(set of $T) \end{verbatim} \builtin{} Cartesian product of sets. This list is only partial, it extends in the obvious way, for greater numbers of sets. \begin{verbatim} set of tuple($T1, $T2): cartesian_product(set of $T1, set of $T2) set of tuple($T1, $T2, $T3): cartesian_product(set of $T1, set of $T2, set of $T3) ... \end{verbatim} } %---------------------------------------------------------------------------% \subsection{Array Operations} %---------------------------------------------------------------------------% \builtin{} Length of an array. \begin{verbatim} int: length(array[$T] of any $U) \end{verbatim} \builtin{} List concatenation. Returns the list (integer-indexed array) containing all elements of the first argument followed by all elements of the second argument, with elements occurring in the same order as in the arguments. The resulting indices are in the range \texttt{1..n}, where \texttt{n} is the sum of the lengths of the arguments. \Rationale{This allows list-like arrays to be concatenated naturally and avoids problems with overlapping indices. The resulting indices are consistent with those of implicitly indexed array literals.} Note that \texttt{'++'} also performs string concatenation. \begin{verbatim} array[int] of any $T: '++'(array[int] of any $T, array[int] of any $T) \end{verbatim} \ignore{ \builtin{} Array merge. Does not change any indices. If any index is repeated in the result, it is a run-time error. Note that it may result in an interleaving of the elements, e.g.~the merge of \texttt{[1:1, 3:3]} and \texttt{[2:2, 4:4]} is \texttt{[1:1, 2:2, 3:3, 4:4]}. \begin{verbatim} array[$T] of any $U: merge(array[$T] of any $U, array[$T] of any $U) \end{verbatim} } \builtin{} Index sets of arrays. If the argument is a literal, returns \texttt{1..n} where \texttt{n} is the (sub-)array length. Otherwise, returns the declared or inferred index set. This list is only partial, it extends in the obvious way, for arrays of higher dimensions. \begin{verbatim} set of $T: index_set (array[$T] of any $V) set of $T: index_set_1of2(array[$T, $U] of any $V) set of $U: index_set_2of2(array[$T, $U] of any $V) ... \end{verbatim} \ignore{ \builtin{} Get the first and last elements of an array, and the tail of an array (i.e.~all elements except the first). All of them abort if the array is empty. \begin{verbatim} any $U: head(array[$T] of any $U) any $U: last(array[$T] of any $U) array[$T] of any $U: tail(array[$T] of any $U) \end{verbatim} } \builtin{} Replace the indices of the array given by the last argument with the Cartesian product of the sets given by the previous arguments. Similar versions exist for arrays up to 6 dimensions. \begin{verbatim} array[$T1] of any $V: array1d(set of $T1, array[$U] of any $V) array[$T1,$T2] of any $V: array2d(set of $T1, set of $T2, array[$U] of any $V) array[$T1,$T2,$T3] of any $V: array3d(set of $T1, set of $T2, set of $T3, array[$U] of any $V) \end{verbatim} \ignore{ \builtin{} Merges an array-of-arrays into an array, by folding \texttt{merge} over the array-of-arrays. It is a run-time error if any of the indices are repeated in the result. \begin{verbatim} array[$U] of $V: array_merge(array[$T] of array[$U] of $V) \end{verbatim} \builtin{} Condenses an array-of-arrays into an array, by folding \texttt{++} over the array-of-arrays. The resulting indices are in the range \texttt{1..n}, where \texttt{n} is the sum of the lengths of the arrays in the argument. \begin{verbatim} array[int] of $T: condense(array[$U] of array[int] of $T) \end{verbatim} } %---------------------------------------------------------------------------% \subsection{Coercion Operations} %---------------------------------------------------------------------------% \builtin{} Round a float towards $+\infty$, $-\infty$, and the nearest integer, respectively. \begin{verbatim} int: ceil (float) int: floor(float) int: round(float) \end{verbatim} \builtin{} Explicit casts from one type-inst to another. \begin{verbatim} int: bool2int( bool) var int: bool2int(var bool) float: int2float( int) var float: int2float(var int) array[int] of $T: set2array(set of $T) \end{verbatim} %---------------------------------------------------------------------------% \subsection{String Operations} %---------------------------------------------------------------------------% \builtin{} To-string conversion. Converts any value to a string for output purposes. The exact form of the resulting string is implementation-dependent. \begin{verbatim} string: show(any $T) \end{verbatim} \builtin{} Formatted to-string conversion for integers. Converts the integer given by the second argument into a string right justified by the number of characters given by the first argument, or left justified if that argument is negative. If the second argument is not fixed, the form of the string is implementation-dependent. \begin{verbatim} string: show_int(int, var int); \end{verbatim} \builtin{} Formatted to-string conversion for floats. Converts the float given by the third argument into a string right justified by the number of characters given by the first argument, or left justified if that argument is negative. The number of digits to appear after the decimal point is given by the second argument. It is a run-time error for the second argument to be negative. If the third argument is not fixed, the form of the string is implemenation-dependent. \begin{verbatim} string: show_float(int, int, var float) \end{verbatim} \builtin{} String concatenation. Note that \texttt{'++'} also performs array concatenation. \begin{verbatim} string: '++'(string, string) \end{verbatim} \builtin{} Concatenate an array of strings. Equivalent to folding \texttt{'++'} over the array, but may be implemented more efficiently. \begin{verbatim} string: concat(array[$T] of string) \end{verbatim} \builtin{} Concatenate an array of strings, putting a seperator beween adjacent strings. Returns the the empty string if the array is empty. \begin{verbatim} string: join(string, array[$T] of string) \end{verbatim} %-----------------------------------------------------------------------------% \subsection{Bound and Domain Operations} %-----------------------------------------------------------------------------% \ignore{ \builtin{} \begin{verbatim} $T: lb(any $T) $T: ub(any $T) set of $T: dom(any $T) int: dom_size(any $T) \end{verbatim} The bound operations \texttt{lb/ub} return fixed, correct lower/upper bounds to the expression. % For numeric types, they return a lower/upper bound value, e.g.\ the lowest/highest value the expression can take. Similarly for Boolean expressions. % For set types, they return a subset/superset, e.g.\ the intersection/union of all possible values of the set expression. % %For tuple/record types, they return a tuple/record %containing the lower/upper bound of each element. % For array types, they return an array of corresponding index set containing the lower/upper bound of each array element. % For example, the lower bound of a set variable that could equal \texttt{\{1,3,5\}} or \texttt{\{1,2,4\}} is \texttt{\{1}\}, and the upper bound is \texttt{\{1,2,3,4,5\}}. The bound operations abort on expressions that have no corresponding finite bound. For example, this would be the case for a variable declared without bounds in an implementation that does not assign default bounds. (Set expressions always have a finite lower bound of course, namely \texttt{\{\}}, the empty set.) \vspace{2mm} The domain operation \texttt{dom} returns a fixed superset of the possible values of the expression. % The \texttt{dom} operation aborts on array expressions. % We could define dom for array values, but it would consume a large % amount of space for all but trivial arguments. % % For example, for array values, it returns a set of arrays % containing the possible values for each element: % \begin{verbatim} % var 1..2: x; % var 5..6: y; % % dom([1:x, 3:y]) = {[1:1, 3:5], [1:1, 3:6], [1:2, 3:5], [1:2, 3:6]}; % \end{verbatim} \vspace{2mm} } The bound operations \texttt{lb/ub} return fixed, correct lower/upper bounds to the expression. % For numeric types, they return a lower/upper bound value, e.g.\ the lowest/highest value the expression can take. %Similarly for Boolean expressions. % For set types, they return a subset/superset, e.g.\ the intersection/union of all possible values of the set expression. The bound operations abort on expressions that have no corresponding finite bound. For example, this would be the case for a variable declared without bounds in an implementation that does not assign default bounds. (Set expressions always have a finite lower bound of course, namely \texttt{\{\}}, the empty set.) \vspace{2mm} \builtin{} Numeric lower/upper bound: \begin{verbatim} int: lb(var int) float: lb(var float) int: ub(var int) float: ub(var float) \end{verbatim} \builtin{} Set lower/upper bound: \begin{verbatim} set of int: lb(var set of int) set of int: ub(var set of int) \end{verbatim} \builtin{} Versions of the bound operations that operate on arrays are also available, they return a safe lower bound or upper bound for all members of the array -- they abort if the array is empty: \begin{verbatim} int: lb_array(array[$T] of var int) float: lb_array(array[$T] of var float) set of int: lb_array(array[$T] of var set of int) int: ub_array(array[$T] of var int) float: ub_array(array[$T] of var float) set of int: ub_array(array[$T] of var set of int) \end{verbatim} \builtin{} Integer domain: \begin{verbatim} set of int: dom(var int) \end{verbatim} The domain operation \texttt{dom} returns a fixed superset of the possible values of the expression. \builtin{} Integer array domain, returns a superset of all possible values that may appear in the array -- this aborts if the array is empty: \begin{verbatim} set of int: dom_array(array[$T] of var int) \end{verbatim} % \pjs{It could return an empty set?} \builtin{} Domain size for integers: \begin{verbatim} int: dom_size(var int) \end{verbatim} The domain size operation \texttt{dom\n{}size} is equivalent to \texttt{card(dom(x))}. \vspace{2mm} Note that these operations can produce different results depending on when they are evaluated and what form the argument takes. For example, consider the numeric lower bound operation. \begin{itemize} \item If the argument is a fixed expression, the result is the argument's value. \item If the argument is a decision variable, then the result depends on the context. \begin{itemize} \item If the implementation can determine a lower bound for the variable, the result is that lower bound. The lower bound may be from the variable's declaration, or higher than that due to preprocessing, or lower than that if an implementation-defined lower bound is applied (e.g.~if the variable was declared with no lower bound, but the implementation imposes a lowest possible bound). \item If the implementation cannot determine a lower bound for the variable, the operation aborts. \end{itemize} \item If the argument is any other kind of unfixed expression, the lower bound depends on the bounds of unfixed subexpressions and the connecting operators. \end{itemize} %-----------------------------------------------------------------------------% \subsection{Option Type Operations} \label{Option Type Operations} %-----------------------------------------------------------------------------% \builtin{} The option type value ($\top$) is written \begin{verbatim} opt $T: '<>'; \end{verbatim} One can determine if an option type variable actually occurs on not using \texttt{occurs} and \texttt{absent} \begin{verbatim} par bool: occurs(par opt $T); var bool: occurs(var opt $T); par bool: absent(par opt $T); var bool: absent(var opt $T); \end{verbatim} One can return the non-optional value of an option type variable using the function \texttt{deopt} \begin{verbatim} par $T: deopt{par opt $T); var $T: deopt(var opt $T); \end{verbatim} % Note that this is not really a function only a pseudo function placeholder % used in the translation of option types to non-option types. % \pjs{Explain better} %-----------------------------------------------------------------------------% \subsection{Other Operations} \label{Other Operations} %-----------------------------------------------------------------------------% \builtin{} Check a Boolean expression is true, and abort if not, printing the second argument as the error message. The first one returns the third argument, and is particularly useful for sanity-checking arguments to predicates and functions; importantly, its third argument is lazy, i.e.~it is only evaluated if the condition succeeds. The second one returns \texttt{true} and is useful for global sanity-checks (e.g.~of instance data) in constraint items. \begin{verbatim} any $T: assert(bool, string, any $T) par bool: assert(bool, string) \end{verbatim} \builtin{} Abort evaluation, printing the given string. \begin{verbatim} any $T: abort(string) \end{verbatim} \builtin{} Return true. As a side-effect, an implementation may print the first argument. \begin{verbatim} bool: trace(string) \end{verbatim} \builtin{} Return the second argument. As a side-effect, an implementation may print the first argument. \begin{verbatim} any $T: trace(string, any $T) \end{verbatim} \builtin{} Check if the argument's value is fixed at this point in evaluation. If not, abort; if so, return its value. This is most useful in output items when decision variables should be fixed---it allows them to be used in places where a fixed value is needed, such as if-then-else conditions. \begin{verbatim} $T: fix(any $T) \end{verbatim} \builtin{} As above, but return \texttt{false} if the argument's value is not fixed. \begin{verbatim} par bool: is_fixed(any $T) \end{verbatim} \ignore{ \builtin{} Fold a binary function over an array in a left-associative manner. For example, \texttt{foldl('+', 0, xs)} is \texttt{sum}, and \texttt{foldl('}\verb+/\+\texttt{', true, xs)} is \texttt{forall}. \begin{verbatim} any $T: foldl(any $T:(any $T,any $U), any $T, array[$V] of any $U) \end{verbatim} \builtin{} Fold a binary function over an array in a right-associative manner. \begin{verbatim} any $T: foldr(any $T:(any $U,any $T), any $T, array[$V] of any $U) \end{verbatim} } %===========================================================================% \clearpage \section{MiniZinc Grammar} \label{Grammar} %===========================================================================% Section~\ref{Syntax Notation} describes the notation used in the following Zinc grammar. %---------------------------------------------------------------------------% \subsection{Items} %---------------------------------------------------------------------------% \begin{productions} \RuleModel \\ \\ \RuleItem \\ \\ \RuleTypeInstSynItem \\ \\ % \RuleEnumItem \\ % \RuleEnumCases \\ % \RuleEnumCase \\ \RuleTIExprAndId \\ \\ \RuleIncludeItem \\ \\ \RuleVarDeclItem \\ \\ \RuleAssignItem \\ \\ \RuleConstraintItem \\ \\ \RuleSolveItem \\ \\ \RuleOutputItem \\ \\ \RuleAnnotationItem \\ \\ \RulePredicateItem \\ \RuleTestItem \\ \RuleFunctionItem \\ \RuleOperationItemTail \\ \RuleParams \end{productions} %---------------------------------------------------------------------------% \subsection{Type-Inst Expressions} %---------------------------------------------------------------------------% \begin{productions} \RuleTIExpr \\ \RuleBaseTIExpr \\ \RuleVarPar \\ \RuleBaseTIExprTail \\ \\ \RuleSetTIExprTail \\ \\ \RuleArrayTIExprTail \\ \\ % \RuleTupleTIExprTail \\ % \\ % \RuleRecordTIExprTail \\ % \\ \RuleTIVariableExprTail \\ \\ \RuleOpTIExprTail \end{productions} %---------------------------------------------------------------------------% \subsection{Expressions} %---------------------------------------------------------------------------% \begin{productions} \RuleExpr \\ \RuleExprAtom \\ \RuleExprBinopTail \\ \RuleExprAtomHead \\ \RuleExprAtomTail \\ \\ \RuleNumExpr \\ \RuleNumExprAtom \\ \RuleNumExprBinopTail \\ \RuleNumExprAtomHead \\ \\ \RuleBuiltinOp \\ \RuleBinOp \\ \RuleBuiltinBinOp \\ \RuleBuiltinUnOp \\ \\ \RuleNumBinOp \\ \RuleBuiltinNumBinOp \\ \RuleBuiltinNumUnOp \\ \\ \RuleBoolLiteral \\ \\ \RuleIntLiteral \\ \\ \RuleFloatLiteral \\ \\ \RuleStringLiteral \\ \\ \RuleSetLiteral \\ \\ \RuleSetComp \\ \RuleCompTail \\ \RuleGenerator \\ \\ \RuleSimpleArrayLiteral \\ \\ \RuleSimpleArrayLiteralTwoD \\ \\ \RuleSimpleArrayComp \\ \\ % \RuleIndexedArrayLiteral \\ % \RuleIndexExpr \\ % \\ % \RuleIndexedArrayComp \\ \\ \RuleArrayAccessTail \\ \\ % \RuleTupleLiteral \\ % \\ % \RuleTupleAccessTail \\ % \\ % \RuleRecordLiteral \\ % \RuleNamedExpr \\ % \\ % \RuleRecordAccessTail \\ % \\ % \RuleEnumLiteral \\ \\ \RuleAnnLiteral \\ \\ \RuleIfThenElseExpr \\ \\ % \RuleCaseExpr \\ % \RuleCaseExprCase \\ \\ \RuleCallExpr \\ \\ \RuleLetExpr \\ \RuleLetItem \\ \\ \RuleGenCallExpr \end{productions} %---------------------------------------------------------------------------% \subsection{Miscellaneous Elements} %---------------------------------------------------------------------------% \begin{productions} \RuleIdent \\ \RuleIdentOrQuotedOp \\ \\ \RuleAnnotations \\ \RuleAnnotation \end{productions} \ignore{ %=============================================================================% \clearpage \section{MiniZinc} \label{MiniZinc} %=============================================================================% MiniZinc is modelling language that is a subset of Zinc. It is easier to implement, and it can be flattened into FlatZinc in a straightforward manner. For more details on the goals of MiniZinc and FlatZinc, please read \CommonMiniZincPaperTitleAndAuthors{}. This section defines MiniZinc by describing the features from Zinc that it does not support. The two languages have identical grammars, although various syntactically-correct constructs are not valid in MiniZinc programs, and should be rejected by post-parsing checks. \Rationale{In the past, the two languages did have distinct grammars, but combining them makes this document much simpler. It also makes the implementation of MiniZinc a little simpler. It can also allow for better error messages if a Zinc-only feature is used in a MiniZinc program; for example, if an enum item appears in a MiniZinc program, instead of a syntax error such as ``syntax error at \texttt{enum}'', a more helpful error such as ``MiniZinc does not allow enum items'' can be emitted. And it allows Zinc features to be added to MiniZinc more easily later on, should we desire.} %---------------------------------------------------------------------------% \subsection{Items} %---------------------------------------------------------------------------% MiniZinc has the following restrictions on items. \begin{itemize} \item Type-inst synonym items are not supported. \item Enum items are not supported. \item User-defined function items are not supported. \item \CommonSolveMinMaxExprTypeInst{} \end{itemize} %---------------------------------------------------------------------------% \subsection{Type-insts and Expressions} %---------------------------------------------------------------------------% MiniZinc has the following restrictions on type-insts and expressions. \begin{itemize} \item Sets can only contain Booleans, integers, and floats. Sets of integers may be fixed or unfixed; other sets must be fixed. \item Arrays must have indices that are contiguous integer ranges (e.g.~\texttt{0..3}, \texttt{10..12}, or the name of a set variable assigned in the model with a range value), or a tuple of contiguous integer ranges. Furthermore, MiniZinc arrays must be declared with index types that are explicit ranges, or variables that are assigned a range value. Because these types are finite, only explicitly-indexed array variables can be declared in MiniZinc. The one exception is that implicitly-indexed arrays are allowed as arguments to predicates and annotations. \item Arrays can only contain Booleans, integers, floats or sets of integers (all fixed or unfixed), or fixed sets of Booleans or floats, or fixed strings. Arrays-of-arrays are not supported. \item Indexed array literals and comprehensions are not supported. \item Tuples can only be used as array indices, and must contain integers, and must be fixed. Furthermore, neither tuple literals nor tuple accesses are supported. \item Records are not supported. Therefore, neither record literals nor record accesses are supported. Furthermore, there are no local namespaces for record field names. \item Enums are not supported, including in data files. Therefore, case expressions are not supported. Furthermore, there are no local namespaces for (non-flat) enum field names. \item The language is entirely first-order; no higher-order types are supported, operation type-inst expressions are not supported, and operations cannot be used as values. \item Arbitrarily constrained type-insts are not supported. \item Implicit type coercions (e.g.~int-to-float, set-to-array) are not supported, with one exception: set-to-array coercions are allowed in comprehension generators. This allows sets to be used as generator expressions, which is very convenient. However, explicit type coercions are supported (e.g.~\texttt{int2float}), as are implicit inst coercions (e.g.~par-int-to-var-int). \item Type-inst variables are not supported in user-defined predicates and functions. However, many of the built-in operations, e.g.~\texttt{show}, have signatures that feature type-inst variables, and they work with all valid matching MiniZinc types. \end{itemize} %---------------------------------------------------------------------------% \subsection{Built-in Operations} %---------------------------------------------------------------------------% MiniZinc has restrictions on built-in operations. \begin{itemize} \item The comparison operators are not supported for arrays. That is, only the following signatures of `\texttt{<}' are supported (and likewise for the other comparison operators): \begin{verbatim} bool: '<'( int, int) var bool: '<'(var int, var int) bool: '<'( float, float) var bool: '<'(var float, var float) bool: '<'( bool, bool) var bool: '<'(var bool, var bool) bool: '<'( string, string) bool: '<'( set of int, set of int) bool: '<'( set of bool, set of bool) bool: '<'( set of float, set of float) var bool: '<'(var set of int, var set of int) \end{verbatim} \item Only the following signatures of \texttt{min} are supported (and likewise for \texttt{max}): \begin{verbatim} int: min( int, int) var int: min(var int, var int) float: min( float, float) var float: min(var float, var float) int: min(array[int] of int) var int: min(array[int] of var int) float: min(array[int] of float) var float: min(array[int] of var float) int: min(set of int) float: min(set of float) \end{verbatim} \item Only the following signatures of `\texttt{in}' are supported: \begin{verbatim} bool: 'in'( int, set of int) bool: 'in'( bool, set of bool) bool: 'in'( float, set of float) var bool: 'in'(var int, var set of int) \end{verbatim} \item For \texttt{array1d}, \texttt{array2d}, etc., the set arguments must be contiguous integer sets, otherwise it is a run-time error. \item % XXX: ones that could be in MiniZinc: concat, head/last/tail, % foldl/foldr (which would require lifting the "entirely % first-order" restriction above). The following built-in operations are not supported: % (and why not?) \texttt{powerset}, % set-of-set \texttt{cartesian\n{}product}, % tuples \texttt{concat}, % (no reason) \texttt{head}, \texttt{last}, \texttt{tail}, % (no reason) \texttt{condense}, \texttt{condense\n{}int\n{}index}, % array-of-arrays \texttt{foldl}, \texttt{foldr}. % (no reason) \iffalse \item The following built-in annotations are not supported: \texttt{tree\n{}search}. \fi \end{itemize} \iffalse % [Seb] % The "globals" library files aren't mentioned anywhere else in this document. %-----------------------------------------------------------------------------% \subsection{Other} %-----------------------------------------------------------------------------% MiniZinc has the following other restrictions. \begin{itemize} \item \texttt{globals.mzn} is the equivalent to the Zinc \texttt{globals.zinc} library. \end{itemize} \fi } %=============================================================================% \clearpage \section{Content-types} \label{Content-types} %=============================================================================% %-----------------------------------------------------------------------------% \subsection{`application/x-zinc-output'} \label{x-zinc-output} %-----------------------------------------------------------------------------% The content-type `application/x-zinc-output' defines a text output format for Zinc. The format extends the abstract syntax and semantics given in Section~\ref{Run-time Outcomes}, and is discussed in detail in Section~\ref{Output}. The full syntax is as follows: \begin{productions} \RuleOutput \\ \\ \RuleSolution \\ \\ \RuleOutcomeStrings \\ \\ \RuleComplete \\ \\ \RuleWarnings \\ \\ \RuleMessage \end{productions} \noindent The solution text for each solution must be as described in Section~\ref{Output Items}. A newline must be appended if the solution text does not end with a newline. %-----------------------------------------------------------------------------% \end{document} libminizinc-2.0.11/doc/spec/version.tex.in0000644000175000017500000000016112646030173017053 0ustar kaolkaol\newcommand{\mznversion}{${libminizinc_VERSION_MAJOR}.${libminizinc_VERSION_MINOR}.${libminizinc_VERSION_PATCH}} libminizinc-2.0.11/doc/spec/common-spec.tex0000644000175000017500000003020412646030173017202 0ustar kaolkaol\usepackage{ifthen} \newcommand{\commenter}[1]{\textbf{#1}:} \ifthenelse{\equal{\showcomments}{true}}{ \newcommand{\comment}[2]{\footnote{\commenter{#1} #2}} }{ \newcommand{\comment}[2]{} } \ifthenelse{\equal{\showresolvedcomments}{true}}{ \newcommand{\resolvedcomment}[3]{\footnote{\commenter{#1} #2 \\ \textbf{Resolution:} #3}} }{ \newcommand{\resolvedcomment}[3]{} } %-----------------------------------------------------------------------------% \newcommand{\backsl}{\symbol{92}} \newcommand{\carat}{\symbol{94}} \newcommand{\n}{\symbol{95}} \newcommand{\nl}{\texttt{\backsl{}n}} \newcommand{\spc}[1]{\texttt{{#1}SP}} \newenvironment{productions} {\begin{tabbing}} {\end{tabbing}} \newcommand{\production}[1]{xxx \= \nt{#1} ::\== \= \kill \> \nt{#1} ::=} \newcommand{\alt}{\\ \>\>~$\mid$~} % alternative \newcommand{\altB}{$\mid$~} % alternative, doesn't insert newline \newcommand{\spl}{\\ \>\>\>} % for splitting a production across a line \newcommand{\nt}[1]{\ensuremath{\langle}\textit{#1}\ensuremath{\rangle}} \newcommand{\nti}[2]{\ensuremath{\langle}\textit{#1}\ensuremath{\rangle_{#2}}} %\newcommand{\term}[1]{\underline{\textbf{#1}}} \newcommand{\term}[1]{\underline{\texttt{#1}}} \newcommand{\slist}[2]{#1 \term{#2} \ldots} % symbol-separated/terminated list \newcommand{\commas}[1]{\slist{#1}{,}} % comma-sep'd/term'd list \newcommand{\semicolons}[1]{\slist{#1}{;}} % semi-colon-sep'd/term'd list \newcommand{\pipes}[1]{\slist{#1}{\bar}} % pipe-sep'd/term'd list \newcommand{\maybe}[1]{[ #1 ]} % optional item \newcommand{\parens}[1]{\term{(} #1 \term{)}} % parentheses \newcommand{\curlies}[1]{\term{\{} #1 \term{\}}} % curly braces \newcommand{\squares}[1]{\term{[} #1 \term{]}} % square brackets \newcommand{\squaresPipes}[1]{\term{[\bar} #1 \term{\bar]}} % [| |] \newcommand{\zeroOrMore}[1]{( #1 )*} % zero or more items \newcommand{\oneOrMore}[1]{( #1 )+} % one or more items \newcommand{\regexp}[1]{\texttt{#1}} % regexp-as-production \newcommand{\dotdotXX}[1]{#1 \term{..} #1} % X..X \newcommand{\dotdotXY}[2]{#1 \term{..} #2} % X..Y \renewcommand{\bar}{|} \newcommand{\dontknow}{\texttt{\n{}}} \newcommand{\Rationale}[1]{\emph{\textbf{Rationale.} #1}} \newenvironment{RationaleEnv}{\em\textbf{Rationale.}}{\em} %-----------------------------------------------------------------------------% \newcommand{\CommonMiniZincPaperTitleAndAuthors}{\emph{MiniZinc: Towards a Standard CP Modelling Language}, by Nethercote, Stuckey, Becket, Brand, Duck and Tack} %-----------------------------------------------------------------------------% \newcommand{\CommonTwoConceptualParts}[2]{ Conceptually, a #1 problem specification has two parts. \begin{enumerate} \item The \emph{model}: the main part of the problem specification, which describes the structure of a particular class of problems. \item The \emph{data}: the input data for the model, which specifies one particular problem within this class of problems. \end{enumerate} The pairing of a model with a particular data set is an \emph{model instance} (sometimes abbreviated to \emph{instance}). #2 Section~\ref{Model Instance Files} specifies how the model and data can be structured within files in a model instance. } %-----------------------------------------------------------------------------% \newcommand{\CommonCharacterSetAndComments}[1]{ %-----------------------------------------------------------------------% \subsection{Character Set} %-----------------------------------------------------------------------% The input files to #1 must be encoded as UTF-8. #1 is case sensitive. There are no places where upper-case or lower-case letters must be used. #1 has no layout restrictions, i.e.~any single piece of whitespace (containing spaces, tabs and newlines) is equivalent to any other. %-----------------------------------------------------------------------% \subsection{Comments} %-----------------------------------------------------------------------% A \texttt{\%} indicates that the rest of the line is a comment. #1 also has block comments, using symbols \texttt{/*} and \texttt{*/} to mark the beginning and end of a comment. } %-----------------------------------------------------------------------------% \newcommand{\CommonEBNFBasics}[1]{ \begin{itemize} \item Non-terminals are written between angle brackets, e.g.~\nt{item}. \item Terminals are written in fixed-width font. They are usually underlined for emphasis, e.g.~\term{constraint}, although this is not always done if the meaning is clear. \item Optional items are written in square brackets, e.g.~\maybe{\term{var}}. \item Sequences of zero or more items are written with parentheses and a star, e.g. \zeroOrMore{\term{,} \nt{ident}}. \item Sequences of one or more items are written with parentheses and a plus, e.g. \oneOrMore{\nt{msg}}. % Having '...' mean two slightly different things for the two cases isn't % nice, but I can't think of a better way to do it that preserves nice EBNF % notation. \ifthenelse{\equal{#1}{sep}}{ \item Non-empty lists are written with an item, a separator terminal, and ``\ldots''. For example, this: \begin{quote} \commas{\nt{expr}} \end{quote} is short for this: \begin{quote} \nt{expr} \zeroOrMore{\term{,} \nt{expr}} \end{quote} }{ \item Non-empty lists are written with an item, a separator/terminator terminal, and ``\ldots''. For example, this: \begin{quote} \commas{\nt{expr}} \end{quote} is short for this: \begin{quote} \nt{expr} \zeroOrMore{\term{,} \nt{expr}} \maybe{\term{,}} \end{quote} The final terminal is always optional in non-empty lists. } \item Regular expressions, written in fixed-width font, are used in some productions, e.g.~\regexp{[-+]?[0-9]+}. \end{itemize} } %-----------------------------------------------------------------------------% \newcommand{\reservedKeywords}{ \texttt{ann}, \texttt{annotation}, \texttt{any}, \texttt{array}, \texttt{bool}, \texttt{case}, \texttt{constraint}, \texttt{diff}, \texttt{div}, \texttt{else}, \texttt{elseif}, \texttt{endif}, \texttt{enum}, \texttt{false}, \texttt{float}, \texttt{function}, \texttt{if}, \texttt{in}, \texttt{include}, \texttt{int}, \texttt{intersect}, \texttt{let}, \texttt{list}, \texttt{maximize}, \texttt{minimize}, \texttt{mod}, \texttt{not}, \texttt{of}, \texttt{op}, \texttt{output}, \texttt{par}, \texttt{predicate}, \texttt{record}, \texttt{satisfy}, \texttt{set}, \texttt{solve}, \texttt{string}, \texttt{subset}, \texttt{superset}, \texttt{symdiff}, \texttt{test}, \texttt{then}, \texttt{true}, \texttt{tuple}, \texttt{type}, \texttt{union}, \texttt{var}, \texttt{where}, \texttt{xor}. } %-----------------------------------------------------------------------------% \newcommand{\CommonInstantiationTypeInstDescription}{ Each type has one or more possible \emph{instantiations}. The instantiation of a variable or value indicates if it is fixed to a known value or not. A pairing of a type and instantiation is called a \emph{type-inst}. } %-----------------------------------------------------------------------------% \newcommand{\CommonInstantiationsDescription}[1]{ When a #1 model is evaluated, the value of each variable may initially be unknown. As it runs, each variable's \emph{domain} (the set of values it may take) may be reduced, possibly to a single value. An \emph{instantiation} (sometimes abbreviated to \emph{inst}) describes how fixed or unfixed a variable is at instance-time. At the most basic level, the instantiation system distinguishes between two kinds of variables: \begin{enumerate} \item \emph{Parameters}, whose values are fixed at instance-time (usually written just as ``fixed''). \item \emph{Decision variables} (often abbreviated to \emph{variables}), whose values may be completely unfixed at instance-time, but may become fixed at run-time (indeed, the fixing of decision variables is the whole aim of constraint solving). \end{enumerate} } %-----------------------------------------------------------------------------% \newcommand{\CommonTypeInstDescription}{ Because each variable has both a type and an inst, they are often combined into a single \emph{type-inst}. Type-insts are primarily what we deal with when writing models, rather than types. A variable's type-inst \emph{never changes}. This means a decision variable whose value becomes fixed during model evaluation still has its original type-inst (e.g.~\texttt{var int}), because that was its type-inst at instance-time. Some type-insts can be automatically coerced to another type-inst. For example, if a \texttt{par int} value is used in a context where a \texttt{var int} is expected, it is automatically coerced to a \texttt{var int}. We write this \coerce{\texttt{par int}}{\texttt{var int}}. Also, any type-inst can be considered coercible to itself. } %-----------------------------------------------------------------------------% \newcommand{\CommonIntegersOverview}{ Integers represent integral numbers. Integer representations are implementation-defined. This means that the representable range of integers is implementation-defined. However, an implementation should abort at run-time if an integer operation overflows. } %-----------------------------------------------------------------------------% \newcommand{\CommonFloatsOverview}{ Floats represent real numbers. Float representations are implementation-defined. This means that the representable range and precision of floats is implementation-defined. However, an implementation should abort at run-time on exceptional float operations (e.g.~those that produce \texttt{NaN}s, if using IEEE754 floats). } %-----------------------------------------------------------------------------% \newcommand{\CommonStringLiterals}{ String literals are written as in C: \begin{productions} \RuleStringLiteral \end{productions} This includes C-style escape sequences, such as `\texttt{\backsl"}' for double quotes, `\texttt{\backsl\backsl}' for backslash, and `\texttt{\backsl{}n}' for newline. For example: \texttt{"Hello, world!\backsl{}n"}. String literals must fit on a single line. } %-----------------------------------------------------------------------------% \newcommand{\CommonOutputOnSuccessOrFailure}{ The output is determined by concatenating the individual elements of the array. Each model can have at most one output item. If a solution is found and an output item is present, it is used to determine the string to be printed. If a solution is found and no output item is present, the implementation should print all the global variables and their values in a readable format. If no solution is found, the implementation should print ``No solution found''; it may also print some extra information about the cause of the failure, such as which constraints were violated. } %-----------------------------------------------------------------------------% \newcommand{\ShowCondDescription}{ Conditional to-string conversion. If the first argument is not fixed, it aborts; if it is fixed to \texttt{true}, the second argument is converted to a string; if it is fixed to \texttt{false} the third argument is converted to a string. The exact form of the resulting string is implementation-dependent, but same as that produced by \texttt{show}. } %-----------------------------------------------------------------------------% \newcommand{\CommonSolveMinMaxExprTypeInst}{ The expression in a minimize/maximize solve item must have type-inst \texttt{int}, \texttt{float}, \texttt{var int} or \texttt{var float}. The first two of these are not very useful as they mean that the model requires no optimisation. } libminizinc-2.0.11/doc/html/0000755000175000017500000000000012646030173014253 5ustar kaolkaollibminizinc-2.0.11/doc/html/footer.html0000644000175000017500000000017112646030173016436 0ustar kaolkaol libminizinc-2.0.11/doc/html/style.css0000644000175000017500000000465712646030173016141 0ustar kaolkaolhtml { -webkit-font-smoothing: antialiased; } body { font: 14px/24px 'Open Sans', sans-serif; } #container { margin: 0 30px; background: #fff; } #header { background: #fff; padding-left: 10px; } #header h1 { margin: 0; } #navigation { float: left; width: 100%; background: #fff; font-family: 'Droid Sans', sans-serif; font-size: 15px; } #navigation ul { margin: 0; padding: 0; } #navigation ul li { list-style-type: none; display: inline; } #navigation li a { display: block; float: left; padding: 5px 10px; color: #666666; text-decoration: none; border-right: 1px solid #fff; } #navigation li a.active { color: #79AE3D; font-weight: bold; } #navigation li a:hover { color: #79AE3D; text-decoration: underline; } #content { clear: left; padding: 10px; } #content h2 { color: #000; font-size: 160%; margin: 0 0 .5em; } #footer { background: #f; text-align: right; padding: 20px; height: 1%; } .logo-title-a { text-decoration: none; } .logo-title { font-size: 20px; } .logo-title span { color:#79AE3D; font-size:27px; } .mzn-arg { font-family: monospace; font-weight: bold; font-size: 110%; } .mzn-parm { font-style: italic; } .mzn-group-level-0 .mzn-group-name { font-size: 150%; font-weight: bold; } .mzn-group-level-1 .mzn-group-name { font-size: 120%; font-weight: bold; } .mzn-decl-type-heading { display: none; /* font-size: 150%; font-weight: bold;*/ } .mzn-fundecl, .mzn-vardecl { width: 75%; margin-bottom: 10px; margin-left: 5%; border: 1px solid #C0C0C0; } .mzn-fundecl-code, .mzn-vardecl-code { font-family: monospace; /* font-weight: bold;*/ font-size: 110%; white-space: pre; margin-bottom: 2px; background-color: #EAEAEA; border-bottom: 1px solid #C0C0C0; padding: 3px; } .mzn-fundecl-more { float: right; text-decoration: none; color: black; } .mzn-fundecl-more-code { display: none; } .mzn-fundecl-equals { display: none; } .mzn-fundecl-reveal-equals { display: inline; } .mzn-fundecl-code .mzn-fundecl-reveal-code { font-size: 10pt; } .mzn-fundecl-body { padding-left: 1em; font-size: 110%; } .mzn-fundecl-reveal-code { /* font-family: sans-serif; font-size: 11pt; */ display: block; margin-top: 5px; } .mzn-fundecl-doc, .mzn-vardecl-doc { padding-left: 3px; } .mzn-id { font-weight: bold; } .mzn-fn-id { font-style: italic; color: blue; } a.mzn-nav-up, a.mzn-nav-next, a.mzn-nav-prev { text-decoration: none; }libminizinc-2.0.11/doc/html/header.html0000644000175000017500000000401512646030173016371 0ustar kaolkaol @TITLE
libminizinc-2.0.11/doc/html/MiniZn_logo.jpg0000644000175000017500000036015612646030173017214 0ustar kaolkaolÿØÿàJFIF,,ÿá:ExifMM*bj(1r2‡i¤Ð-ÆÀ'-ÆÀ'Adobe Photoshop CS4 Macintosh2011:09:30 11:00:42  ‡ ž&(.HHÿØÿàJFIFHHÿí Adobe_CMÿîAdobed€ÿÛ„            ÿÀ† "ÿÝ ÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?õUG3®tœ'šò2XÛ…—¸Y•¹«ë__º‹?ga<×`äZÝ7 eLwæ»o½ïX=3 u¤ÝøÌ ¤Hõ¬;XHä6žÿì±_ÁÈÄãsÏÛùz¶Ng3ñŒ§-ÞÉ›¬cþ+×ÿξÿrOý·oþ“Kþuôû’í»ôšÀÿ™=Wý6?ùÏÿÒiÌž«þ›üçÿé4ÿ»òç¥þ4õ[Þþ)ÿ‰£öKÿV;ÿó¯ Ü“ÿmÛÿ¤Òÿ}þäŸûnßý&°?æOUÿMþsÿôš_ó'ªÿ¦Çÿ9ÿúM/»òç¥þ4õZ¾÷ñOüM²_ú±ßÿ}þäŸûnßý&³~³}eè·ý[êÔÕ]e˜Y c};“Un®¯j¥ÿ2z¯úlóŸÿ¤Õ»õG©ct>¥‘e´U‰{Ü_0ÚÞí&´%Ëò"$ŒÒ&kÿÄ]kâF@^ /Imÿ†>2’µÒ°Pêxxí9w×@w‡¨öÕ?ô—¥ÿ~’ί•Ò2ún×ÙfCºE®˜ÐÿÕé#óvÙöµœë>T®u>Õ:E•ÕÔ±¬Ä²êÛml°A,wù?Ëgó•ÿ„^þ7°ðGévàú*çô×5¿š}:ß]_õ¦c,ß­_Wò¯úßÑú7\ë–e7/¶Õ™e¾Ê©£Ò©îßeÖ±¬~MŽÿ ê_ôSçêÞHêyøùY8xϾŒz¹V0H­‡óŸþkÝýFYgЭëÐiÿ½&¬Òº]k:ÆS_f06ÂïÒÙUŽõ,ßSwìßOпӳ#Ð}‹'ê×DëUtï­Øôõ#‚:].¯:ŠØ,nG¦2÷Õê¼±ÔÿF{=ZÿÁÚ’ž%3©fUƒƒK²2¯vÚª`’OÒ?ÕkZ7½îú ^‡þ,¾¶ýa¿#§ýWÃÆÆv>û/½ì±Ö6î¾çnmÍ­¯síô)ýó–Tƒ™Õòþ´+é™ÎÁf3¬ÆÀË­­°4TË_m¢½þ•ÌÊ·Õþ¾5•ïIOŸäãdbdY“[ª¾—[[„¹¦×!®Óêu¿Y¾±õü z§ù[ Û[­¨ÆAe®¢Û¬ud·½þ—±ž§óÿ¢þe]êŸâÓ¤UÒ:ý'¬ î£Ñçuv´3Ú=G°msCÙS.üüÓUè~ŠÏSÓJ|ù%Úô?¨-ýŽ·õ›ª~ÊÆÍqfA¾÷ve¯/üÇFÿæÿ™ý/¬¹Ï¬=3 ¥u[p°sëêtWrj ?J·}*÷3þÛªÿÏU¥?ÿгxvoU°µÙ9%³á¾ÍƒüÍËÒi¦º*e542ºÚÆŽ^oÿ,Sÿ†™ÿŸBôµ¥ñ3^ÔGÊÑÈø0ß™ùŒêÔ’I,×]I$’JRÉúÙÿ‰^³ÿ„2¿óÍ‹YdýlÿįYÿÂ_ùæÄ”ø—øµÇ¦ÿ®8ÞZ*¥Ï´—87ÜÖ?ÐßIßhô}«¸úŸÕ:.wPëôuK+eX^ί†û^d›kÞÖ¸ývTÏûyyI)ô—_[ÿÝ{+%ÍnXêÎή­ÀA´Ðë==Ñ»ôwe«__ò1­úûõzÊî­õ²¼@÷µí-‘fíÏØÕæ‰$§ÔV(ÿÃ$Ý_¡Ïn? lþrv}$Ý/¿øänº¶úÿhôeÀoŸÚQékúO¤ß ¼Á$”ú—ø»é?eú©Ô3±óq°úÇVœ[o°4ÕKO¦ë[¶/ª×¿ÖµŸ™ú;õa¿Uþºô+oêX¹Uä;&_KÆÖzt»ù×¾úO[ؼí$”ú_Ô¬œjÿÆŸ[ºËkeN~nÛ憙ÈnÝ®q÷nT> dcÓõkë•vÚÊÝfmms€.>–pÚÍÇßô—’J}@ô–ÿŒ/ª}Ž•™EG¡Öq²±os ÛU>·±–Yïû5/¯ô~él¯Öõi\Ö_Eê×têó)Ïm&ôoõ,嬹¿ákkíôÿÒ,Ô’Sÿѵÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷ÞSë7׋:T=¸(Yw¨n5ý7ZÍ›= ¾£ûë+ÿKÿò¥¿û÷‘fŒ›+oÖpæ´ýŽžHá2—-ëSþ‘Ÿçšì=çþ:—ÿåKö(ÿï"_øê_ÿ•-ÿØ£ÿ¼‹ƒõ©ÿHÏó‚ ‰Aà„”÷_øê_ÿ•-ÿØ£ÿ¼‹_êßÖ›~´]•‡L®¬:ꌇ:ßY®õeŒÇu/¢¦½¶VÛ½OýJ¼¹Îk\ã h$Ÿ ½{êgEwGèTÕsvåä´eâÇú/úÅM«þ´’›_ógêßþUaì=_úM/ù³õoÿ*°¿ö¯ý&´’IoüÙú·ÿ•X_ûWþ“Kþlý[ÿʬ/ý‡«ÿI­$’S›ÿ6~­ÿåVþÃÕÿ¤Òÿ›?Vÿò« ÿaêÿÒkI$”æÿÍŸ«ùU…ÿ°õé5çO§ôêúŽc‡ŽÖ²ûZÐ)®phÅê«Ìº·ü§ÿ†.ÿ«rÑø\Aœì ÝÈøÜˆÇŠ‰£·“ÝÿÍŸ«ŸùU…ÿ°õé4¿æÏÕ¿üªÂÿØz¿ôšÒIg:îoüÙú·ÿ•X_ûWþ“Kþlý[ÿʬ/ý‡«ÿI­$’SÿÒµÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷ÐÛ…‡{ýK¨®×Än{ã¶ç5Ù7þâSÿm·ÿ"¬¤³]w;>ž‹Óð¯ÎÉÆ¥´cVël"¶L4n†éî{¿1xÕùå_nUÍk-½î±ìniqŸIŸÈ©¿¢bï?ÆoWÛV7D©ÚÝ9Cþ ŽýZ³ÿÏWÿAHI€5$¤—oêoGý­×éeÝ‹‡Y>aýZ“¡þw#ß·óé¢õêG©àt¼geu ÙCtÜóÉìÊØ=öXïÍ®¿Ò,?¨ôî†Ü›[·+¨‘‘dòÖú­_اôgúk®ZX¾®`õü1N@ôò*“‹”Ð êyíýú¬ÓÑô.ÿ¶ìIÖ?ÆOPºöŽ‹Sq±ëpvü†î} ƒuM?«Rÿë?'ÿ =vëVéµZñ]aÃ)¶8Eì®eÏ;[µý'©ùôì¹xþ^&N]ØYm ÈÆy®Ö‰‰潓¢µŽeµÁ= =â·ÔáU¥¦ÚÁ!¯5’êMŒú/ôœïÑîI/sÖÿÆ[ËOA¨ >ÛÓÏkõmÈuø^Æ.fß­Yí~÷õKü鱿æWSZ²œàÑ.0<~*彬ӎr®éùUã´nu®©àŽ^öÇ©[?—cS¹ÒÿÆ_ð âÞ¥ùÍs[UÀÁ]KYK¿©u>ÿôõ/Eé=[¬`³;ûê|‚‡±ãéÕk?2Ö/]GøºêVbõóƒ'Ðê5¸võ©o«]ŸöÃo­ÿõŸôI)õæ][þSÎÿÃÕ¹zjó.­ÿ)çá‹¿êÜ´¾óäò›ñÏæ±|þO¦¤’K5ØRI$’ŸÿÓµÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷Ô¡uµQSî¹Á•TÒûíZѹÎwõZ¦¸ÿñ“Ö>ËÒ™Òªt]ÔIG#½®¿þÞ{ªÇÿвåšë¼TêVun¥“Ôì§îcO-¨ ˜õb–³Ôÿ…õŸ«}#ö×[ÆÁpÝ>¶_‡£Yì<?cªÆÿ¯,Åéâã£ý“¤¿©ÚØ»©ê瑎Éû7ý½ºÌŸê]RIzä’I$>mþ3°ÙWWÃÌhåÐúßÍakö2¶ÿÖ×»¯ñ©üïIødÿî²à®þfÏê»ò$—Ѿ }Vªœzúæ}aÙWØLxŸJ£ônÚíNK}ûþ4~‹ô¬ú²­Ó?äÜOøšÿêZ¬¤‡Å:î%X]s¨bRÐÚiÈx­ƒ@Öº.mm¹_«±ŠïÔŸüVôßë]ÿ¶ùZ¿ñOÕ?ãÿô]HÿRñ[Ó­wþÛä$—×—™uoùO;ÿ ]ÿVåé«Ìº·ü§ÿ†.ÿ«rÒøWÏ“È~n7Ç?šÅýóù>š’I,×aI$’JÿÔµÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷Ô¼cëWý³ÖòsÚwQ>Ž/‡£Y"·ø÷ºÜŸúòô/¯ý`ôî„üz·+¨“\rÖúÕ¿Ø£Ø×ÿ¦¶•å` @k°¥¿¬uLn˜É!ߦpå´·ß’ùüßÑþŽ¿øk*^×]lª¶×[C+` c 4kZðÜl¼¼K ¸—Ùc†Óe.,qlîÙ½ží»š¬~Ýëßùi™ÿoÙÿ’IO¶$¼Oöï^ÿËLÏû~Ïü’6[ëŽÎÄkºž[šìŠæ›ÞAÚÚæ»Ýô\Ô•OOþ5?é? ŸýÖ\ßÌÙýW~EÞÿOçzOÃ'ÿu—wó6Uß‘%>åÓ?äÜOøŠÿê­*½3þMÄÿˆ¯þ¡ªÒH|këWþ)ú§üþ‹©êOþ+zoõ®ÿÛ|„­_ø§êŸñÿú.¤©?ø­é¿Ö»ÿmòKëË̺·ü§ÿ†.ÿ«rôÕæ][þSÎÿÃÕ¹i|+çÉä?7ãŸÍbþùüŸMI$–k°¤’I%?ÿÕµÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷ß>úãÐ>µu®´ë¨ÃÂÇ`§n­² Y}Ûÿc­·ôñxô¬Où‹õ³þà·þÞ«ÿ&½q%šëÛäóëgýÁoý½WþM/ù‹õ³þà·þÞ«ÿ&½q$•o‘ÿÌ_­Ÿ÷¿öõ_ù4\_©Z«ÌƱøM ®ú^óëTa¬±–<ý?Üjõt’U¼×þƒÕúÅ<ôÚã_êËÚÈßèzÎ9»·zo\¿Pþ¶º·´`¶KH¦«’?®½y$”ƒ§ÓƒUƒm•ÔÆ¼s45Ú„t’IO™ý`úŸõ—3®çåãa‹1ï»}Oõkl·el®væûš‹õ[ê—Ö,¬X9¹˜‚¬ja±âÚÝ©º¦ûâç~’Æ/GI%Z—™uoùO;ÿ ]ÿVåé«Ìº·ü§ÿ†.ÿ«rÒøWÏ“È~n?Ç?šÅýóù>š’I,×aI$’JÿÖµA ëh”ÙžÑh^–¼÷ë/O~UºAô²\ëªwc¸îµŸÖ®Ç™é®‡£}kľ†ÕÔ,d´lvŒò÷ý ÝûíýmjóØå›,¸Ç­xu:¸¿ Ë ³òùOŒî&Z /Ñz•?Û=#þçcÿÛ¬ÿÉ%ûg¤ÜìûuŸù%›ídýÉ}…×÷qþüÆ Ä•?Û=#þçcÿÛ¬ÿÉ%ûg¤ÜìûuŸù$½¬Ÿ¹/°«ÝÇûñÿ7Tÿlôûÿn³ÿ$—íž‘ÿs±ÿíÖä’ö²~ä¾Â¯wïÇü`ÜISý³Ò?îv?ýºÏü’_¶zGýÎÇÿ·Yÿ’KÚÉû’û ½Ü¿ñƒq%OöÏHÿ¹Øÿöë?òI~Ùé÷;þÝgþI/k'îKì*÷qþüÆ Ä•?Û=#þçcÿÛ¬ÿÉ%ûg¤ÜìûuŸù$½¬Ÿ¹/°«ÝÇûñÿ7™uoùO;ÿ [ÿVå×õo­x8Ô½˜V œ’!…šÖÒ=ö}íýÆ.c ôû:T©„W[…¹:ûZw{¿•sý‹Káøå†93d­8´>—â™!žxy|DN|Zðú„oÒú*I$²µ$’I)ÿ×ô>ºÞ’ìÞªàÊK€cÄï?EÔì~ÿìýç?F¸l¬L:ž~Ë›^E}¥–±ÿ6šÝ_þ¼%­ðÞ.^å^¿'³ôâõñuÃøÇ¿jëK÷=ÿüoÑÁý÷ÕvÞþE>ÑûÃñÿȯ)Ii8ºxÎ}[hýáøÿäRÚ?x~?ùå)$­­´~ðüò)m¼?üŠò”’VžóŸVÚ?x~?ù¶ÞþEyJI+OùÏ«m¼?üŠ[GïÇÿ"¼¥$•§‡üçÕ¶ÞþE6ÑûÃñÿȯ*I%iáÿ9õìl\[\>Ñ›^;;–½ß&6°ÏüwWÙÑ™ˆæô§ú‹^éxÛ½¬wõ=žŸú5óJK;â\^Þ¾åXýÏgü.[±ð~sOfë_ç=ÿðxýÞà~ªI|ª’ÈwŸª’_*¤’ŸÿÙÿíÊPhotoshop 3.08BIM%8BIMí,,8BIM&?€8BIM x8BIM8BIMó 8BIM' 8BIMõH/fflff/ff¡™š2Z5-8BIMøpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿè8BIM@@8BIM8BIMIž‡ Untitled-1‡žnullboundsObjcRct1Top longLeftlongBtomlongžRghtlong‡slicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongžRghtlong‡urlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?ð8BIM8BIM   †àû@ÿØÿàJFIFHHÿí Adobe_CMÿîAdobed€ÿÛ„            ÿÀ† "ÿÝ ÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?õUG3®tœ'šò2XÛ…—¸Y•¹«ë__º‹?ga<×`äZÝ7 eLwæ»o½ïX=3 u¤ÝøÌ ¤Hõ¬;XHä6žÿì±_ÁÈÄãsÏÛùz¶Ng3ñŒ§-ÞÉ›¬cþ+×ÿξÿrOý·oþ“Kþuôû’í»ôšÀÿ™=Wý6?ùÏÿÒiÌž«þ›üçÿé4ÿ»òç¥þ4õ[Þþ)ÿ‰£öKÿV;ÿó¯ Ü“ÿmÛÿ¤Òÿ}þäŸûnßý&°?æOUÿMþsÿôš_ó'ªÿ¦Çÿ9ÿúM/»òç¥þ4õZ¾÷ñOüM²_ú±ßÿ}þäŸûnßý&³~³}eè·ý[êÔÕ]e˜Y c};“Un®¯j¥ÿ2z¯úlóŸÿ¤Õ»õG©ct>¥‘e´U‰{Ü_0ÚÞí&´%Ëò"$ŒÒ&kÿÄ]kâF@^ /Imÿ†>2’µÒ°Pêxxí9w×@w‡¨öÕ?ô—¥ÿ~’ί•Ò2ún×ÙfCºE®˜ÐÿÕé#óvÙöµœë>T®u>Õ:E•ÕÔ±¬Ä²êÛml°A,wù?Ëgó•ÿ„^þ7°ðGévàú*çô×5¿š}:ß]_õ¦c,ß­_Wò¯úßÑú7\ë–e7/¶Õ™e¾Ê©£Ò©îßeÖ±¬~MŽÿ ê_ôSçêÞHêyøùY8xϾŒz¹V0H­‡óŸþkÝýFYgЭëÐiÿ½&¬Òº]k:ÆS_f06ÂïÒÙUŽõ,ßSwìßOпӳ#Ð}‹'ê×DëUtï­Øôõ#‚:].¯:ŠØ,nG¦2÷Õê¼±ÔÿF{=ZÿÁÚ’ž%3©fUƒƒK²2¯vÚª`’OÒ?ÕkZ7½îú ^‡þ,¾¶ýa¿#§ýWÃÆÆv>û/½ì±Ö6î¾çnmÍ­¯síô)ýó–Tƒ™Õòþ´+é™ÎÁf3¬ÆÀË­­°4TË_m¢½þ•ÌÊ·Õþ¾5•ïIOŸäãdbdY“[ª¾—[[„¹¦×!®Óêu¿Y¾±õü z§ù[ Û[­¨ÆAe®¢Û¬ud·½þ—±ž§óÿ¢þe]êŸâÓ¤UÒ:ý'¬ î£Ñçuv´3Ú=G°msCÙS.üüÓUè~ŠÏSÓJ|ù%Úô?¨-ýŽ·õ›ª~ÊÆÍqfA¾÷ve¯/üÇFÿæÿ™ý/¬¹Ï¬=3 ¥u[p°sëêtWrj ?J·}*÷3þÛªÿÏU¥?ÿгxvoU°µÙ9%³á¾ÍƒüÍËÒi¦º*e542ºÚÆŽ^oÿ,Sÿ†™ÿŸBôµ¥ñ3^ÔGÊÑÈø0ß™ùŒêÔ’I,×]I$’JRÉúÙÿ‰^³ÿ„2¿óÍ‹YdýlÿįYÿÂ_ùæÄ”ø—øµÇ¦ÿ®8ÞZ*¥Ï´—87ÜÖ?ÐßIßhô}«¸úŸÕ:.wPëôuK+eX^ί†û^d›kÞÖ¸ývTÏûyyI)ô—_[ÿÝ{+%ÍnXêÎή­ÀA´Ðë==Ñ»ôwe«__ò1­úûõzÊî­õ²¼@÷µí-‘fíÏØÕæ‰$§ÔV(ÿÃ$Ý_¡Ïn? lþrv}$Ý/¿øänº¶úÿhôeÀoŸÚQékúO¤ß ¼Á$”ú—ø»é?eú©Ô3±óq°úÇVœ[o°4ÕKO¦ë[¶/ª×¿ÖµŸ™ú;õa¿Uþºô+oêX¹Uä;&_KÆÖzt»ù×¾úO[ؼí$”ú_Ô¬œjÿÆŸ[ºËkeN~nÛ憙ÈnÝ®q÷nT> dcÓõkë•vÚÊÝfmms€.>–pÚÍÇßô—’J}@ô–ÿŒ/ª}Ž•™EG¡Öq²±os ÛU>·±–Yïû5/¯ô~él¯Öõi\Ö_Eê×têó)Ïm&ôoõ,嬹¿ákkíôÿÒ,Ô’Sÿѵÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷ÞSë7׋:T=¸(Yw¨n5ý7ZÍ›= ¾£ûë+ÿKÿò¥¿û÷‘fŒ›+oÖpæ´ýŽžHá2—-ëSþ‘Ÿçšì=çþ:—ÿåKö(ÿï"_øê_ÿ•-ÿØ£ÿ¼‹ƒõ©ÿHÏó‚ ‰Aà„”÷_øê_ÿ•-ÿØ£ÿ¼‹_êßÖ›~´]•‡L®¬:ꌇ:ßY®õeŒÇu/¢¦½¶VÛ½OýJ¼¹Îk\ã h$Ÿ ½{êgEwGèTÕsvåä´eâÇú/úÅM«þ´’›_ógêßþUaì=_úM/ù³õoÿ*°¿ö¯ý&´’IoüÙú·ÿ•X_ûWþ“Kþlý[ÿʬ/ý‡«ÿI­$’S›ÿ6~­ÿåVþÃÕÿ¤Òÿ›?Vÿò« ÿaêÿÒkI$”æÿÍŸ«ùU…ÿ°õé5çO§ôêúŽc‡ŽÖ²ûZÐ)®phÅê«Ìº·ü§ÿ†.ÿ«rÑø\Aœì ÝÈøÜˆÇŠ‰£·“ÝÿÍŸ«ŸùU…ÿ°õé4¿æÏÕ¿üªÂÿØz¿ôšÒIg:îoüÙú·ÿ•X_ûWþ“Kþlý[ÿʬ/ý‡«ÿI­$’SÿÒµÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷ÐÛ…‡{ýK¨®×Än{ã¶ç5Ù7þâSÿm·ÿ"¬¤³]w;>ž‹Óð¯ÎÉÆ¥´cVël"¶L4n†éî{¿1xÕùå_nUÍk-½î±ìniqŸIŸÈ©¿¢bï?ÆoWÛV7D©ÚÝ9Cþ ŽýZ³ÿÏWÿAHI€5$¤—oêoGý­×éeÝ‹‡Y>aýZ“¡þw#ß·óé¢õêG©àt¼geu ÙCtÜóÉìÊØ=öXïÍ®¿Ò,?¨ôî†Ü›[·+¨‘‘dòÖú­_اôgúk®ZX¾®`õü1N@ôò*“‹”Ð êyíýú¬ÓÑô.ÿ¶ìIÖ?ÆOPºöŽ‹Sq±ëpvü†î} ƒuM?«Rÿë?'ÿ =vëVéµZñ]aÃ)¶8Eì®eÏ;[µý'©ùôì¹xþ^&N]ØYm ÈÆy®Ö‰‰潓¢µŽeµÁ= =â·ÔáU¥¦ÚÁ!¯5’êMŒú/ôœïÑîI/sÖÿÆ[ËOA¨ >ÛÓÏkõmÈuø^Æ.fß­Yí~÷õKü鱿æWSZ²œàÑ.0<~*彬ӎr®éùUã´nu®©àŽ^öÇ©[?—cS¹ÒÿÆ_ð âÞ¥ùÍs[UÀÁ]KYK¿©u>ÿôõ/Eé=[¬`³;ûê|‚‡±ãéÕk?2Ö/]GøºêVbõóƒ'Ðê5¸võ©o«]ŸöÃo­ÿõŸôI)õæ][þSÎÿÃÕ¹zjó.­ÿ)çá‹¿êÜ´¾óäò›ñÏæ±|þO¦¤’K5ØRI$’ŸÿÓµÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷Ô¡uµQSî¹Á•TÒûíZѹÎwõZ¦¸ÿñ“Ö>ËÒ™Òªt]ÔIG#½®¿þÞ{ªÇÿвåšë¼TêVun¥“Ôì§îcO-¨ ˜õb–³Ôÿ…õŸ«}#ö×[ÆÁpÝ>¶_‡£Yì<?cªÆÿ¯,Åéâã£ý“¤¿©ÚØ»©ê瑎Éû7ý½ºÌŸê]RIzä’I$>mþ3°ÙWWÃÌhåÐúßÍakö2¶ÿÖ×»¯ñ©üïIødÿî²à®þfÏê»ò$—Ѿ }Vªœzúæ}aÙWØLxŸJ£ônÚíNK}ûþ4~‹ô¬ú²­Ó?äÜOøšÿêZ¬¤‡Å:î%X]s¨bRÐÚiÈx­ƒ@Öº.mm¹_«±ŠïÔŸüVôßë]ÿ¶ùZ¿ñOÕ?ãÿô]HÿRñ[Ó­wþÛä$—×—™uoùO;ÿ ]ÿVåé«Ìº·ü§ÿ†.ÿ«rÒøWÏ“È~n7Ç?šÅýóù>š’I,×aI$’JÿÔµÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷Ô¼cëWý³ÖòsÚwQ>Ž/‡£Y"·ø÷ºÜŸúòô/¯ý`ôî„üz·+¨“\rÖúÕ¿Ø£Ø×ÿ¦¶•å` @k°¥¿¬uLn˜É!ߦpå´·ß’ùüßÑþŽ¿øk*^×]lª¶×[C+` c 4kZðÜl¼¼K ¸—Ùc†Óe.,qlîÙ½ží»š¬~Ýëßùi™ÿoÙÿ’IO¶$¼Oöï^ÿËLÏû~Ïü’6[ëŽÎÄkºž[šìŠæ›ÞAÚÚæ»Ýô\Ô•OOþ5?é? ŸýÖ\ßÌÙýW~EÞÿOçzOÃ'ÿu—wó6Uß‘%>åÓ?äÜOøŠÿê­*½3þMÄÿˆ¯þ¡ªÒH|këWþ)ú§üþ‹©êOþ+zoõ®ÿÛ|„­_ø§êŸñÿú.¤©?ø­é¿Ö»ÿmòKëË̺·ü§ÿ†.ÿ«rôÕæ][þSÎÿÃÕ¹i|+çÉä?7ãŸÍbþùüŸMI$–k°¤’I%?ÿÕµÿ,Sÿ†™ÿŸBôµæ˜ßòÅ?øiŸùô/KZ_ß÷K‘ð_—?÷ß>úãÐ>µu®´ë¨ÃÂÇ`§n­² Y}Ûÿc­·ôñxô¬Où‹õ³þà·þÞ«ÿ&½q%šëÛäóëgýÁoý½WþM/ù‹õ³þà·þÞ«ÿ&½q$•o‘ÿÌ_­Ÿ÷¿öõ_ù4\_©Z«ÌƱøM ®ú^óëTa¬±–<ý?Üjõt’U¼×þƒÕúÅ<ôÚã_êËÚÈßèzÎ9»·zo\¿Pþ¶º·´`¶KH¦«’?®½y$”ƒ§ÓƒUƒm•ÔÆ¼s45Ú„t’IO™ý`úŸõ—3®çåãa‹1ï»}Oõkl·el®væûš‹õ[ê—Ö,¬X9¹˜‚¬ja±âÚÝ©º¦ûâç~’Æ/GI%Z—™uoùO;ÿ ]ÿVåé«Ìº·ü§ÿ†.ÿ«rÒøWÏ“È~n?Ç?šÅýóù>š’I,×aI$’JÿÖµA ëh”ÙžÑh^–¼÷ë/O~UºAô²\ëªwc¸îµŸÖ®Ç™é®‡£}kľ†ÕÔ,d´lvŒò÷ý ÝûíýmjóØå›,¸Ç­xu:¸¿ Ë ³òùOŒî&Z /Ñz•?Û=#þçcÿÛ¬ÿÉ%ûg¤ÜìûuŸù%›ídýÉ}…×÷qþüÆ Ä•?Û=#þçcÿÛ¬ÿÉ%ûg¤ÜìûuŸù$½¬Ÿ¹/°«ÝÇûñÿ7Tÿlôûÿn³ÿ$—íž‘ÿs±ÿíÖä’ö²~ä¾Â¯wïÇü`ÜISý³Ò?îv?ýºÏü’_¶zGýÎÇÿ·Yÿ’KÚÉû’û ½Ü¿ñƒq%OöÏHÿ¹Øÿöë?òI~Ùé÷;þÝgþI/k'îKì*÷qþüÆ Ä•?Û=#þçcÿÛ¬ÿÉ%ûg¤ÜìûuŸù$½¬Ÿ¹/°«ÝÇûñÿ7™uoùO;ÿ [ÿVå×õo­x8Ô½˜V œ’!…šÖÒ=ö}íýÆ.c ôû:T©„W[…¹:ûZw{¿•sý‹Káøå†93d­8´>—â™!žxy|DN|Zðú„oÒú*I$²µ$’I)ÿ×ô>ºÞ’ìÞªàÊK€cÄï?EÔì~ÿìýç?F¸l¬L:ž~Ë›^E}¥–±ÿ6šÝ_þ¼%­ðÞ.^å^¿'³ôâõñuÃøÇ¿jëK÷=ÿüoÑÁý÷ÕvÞþE>ÑûÃñÿȯ)Ii8ºxÎ}[hýáøÿäRÚ?x~?ùå)$­­´~ðüò)m¼?üŠò”’VžóŸVÚ?x~?ù¶ÞþEyJI+OùÏ«m¼?üŠ[GïÇÿ"¼¥$•§‡üçÕ¶ÞþE6ÑûÃñÿȯ*I%iáÿ9õìl\[\>Ñ›^;;–½ß&6°ÏüwWÙÑ™ˆæô§ú‹^éxÛ½¬wõ=žŸú5óJK;â\^Þ¾åXýÏgü.[±ð~sOfë_ç=ÿðxýÞà~ªI|ª’ÈwŸª’_*¤’ŸÿÙ8BIM!UAdobe PhotoshopAdobe Photoshop CS48BIMÿáohttp://ns.adobe.com/xap/1.0/ ÿâ XICC_PROFILE HLinomntrRGB XYZ Î 1acspMSFTIEC sRGBöÖÓ-HP cprtP3desc„lwtptðbkptrXYZgXYZ,bXYZ@dmndTpdmddĈvuedL†viewÔ$lumiømeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ óQÌXYZ XYZ o¢8õXYZ b™·…ÚXYZ $ „¶ÏdescIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view¤þ_.ÏíÌ \žXYZ L VPWçmeassig CRT curv #(-27;@EJOTY^chmrw|†‹•šŸ¤©®²·¼ÁÆËÐÕÛàåëðöû %+28>ELRY`gnu|ƒ‹’š¡©±¹ÁÉÑÙáéòú &/8AKT]gqz„Ž˜¢¬¶ÁËÕàëõ !-8COZfr~Š–¢®ºÇÓàìù -;HUcq~Œš¨¶ÄÓáðþ +:IXgw†–¦µÅÕåö'7HYj{Œ¯ÀÑãõ+=Oat†™¬¿Òåø 2FZn‚–ª¾Òçû  % : O d y ¤ º Ï å û  ' = T j ˜ ® Å Ü ó " 9 Q i € ˜ ° È á ù  * C \ u Ž § À Ù ó & @ Z t Ž © Ã Þ ø.Id›¶Òî %A^z–³Ïì &Ca~›¹×õ1OmŒªÉè&Ed„£Ãã#Ccƒ¤Åå'Ij‹­Îð4Vx›½à&Il²ÖúAe‰®Ò÷@eНÕú Ek‘·Ý*QwžÅì;cвÚ*R{£ÌõGp™Ãì@j”¾é>i”¿ê  A l ˜ Ä ð!!H!u!¡!Î!û"'"U"‚"¯"Ý# #8#f#”#Â#ð$$M$|$«$Ú% %8%h%—%Ç%÷&'&W&‡&·&è''I'z'«'Ü( (?(q(¢(Ô))8)k))Ð**5*h*›*Ï++6+i++Ñ,,9,n,¢,×- -A-v-«-á..L.‚.·.î/$/Z/‘/Ç/þ050l0¤0Û11J1‚1º1ò2*2c2›2Ô3 3F33¸3ñ4+4e4ž4Ø55M5‡5Â5ý676r6®6é7$7`7œ7×88P8Œ8È99B99¼9ù:6:t:²:ï;-;k;ª;è<' >`> >à?!?a?¢?â@#@d@¦@çA)AjA¬AîB0BrBµB÷C:C}CÀDDGDŠDÎEEUEšEÞF"FgF«FðG5G{GÀHHKH‘H×IIcI©IðJ7J}JÄK KSKšKâL*LrLºMMJM“MÜN%NnN·OOIO“OÝP'PqP»QQPQ›QæR1R|RÇSS_SªSöTBTTÛU(UuUÂVV\V©V÷WDW’WàX/X}XËYYiY¸ZZVZ¦Zõ[E[•[å\5\†\Ö]']x]É^^l^½__a_³``W`ª`üaOa¢aõbIbœbðcCc—cëd@d”dée=e’eçf=f’fèg=g“géh?h–hìiCišiñjHjŸj÷kOk§kÿlWl¯mm`m¹nnknÄooxoÑp+p†pàq:q•qðrKr¦ss]s¸ttptÌu(u…uáv>v›vøwVw³xxnxÌy*y‰yçzFz¥{{c{Â|!||á}A}¡~~b~Â#„å€G€¨ kÍ‚0‚’‚ôƒWƒº„„€„ã…G…«††r†×‡;‡ŸˆˆiˆÎ‰3‰™‰þŠdŠÊ‹0‹–‹üŒcŒÊ1˜ÿŽfŽÎ6žnÖ‘?‘¨’’z’ã“M“¶” ”Š”ô•_•É–4–Ÿ— —u—à˜L˜¸™$™™üšhšÕ›B›¯œœ‰œ÷dÒž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½¾ ¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿÿîAdobedÿÛ„        ""   ÿÀž‡ÿݱÿÄ¢  s!1AQa"q2‘¡±B#ÁRÑá3bð$r‚ñ%C4S’¢²csÂ5D'“£³6TdtÃÒâ&ƒ „”EF¤´VÓU(òãóÄÔäôeu…•¥µÅÕåõfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù*:JZjzŠšªºÊÚêúm!1AQa"q‘2¡±ðÁÑá#BRbrñ3$4C‚’S%¢c²ÂsÒ5âDƒT“ &6E'dtU7ò£³Ã()Óã󄔤´ÄÔäôeu…•¥µÅÕåõFVfv†–¦¶ÆÖæöGWgw‡—§·Ç×ç÷8HXhxˆ˜¨¸ÈØèø9IYiy‰™©¹ÉÙéù*:JZjzŠšªºÊÚêúÿÚ ?õN*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯˜ÿç8㟣ÿÆiÿâ1⯑ñWb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­¯_¿ÿÐõN*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯˜ÿç8㟣ÿÆiÿâ1⯑ñWb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­¯_¿ÿÑõN*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯˜ÿç8㟣ÿÆiÿâ1⯑ñWb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­¯_¿ÿÒõN*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯˜ÿç8㟣ÿÆiÿâ1⯑ñWb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­¯_¿ÿÓõN*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯˜ÿç8㟣ÿÆiÿâ1⯑ñWb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­¯_¿ÿÔõN*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯˜ÿç8㟣ÿÆiÿâ1⯑ñWb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­¯_¿ÿÕõN*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅP—Úµ€åw4qòØ×–çôƒ/phÉžþ£X±ëßÍ-×a9”ŽÑ©?ŽË™ÐìÌÒéÃýgW“¶tðþ./ê“Üþvi¨i HŸ4YiÈÐLRÊj•j©ì¹®ÖèF˜|\Nã³{Pë$Epp׋ê|ëš—|ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±VÀ'a¹Å[deû@ž*·v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«j¥¶§m”¯Ú|ñU¸«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±VÀ$ÐnqVÙ~Ð#犭Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]ж½~üUÿÖõN*ìUØ«±Wb®Å]Š»v*ìUت]¬yŠÃGNwó$^Ÿˆÿªƒâ9‘‹O<¦¢8œLú¼ẍÿºÿJÀ5¯ÎØ”Òà/þ\¦ƒþwÿ†\Ýáìbw™ÿ6ñO5¨öˆ ±Æÿ¥?ø–ªþaëZD— Ùàð¿ü6nqh1cä/úÞ§ÏÚ¹òó—õ= vIF.䳤îs< ud“¹[ŠŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«Í?$‡ú’?ض*øÃþròÿ.æ]OK-6‹pÜT¶í ý)ö‘¿ÝR±‹âu^1Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅYçäïå=ïæN®4ëfômaîg¥x%z/óK'ÙÙ}•Å_sy'òƒË>LaÒ¬£õo4ŠV?ÌÒ¿ÅþÅ8¯ù8ª{«ùSIÖa6º•œ° ¬‘« ü*>ö8«ä¯ùȯùÆè|§y—Ë¿F‚=x ,a© ’6?‡—ÂÜ¿»ÿSì*ù×v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»mzýø«ÿ×õN*ìUØ«±Wb®Å]Š»v*•ëÞg°Ð£õoåOÙQ»7ú©™84ÓÌj#þ%ÃÔë1é…Ì×ôŠ_æ¼§Ì¿œ×Õ‡L_ªÃüÝd?OÙOö?ðYÓiû&Þ¼—û‹ÕööL›cýÔþSþ;øõ0î$¸s,Ì]ÛrÌjOÓ›¸ÄDPy©HÈÙŒkòPŸð튽·v*…ÕtÈ5[I´ûµoqE"žêË»~`ësi—·jÖò¼Dû£ÿqT*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»mzýø«ÿÐõN*ìUØ«±Wb®Å]е$‹—r@©'`/’ ró/8þo$­4:;ô3ðøÆ¿µþ·Ùÿ[:-'eêÉþ“þ)äuýº#éÃê?êŸÃþgóžQy{=ì­qtí$¬jYIΚÂ/&Id\GìúÁb¯“ñWb®Å]о×ÿœ7óT:‡•¤Ñy¬ió¿ÃßÓ”ú¨ÿò3Õ_ö8«ßqWb¨-oX·ÑlgÔï\GomJì{*ŽG~bëz›j·÷ƒŠ5ÌÒJGv/ÿb¨,UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUúÿ8ñ昼Åä½>TjËm¶”WpÑ|ÿ¬œý–*ôŒUØ« üçóT>Xò–¥¨JÁXÀñEâdzQþɹª¸«óƒv*Éÿ,#Y|Ѥ¤€25í¸ Š‚ ‹±«ôoü3¥ÿË¿üŠOù§wøgJÿ–;ùŸóN*ïðΕÿ,vÿò)?æœUßá+þXíÿäRÍ8«¿Ã:Wü±ÛÿȤÿšqW†t¯ùc·ÿ‘Iÿ4â®ÿ é_òÇoÿ"“þiÅ]þÒ¿åŽßþE'üÓŠ»ü3¥Ë¿üŠOù§wøgJÿ–;ùŸóN*ùþrÿÍ6RêðycLŠ(ÒÅ}IÌhªL²…¯ûî-ÿç¦*ùïv*ûþpûÍPê~R:O/ô:gV^ü$>¬Mþ¯÷‰þÃ{®*ìU/ó»o i×:µëq‚Ö'•Íi²Ž\GùMöWü¬Uù‰©_>¡u5ä¿ÞO#Hß6%ÏëÅPØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUµë÷â¯ÿÑõN*ìUØ«±Wb®ÅPz¾¯m¤[µåëˆâNç©?Ê£ö˜å¸±K,¸c¹hÏž8#Ç3Ãðï:þb]y…ÌV vAÕ¿Ê—þiû9ÙhôÁ¹õdþwüKç}£Ú³ÕèÅüßç]ˆfÑÑ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«Í?¯?ì±U3~zù7˰™®µ8% TGnâgoeXyÃqÅ_þxþyÞ~eݤq¡¶ÒmÉ0ÀMKþ©Çì¯Ùöi±W–â®ÅYOågü¥zGüÇ[ÿÉÅÅ_¥x«±Wb®Å]Š»v*ìUتKç_5[ùSG»×/?ºµ‰žŸÌb1ï#ñLUù§®kÝõÆ©zÜî.¥ydosɱT*ìU–~Yþdê_—º²kYå· bcðʇíFÿñ$ØlUö¿‘ÿç$|Ÿæ˜Ušñ,.ˆø¡º!>Ò·îÙâ©ö·ùÍå qwªÚ•"•dcNÊ—lUòwçïüäl¾_к2=¾ŒÉ‹ìóöLŠ6H—í,Íñ?òª¯Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å[^¿~*ÿÿÒõN*ìUØ«±Wb©g˜|Ãk ÚµåãQFÊ£«å\ÈÓéåš\1ÿ¤\MVªhqÏþ’xšüÛwæ;ŸZàñ‰»Œ”þfÎßK¥Žž49ÿ¿œù¦·]=T®_OðCù©f:çb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*óOÏ÷–Ïþ2Iú“9ÞÚúcï“×{7õÏú°ûäò,åžåØ«±Wb®Å]Š»v*ìUö?üá6‰õ}PÕXQ®®–0|V$¯üNwÅ_Fâ®Å]оdÿœÚò·­a§y†5ø ‘­¤?äÈ=X¾…häÿ‘˜«älUØ«±Wb¯GÿœzòÏø‡Îºu»QC'ÖåõGü:¦*ý Å]Š»H¼÷£.µ êk ýbÚTÜ©ãÿ Š¿2™J­±‡[Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬§ò³þR½#þc­ÿäââ¯Ò¼UØ«±Wb®Å]Š»v*ìUòÇüæ‡æµòu£îisuCÛ¥¼Mÿ /üŠÅ_)b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Vׯߊ¿ÿÓõN*ìUØ«±T³¬[èö¯{vÜbAô“ÙWü¦Ë°â–YÇ™qõã‚súbùïÍžj¹óÙ¹œÒ5¨;*ÿÍ_ÌÙÝit±ÁçKùϘkµ²ÕOŠ_OðGù±I3-×»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯4üðÿylÿã$Ÿ©3í¯¦>ù=w³\ÿ«¾O"ÎYî]Š»v*ìUØ«±Wb®Å_ ÿóš'è"é¨~ÔèÓŸùèÍ"ÿÂqÅ^›Š»v*À¿=¼¯þ%òn¥`«ÊU„Íÿ.#ë/ßÃŽ*üèÅ]Š»v*úþpÊüçԼà Ú5KXÏ»~úoø°ÿÁ⯬qWb®Å]Š¿4?2´OÐ~eÔôÊPAu*­—‘(~”¦*ƱWb®ÅWÇ É²)b<qUÿSŸýöÿð'wÔçÿ}¿ü ÅZkYPrd`r*¥Š»v*ìU’ùòç\ó½×Ôôf‡Û~‘§üd•¾ÿ‰b©_˜|½}åÛét½V‚îâèÃqî?™[í+/ÂØª]Š»V´´šòU·¶F–g4T@Y‰ðU_‰±W®ùKþqOÎzú¬Óß nå¨ßò*1$ŸðJ¸«>ƒþpvì 3k«÷ #ï2¯üGKµŸùÂmr/¦ê6× –EhÉÿ“«ÿ мƒÎß”^fòU_[²’(+OYhñŸùë%ì¸â¬;v*ìUØ«±UHà’ATVaì ÅW}N÷ÛÿÀœUßSŸýöÿð'[%¼‘Šº²pF*§Š»F躴ú=ì•¡âÚD–2E@d<Ö«ßqнkþ†ãÏïûù˜«¿èn<÷þÿ·ÿ‘ Š»þ†ãÏïûù˜«¿èn<÷þÿ·ÿ‘ Š»þ†ãÏïûù˜«ß¿ç<ÿæÏ>Áw«ù†XÚÂ6Â%NR}¹[’þÊ)EÿeþN*öüUتYÕ­ô{)õ+Æ omK#Ê£“b¯ÍO<ù²ãͺÕÞ¹vO©u+8öW¤qü£Šb©*ìUتøáy6E-O\UÔçÿ}¿ü Å]õ9ÿßoÿqVžÖT™ÜƒŠ©b®Å]Š»dþEüµ×|ópmtVŸÛü1§üd•¾ÿWíb©>»¡^è7²éšœMÔ Uцàÿü­ûXªv*¯ge=ô«miÍ3š*F¥˜ŸòU~&Å^½åOùÅ9몲ÜEŸw¹z7üŠŒI'üUžCÿ8;vPµˆÕû…·$}æUÿˆâ©f³ÿ8O¯[©}3P¶¹#¢º´Dü¿½OølUäuü¦ó/’É:ÝŒ‘B =eâ?óÚ>Iÿб UØ«±Wb®Å]Š»v*ÌüŸù=æ¯7…“GÓå’é+ŽüýYx+±Å^Ÿ¥ÿÎy¦åCÞ]YÛÕK;‘ÿœ?áñTsÎë´4Ô­ íðÉÿ4⩯ÿ8uç+!ÊÕ­ný£”©ÿ’Ë*ó5~[ù‹Ê‡ýÍØOlŸÎËTÿ‘«Ê?ølUb®Å]Š»v*ìUØ«k×ïÅ_ÿÔõN*ìUتÙeHPÉ! Š $ôwš”„E—€þ`ùÑüÇwÆEœ$ˆ×Çþ,oõ¿güœíô1‚;ÿy/«þ%ó>Ôíªî¡ôű<ÙºWb®Å]Š»v*ìUØ«±Wb®Å]Š»vv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU柞ï-Ÿüd“õ&sµôÇß'®öoëŸõa÷ÉäYË=˱Wb®Å]Š»v*ìURZy$ûNÁGÌšb¯Óÿ-éCHÓ-4åÐGßä¨\U1Å]Š»[,k*ÜUXAî*üÎüÁòãyoÌú; }ZâD_u¯îÛý’qlUb®Å]Š¿@ç|°4$X†–ó•ÓÿÏCû¿ù"±â¯SÅ]Š»v*øCþrÓCý盉ÔQ/a†qóãè?ü<<±Wb®Å]оÿœ%_[ÔÃÑS¨ÿ‹*ûêÑ"ýÃwÕ¢þEû†*ó¯ùȈ#_!êåTè¯aþü~zb®ÅUì¬g¿™-m#y§…DE,ÌOeUÜ⯥*?ç®/8j^us&Œ,ã?¼#þ/“¤_êGñÿ–˜«êËÚ—íNÒ`ŽÚÖ1EŽ5 ùÿ”ßÌÍñ6*óOùÈ?É(0ôÓwb¡5»E&éê(ø´ŸëºÛöü–|Uð]Õ´¶²½½Â˜åŠ:°¡V‹+8«Ô'çõŸÌG[- 5îïO´¶éþìoòÿ»_ø\Uöoåïå'—¼…‹F¶Q9{‡ø¥õ¤ý•ÿ!8'ù8«1Å]Š»Y<Ü#C2«ÆâŒ¬̧|Ëùéÿ8«osºï’£N ¼¶Kö\ Ù­¿‘ÿ⟰ßî¾g|”èÈÅÀЃÔUn*ìUØ«ì?ùÂh‘ô-K’ƒþ–½GüV¸«èß«Eü‹÷ UßV‹ùî«À¿ç3bDò¥¹Uýq:ò$Å_b®Å]Š»v*ìUت#O°›P¹ŠÎÕKÍ3¬h£©f¤Ôê!C²ÿÏYácuý¬Uñ®*ìUØ«±WÒó„q«ë `ú4}Gùx«ëß«Eü‹÷ UßV‹ùî«Ìç%a|…ªPû÷ìx«ó÷v*ˆÓôëFt´²‰çžCÅ#K3UÜ⯦?)ÿçf¹á©yÙÌQìÂÎ&øÏüÄJ¿cýH¾/ø±1WÔÚ&…c¡Z¦Ÿ¥Áµ¬B‹j»ö¿™¾Ób¯+ÿœ‰ü‡ÏúqÔtä ®Z)1‘·¬£so'üÉoÙ‡ì¾*øBx^ T¤ˆJ²‘BÙ”lUêÿ“ŸóŽÚÇæ-ôÕ²ÑÁÞáÆïO´¶Ñþßüdþïýo³Š¾ËòåG—ü‡‡D¶T”Š<ïñJÿëËÿ'ÿÈÅY~*ìUتʹW1´¢É‚X¤̧b1WËÿžßóаúRëþJƒ /-Šî~ÓZ+Åò+÷x«åR¦‡b1V±Wb®Å]Ч>RòާæÝB='E…§º— ~Ô’7ÙH×ö±WÙ•ó‹•/uÕMOSØüb°Æ⨛ûÊ¿%ÿb‰Š½½PP€1VñWb®ÅVOo¦UxØP«AêqW~lÿÎ&i`G¿ò°M;Pݽ!´û†?Íîÿâ¼Uñï˜|»åÛÙt½Z·»„ÑѺüÇfVý–_…±T·v*ìUØ«±Vׯߊ¿ÿÕõN*ìUØ«Êÿ7¼åÄ~‚´mÍ ì?ábÿŸ:^ÊÒ•—ü“ÿ‹xÞÝí ýÌä¯ýSÿŠy>tÏìUØ«±Wb®Å]Š»v*ìU¦è÷š›úVP¼ÍþH­>g Ê²eŽ1r<-øtóÌjÏú¬ãHü–Ôn@{éRÝOañ·áÅ?áóO—¶!¤ÿ±‹Ñ`ö$·™Ž?örÿ‰ÿdË,&´xúA–sîÜGÜœsY>×Ë.\0üIÝbì 1ú¸§ñáÿrAù{¡B(¶qŸv©ÿ‰fµùñaËÁàŠ,yCH}Rø•~o'ó¥ónü†æCý+á#þY!ÿ€þo'ó¥ó_Èáþd?Ò»ü#¤Ë$?ðÍäþt¾kù?̇úW„tùd‡þcù¼ŸÎ—Í#‡ùÿJïðŽ‘ÿ,ÿÀ 7“ùÒù¯äpÿ2é]þÒ?å’øæò:_5üŽæCý+¿Â:Gü²Cÿ1üÞOçKæ¿‘ÃüÈ¥wøGHÿ–Hà?›Éüé|×ò8™ô®ÿéòÉüÇóy?/šþGó!þ•ßá#þY!ÿ€þo'ó¥ó_Èáþd?Ò»ü#¤Ë$?ðÍäþt¾kù?̇úW„tùd‡þcù¼ŸÎ—Í#‡ùÿJïðŽ‘ÿ,ÿÀ 7“ùÒù¯äpÿ2é]þÒ?å’øæò:_5üŽæCý+¿Â:Gü²Cÿ1üÞOçKæ¿‘ÃüÈ¥wøGHÿ–Hà?›Éüé|×ò8™ô®ÿéòÉüÇóy?/šþGó!þ•ßá#þY!ÿ€þo'ó¥ó_Èáþd?Ò»ü#¤Ë$?ðÍäþt¾kù?̇úW„tùd‡þcù¼ŸÎ—Í#‡ùÿJïðŽ‘ÿ,ÿÀ 7“ùÒù¯äpÿ2é]þÒ?å’øæò:_5üŽæCý+¿Â:Gü²Cÿ1üÞOçKæ¿‘ÃüÈ¥wøGHÿ–Hà?›Éüé|×ò8™ô®ÿéòÉüÇóy?/šþGó!þ•ßá#þY!ÿ€þo'ó¥ó_Èáþd?Ò»ü#¤Ë$?ðÍäþt¾kù?̇úW„tùd‡þcù¼ŸÎ—Í#‡ùÿJïðŽ‘ÿ,ÿÀ 7“ùÒù¯äpÿ2é]þÒ?å’øæò:_5üŽæCý+¿Â:Gü²Cÿ1üÞOçKæ¿‘ÃüÈ¥wøGHÿ–Hà?›Éüé|×ò8™ô®ÿéòÉüÇóy?/šþGó!þ•ßá#þY!ÿ€þo'ó¥ó_Èáþd?Ò»ü#¤Ë$?ðÍäþt¾kù?̇úW„tùd‡þcù¼ŸÎ—Í#‡ùÿJïðŽ‘ÿ,ÿÀ 7“ùÒù¯äpÿ2é]þÒ?å’øæò:_5üŽæCý+¿Â:Gü²Cÿ1üÞOçKæ¿‘ÃüÈ¥wøGHÿ–Hà?›Éüé|×ò8™ô®ÿéòÉüÇóy?/šþGó!þ•ßá#þY!ÿ€þo'ó¥ó_Èáþd?Ò»ü#¤Ë$?ðÍäþt¾kù?̇úW„tùd‡þcù¼ŸÎ—Í#‡ùÿJïðŽ‘ÿ,ÿÀ 7“ùÒù¯äpÿ2é]þÒ?å’øæò:_5üŽæCý+¿Â:Gü²Cÿ1üÞOçKæ¿‘ÃüÈ¥wøGHÿ–Hà?›Éüé|×ò8™ô®ÿéòÉüÇóy?/šþGó!þ•ßá#þY!ÿ€þo'ó¥ó_Èáþd?Ò»ü#¤Ë$?ðÍäþt¾kù?̇úWÍßóšZ=žŸa¤›8R"ÓO^ ~ü2©æ–O¨™7bÓÃÐ#ê¾RÊœ‡b®Å]Š»v*ìUØ«2ü›ÐÿNy¿I°#’½ÔlÃü”>´Ÿð‘¶*ý"Å]Ѝµì+:Ú³£H«Üª•Wo’´‰ÿŠ«b®Å_ÿÎdù_ôoš¢ÕÐR=FÝI>2Eû—ÿ’^†*ðÖ+("‚5G²Ž+Š¢1U«Øm^v¬Ê€žìÇŠ/û&ÅU±Wb¯”ç7ô:K¥k ë, {íÆXÿ\˜«åœUØ«±WÒ_ó„_ñÛÔÿæ?äàÅ_ab®Å^sÿ9ÿ(¯ÿWþNGŠ¿-ÿݳwò:qO÷çó⯳Á®ãv*ìUä>hÿœhÐ<Çæ´óMåD 9Oj¢‹4 ü2»vVß'ûµ¿kíóUëpA¼k *©ªªŠª: U~*ìUØ«±Wb®Å_ÿÎ\~SÇåíF?4éˆËPr³ªŠžœ¹«p¼›þ2#ÿ6*ùçv*ìU2òß—o|ǨA¤i‘™nî\"(ñþfþTQñ;~Êâ¯ÐOÉïÊ ;òßL¶ÀK(æàÝ¿•–ÿu§û&øñV}Š»v*ìUØ«±Wb¯5üïü˜²üÈÓ ÑbÕ Rm§§~¾ŒŸÍ ŸòM¾5ÿ)WÀ:¾‘u£ÞM§_Æbº·vŽDnªÊhÃAâ®Å]Š»mzýø«ÿÖõN*ìU&ów˜£òþŸ%óîàq™ÏÙñ³“™z]9Ï1ôßÕp5Ú±¦ÆfÌþ»ç«™.¥yæbÒHK1=ÉÎú1:>U9™“#õIK$ÁØ«±Wb®Å]Š»v*ˆ°Óî5 –ÚÒ6–Vèª*rÈ .G†-¸±K)áˆâ“Õ|­ù7An5¶õ¯¢‡áë¿VÿcœÖ§µÉÛßÓ“Ùè»VoWû\~Ÿó¤ô‹+,cZƱF:*áœüæfnG‰êñâŽ1Q1þоA±Ø«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]оcÿœáÿŽ~ÿ§ÿˆÇоGÅ]Š»v*ìUØ«±Wb¯sÿœ<Ðþ¿ç#|«cm,€ø3Òÿ„’LU÷*ìUáþ}óÑÑ5´+jA5£Ã&ûVwnÿž–ðâ¯pÅ]мþs#Ë?¤|­«¬š}Â’@ý‰¦ßG?O|OŠ»{7üâw•¿MyÖ©°éÑ=ÁðåOJ/§œž§üóÅ_wb®Å^ÿ99çÐCBÓã~/q©C;ÿÆ8ÿÉI#ÿ€Å^à"£¡Å]мCþrÿDý!äÃv¢­eqŸ Õ…¿äâ⯆±Wb®Å_IÎÇoSÿ˜Tÿ“ƒ}…Š»yÏüäWü Z¿üa_ù9*üñÅ]Š»}sÿ8™ùÕ&¤ƒÉZÔœ¦‰ ²‘Žì‹ö­›Å£_Š/ø¯’þÂ⯦ñWb®Å]Š»Y=Ävèe™•w,Ä>“Š¥–>oѵ = ;ëYåþHæFoøbqTÛv*ìU„~uùe<Éå NÁÀ,-ÞT¯gˆzÉOø8«ó‹v*ìUö/üáüpu/ù‹_ù6¸«èüUØ«Àç4?å¶ÿ˜ÄÿˆIо)Å]Š»v*ìUØ«`4“Š¿D¿"|€<å[]:Eãw(õî6ßÔr(ãñ‹ý†*ôUØ«Äÿç,?0ÿÃ>X:U»RóU&CB"Ü?Ò Åÿ=qWÂø«±Wb®Å]о•ÿœ!ÿŽÆ©ÿ0ÑÿÄñW×ø«±W˜ÿÎKÿʪ©ü~|â®Å]оÁÿœOüë“Y‹ü­È^î­¤Œwx×í@ÇöžñGüÑÆ–ÅRë6èúŒž•õ´òÿ,s#øbqT×v*ìU~{ùi|ÅäÝN̯'Hxýž/ß/üC~tb®Å]оËÿœDüª]L>nÔý6üq·ä7H+ö‡ùS·ü“TþlUôN*ìUتEæ_>h^XPu»ë{Bw $€1ÿV?ïýŠâ¬v×óûÈ×R£Ö-ƒç%üŠ«øâ¬ÛOÔíu(EÍŒÑÜBÝ&§äÈJ⨜UJòò(^æéÖ(cRÎîBªÕ™›e«åOΟùËW›ÔѼŽÅu{â(ÇþaTýøÌÿûíWí⯗çžK‰i˜¼ŽIfcRIêY\UOv*ìUØ«k×ïÅ_ÿ×õN*ìUá¿›^eý'¨ýF¬•]º?lÿ±ûÙv^ŸÃ‡ú²¸þÎûsWãdàF/úiü_ñ,7/8ìUØ«±Wb®Å]Š»O|§äûÏ2Oé[Ž1/÷’‘ð¨ÿŸüœÃÕjã§~¯á‹²Ðè'ª•Géþ)ÿ ãÏwòו,|½£fŸûrÙ¿Ö?ñ®qzTó›—ú_á‹èÚM4±¨ëOøäœf#žìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»|Çÿ9Ãÿýþ3Oÿ|Š»v*ìUØ«±Wb®Å_YÿÎh¡mµ]XÝâ~JFÿ‰®*ú‡v*øWþrwÌREù‹-Õ³~òÀ[„> гÄÛ}³åÍf-oMµÕ 5ŽêæSìêøâ©Ž*Ç¿1<´<ÏåíCF"­snèŸëÓ”GýŒª˜«ó9С*„qU¸«ì/ùÂ,}[H¿×œ|WS,(ɈroøyáqWÒX«±WÂßó–žk:¿Ö&ýÞ›@´ìÿßIôò“û Uö¿–u¨év—«Òx"²UlU2ÅX‡æþ‡úsÊ:­€g´‘”ìƒÖŒÁƸ«ókv*ìUô—üáüvõ?ù…Où81WØX«±WœÿÎEÊ«ÿÆÿ“‘â¯ÏUØ«±TÃ@×.tBßU±n6²,¨}Ôòßü–û-þN*ý1ò¾¿˜t»]b×û«¸RUiÈrãóO²ØªgŠ»v*óÏÎ_Îm;òÓONúŒà‹{phX÷dŸÉ ~Ó~רLUðÏŸ?3õï<ܵηrò%j©+xâû/·þV*ÅUŠÊH ÔÛ}uÿ8—ùÏ}­É'”uÉŒòÅ–ÖW5r«ýäçwá^q×âáÏùW}3Š»Cj‘¬–“#î­ƒò â¯ËisŠ­Å]оÅÿœ#ÿŽ¥ÿ1kÿ&×}Š»xüæ‡ü¢vßóŸñ 1WÅ8«±Wb®Å]Š»zÏüã7å÷ø¿ÍIp¼¬´ê\Í^„©ýÄgýyxÿ°GÅ_}â®Å\M78«óßþró ükæ»›ˆ_••§ú5¿‡'œŸóÖ^oþ§ Uæx«±Wb®Å]о•ÿœ!ÿŽÆ©ÿ0ÑÿÄñW×ø«±W˜ÿÎKÿʪ©ü~|â®Å]ЦžXó Ï—5;mbÈñ¸µ•e_~'ìŸò\|-Š¿L|¿¬Ã®iöÚ­©¬7Q$È}C׊£ñWb®Å^qùÑùÕ§þZX õ9Áú½µi^Þ¬¿É ÿÃý„þeUðמ2õï;Ü›­réåªÄ "Ohâÿ­öÿÊÅXÊ;FÁЕe5lA«ìùÄ¿ÎKï0úÞU×%iî-ãõm¥sWhÁ $NÇíú|‘‘¾×_ËŠ¾’Å]Š¥žgPÚUâ°¨6ò‚?Ø6*ü¾Å]вO˯(Iç ~ËBŽ \ʪä~ÊŽgÿc¶*ý*²³†Æí-G(¨ˆ½TqUê®*­Š»xüä—üä$žMáÏ.¸ý/"ÖYh ­öBƒðúî>-ÿ»O‹ö—|e¨\j3½Ýì4òO$ŒY˜ø³6øªd~HüÂÖ¼“x/´;—«VJÖ7Ë,_eÿâ_ËŠ¾ÇòïüåO–®ü´uíUþ¯{îä³_ŠF’•W_ÚŠOÙvþïìÈß*ù‡ówóçZüÆ”Ã1ú®”­XíPìiöZvÿwIÿ¿°˜«ÌñWb®Å]Š»v*ÚõûñWÿÐõN*“ù»\&™5ïíªÑ?Ö? f^“Gý7õ\ v§òøŒÿÒÿ_ø_6Èí#sVcROrsÐ§Ê ½ÊÜPìUØ«±Wb®Å]ЧþNòÇ™nÄUaMå’›(ÿšÛöFajõCO?WðÅÙh42ÕÏ„mãŸóãÏ t}ÛH¶K;4 ¤žìÇ»áòå–YqK›é¸0GD *!”¹Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯˜ÿç8㟣ÿÆiÿâ1⯑ñWb®Å]Š»v*ìUØ«ï/ùÄýé¾F¶™¾Õä²Ïôrô—ð‹{*ìUùÁùÓ©OÎZ½Òš©»‘GÉ¥ÿb¯­ÿçüÓúkÉqY;Vm:W€ï¿}h¿ádô×þ1â¯hÅ]Š¿:=¼¯þó–§d£ŒO1ž?õeýð§²óáþÇ`8«ô{òWËáŸ(išk2ˆI~rþùÁÿT¿ö8«6ÅT5 Øì-廜ñŠižÁG&Å_˜¾gÖä×µK­Zjóº™å5íÉ‹SýŽ*ýü„ÔÿIyGžµãj±È¢mÿæV*ϱU²F²)FV|*üÁóFŽt]VóKn¶·ÿù Éü1T¯v*úKþp‹þ;zŸü§üœ«ì,UØ«Îç"¿åÕÿã ÿÉÈñWçŽ*ìUØ«±WÞ?󉺻êE·ŽCSk4ÐoUäî*öÑj,Çÿ†KýëËs£xçb®Å]Š»v*ìU¥i“j—1ÙZ¯)en ì¹^\ƒL¥ôÅ»f„~©>‹òÇ— òý’Y[Š‘»·vcö˜ÿƹÁju<¸ù¿Ñ‹êš=$tÐùÒþt“lÅs]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]оcÿœáÿŽ~ÿ§ÿˆÇоGÅ]Š»v*ìUØ«±Wb¯Ó?Ë­ô—4Ý.”k{XQ‡ù\©ÿËd8ªÉåFÒФýÃ~]ëWçP¾¸½=g•äÿ‚bÿÇ}ÿ8Wæªk—ºš%äTåÄêœÿоÆÅ]оDÿœÙò¿¡¨éÚükðÜDÖîÊŒóJÿ°“þxw凖ÄþeÓ´r9%ÅÂäÎ_ù&­Š¿K  è1Wb¯+ÿœ›óOøÉ¼ &½ãhŸóÐþ÷þH,¸«óÿ}Õÿ8‡©›Ï#Ç5ú­ÌÑ|"ùн«v*üýÿœ™Ñ?DùïQQn N¿ìÕyÃóÅ^[Š»}%ÿ8Eÿ½OþaSþN Uö*ìUç?ó‘_òjÿñ…ääx«óÇv*ìUØ«í_ùÂÿùDîæ1ÿââ¯Å]оoÿœÚÔ'‡DÓ­#r°ÍræE¢ü¿ÕæØ«ã¼UØ«±Vùÿ)Îÿ1+ú›~Šâ®ÅT5÷š_õõb¯ËY~Û|Î*³v*ûþpþ8:—üůü›\Uô~*ìUà?óšò‰ÛÌbÄ$Å_â®Å]Š»v*Î?%ü†Þxó=ž’V¶ü½[ƒá|RÁÿwþ³â¯Ñ¨ãXÔ"@€ Uv*ìUð¯üågæø£Í ¦Û¿+=(‡c!ÿzþ Œ_óËx®*ìUØ«±Wb®Å_JÿÎÿÇcTÿ˜hÿâx«ëüUØ«Ìç%ÿåÕ?ÔþNÇŠ¿>qWb®Å]оÚÿœ1·“çCÑo¤§Ò‘b¯zÅ]оeÿœßÔî"Ó´›Ü‹yåžI~ÓF±«þ¯­&*ùv*ìUè_óßòhÿóÿ¶*ýÅ]Š¥¾eÿŽ]çüÃËÿlUù{Š»}“ÿ8M¦ˆ¼½¨_Óy®ÄuöŽ5oùŸŠ¾‹Å]м;þs[k&}N3C{uL,¾©ýÔÿ=#9÷«v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUóüçüsôøÍ?üF*ìUØ«±Wb®Å]вËíôç˜tí2œ…ÅÔHÃü’ßü',UúhlUØ«üÊÕ?EygT¾†9Ø|ÄmÇþ~g⬻ò—Í?áo4麻1Ep‚Cÿ¿î¦ÿ’nØ«ô›v*ò/ùÊ+þòEÔ¨µ–ÁÒé~JxKÿ$d‘¿Øâ¯ ÿœ1òÇ×üÉs¬¸¬vôSÛœ§‚ÿÉ5—}£Š»|—ÿ9·æRëMòôgh‘îdì}(¿“|¿Š¾½ÿœ!Ô½M/T°'û©ãõÔ©ÿ“X«é|UØ«ãÏùÍÐÖ´íUV‹qnÑâÑ7/øŒËоnÅ]о’ÿœ"ÿŽÞ§ÿ0©ÿ'*û v*óŸùȯù@µøÂ¿òr*ìUØ«±Wb®Å]нþqSDý'ç«I¶‰,äŽÄ/ÿ†“}늻yüäΧõ!jd4ËCýœˆþž*üûÅ[˜«ô‡òsÍÌþSÓu2yHÐ*I½~8ÿu%~lœ±VeŠ µ½*=ZÆãNœV;˜ž&¯ƒ©O㊼þqSȲy_Ë—])7W’ò¨¡ã ú²ø4•×þ2b¯iÅ]Š¿;?|Óþ%óž¥x­Ê¥6ñxq‡÷?³²´ŸìñWžâ¯¤ç 5/K[Ô¬IþúÙ\tzÌÌUö*ìUóçüæ–‡õ¿,Zjj*ÖwaO²J¬­ÿ%,Uñv*ìUô—üáüvõ?ù…Où81WØX«±WœÿÎEÊ«ÿÆÿ“‘â¯ÏUØ«±Wb¯µç ÿå¹ÿ˜ÇÿˆGнÿv*ùŸþsþ9zOüÄKÿ\Uò*ìUØ«?ü‚ÿ”çGÿ˜•ýMŠ¿EqWbª‡ûÍ/úú±W嬿m¾gYŠ»}‹ÿ8GÿKþb×þM®*ú?v*ðùÍùDí¿æ1?âb¯ŠqWb®Å]ЧÞDò•Ç›µ»M ×ûË©Bü«ö¥“åaŸ~•éU¾‘gf¼-íãX‘|GÅQx«±WÆ󘿘_¥µ¨¼¯jÕ·ÓG9iÐÌãìÿÏ(¸ÿ³y|v*ìUØ«±Wb¯¥ç㱪Ì4ñ‹#ÇŽ*ø£v*ûþp«Í?[ѯ´¯g0™ùþé#oø`š/ø_Wþeb¯»ñWb¯=ÿœÑ?LùU·¥Y õ—jšÄVù—Š¿;qWb¯¤¿ç¿ã·©ÿÌ*ÉÁоÂÅ]мçþr+þP-_þ0¯üœ~xâ®Å]Š»}«ÿ8_ÿ(ÏüÆ?üB‡üÌÅ_£˜«±T.­bº…œöoögã?&qWåî£fÖW2Ú?Ú…ÙÍOUо’ÿœ"ÿŽÞ§ÿ0©ÿ'*û v*óŸùȯù@µøÂ¿òróÇòÚÈÿù³wý ÷ž?–ÓþGÿ͘«ô'Þxþ[Oùÿ6b¯Õ´Ét«É´ûšzÖòXÔü¹tÖÅ´–·hVE#éSö]ÊO‡JñVsùuù3æ?>αévÌ–µ£ÜÊ Ä£¿Æ¼oø®>OоÏòïüãß–4¿-Ÿ+][­Ür|sLâ’4´§¬Ž>(¸ºø}•ø~.OÉWËŸœßóš·ËêZw+í¯¨£÷‘ „_Ùÿ‹—àþoOxÖ*ìUØ«±Wb®Å[^¿~*ÿÿÖ蟳r¿·Œ³üNuŒ=ÿIàý¢•äˆþ‹Î3~òŽÅ]Š»v*ìUÇ ¾™òÅ·Õ´»XGìCÿ…çz™qd‘þ”Ÿ\ÑÃGô#÷&yŽå»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUóüçüsôøÍ?üF*ìUØ«±Wb®Å]Š¿H?%ôOОOÒ¬˜quµGaþSUÿáŸf˜«±WÅ_ó™ú™¸ó]µ~{4ûÝÝê\U૱T~ƒ«Ë£júœ‰m¥IVž(ÁñWéÞ“¨Ç©ÚC}¬W¤ŠGƒCEb®Å]о"ÿœÃóOé_6¦—V-6B;z’~úCÿbFÿSxF*ìU¢_6ŸoxŸj £|Õƒÿ Uú‹‹* ÕXˆ8ªìUØ«ó£óßCý ç]ZÓ7 *òeuü$ÅX*úKþp‹þ;zŸü§üœ«ì,UØ«Îç"¿åÕÿã ÿÉÈñWçŽ*ìUØ«±WÚ¿ó…ÿò‰ÜÿÌcÿÄ#Å^ÿŠ»|Ïÿ9¿ÿ½'þb%ÿˆ.*ùv*ìUŸþAÊs£ÿÌJþ¦Å_¢¸«±U Cýæ—ýFýX«òÖ_¶ß3ЬÅ]оÅÿœ#ÿŽ¥ÿ1kÿ&×}Š»xüæ‡ü¢vßóŸñ 1WÅ8«±Wb¯¢?ç/¿KkSyžé+o§ÐÌã·üb‹þNGоÌÅ]Š»v*ìUØ«±Wb®Å]Š¿3?1?å$Õ?æ6ãþN>*DZWÒ¿ó„?ñØÕ?æ?øž*úÿv*óùÉù@uOõ#ÿ“±â¯ÏœUØ«±Wb¯¶?ç ?å¸ÿ˜é?âb¯|Å]о[ÿœåþãDÿ^ëõ[⯓ñWb®Å^…ÿ8ýÿ)Öÿ1ñ«b¯Ñ,Uت[æ_øåÞÌ<¿ñÅ_—¸«±Wb¯®çÿ6îÕ¼“©IIàå%™cö“íKÿ*#ûÅï¾_ï¼UôÞ*ìUتRÑìµDôµ"¸ŒtYQ\}ÎJ-?.<·fæK}2ÍšÔ@•¯ü*ÈQ5€*@À U¼U§Eu*À"„„b¯›:¿çíµoSYòb­½á«=§Hä=ý÷̇ù?ºoø¯|©i·:eÌ–W±´70±I#qFViYqT6*ìUØ«±Vׯߊ¿ÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í²}GÞû/¤T+ä]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ùþs‡þ9ú?üfŸþ#*ùv*ìUØ«±Wb©†¦6«¨Ûiè95ÄÑÄúÌ~ŸÚÛ%¬)oÉ…_F*«Š»~~ÿÎMê_óî¤AªÂcˆ°9ÃòÅ^[Š»v*ûçþqoÍ?§¼‘i·)¬í_䇔?òAã\Uëx«±U—¥¼m4†ˆŠY€§~eyßÌ/æMn÷X}ÍÔòH>DüèN8ªGŠ»o~˜þ]jCSòÞ™z L¶1>ü—ü6*ȱWb¯Šç3´?©ù® EEòÑ*|^6hÛþIú8«ÀqWÒ_ó„_ñÛÔÿæ?äàÅ_ab®Å^sÿ9ÿ(¯ÿWþNGŠ¿­/lÛNÓÙf×n÷iÔBû¾où•û³ýLUð•íì×Ó½ÕÓ´³ÊÅÝØÔ³Vf8ª†*ìUØ«±Vׯߊ¿ÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]г/ÉÝOLÒ¼Ù§j:ܾ…´ÂW~%¨Pá@ͼ¡1WÝÚWçG“µB®­hXöiø8b¬®ËT´¾­&Žaã†ÿˆœUŠ¿4?2õOÒ¾gÕo¨šöv##pÿ…ÅXÖ*ìUØ«é/ùÃ/;ÛéWºŽ‹4pÅqN†F 9!àê mVI?á1WÕŸâíþ[­ärÍX«¿ÅÚ7ü·ZÿÈäÿš±WŸþ}~céúW“u±»†K©âú¼kŠÍYO¤Ì5~ÙßýŽ*øv*ìUØ«ôþq¯S‡ôÆbGˆÿ°w_ÕŠ½2Y’/+QÔ“AбÝWó+ËZH­ö§i;4É_»•qWËßó–˜Xó„yЯîîÖI‚ G ¿6P¿n5Å_8b¯¢ç 5;M?YÔžöhàVµ@ ŽÏ·21WÖ¿âíþ[­ärÍX«¿ÅÚ7ü·ZÿÈäÿš±WŸÎ@y“Kºò>­ ½Ý¼’´+ÅVT$üiÑCb¯€±Wb®Å]оÈÿœ=×,,<­qåÌ0¹¼rIM8G¿5Å^íþ.Ñ¿åº×þG'üÕŠ»ü]£Ëu¯üŽOù«|ãÿ9£¬Øêf–¶WNVyIȬG½xоOÅ]Š»g‘WÛy×HšwXã[•,Ì@Qº³mŠ¿@ÿÅÚ7ü·ZÿÈäÿš±W‹´oùnµÿ‘Éÿ5bªÞlÑÚÞEÖÕ(ßîäðÿ[~eËöÛæqU˜«±W×ó†:ÕŽŸ¡ê){q ×j@’ERG¦»ÑÈÅ_C‹´oùnµÿ‘Éÿ5b®ÿhßòÝkÿ#“þjÅ^ÿ9…®X_ùZÞ;;˜fqx„¬r+p“~*kо7Å]нoþq—Ê–zÏš¢¿ÕeŠ+-4 ƒêº¨iû΃™¿yûßùåžÖ*ûü]£Ëu¯üŽOù«wø»Fÿ–ë_ùŸóV*ïñvÿ-Ö¿ò9?æ¬Ußâíþ[­ärÍX«¿ÅÚ7ü·ZÿÈäÿš±W‹´oùnµÿ‘Éÿ5b®ÿhßòÝkÿ#“þjÅ]þ.Ñ¿åº×þG'üÕŠ»ü]£Ëu¯üŽOù«wø»Fÿ–ë_ùŸóV*ïñvÿ-Ö¿ò9?æ¬UùÃù"Éæ-Mã!•¯' ƒPA‘·uÅXþ*ú3þp¿T´ÓõmMïfŽkxÀ2:­O>ÜÈÅ_Y‹´oùnµÿ‘Éÿ5b®ÿhßòÝkÿ#“þjÅ^mÿ9æ=2ïȺœ6×pK+$tT• ÞÇÑUªqWÁX«±Wb®Å_eÎk–Sž;˘as{! $Цœ"ß‹5iнÓü]£Ëu¯üŽOù«wø»Fÿ–ë_ùŸóV*ù›þs[X²ÔaÑ…”ñOÁ®¹zn­Jˆ)Ë4Å_-b®Å]гïÈkˆ­¼ï¤Í;¬q­ÅYœ…qn¬Ûb¯Ðñvÿ-Ö¿ò9?æ¬Ußâíþ[­ärÍXª_æ/5é¦]¢ß[0J'^-þV*üÑÅ]Š»v*ŽÑ5ËÝî=GL™íî¡<’D4 ÿŸÚ_ÚÅ_\þSÿÎ^iÚª&Ÿç,¯¹Qû—÷}¨þI•ÙÅ_CXêú„Ksg*M î¯SòeÛWÅ]Š»@ë톋^jw[@ ’ò¸Q·»b¯œ?6ÿç/í­’M3É#ÖœÕZòE¢/üÃÆßÿIû¿òdÅ_(êZ•Χs%õô5ÌÌ]äsVb{³U Š»v*ìUØ«k×ïÅ_ÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*¯o{=±åñV#þ#в+ó{ÍÚUž­xŠ:)™™à²â¬JIF.æ¬Ä’OrqU¸«±Wb®Å]Š»v*ìUØ«±Wb¬ŸGüÎó.‰bºV—¨ÜZÙ«3ár‚­»n”mþxªQæKQ%¯n¦˜ž¦I¿âGKñWb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ùsÎÚ×–_ÕÑog´nþ“•ýdû þÉqW¥iŸó–¾{²@’ÜAsM«, _ù#èâ©”ßó™~tQc±Ou…ÿãy›cú¿üåŸ5%)ú@[¡íQ¡ÿƒâdÿ‡Å^s­y‹Q×%7:­Ì×RŸÚ™ÙÏü98ª]Š»v*ìUØ«±Wb­¯_¿ÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«k×ïÅ_ÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«k×ïÅ_ÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«k×ïÅ_ÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«k×ïÅ_ÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«k×ïÅ_ÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«k×ïÅ_ÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«k×ïÅ_ÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«k×ïÅ_ÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æ?ùÎøçèÿñšøŒx«ä|UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«kŠ¿ÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUتVòþ¬ª¦©kÚÆIQ4k Rzñõ¸â©oü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1WʹòÏýZl?é/ù£wü«Ÿ,ÿÕ¦Ãþ‘¢ÿš1V=çÿ ùvßC»–2É$Te¶ˆñ/CÃ3´Ë{ÝgiÈLj<&ºX<ü?¦ÿË%¿üŠOù§;oËãþl?ÒÅó_Íeþ~Oôóýnÿé¿òÉoÿ"“þiÇòøÿ›ô±_Íeþ~Oôóýnÿé¿òÉoÿ"“þiÇòøÿ›ô±_Íeþ~Oôóýnÿé¿òÉoÿ"“þiÇòøÿ›ô±_Íeþ~Oôóýnÿé¿òÉoÿ"“þiÇòøÿ›ô±_Íeþ~Oôóýnÿé¿òÉoÿ"“þiÇòøÿ›ô±_Íeþ~Oôóýnÿé¿òÉoÿ"“þiÇòøÿ›ô±_Íeþ~OôóýoRüšò^‡{ Ѻӭ%âÉNvñµ*NIœßk㌠x@?¥ì½ŸË)Æ\FSÞ?QâÿtôùW>Yÿ«M‡ý#Eÿ4g>õnÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«M‡ý#Eÿ4b®ÿ•såŸú´ØÒ4_óF*ïùW>Yÿ«Mý#Eÿ4b¯ÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU(óg™"òÖ™6¯p$PJ¥9›r*¿µŠ¼Ëþ†{Gÿ–+¿ù'ÿU1M;þ†{Gÿ–+¿ù'ÿU1Zwý öÿ,WòOþªb´ïúíþX®ÿäŸýTÅißô3Ú?ü±]ÿÉ?ú©ŠÓ¿èg´ùb»ÿ’õS§ÐÏhÿòÅwÿ$ÿê¦+Nÿ¡žÑÿåŠïþIÿÕLVÿC=£ÿËßü“ÿª˜­;þ†{Gÿ–+¿ù'ÿU1Zwý öÿ,WòOþªb´ïúíþX®ÿäŸýTÅißô3Ú?ü±]ÿÉ?ú©ŠÓ¿èg´ùb»ÿ’õS§ÐÏhÿòÅwÿ$ÿê¦+Nÿ¡žÑÿåŠïþIÿÕLVÿC=£ÿËßü“ÿª˜­;þ†{Gÿ–+¿ù'ÿU1Zwý öÿ,WòOþªb´ïúíþX®ÿäŸýTÅißô3Ú?ü±]ÿÉ?ú©ŠÓ¿èg´ùb»ÿ’õS§ÐÏhÿòÅwÿ$ÿê¦+Nÿ¡žÑÿåŠïþIÿÕLVÿC=£ÿËßü“ÿª˜­;þ†{Gÿ–+¿ù'ÿU1Zwý öÿ,WòOþªb´ïúíþX®ÿäŸýTÅißô3Ú?ü±]ÿÉ?ú©ŠÓ¿èg´ùb»ÿ’õS§ÐÏhÿòÅwÿ$ÿê¦+Nÿ¡žÑÿåŠïþIÿÕLVÿC=£ÿËßü“ÿª˜­;þ†{Gÿ–+¿ù'ÿU1Zwý öÿ,WòOþªb´ïúíþX®ÿäŸýTÅißô3Ú?ü±]ÿÉ?ú©ŠÓ¿èg´ùb»ÿ’õS§ÐÏhÿòÅwÿ$ÿê¦+Nÿ¡žÑÿåŠïþIÿÕLVÿC=£ÿËßü“ÿª˜­;þ†{Gÿ–+¿ù'ÿU1Zwý öÿ,WòOþªb´ïúíþX®ÿäŸýTÅißô3Ú?ü±]ÿÉ?ú©ŠÓ¿èg´ùb»ÿ’õS¤×ÊߟVdÔaÒl¬®½YÚ•oNŠäÎô“ì¢â´ôüPìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*Æÿ1ÿãyþ ÿ‰.l;?ûèûÿCªí_ñyû¿ßÎùݾZìUØ«±Wb®Å]нsò7û‹¿õÓõ6rýµÎ?·ös韾/PÎq슻v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»ÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUôüã_”=yüÇ:üsVkü€þñÿÙ¿Ãþ÷áC±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*Ðtiµ»ø4ËQYn ö¯Úo’/ÅŠ¾ÕÑ4ˆ4k(tëQHmÑQ~Ôÿ”ßi°±Fâ®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬oóþ8Ÿêø’æÃ³ÿ¾¿ô:®ÕÿŸ»ýð|ïÛå®Å]Š»v*ìUØ«×?#¸»ÿ]?Sg/Û\ãñ{g>™ûâõ çÁØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*÷ùÆÏ'z³OæK…øc¬WùŽó8ù/ÿ‚Åô;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»c˜ÿñÀ¼ÿPÄ—6Ÿýô}ÿ¡Õv¯ø¼ýßïƒç|îß-v*ìUØ«±Wb®Å^¹ùýÅßúéú›9~Úç‹Ûû9ôÏߨg8öÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š¿ÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»W°±›P¸ŽÎÕyM3¬h-ö¤öoɰ±M±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬oóþ8Ÿêø’æÃ³ÿ¾¿ô:®ÕÿŸ»ýð|ïÛå®Å]Š»v*ìUØ«×?#¸»ÿ]?Sg/Û\ãñ{g>™ûâõ çÁØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»{üã—“ÿHj2k× XlÇê:ÊÃíÏ(ÿá—ÒPìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š®Š'™Ö(Ágr@êIØ Uöoå÷•ÊÚ-¾–´õyJGyâÿÁ|8X²,UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]нGþqûʦu¿Òs­m´ð~†SýÐÿa¼Ÿð8©}A…‹±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]òÜø UöåG”•´-RæQêÌËoÙÿžkÅ?ØábÌ1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]б¿Ìøà^¨?âK›Ïþú>ÿÐê»Wü^~ï÷Áó¾wo–»v*ìUØ«±Wb¯\üþâïýtýMœ¿msÅíýœúgï‹Ô3œ{b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å^ù%äïñ½’­ml©4žƒû”ÿdÿú¨Ø©}c…‹±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]б¿Ìøà^¨?âK›Ïþú>ÿÐê»Wü^~ï÷Áó¾wo–»v*ìUØ«±Wb¯\üþâïýtýMœ¿msÅíýœúgï‹Ô3œ{b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®&˜«ëÉ'ÿ‡tä™iuyIäñÝ'ûÿá™° ½;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬Ãò£Êâz I•¬_¾ŸýE?cþz?ÿ‚Å_`M‡L,]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯¨?çüúEý%:ÒçP"MÆâ1ýÒÿ²þóý’áAzŽ(v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬oóþ8Ÿêø’æÃ³ÿ¾¿ô:®ÕÿŸ»ýð|ïÛå®Å]Š»v*ìUØ«×?#¸»ÿ]?Sg/Û\ãñ{g>™ûâõ çÁØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU„~uÊ%¨¨Ÿòq1H|‹.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±VEùåVóNµm¥û§nRŸ×â“þ|ì±Wٰİ¢ÅâŠv¦+±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*Æÿ1ÿãyþ ÿ‰.l;?ûèûÿCªí_ñyû¿ßÎùݾZìUØ«±Wb®Å]нsò7û‹¿õÓõ6rýµÎ?·ös韾/PÎq슻v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»ÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU!ó×–ßÌÚ=Æ‘‚&¸ ‘P(Êý?Øâ¯ÿ¡_¼ÿ«Œò,ÿÍXnÿ¡_¼ÿ«Œò,ÿÍX­»þ…~óþ®1ÿȳÿ5b¶ïúûÏú¸Çÿ"ÏüÕŠÛ¿èWï?êãü‹?óV+nÿ¡_¼ÿ«Œò,ÿÍX­»þ…~óþ®1ÿȳÿ5b¶ïúûÏú¸Çÿ"ÏüÕŠÛ¿èWï?êãü‹?óV+nÿ¡_¼ÿ«Œò,ÿÍX­»þ…~óþ®1ÿȳÿ5b¶ïúûÏú¸Çÿ"ÏüÕŠÛ¿èWï?êãü‹?óV+nÿ¡_¼ÿ«Œò,ÿÍX­»þ…~óþ®1ÿȳÿ5b¶ïúûÏú¸Çÿ"ÏüÕŠÛ¿èWï?êãü‹?óV+nÿ¡_¼ÿ«Œò,ÿÍX­»þ…~óþ®1ÿȳÿ5b¶ïúûÏú¸Çÿ"ÏüÕŠÛ¿èWï?êãü‹?óV+nÿ¡_¼ÿ«Œò,ÿÍX­»þ…~óþ®1ÿȳÿ5b¶ïúûÏú¸Çÿ"ÏüÕŠÚ…÷üãdöIws©Dĥ݌g`£‘ý¬VÞ0i_‡qØûb—b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUô‡üã“þ¡¦É¯N´šôñ޽¢S×þz¿Åþª&°â‡b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUþcÿÇóýAÿ\Øv÷Ñ÷þ‡UÚ¿âó÷¾ó»|µØ«±Wb®Å]Š»zçäo÷ë§êlåûkœ~/oìçÓ?|^¡œãØ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«È?ç#|ßú?LB©5鬔ê"Sÿ3áÿU_CæÜRìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅSo)ùv_1ê–úLjwŸåQñHÿìS–*ûRÂÆ+ xí-—„0 D°QÄab¯Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU§u@YÈ :“°ÅXæ­ù‘åÝ$ñ¼¿~ÈpÍÿœŽ*Äïÿç"ü³m´âãýHè?ä³EŠi!ºÿœ ³Sþ§Êãü¹RÉi/—þr†b?w¦¨>ò“ÿ Všþr‚àÞiÈG´¤Ƈ¤\ó”Q¦ÓX{¬Àþ?ãŠÒogÿ9/¡IµÅ½ÌGÄaÿ ÿ …iéßž>S½Ûë¢á22Ã2ðÿ†Åi–éºþŸ©€Ö7Nò8oø‰ÅüUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUþcÿÇóýAÿ\Øv÷Ñ÷þ‡UÚ¿âó÷¾ó»|µØ«±Wb®Å]Š»zçäo÷ë§êlåûkœ~/oìçÓ?|^¡œãØ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU©$XÔ»EI=€Å_~bù­¼Ó­ÜjUýÉn×áOø/·þË&5Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±W¿ÿÎ5ù?ÒŠ1Ü/Å-a‚¿Êï_ý“üì1A{–;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬gΘºG”bç¨Ê=b*¦ò7ûÙ_òßáÅ^ªÿÎEë·‚]Y,pZFÛ@G.cþ.“íWþ1ñãþVT÷/ ~aéþs´úÅ™áp”õacñ!ÿþËábÊqWb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUتɧŽ2ÌÁEK1 ÜœUç¾füùòæŠLpH׳ـTWþ2ŸÝÿÀòÅ4òß0ÎHkw¤¦—VQöjz÷¿îÿäž§kkÕµ¦å¨ÝÍ?³9§Ð¿g¥!@è)Š·Š»v*ìUØ«±Wb­Äí sˆ”o4?z⬷BüÙó.‹Am{#Æ?boÞ-#оÖÐth4K4ÛQHmÐ"ûÓ«ò˜üM…Š;v*ìUØ«±Wb®Å]Š»v*ìUØ«±T­¬Yéíy¨J@›–sAм'Ï¿ó‘S\r³ò˜£èndÿŒQŸ±þ³ü_ä.ÓÅnîæ¼•®.]¥™ÍYÜ’Äû±Å*Xªeåï1^ùzö=KMÇiÛoö|?ÕÀšxÏ™<í¬y•ùê·/2Ö¡+DêÄ¿ümŠRPüñ×ü¾V)äúõ¨Û„Ƭù}¿ø>x­=ãÉ_œš¸ÃŸW¼? ?ñ[ý‰?ØüäaC7ÅÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»c˜ÿñÀ¼ÿPÄ—6Ÿýô}ÿ¡Õv¯ø¼ýßïƒç|îß-v*ìUØ«±Wb®Å^¹ùýÅßúéú›9~Úç‹Ûû9ôÏߨg8öÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š¿ÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUò7ç›ÿÄÚüÒDÜ­m«>)øÜÆI?áx`d>*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å^ßÿ8ÙäÿZâo1Ü/Áa‚¿ÌGï[ýŠqOöX ¾‚‡b®Å]Š»v*ìUØ«±Wb®Å]й˜(©Ø§yWŸ¿?tݵžŽõàØt‡ü§Þ«ü)§Ï~gó~§æ{­jÓ´¬>ÊôEöŽ1ð®¤ø«±Wb®ÅSO,ù–÷ËwÑêzsðš3¸ìËûQ¸îо»ò'ìüá§.¡fhãá–2~(ߺ··ò7í.,‹v*ìUØ«±Wb®Å]Š»v*¥uw ¤MqrëH*ÌÄ»Uã>yÿœŒ¶´åiå´Šƒ<€ˆÇücOµ/ü*­4ð½Ìš˜'7z¬ïq);r;õì'ûR–â®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]î:Æ*õ ~|êz[M[•õˆ ©?½AþCŸïùÿŠÓè¯-y«Nó-¨½Ò¦Y¢=i³)þYí#ab›b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*Â?8¼ßþÐ&š&¥ÕÇî!ñäÃâù期¾EÀ—b®Å]Š»v*ìUØ«±Wb®Å]Š»v*­ee5ôñÚ[/)¦uD¹cÄb¯´üŸå¸¼·¥[é0n @ÿ3äöO…ŠqŠ»v*ìUØ«±Wb®Å]Š»v*Å<íù™£ùB?ôéyÜ‘U‚:?1û þS⯜ü÷ùìy´´¾«bzAê?âé>ÔŸêýòp2¦ Š»v*ìUØ«±Wb¬È~x»òv¢º…§Å¢Ívtðÿ]Ýmû8«ëí^´×ì¢Ô´÷çËP{aû.½ Ãv*ìUØ«±Wb®Å]аOÌÍý+Ê ÖäýgP¦Ð!éÿŸý×ÿÿ'¾oóŸæ.¯æùyê2Òj%DkþÇöÛü·À–3Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±TÓËžgÔ<·t/´©L2޽ՇòHqWÓ¿–›Ö>qAk5-õ5Dìôêð·í©ö×þ ŠŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ùkóóΧ5ÓcVÚÀÅ:ó7üF?ö™â®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUëßóŽ~Pý#ªI®Nµ†Èq޽åa×þyÇÿ ëŠ é<(v*ìUØ«±Wb®Å]Š»v*€Öõëݯ5)’WöœÒ¾Ê:³’¸«Á<ûÿ9uÊÏËjm¡;‡¼aÿ§û«ýo·þ¦ÓÆæžIݦ™™äsVf$’|YŽ)YŠ»v*ìUØ«±Wb®Å]нòƒó6O'ß}^è–ÒîX Gò7A:ÿÌÏæ_õqWÕÐÌ“"ËG•¨ ô# Ø«±Wb®Å]Š¡ïõ }:»¼‘a‚1Vw4|ñWÏß™ó3ßòÓü²Lû†¸;;Æ!þê_òþßú˜OwgbîK3’MI>$â–±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUت¥½Ä–ò,ð1ŽT!•”Ђ:2œUô—äÿç:ù‡Ž­0MD G'A5;“7ù?·û8QO[ÅÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»c˜žk_+h·™#ÕUá=äo†?»í·ù+о4’F•Œ’ÎijÔ“¹8-Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUtQ4®±Æ ;ªRNÀ Uö_å×”×ʺ-¾™·ª«ÎSã#|R}ßgýŽ,“v*ìUØ«±Wb®Å]Š´î±©w (Ü“°«Èüýÿ9a¤r³ÐBÞÝ ƒ%t§ýaýïû‡ü¼ §€y͘îMæ«3O'jý•Ë}”\R•b®Å]Š»v*ìUØ«±Wb®Å]Š»{Ÿäæy‰—Êú£ü þò»‡þYÏüÊÿ€þ\P^ý…Å]Š»cžvóî›äû_­j/ûƯ§îîÉ_åþgo…qW˾}üÊÔüç?+ÆôíTÖ;t? û·ûòOòÛý ˜ž*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«híBU”‚4 Žã}1ù/ù¹þ#ŒhÚ»ÒQ¯ÀçoYGüÎ_Ûþo·üØP^±ŠŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»|Ýÿ9æÿÒœz XlÇ9)ÞV?çœñ< Å.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUé¿>Oý7® Bu­¶ž›ô2îGûäÿcŠ—Ô˜X»v*ìUØ«±Wb®ÅXwž5t()K™=kÊ|0FAö}¢_õñWÎ~{üØÖ<ÞÆ)ßêö]­â$)ÿŒ­ö¥ÿeðÿ““ Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«jÌ„2’‚6 Žø«ê¿ÉŸÌ¡æÝ?ê·¬?IÚ€$ÿ-z,ãõIþ_úØP^‹ŠмóóCó~ÏÉñ›;n7£†:ü)^5?áSí6)|Á®k·ºíÛê”­5ÄY»åE舿²«( UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅUm.æ³™.mœÇ4LM ‘ц*ú×ò£ó/9éÜ¥!u(³ ñý™P$Ÿð­ðáC7ÅÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUþcÿÇóýAÿ\Øv÷Ñ÷þ‡UÚ¿âó÷¾ó»|µØ«±Wb®Å]Š»zçäo÷ë§êlåûkœ~/oìçÓ?|^¡œãØ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š¥>kó >]Ó.5[Šp {·ì'û'øqWÅš…üÚÄ··,Zi¤r{³G$>*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ùoо¾ü¤ò‡ø_A‚ÚAK™¿}7úì>ÏüóN)…‹3Å]Š»v*ìUØ«±Wb¯ü×ü‰vi5¯-‚ìļ¶Õ©$ý§€Ÿù5ÿü˜oe*J° ƒBPqKX«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*™ùkÌw~\Ô"Õ,“BkŅíÆßäºâ¯±ü§æ‹_3éÑj–&±Ê7^èÃíÆÿå'üÝ…‹Î7:“Aç£hl$Ô¤’ÖöÍ?ü›ý¯åÅ4ùºy丑¦™‹Èä³3’Ov'Vb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUتyä¯6ÜùOS‹Uµß¤‰ÙÐý¸Ïükü¯Š¾ÉÑu{}fÎ-FɹÁ:Sìˆý¬,Q˜«±Wb®Å]Š»v*ìUØ«±Wb®Å]б¿Ìøà^¨?âK›Ïþú>ÿÐê»Wü^~ï÷Áó¾wo–»v*ìUØ«±Wb¯\üþâïýtýMœ¿msÅíýœúgï‹Ô3œ{b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]мþrWÍüÚ-ÀÛ-'žž?î”?òsþEàHxV)v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬÷òWÉßâM~32òµ³¤òÔlH?ºý›ÿ£â¥õ¦.Å]Š»v*ìUØ«±Wb®Å^Wù¯ù-™CêšHXu0*âÍþ¿òËü²~×íÿ2©·Í–sYLö·HÑM*è„ØŒ QÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±VCå¯>êÞ[¶¹³Ó&1Çv 7ŠŸ÷ä_É'‡–*ÇÉ$ÔîNäœU¬UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUíŸóŽž{ú­Ãùfí¿u12[“ÙúÉüôÿ—þ¾(/¡p¡Ø«±Wb®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅPº¶§—i5ýÑã Ò9öQË|Sæ-rm{P¸Õ.¼¸½<ì§ûøp2K±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ú»ò7ÉçËÚ M:Òêö“IâܧûÿâXP^‡ŠŠ»v*ìUØ«±Wb®Å]Š»yïæ·å5·œ`7v¡aÕc_‚NÀÿuMÿ¿ÚOõqKåGN¸Ón$³½¢¸‰¸º7PF¡ñWb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±U{Ù¬gŽîÙ¸M ‡Fðe5«í'y’/2éVú¬; _åaðÈŸì_ çv*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å^/ÿ9#çªYCåûv¤—GÔ–Ÿïµ? ÿ³“þ!!ó¶)v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬»ò¯Ê'Í:ôn+mõg=¸)û?óѾ UöEÀabìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯8üÞü©‹Íöß]²5XWàn‚Eî©?æ[þÏú¸¥òÍż–Ò4©Icb¬¬(AU†©â®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯sÿœhóQYn|½3|,>±÷I—þ Ø ½û Š»v*ìUØ«±Wb®Å]Š»v*Æÿ1ÿãyþ ÿ‰.l;?ûèûÿCªí_ñyû¿ßÎùݾZìUØ«±Wb®Å]нsò7û‹¿õÓõ6rýµÎ?·ös韾/PÎq슻v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»ÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb«.'KxÚiHXÑK3€V8«âÿ=ù¡üѬÜê­^5#´kðÄ¿ð?•’CŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÓ¿óžOý£Vu¥Æ CŠõî‡û?ŠOöI…꘡ث±Wb®Å]Š»v*ìUØ«±Wb®Å]мsó×ò¬j°·˜t¤ÿL‰k:/û±íø¶1ÿ˜8â—b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±T÷Ⱦ`>^Öí50h±J9û£|ÿÂ6*ûQX0 ¦ ô8X»v*ìUØ«±Wb®Å]Š»v*ìUþcÿÇóýAÿ\Øv÷Ñ÷þ‡UÚ¿âó÷¾ó»|µØ«±Wb®Å]Š»zçäo÷ë§êlåûkœ~/oìçÓ?|^¡œãØ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯,ÿœ„óè}ip5.uSn¢5ÞVÿeðÇþˇÌ8ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅSÿ!ùUüÓ¬ÛéJ§#r”ŽÑ¯Å!ÿøqWÙð@F°Ä¢ª`6 ø«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ùó×òÛü=yúgOJi÷Mñ(G!ýŸøÇ'ÚOò¹.AåX«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÇ}ù[­kËv7ljþÿÖOÝŸøŽ,«v*ìUØ«±Wb®Å]Š»v*ìUþcÿÇóýAÿ\Øv÷Ñ÷þ‡UÚ¿âó÷¾ó»|µØ«±Wb®Å]Š»zçäo÷ë§êlåûkœ~/oìçÓ?|^¡œãØ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±W©éо>ü×óyóF½=Ò5m¢>Œ>ý¯öoÉð2aø«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»}ÿ8ßå©iòëó­%¼<"¯QÏüõ“þ ˜ ½“ Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¨ {D¶×lfÓoW”©V ¿å)ø—|iæÏ-\ùkRŸJ»-³ve;Ç ÿYp2J1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅZä™ûâõ çÁØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±VùÙçðæ*ÂÜnï+Tê*?{'ûÿáÙ1H|˜6ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅS_+y~_1jvúLná“à½dö ɱWÚšvŸm•²ñ†TAàqX¢1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±W’ÎByjÚ`×-V·V#ã§Vˆý¯ùßÿ'ÔÅ!óN»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅY•¼…¬ù¥øéVí$u¡•¾ÇÎFÛþ““нwËŸóŒ±(k·lç¼vãˆÿ‘¯ñÂ.(·¢i?”>WÒÀô¬"‘‡íJ „ÿÈÞKÿ … ’ÛF²µAo`tâŠ?PÅUd°·”RH‘‡ºƒŠ¥‡´@ualä÷ô”ø5±V¯ÿÎ:y~ü°2ÙIÛƒs_ø 9ÄñM¼Ο’Úï–®8 »5ÜË'ˆÿ‹"ûiþ·ÄŸå`M° kŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å^×ÿ8Ã{ÃP¿´®ÒB’SýF+ÿ3qA} …Å]Š»v*ìUØ«±Wb®Å]б¿Ìøà^¨?âK›Ïþú>ÿÐê»Wü^~ï÷Áó¾wo–»v*ìUØ«±Wb¯\üþâïýtýMœ¿msÅíýœúgï‹Ô3œ{b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÊ_ž~oÿkï-[[žýóÿÁüì02;Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ß?çüŸÁ'ó%Âîõ‚ ŽÃûçë7ÁþűA{®;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»[4I24RÈà«ЃÔUñ§æ'”ÛÊºÕÆ™OÝÎãnŸð?`ÿ”¸1¼UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅQšN‘w«Ü¥–ŸOq!øQOÌÿ*ÿ”Ø«ßüƒÿ8ñibóÌ„\Üu/÷kþ¹ÿv·ü“ÿ[[Øííã·A ±Æ¢Šª{(Â…ø«±Wb®Å]Š»v*ñ¯ÍŸÈèu$“Wòôb;ÁV’Ùeñ1Ø›þOõ°&ß:2•%XÀЃ±b–±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*õ/ùÇÌ~ed$¶‘OÐQÿã\T¾ŸÂÅØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÐóxò®…=úš\0ôáñcl§ý‡Ûÿcо:$±«“ÔàdÖ*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¨½JŸW¼‡NµšáÖ5ù“×ä¿k}­åý 2ÔR+t=éö›æÍñ6)†*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUثƿç$¼«õÍ:v¬–ÂB?ßn{ÿ©'ø< œñK±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅY/‘|¨ùÊïêÖŒIOVf øÙÿ•?ã\UõG’|ƒ¦y>×êÚzVFÔ™·w?å7òÿ*/Ã…‹$Å]Š»v*ìUØ«±Wb®Å]оzÿœ…ü»[)™ì‘JÁnTvsö&ÿžŸfOòø·í`Hxž)v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯Gÿœ~ÿ”®øÅ/üG/ª°±v*ìUØ«±Wb®Å]Š»v*ìUþcÿÇóýAÿ\Øv÷Ñ÷þ‡UÚ¿âó÷¾ó»|µØ«±Wb®Å]Š»zçäo÷ë§êlåûkœ~/oìçÓ?|^¡œãØ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«æoùÈ7þ•Õ×G«o`>*t2°øÿäZ|ësÀò|RìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å^Ùÿ8Ûäï¬ÜÍæ+…ø ¬0×»‘û×ê'ÁþÏüœP_BáC±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅPþ³aq¦ÜwqF}ª6ošŸ‰qWÄ—ÖrXÜIi8¤°»FÃÝOÀÉCv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*Ëÿ-¿.nüí{èÇX¬â¡žjtÈŸÍ+Âý¦Å_Xyw˶^]²MÓcAØw'öÛö¿i°±L±Wb®Å]Š»v*ìUØ«±Wb®ÅP:îµc6›v+ Âo§ö¾kö—|Q¬éSi³é×"’ÛÈÑ·ÍM+þËí`dƒÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUèÿóßò•Ãÿ¥ÿˆâ¥õV.Å]Š»v*ìUØ«±Wb®Å]б¿Ìøà^¨?âK›Ïþú>ÿÐê»Wü^~ï÷Áó¾wo–»v*ìUØ«±Wb¯\üþâïýtýMœ¿msÅíýœúgï‹Ô3œ{b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU$ó¯™bòÖ‘sªËþéCÄ3Ÿ†4ÿdø«âë«©næ{™Û”²±wcݘòl ”±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»U´´–òd¶·^RÊÁìÇŠŒUö’ü³–t›}*~å"?iÏÅ#ÿ²|,S¼UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_)~|è?¢¼Ï4ª)â,ãæ~ ?á“ ó¼UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU‘ùÈ÷žqÔWO´øcÒ‘²'ó¬ß°¿Íо»òß—,ü»c›§§bKÚw?´íûG Ïv*ìUØ«±Wb®Å]Š»v*ìUØ«±WÌ?ó‘z°ó ß ¢^Äÿ®Ÿ»oø^–b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ôùÇïùJáÿŒRÿÄqRú« b®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUóßüä—œ>±u—`o‚&šÜÝ)ÿQ>/öx%Š]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«Öÿç|¡úOU}ju¬"‰^†Vó->/õ™qA}-…Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUâ_ó“š7©geª¨Þ)>Î9§Ücoø, žñK±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU£h÷:ÍäZuŠ.'n*£õŸ_´Íо¾ü¾ò5¯“tÔ°·£LßÒÓw~çýUû(¿Ë…‹&Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«Æÿç&´±.“i~Åü>‰ÿÕ< œ±K±Wb®Å]Š»v*ìUØ«±Wb®Å]нþqûþR¸ã¿ñT¾ªÂÅØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*×uˆ4[õ+£Hmѽè>Èÿ)¾Ê⯊u­^}bö}JèÖk‡iÚ¿²=”|+’ v*ìUØ«±Wb®Å]Š»v*ìUØ«±UÈ#@Y˜€êIè*û'òßÊKå]ßN õ¸ó˜Žò7Äÿð?cýŽ,›v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬ó·Lúÿ•/E*ЪÌ?Ø0vÿ„åŠ_#àK±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUôßäO坸~ÏôÖ ”Ô.Ôq¬qÂû<ŸiÿØ®«b‡b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU€~{Y‹Ÿ)Ý·xŒr¡ÕOü+6)“p%Ø«±Wb®Å]Š»v*ìUØ«±Wb®Å^ÿ8ýÿ)\?ñŠ_øŽ*_UabìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ðÿùÉO7úPAåÈ┉¦§òƒû¤ÿfÿû Ÿ±K±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»z_ä/“¿Në¢úe­®ž§Àȹ_ø”Ÿì1Rú› b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU.ó%¾Ó.­XTK ‹OšœUðò‚£‹užMâ®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU韑¿—ŸâmKôâ×O²`H=O´‘ÿª¿mÿدíb¥õ..Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±V-ù§­åIzÒÙÛþsÿqWÆø;v*ìUØ«±Wb®Å]Š»v*ìUØ«Ñÿç¿å+‡þ1KÿÅKê¬,]Š»v*ìUØ«±Wb®Å]Š»c˜ÿñÀ¼ÿPÄ—6Ÿýô}ÿ¡Õv¯ø¼ýßïƒç|îß-v*ìUØ«±Wb®Å^¹ùýÅßúéú›9~Úç‹Ûû9ôÏߨg8öÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š¿ÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»Q½¼ŠÊ .®,Q)vcØSо-ó‡™%ó.«q«M_ß¹*ì øcOö)Ç$›v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯¯?(<ŸþÐ!†U¥Ôÿ¾›Ç“ “þy§†kŠŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±W¡èqWÃzݱµ¿¹·;æ‘~æ8 ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»EiZ]Æ«u…šóžwƒÜÿûX«ìß&yZßÊú\U·H—âoæs¼’õ› ëv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Ф>‹Õòö¥iÊÒq_ö о,;v*ìUØ«±Wb®Å]Š»v*ìUØ«Ñÿç¿å+‡þ1KÿÅKê¬,]Š»v*ìUØ«±Wb®Å]Š»c˜ÿñÀ¼ÿPÄ—6Ÿýô}ÿ¡Õv¯ø¼ýßïƒç|îß-v*ìUØ«±Wb®Å^¹ùýÅßúéú›9~Úç‹Ûû9ôÏߨg8öÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š¿ÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»y'üäW›ÿFé)¢ÀÔžøütê"_·ÿ#àÿWž‡Í8¥Ø«±Wb®Å]Š»v*ìUØ«±Wb®Å]г¯ÉŸ'ÿ‰µø–eåkiIå¯CCû´ÿg'ü"¾*_[ábìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ø¿óCÌz”c`.¥§üL{v*ìUØ«±Wb®Å]Š»v*ìUØ«±W»ÿÎ7ù"¦O3Ý/JÅo_ù-/üË_öx ½ë Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅRO<Ç Pÿ˜Y¿â о(02ov*ìUØ«±Wb®Å]Š»v*ìUØ«Ñÿç¿å+‡þ1KÿÅKê¬,]Š»v*ìUØ«±Wb®Å]Š»c˜ÿñÀ¼ÿPÄ—6Ÿýô}ÿ¡Õv¯ø¼ýßïƒç|îß-v*ìUØ«±Wb®Å^¹ùýÅßúéú›9~Úç‹Ûû9ôÏߨg8öÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š¿ÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š´Ìc@IÅ_þeù´ù§\¸ÔÖ}8ãì§ýŸ÷Ÿì°2bø«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»}Wùäïðþ‚—3¯«êLõꟹOø‹ýž£b‡b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÇ›Qz~iÔEkY‰ûÀ81,UØ«±Wb®Å]Š»v*ìUØ«±Wb­1 '}Ååí& #O·ÓíŒ0ƪ£èêÊcñ6)†*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*’yãþ8Z‡üÂÍÿlUñ@é“x«±Wb®Å]Š»v*ìUØ«±Wb®Å^ÿ8ýÿ)\?ñŠ_øŽ*_UabìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]мãóÛΠ4µ…©u}XRBÓ÷Ïÿð³Å!ò®»v*ìUØ«±Wb®Å]Š»v*ìUØ«±VWùaåæ­vÞÁÅmÔú³xpMÊÿÏCû¿öX«ìUP *аX·Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]о?üàÿ”«PÿŒ£þ"¸0ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­?CòÅ_w[tŸêՅЦ*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*’yãþ8Z‡üÂÍÿlUñ@é“x«±Wb®Å]Š»v*ìUØ«±Wb®Å^ÿ8ýÿ)\?ñŠ_øŽ*_UabìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]оJüèóø“̘›•­¥`Š ï_ýœŸðЏŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÓó>Oý£^u¥Åù µê"_îÿäg÷ŸðP^­ŠŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]о?üàÿ”«PÿŒ£þ"¸0ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­?CòÅ_w[tŸêՅЦ*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*’yãþ8Z‡üÂÍÿlUñ@é“x«±Wb®Å]Š»v*ìUØ«±Wb®Å^ÿ8ýÿ)\?ñŠ_øŽ*_UabìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅXgæç›ÿÂú÷1µ.fýÌ><Ûö¿çšr|Rùç¾»v*ìUØ«±Wb®Å]Š»v*ìUØ«±T÷ÈÞW“ͽ¾•Ù‘«!ð~)þ}¡oo´k ,q¨U P ,U1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿ8?å*Ô?ã(ÿˆ®L;v*ìUØ«±Wb®Å]Š»v*ìUØ«OÐü±WÝÖßÝ'ú£õab©Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]ФžxÿŽ¡ÿ0³Ä|P:`dÞ*ìUØ«±Wb®Å]Š»v*ìUØ«±W£ÿÎ?ÊWüb—þ#Š—ÕXX»v*ìUØ«±Wb®Å]Š»v*Æÿ1ÿãyþ ÿ‰.l;?ûèûÿCªí_ñyû¿ßÎùݾZìUØ«±Wb®Å]нsò7û‹¿õÓõ6rýµÎ?·ös韾/PÎq슻v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»ÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_/Î@y¿ôηú6­¶ž mÐÈw”ÿ±øcÿcy~*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_EÎ7y?ê–2ù‚u¤·GÓŠ½£Sñ7üô“þ ¸ ½Ÿ Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»|ùÁÿ)V¡ÿGüEp2aØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅZ~‡åоî¶þé?Õ« LUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU$óÇüpµù…›þ Ø«âÓ&ñWb®Å]Š»v*ìUØ«±Wb®Å]нþqûþR¸ã¿ñT¾ªÂÅØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¬{ÏþiO+è×:£Sš/Áý©áà·oòqWÆSLó;K)-#’ÌÇ©$ÕŽK1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»Lü³ Íæ JßJ·ûw¿Ê?mÿØ'&Å_jézl:e¬V6«ÆQG²Šab‰Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»|ùÁÿ)V¡ÿGüEp2aØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅZ~‡åоî¶þé?Õ« LUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU$óÇüpµù…›þ Ø«âÓ&ñWb®Å]Š»v*ìUØ«±Wb®Å]нþqûþR¸ã¿ñT¾ªÂÅØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯œ¿ç$<Þou´÷VƒÔ–äað/ûÿâx7Š]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÞçüŸA?™.­`‚¿òYÇü*Áâ‚÷Œ(v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ãÿÎùJµøÊ?â+“Å]Š»v*ìUØ«±Wb®Å]Š»v*Óô?,U÷u·÷Iþ¨ýXXªb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb©'ž?ã…¨Ì,ßñÅ_˜7Š»v*ìUØ«±Wb®Å]Š»v*ìUèÿóßò•Ãÿ¥ÿˆâ¥õV.Å]Š»v*ìUØ«±Wb®Å]б¿Ìøà^¨?âK›Ïþú>ÿÐê»Wü^~ï÷Áó¾wo–»v*ìUØ«±Wb¯\üþâïýtýMœ¿msÅíýœúgï‹Ô3œ{b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±T³ÌÚô>_Ón5KŸîíеöäâ‚ú# Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUñÿçü¥Z‡üeñÀɇb®Å]Š»v*ìUØ«±Wb®Å]Š»iú–*ûºÛû¤ÿT~¬,U1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±T“ÏñÂÔ?æoøƒb¯ŠL ›Å]Š»v*ìUØ«±Wb®Å]Š»v*ôùÇïùJáÿŒRÿÄqRú« b®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUتRÔ!Óm¥½¹n0Â#“Ø(äqWÅ^f׿ó¥qªÜWÖ¡ì½?Ø'ÀÉ,Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUVÖÖ[¹RÚ/,¬u,ÇŠ¿}¡ä,Gå"ÛJ¬H9Ÿ?ÿ…ŠyŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ãÿÎùJµøÊ?â+“Å]Š»v*ìUØ«±Wb®Å]Š»v*Óô?,U÷u·÷Iþ¨ýXXªb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb©'ž?ã…¨Ì,ßñÅ_˜7Š»v*ìUØ«±Wb®Å]Š»v*ìUèÿóßò•Ãÿ¥ÿˆâ¥õV.Å]Š»v*ìUØ«±Wb®Å]б¿Ìøà^¨?âK›Ïþú>ÿÐê»Wü^~ï÷Áó¾wo–»v*ìUØ«±Wb¯\üþâïýtýMœ¿msÅíýœúgï‹Ô3œ{b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«Æÿç#üáõ>-¤·‡œ´ížŸóÒOø†‡ÎX¥Ø«±Wb®Å]Š»v*ìUØ«±Wb®Å]нcþqßÉÿ¥uvÖ'ZÛØ†½ ­öäZü_ëqÅôÎ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÇÿœò•jñ”ÄW&Š»v*ìUØ«±Wb®Å]Š»v*ìU§è~X«îëoî“ýQú°±TÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅRO<Ç Pÿ˜Y¿â о(02ov*ìUØ«±Wb®Å]Š»v*ìUØ«Ñÿç¿å+‡þ1KÿÅKê¬,]Š»v*ìUØ«±Wb®Å]Š»c˜ÿñÀ¼ÿPÄ—6Ÿýô}ÿ¡Õv¯ø¼ýßïƒç|îß-v*ìUØ«±Wb®Å^¹ùýÅßúéú›9~Úç‹Ûû9ôÏߨg8öÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š¿ÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUl²¤(ÒÈB¢‚ÌO@Sо2üÀóKù£Z¹Õ >›·íü1ýÿm¿Êl ˜î*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­ª—!TÄ€êIè1WØÿ–~Q_*èvúyœRcã#nÿð?cýŽ,§v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿ8?å*Ô?ã(ÿˆ®L;v*ìUØ«±Wb®Å]Š»v*ìUØ«OÐü±WÝÖßÝ'ú£õab©Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]ФžxÿŽ¡ÿ0³Ä|P:`dÞ*ìUØ«±Wb®Å]Š»v*ìUØ«±W£ÿÎ?ÊWüb—þ#Š—ÕXX»v*ìUØ«±Wb®Å]Š»v*Æÿ1ÿãyþ ÿ‰.l;?ûèûÿCªí_ñyû¿ßÎùݾZìUØ«±Wb®Å]нsò7û‹¿õÓõ6rýµÎ?·ös韾/PÎq슻v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»ÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUåÿóoý ¡þŽ©s¨§Qþù¿æ_ûÿÐê»Wü^~ï÷Áó¾wo–»v*ìUØ«±Wb¯\üþâïýtýMœ¿msÅíýœúgï‹Ô3œ{b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*Á9üßþÐ&h›Õ×î"ñ‡ÆÿóÎ>_ì¸âù m.Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUœ~Ny?üM¯Å«ÊÖÖ“ÍàBŸÝÇÿ=þž*_\ábìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»|ùÁÿ)V¡ÿGüEp2aØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅZ~‡åоî¶þé?Õ« LUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU$óÇüpµù…›þ Ø«âÓ&ñWb®Å]Š»v*ìUØ«±Wb®Å]нþqûþR¸ã¿ñT¾ªÂÅØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ùWóßÍÿ§µæ´…«kaX– ÿ»›þ ÷ì028Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«êÈo'~Жòe¥Õý&jÂS÷)ÿñÿ³Â‚ôœPìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»|ùÁÿ)V¡ÿGüEp2aØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅZ~‡åоî¶þé?Õ« LUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU$óÇüpµù…›þ Ø«âÓ&ñWb®Å]Š»v*ìUØ«±Wb®Å]нþqûþR¸ã¿ñT¾ªÂÅØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»c™>m_*è—ˆ#Ö§GŒð§üÛÿcо6wg%œ’ÄÔ“Ô“ß&±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»e–žRo5k–úyÀ©9ðwoø?±þË}ªQ@ÂżUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*øÿóƒþR­Cþ2øŠàdñWb®Å]Š»v*ìUØ«±Wb®Å]Š´ýË}ÝmýÒª?V*˜«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUتIçøájó 7üA±WŦMâ®Å]Š»v*ìUØ«±Wb®Å]Š»z?üã÷ü¥pÿÆ)â8©}U…‹±Wb®Å]Š»v*ìUØ«±Wb¬oóþ8Ÿêø’æÃ³ÿ¾¿ô:®ÕÿŸ»ýð|ïÛå®Å]Š»v*ìUØ«×?#¸»ÿ]?Sg/Û\ãñ{g>™ûâõ çÁØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»|Õÿ9æÿÒz¬z, X,E^ ¬?æZ|?ë3àHy)v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯¦?çüŸú/Hmfu¥ÅùªÔn"_±ÿ#÷ŸðP^³ŠŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_þpÊU¨ÆQÿ\ ˜v*ìUØ«±Wb®Å]Š»v*ìUØ«±VŸ¡ùb¯»­¿ºOõGêÂÅSv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»I<ñÿ-Cþafÿˆ6*ø tÀɼUØ«±Wb®Å]Š»v*ìUØ«±Wb¯Gÿœ~ÿ”®øÅ/üG/ª°±v*ìUØ«±Wb®Å]Š»v*ìUþcÿÇóýAÿ\Øv÷Ñ÷þ‡UÚ¿âó÷¾ó»|µØ«±Wb®Å]Š»zçäo÷ë§êlåûkœ~/oìçÓ?|^¡œãØ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Фþpó^[Ò®5Yú@„¨þf;FŸìž˜«âËÛÉo§’îå‹M3³»ìÇ“`d£Š»v*ìUØ«±Wb®Å]Š»v*ìUتyä¯,Iæ}^ßI¤¯ñŸ­ÿŠ¾ÐµµŽÒ$·BÅ…U€Q…Š®*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*øÿóƒþR­Cþ2øŠàdñWb®Å]Š»v*ìUØ«±Wb®Å]Š´ýË}ÝmýÒª?V*˜«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUتIçøájó 7üA±WŦMâ®Å]Š»v*ìUØ«±Wb®Å]Š»z?üã÷ü¥pÿÆ)â8©}U…‹±Wb®Å]Š»v*ìUØ«±Wb¬oóþ8Ÿêø’æÃ³ÿ¾¿ô:®ÕÿŸ»ýð|ïÛå®Å]Š»v*ìUØ«×?#¸»ÿ]?Sg/Û\ãñ{g>™ûâõ çÁØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]оÿœ”ó«4\¾Àžz1þåú«Wÿd¸Š]Š»v*ìUØ«±Wb®Å]Š»v*ìUتyå?9jTîô¢‰4‰À³ j-yQy}šþÖ*Êåù³ýÿüŠ\Vÿ+ÿÍŸïø¿äRâ´ïù_þlÿÅÿ"—§Êÿógûþ/ù¸­;þWÿ›?ßñÈ¥Åißò¿üÙþÿ‹þE.+Nÿ•ÿæÏ÷ü_ò)qZwü¯ÿ6¿âÿ‘KŠÓ¿åù³ýÿüŠ\Vÿ+ÿÍŸïø¿äRâ´ïù_þlÿÅÿ"—§Êÿógûþ/ù¸­;þWÿ›?ßñÈ¥Åißò¿üÙþÿ‹þE.+Nÿ•ÿæÏ÷ü_ò)qZwü¯ÿ6¿âÿ‘KŠÓ¿åù³ýÿüŠ\Vÿ+ÿÍŸïø¿äRâ´ïù_þlÿÅÿ"—§Êÿógûþ/ù¸­;þWÿ›?ßñÈ¥Åißò¿üÙþÿ‹þE.+Nÿ•ÿæÏ÷ü_ò)qZwü¯ÿ6¿âÿ‘KŠÓ¿åù³ýÿüŠ\Vÿ+ÿÍŸïø¿äRâ´ïù_þlÿÅÿ"—§Êÿógûþ/ù¸­;þWÿ›?ßñÈ¥Åiõ™;Ok Ònï1ù ÂÅŠ»v*ìUñÿçü¥Z‡üeñÀɇb®Å]Š»v*ìUØ«±Wb®Å]Š»iú–*ûºÛû¤ÿT~¬,U1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±T“ÏñÂÔ?æoøƒb¯ŠL ›Å]Š»v*ìUØ«±Wb®Å]Š»v*ôùÇïùJáÿŒRÿÄqRú« b®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅPzέ‘e6£txÃ3±öõŸÙÅ_ëÚÌÚÝüúѬ·>Õû+òEøp2@b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»}Ë¢ÿ¼6ÿñŠ?øˆÂÅŠ»v*ìUñÿçü¥Z‡üeñÀɇb®Å]Š»v*ìUØ«±Wb®Å]Š»iú–*ûºÛû¤ÿT~¬,U1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±T“ÏñÂÔ?æoøƒb¯ŠL ›Å]Š»v*ìUØ«±Wb®Å]Š»v*ôùÇïùJáÿŒRÿÄqRú« b®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å^'ÿ9'æÿ«ÚÃåÛvøî«5;"ŸÝ¯û9?äÞ‡ÏX¥Ø«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_rè¿ï ¿übþ"0±Fb®Å]Š»|ùÁÿ)V¡ÿGüEp2aØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅZ~‡åоî¶þé?Õ« LUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU$óÇüpµù…›þ Ø«âÓ&ñWb®Å]Š»v*ìUØ«±Wb®Å]нþqûþR¸ã¿ñT¾ªÂÅØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±WbªwW1ÚÄ÷°XãRÌǰ¬qWÅÞuó4žgÕîui+IŸàöP|1/üü6I*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯¹t_÷†ßþ1GÿX£1Wb®Å]о?üàÿ”«PÿŒ£þ"¸0ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­?CòÅ_w[tŸêՅЦ*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*’yãþ8Z‡üÂÍÿlUñ@é“x«±Wb®Å]Š»v*ìUØ«±Wb®Å^ÿ8ýÿ)\?ñŠ_øŽ*_UabìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯(ÿœ‡óè­tˆ—æN¢%þóþ ñþ‡Ì¸ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_rè¿ï ¿übþ"0±Fb®Å]Š»|ùÁÿ)V¡ÿGüEp2aØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅZ~‡åоî¶þé?Õ« LUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìU$óÇüpµù…›þ Ø«âÓ&ñWb®Å]Š»v*ìUØ«±Wb®Å]нþqûþR¸ã¿ñT¾ªÂÅØ«±Wb®Å]Š»v*ìUØ«±V7ùÿ ÏõüIsaÙÿßGßúWjÿ‹ÏÝþø>wÎíò×b®Å]Š»v*ìU럑¿Ü]ÿ®Ÿ©³—í®qø½¿³ŸLýñz†s`ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±W3;о:üÑóqóN»q|¦¶è}(|8'íõÛ”Ÿì°2bx«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»}Ë¢ÿ¼6ÿñŠ?øˆÂÅŠ»v*ìUñÿçü¥Z‡üeñÀɇb®Å]Š»v*ìUØ«±Wb®Å]Š»iú–*ûºÛû¤ÿT~¬,U1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±T“ÏñÂÔ?æoøƒb¯ŠL ›Å]Š»v*ìUØ«±Wb®Å]Š»v*ôùÇïùJáÿŒRÿÄqRú« b®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wž~xùÃü= ¼0·«ÚÃ:€Gï_ýŠÃ6)”@¦»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯¹t_÷†ßþ1GÿX£1Wb®Å]о?üàÿ”«PÿŒ£þ"¸0ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­?CòÅ_w[tŸêՅЦ*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*’yãþ8Z‡üÂÍÿlUñ@é“x«±Wb®Å]Š»v*ìUØ«±Wb®Å^ÿ8ýÿ)\?ñŠ_øŽ*_UabìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±WÉßÞoÿy‚HâjÚÙVéÐ|ÿìŸáÿU02?Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wܺ/ûÃoÿ£ÿˆŒ,Q˜«±Wb®Å_þpÊU¨ÆQÿ\ ˜v*ìUØ«±Wb®Å]Š»v*ìUØ«±VŸ¡ùb¯»­¿ºOõGêÂÅSv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»I<ñÿ-Cþafÿˆ6*ø tÀɼUØ«±Wb®Å]Š»v*ìUØ«±Wb¯Gÿœ~ÿ”®øÅ/üG/ª°±v*ìUØ«±Wb®Å]Š»v*ìUþcÿÇóýAÿ\Øv÷Ñ÷þ‡UÚ¿âó÷¾ó»|µØ«±Wb®Å]Š»zçäo÷ë§êlåûkœ~/oìçÓ?|^¡œãØ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«üÖóxò¶ƒ=â\È=(|y¾Ü¿Ø/'ÿcо=©;ÎNÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wܺ/ûÃoÿ£ÿˆŒ,Q˜«±Wb®Å_þpÊU¨ÆQÿ\ ˜v*ìUØ«±Wb®Å]Š»v*ìUØ«±VŸ¡ùb¯»­¿ºOõGêÂÅSv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»I<ñÿ-Cþafÿˆ6*ø tÀɼUØ«±Wb®Å]Š»v*ìUØ«±Wb¯Gÿœ~ÿ”®øÅ/üG/ª°±v*ìUØ«±Wb®Å]Š»v*ìUþcÿÇóýAÿ\Øv÷Ñ÷þ‡UÚ¿âó÷¾ó»|µØ«±Wb®Å]Š»zçäo÷ë§êlåûkœ~/oìçÓ?|^¡œãØ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«æ/ùÈO7þ—ÖF•VßOM:[ûÃþÁxÇÿy^*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»}Ë¢ÿ¼6ÿñŠ?øˆÂÅŠ»v*ìUñÿçü¥Z‡üeñÀɇb®Å]Š»v*ìUØ«±Wb®Å]Š»iú–*ûºÛû¤ÿT~¬,U1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±T“ÏñÂÔ?æoøƒb¯ŠL ›Å]Š»v*ìUØ«±Wb®Å]Š»v*ôùÇïùJáÿŒRÿÄqRú« b®Å]Š»v*ìUØ«±Wb®ÅXßæ?üp/?Ôñ%͇gÿ}èu]«þ/?wûàùß;·Ë]Š»v*ìUØ«±W®~Fÿqwþº~¦Î_¶¹ÇâöþÎ}3÷ÅêÎ=ƒ±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìU!ó×™ãòÎsªÉNQ%#ÌíðÆ¿ðx«âùç’âFžf/,ŒY˜÷$ÕŽK1Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«î]ýá·ÿŒQÿÄF(ÌUØ«±Wb¯ÿ8?å*Ô?ã(ÿˆ®L;v*ìUØ«±Wb®Å]Š»v*ìUØ«OÐü±WÝÖßÝ'ú£õab©Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]ФžxÿŽ¡ÿ0³Ä|P:`dÞ*ìUØ«±Wb®Å]Š»v*ìUØ«±W£ÿÎ?ÊWüb—þ#Š—ÕXX»v*ìUØ«±Wb®Å]Š»v*Æÿ1ÿãyþ ÿ‰.l;?ûèûÿCªí_ñyû¿ßÎùݾZìUØ«±Wb®Å]нsò7û‹¿õÓõ6rýµÎ?·ös韾/PÎq슻v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»ÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUó·üäœ>·{—­Û÷vÃ՚݇îÔÿ©Åÿ=0$<_»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]оåÑÞøÅüDabŒÅ]Š»v*øÿóƒþR­Cþ2øŠàdñWb®Å]Š»v*ìUØ«±Wb®Å]Š´ýË}ÝmýÒª?V*˜«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUتIçøájó 7üA±WŦMâ®Å]Š»v*ìUØ«±Wb®Å]Š»z?üã÷ü¥pÿÆ)â8©}U…‹±Wb®Å]Š»v*ìUØ«±Wb¬oóþ8Ÿêø’æÃ³ÿ¾¿ô:®ÕÿŸ»ýð|ïÛå®Å]Š»v*ìUØ«×?#¸»ÿ]?Sg/Û\ãñ{g>™ûâõ çÁØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*—ù‹[‡BÓçÔîM"·BçÞŸeÙ7ʾ)ÕõIµkɵ £Êk‡iû±¯Ü¿ep2Bb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯¹t_÷†ßþ1GÿX£1Wb®Å]о?üàÿ”«PÿŒ£þ"¸0ìUØ«±Wb®Å]Š»v*ìUØ«±Wb­?CòÅ_w[tŸêՅЦ*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*’yãþ8Z‡üÂÍÿlUñ@é“x«±Wb®Å]Š»v*ìUØ«±Wb®Å^ÿ8ýÿ)\?ñŠ_øŽ*_UabìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ð¿ùÉ_7qŽ.@Û½'žžû”ÿdÜŸýŠàHx)v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*û—Eÿxmÿãñ…Š3v*ìUØ«ãÿÎùJµøÊ?â+“Å]Š»v*ìUØ«±Wb®Å]Š»v*Óô?,U÷u·÷Iþ¨ýXXªb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb©'ž?ã…¨Ì,ßñÅ_˜7Š»v*ìUØ«±Wb®Å]Š»v*ìUèÿóßò•Ãÿ¥ÿˆâ¥õV.Å]Š»v*ìUØ«±Wb®Å]б¿Ìøà^¨?âK›Ïþú>ÿÐê»Wü^~ï÷Áó¾wo–»v*ìUØ«±Wb¯\üþâïýtýMœ¿msÅíýœúgï‹Ô3œ{b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*Å5¯Ê¿.ëwo¨j6‚k™iÉ˽MèÝ—@ÿÊ‘ò—ü°'üÿÍx¦Ýÿ*GÊ_òÀŸðoÿ5â¶ïùR>Rÿ–ÿƒù¯·Ê‘ò—ü°'üÿÍx­»þT”¿å?àßþkÅmßò¤|¥ÿ, ÿÿó^+nÿ•#å/ù`Oø7ÿšñ[wü©)ËÁ¿ü׊ۿåHùKþXþ ÿæ¼VÝÿ*GÊ_òÀŸðoÿ5â¶ïùR>Rÿ–ÿƒù¯·Ê‘ò—ü°'üÿÍx­»þT”¿å?àßþkÅmßò¤|¥ÿ, ÿÿó^+nÿ•#å/ù`Oø7ÿšñ[wü©)ËÁ¿ü׊ۿåHùKþXþ ÿæ¼VÝÿ*GÊ_òÀŸðoÿ5â¶ïùR>Rÿ–ÿƒù¯·Ê‘ò—ü°'üÿÍx­»þT”¿å?àßþkÅmßò¤|¥ÿ, ÿÿó^+nÿ•#å/ù`Oø7ÿšñ[wü©)ËÁ¿ü׊ۿåHùKþXþ ÿæ¼VÝÿ*GÊ_òÀŸðoÿ5â¶ïùR>Rÿ–ÿƒù¯·Ê‘ò—ü°'üÿÍx­»þT”¿å?àßþkÅmßò¤|¥ÿ, ÿÿó^+nÿ•#å/ù`Oø7ÿšñ[wü©)ËÁ¿ü׊ۿåHùKþXþ ÿæ¼VÝÿ*GÊ_òÀŸðoÿ5â¶ïùR>Rÿ–ÿƒù¯·Ê‘ò—ü°'üÿÍx­»þT”¿å?àßþkÅmßò¤|¥ÿ, ÿÿó^+nÿ•#å/ù`Oø7ÿšñ[wü©)ËÁ¿ü׊ۿåHùKþXþ ÿæ¼VÝÿ*GÊ_òÀŸðoÿ5â¶ïùR>Rÿ–ÿƒù¯·Ê‘ò—ü°'üÿÍx­»þT”¿å?àßþkÅmßò¤|¥ÿ, ÿÿó^+nÿ•#å/ù`Oø7ÿšñ[wü©)ËÁ¿ü׊ۿåHùKþXþ ÿæ¼VÝÿ*GÊ?òÀŸðoÿ5â¶Í¡…aEŠ1D@6¡~*ìUØ«±V%«þTyoWº’þúÍd¸”ÕØ³ŠžŸ²ØªþT”¿å?àßþkÅ6ïùR>Rÿ–ÿƒù¯·Ê‘ò—ü°'üÿÍx­»þT”¿å?àßþkÅmßò¤|¥ÿ, ÿÿó^+nÿ•#å/ù`Oø7ÿšñ[wü©)ËÁ¿ü׊ۿåHùKþXþ ÿæ¼VÝÿ*GÊ_òÀŸðoÿ5â¶ïùR>Rÿ–ÿƒù¯·Ê‘ò—ü°'üÿÍx­»þT”¿å?àßþkÅmÇòGÊ'o¨'üÿÍx­³…P (è6Å â®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wbª7¶q_A%­Âó†U(ëâ¬8°ÅXgü©(ÿËÁ¿ü׊mßò¤|¥ÿ, ÿÿó^+nÿ•#å/ù`Oø7ÿšñ[wü©)ËÁ¿ü׊ۿåHùKþXþ ÿæ¼VÝÿ*GÊ_òÀŸðoÿ5â¶ïùR>Rÿ–ÿƒù¯·Ê‘ò—ü°'üÿÍx­»þT”¿å?àßþkÅmßò¤|¥ÿ, ÿÿó^+nÿ•#å/ù`Oø7ÿšñ[wü©)ËÁ¿ü׊ۿåHùKþXþ ÿæ¼VÓòËËúÒßé–‹ ‚¡ƒ1ØŠ7ÚcŠF*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÑžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÒžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÓžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÔžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÕžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÖžþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿמþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õÏÈßî.ÿ×OÔÙËö×8ü^ßÙϦ~ø½C9ǰv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿОþsÿÇU?ãÎò?»?Ö|ûÚïGõ^›·™v*ìUØ«±Wb®=0¥õ-‡ûÏú‹ú³Í§õ{ìX¾‘ýP¯lv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«üÇÿŽçúƒþ$¹°ìÿï£ïý«µÅçîÿ|;çvùk±Wb®Å]Š»v*õïÈä?V»~ÅÐ~9nÚ>¨û‹Ü{8=2?Ò‹Ó³z÷b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿÑèñÔ ~Ügð9Öö1¸ý'‚öŠ5’'¾/9ÍóÊ»v*ìUØ«±W*úoËwçLµ˜~Ü1ŸøQžw¨IéIõÍ$øñDÿB?îSÇrÝŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*Ä¿5.D:À?¶Q>ö´ìÈÞaån“¶§Ã§—ô¸cþÉàÛ¾fìUØ«±Wb®Å]н“òB:i÷/ã0r뜧lŸXÑý/yìèýÜôÿÞ½#9÷«v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÒêßžVßœãÆE?ð¤gKزú‡õ^7Ú8m Z?î^M3Å;v*ìUØ«±Wb¯ü¬Ô>¹ À+V„´Gè5_øF\â;Ocý/Sé‹—N?¡püšËsVîÝŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*óÎÝ@GcofÅ,…ˆöAÿ5:çAØØîf_Íû§”ö‹-cŒ?./ôŸô“Æó«x7b®Å]Š»v*ìU¶þžˆ¼’¹û¨¿Ã8ÞÖ•å®è‡Ñ{5‚ÿ)3ŒÓ=±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿÓíÿœ–^¾Š&xeF?#Xÿ[.n»"u–¿ÿó¿‹ÿ2cþ!á¹Ø¾vìUØ«±Wb®Å]нKòGW -Ƙçí*|ÇÂÿñ®s³ŠÀŸùcìîz2ÆzúãþùëY˽³±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å^ù»«‹í`Û¡ªZ ý‘øßõñÿc§ebàÅêž§Î{w?‰›„rÄ8Îú¤Â3nóÎÅ]Š»v*ìUØ«èß Ù=Ò2(LaÏû/þ6Î ]><²>î_TìÌ|"?£ÅþŸÔŸæ ³v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÔô—›ôïÒ:MÕ¨f‰ŠüÇÄ¿ðË™ZLžHËúN¿‹†QþüyóVz äÎÅ]Š»v*ìUتkå}i´]F õû1·Äu? øÇÔáñ cßþéÍÑj?/Où§Õý_â}+©2,±ÈÀ0#¡¡Ï="Ö#!!avNÅ]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅP:æ­“e5ôßf%-ó?²¿ì›á˰â9d"?‰ÇÔç`f€>g»º{¹žâSY$bÌ}É®zb"Âù&I™ÈÈó—©G$ÖìUØ«±Wb®ÅUìmZîâ;hþÔ®¨>lxäg.IþÌp3ˆþ"#þ™õ ¼ o›*(Qò™ç—²û ""©‘dìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÕõIŠ˜«æŸ6iGJÕ.lé@’?Ꟊ?áNz—/‰ŒKÉò]n,¡üÙ±þ§2\'b®Å]Š»v*ìUí?”iÖgIœþþØU+Þ?úö~øä»[MÁ/}3ú¿¯ÿ{þÂÖøð×éÿ…ÿÇ^‡š¨v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ò/ÎO4‰¥]ݾèóS»~±ûYÔöFš‡ˆ‹èx~ßÖñ†?ÃêÉýoá‹Ì3¢yb®Å]Š»v*ìU˜þTé&ÿ[ŽB*–àÈ~cáOøfÍWjeàÄGóý.÷±0x™Áé×ÿ÷¼â_Jv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«ÿÖõN*òÎÍÓ¸ƒTAðÈ=7ÿYwO½âÔö>kø}Qxhtõ!”¢_ÖÓøþ‹Ìs¢yb®Å]Š»v*ìU£jóéqßZšI¯±´§ü–VlC,LeüNFŸ<°LN?T_Fù{^·×lÒúÔü.7^êÃí#|³Ô`8dc'Õ4º˜ê '¿ìeüÔÇ1Ü·b®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«óÏ›£ò݉˜PÜÉU‰_)<Êž.Å]Š»v*ìUØ«Ú&4_ªéòj(×-EÿU6ü_–r]¯›Šbø?ÝIïýŸÓðc9ùCþÂñç¡æ…ꊻv*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿ×õN*’yÓAý9¥Ífd§(ÿÖ]×þ ìæf?ƒK§ñU×v†›óŒ?‹ê‡õâù½”©¡ØŒïß*k;v*ìUØ«±Wb¬“És›Ë7\Å^ÖJ cñÿ-Ë\ÀÖi¢5ücé“¶ìîЖ’wϾ¸ÿ¾þ³è ;QƒQ.­\I‚ óëœ>Lgá–Ò¦b˱‰âŒ‘[k±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»K<Åæ]Õ¯/€lª:³vEÌ>žYåÃúEÄÕj¡¦‡ÿé)5óטüÅs¯ÝµíÑÜìª:*öEÎëO§ŽðÇþ’|¿Wª–¦frÿ7ú1þjW™±Wb®Å]Š»v*ŠÓ4ù5˜¬á’V >œ¯&AŽ&Gø[°â9d 9Ìð¾™Ó,#Ó­¢³„R8 úyæL‡$Œñ>·‡ÅÊ…•·;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÐõN*ìUáš¾Zý©›¨…-îêâ»ïøÿÙgiÙš ú±úÍþÎ;kIàåâF_WùÿÇÿ³nóîÅ]Š»v*ìUØ«±VIäß;ÝyfjÇûËg?¼ˆùIü¯˜½u}§ü2vÚÑž’[z±Ÿªâ{¶æ+=vÜ\ظeý¥èʕ׶qyôòÂxdFÓjá¨üT¬™f;–ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±TƒÍžt²òÜ<®œì>”üGçü«þVgitsÔ¾Ÿâ›¬Öö„4¢å¼ÿ†Åÿ‹ÁüÇæ[¿0\›«Æ¯dAöT*Œí4úxà é'Î5zÉêeÅ?ócü0J³%Âv*ìUØ«±Wb®Å]нCòcË^¤¯­L>ëUîÇí¿ûøÙ6s½¯¨ 1޾©ÿ½{gô–Ncü>œÖþ)=s9g·v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÿÑõN*ìU"ó§–“Ì:t–› ‡Çx8éô7ÙlÍÑê< ‰ñUÖö†j±˜ÿÕë¾sšÚ)AWBCÔ×;ÐA,”LM‹0±v*ìUØ«±Wb®Å]Š£t­bëIœ]XÈb”wý˜teʲâŽQÃ!ÄŒç†\P<2zו¿8moƒWÞnž ©CÿGœÆ§²eñúãüßãÿ=®·¡=²þî_Îÿ'ÿzÇ: a`è¡”Ô‘¢”LM¨Œ„…P_‘dìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»Cßê6ú|FâîEŠ1Õ˜ÐeÇ)šˆâ-YrÇâ™ôžeæ¯ÎAF·Ð×~ž³ù6Ÿñ³ÿÀçE¥ì޹ÒGýôžG[ÛÿÇþVKýìâ¿Ò¼ºîîkÉZ{—i%sVf5':8ÀDPØ<|òž))“[±Wb®Å]Š»v*ìU£i3j÷qØÛ É+SØÚcì£|«6QŠ&Gø\> g˜„~©>“Ñô¨t›H¬mÅ#‰B>ìsϳe9dd‰õ>†ú`ŒÊ›ÝŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUÿÒõN*ìUØ«É7¼›é·éËEøZ‚p;Ù—ý—Ù|ê;+Wº—ùŸñ/Ûº >4ä¯ü_üSËs£xçb®Å]Š»v*ìUØ«±Wb©–æ=CFnv¼^* Tÿ¬‡áÊ3iá—êN^ŸW“¸÷?éYæ‘ùÛq ©[¬ƒù£ û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEߦì?å¢ù¿×}ÒÿJ¿™Çü見¿MØËD?ò1®> û¥þ•3ùÐÿM~›°ÿ–ˆäbÿ\|÷Ký*þgó¡þš.ý7aÿ-ÿÈÅþ¸ø3î—úUüÎ?çCý4]únÃþZ!ÿ‘‹ýqðgÝ/ô«ùœ·úh»ô݇ü´Cÿ#úãàϺ_éWó8ÿôÑwé»ùh‡þF/õÇÁŸt¿Ò¯æqÿ:é¢ïÓvòÑüŒ_ëƒ>é¥_Ìãþt?ÓEÇ\°¦æÆEþ¸øî—úUüÎ?çCý4PW>uÑm¿½¼„ÀŸ¹rèèòË”eòqåÚcÎpù¤:‡ç‹l€Épßä-üœ37då—:‡Çþ%×eíìåÅ“ú£þ/…ˆk:…È)a[©ý£ñ·ð_ø\ÚâìxGê&ì]h2Khýœ˜.¥«]êrzײ¼ÏâÆ´ÿTt_ö9¹ÇŠ8ÅDp¼îlóÌndÏúÈL±¡Ø«±Wb®Å]Š»v*ìUØ«Û?*<œt»oÒwKK›ðƒÕSþj~¿ð9Èv¦¯Ä—~ˆ²ŸüuôÄÐx1ñ%ýæO§úÿãÏ@ÍÓ;v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±WÿÓõN*ìUتżw1´3(xÜe==rQ‘‰°ÆpwŒŸ>ùïÉÒynð¢Õ­%©‰ý¿‘¿ËOù»;¬j#ý8ýo˜ö–€é'_äåýÜ¿ÞÿZ,g6¡Ø«±Wb®Å]Š»v*ìUØ«±Wb®Â® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠºƒu*ê UÔ«¨1WPb® Å]AŠ»vv*ìUØ«±Wb®Å]Š»v*ìUØ«=ü°ò9Ö'âÿ¡ÂvöØ~Ïú‹û_ð9¥í-o„8#ýä¿ØEé;³|yx“þêô²ñ?Î{~qÏ¡»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb¯ÿÔõN*ìUØ«±T¿_ЭµËG²»FèGU?²ëî2üå†\QquZhê a/úGúOž|Í廟/ݵÐ÷G™s»Ój#žÒ7ó/ül¿µ™ZmL°KŠ?çGùγG T8eþl¿˜ùÿ̾Y»òõɵ¼_tqöXx©ÿs¸Óêcž§¥“-˜úݸި>0?Êþhå>Ÿµ1äÚ_»—ûôÏ«ìL¸w‡ïaý¯ý'üK t(J° Ž æàyò+šÜPìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®ÅUm­¥¹q ÒHÛPI?@ÈÊB"ÎÌá3QRþ‹Ð<³ù;yxDÚ³}^.¼ ŸøÕ3G©íhÃhzåüïàzm`Î{åýÜ›þSþ:õmËÖ:$^…„B5îz³®ßi³šÍ¨žcr6öš}.=8¨÷Rþ´“ÇrŠ»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ÿÿÑõN*ìUØ«±Wb®Å]Š»v*ìUتM®yCLÖÁ7°+?ó…¿à×2ðêòaúOù¿ÂàjtµXßùßÇþ™çÚ×䔋WÒ§ ?’]üíÿ ¹½ÃÛ#”ÇùÐÿ‰yG³¤oŠ_æäÿŠ`ú¯“5m,Ÿ­[8QûJ9/ür¸Å«Ç“é!ç³v~l?Teþê?ìRb)™n½¬UØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*¹œ…PI=ÄšHÉi>@ÖuJmÙþÔŸÿ†ÌºìXùŸô¾§gƒ²ófåýiúÖ‰ù'QõYËŸä‹aÿßü*æ—7l“´ùÓÿ‰z=?³ o–\_ÑÇÿô ËÖ:zv¬C¹â?ë?Ú9£ËžyMÈñ=6 .< Ý¦L2‡)Ø«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š¿ÿÒõN*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®>ø«óøgÒßUåOÚãÏèãûÌØàñÿÉñÿ½ÿ‰u¯Êÿ•ð¿ØñÿŰ[Û/ ÎO§q$'ü)òR93s ë0%ýn÷²‹ÎdÇÙòå)Cú¾'ûøM#»Ð¼®jmµFÏ Ÿ­cÌÈçÏÖìáÿëç¦Òÿ_ôØçÿ•Ë¢iÀþëR€ò£œÌ–Ì‘š}a/ôØ¿âÜ9iñôÉô¹¿ê’Ÿè[?ú¸ÛÿÀOÿdù/_ÌŸÏýTaùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕ~…³ÿ«¿üÿöO/æOç‹þª/åáþ©ý.ú¢ïжõq·ÿ€ŸþÉññ¥üÉüñÕEü¼?Õ1ÿ¥ÏÿT]úÏþ®6ÿðÿÙ>>4¿™?ž/ú¨¿—‡ú¦?ô¹ÿê‹¿BÙÿÕÆßþû'ÇÆ—ó'óÅÿUòðÿTÇþ—?ýQwè[?ú¸ÛÿÀOÿdøøÒþdþx¿ê¢þ^ê˜ÿÒçÿª.ý gÿWø ÿìŸ_ÌŸÏýT_ËÃýSú\ÿõEß¡lÿêãoÿ?ý“ããKù“ùâÿª‹ùxªcÿKŸþ¨»ô-Ÿý\mÿà'ÿ²||i2<_õQ/õLésÿÕh4=0ÿ}©Â?ÕŠcúá\Í“¤%þ›ü[dtغä‡úLßõM6´Ðü¦´7:£·ˆH\~¸Û1§›QÒý<âœØi´ŸÅ’_æÂñ ömäX3LÝŒ¢P?áR4Ì,’Öœ?ÕàÿŠ“²ÅÏ^?ëøŸñ0‹?ÐAñÿqV§üUÆ¿M>,ÑçñÊqÿoK¦ð?Éxæp§y†ì]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å]Š»v*ìUØ«±Wb®Å_ÿÙlibminizinc-2.0.11/INSTALL.txt0000644000175000017500000000355512646030173014421 0ustar kaolkaolMiniZinc 2 ========================= Installation Instructions ------------------------- These instructions are for compiling and installing MiniZinc 2 from the source distribution. MiniZinc 2 is based on the libminizinc C++ library. In order to compile and install libminizinc you will need the following software: Compilation instructions: ------------------------- Prerequisite software: - cmake - A recent C++ compiler, libminizinc has been tested with recent versions of clang, g++, and Microsoft Visual C++. - The bison and flex parser/lexer generators. These usually come packaged for Linux distributions, and they are part of the Xcode developer tools for Mac OS. On Windows, you can e.g. install them via cygwin. Download the source code from the git repository or uncompress a source archive. Then change into the toplevel directory (the one containing this file). To perform the build: > mkdir build > cd build/ > cmake .. > cmake --build . To install MiniZinc: > cmake --build . --target install This will install MiniZinc in the standard location for you system. In order to change the installation prefix, invoke cmake as follows before invoking cmake --build: > cmake -DCMAKE_INSTALL_PREFIX:PATH= .. Running ------- The build produces the mzn2fzn and solns2out tools. These are drop-in replacements for the MiniZinc 1.6 versions. Add the bin directory in the installation path to your PATH environment variable if necessary, or (if you did not install) add the "build" directory to your PATH. We currently do not provide the minizinc driver program that was part of MiniZinc 1.6 in the source distribution. It is however included in the binary distributions. If you have both MiniZinc 1.6 and 2 installed (and MiniZinc 2.0 occurs on the PATH before 1.6), you can use the old minizinc driver with the new versions of mzn2fzn and solns2out. libminizinc-2.0.11/mzn2doc.cpp0000644000175000017500000002444012646030173014626 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include #include #include #include using namespace MiniZinc; using namespace std; std::string stoptime(clock_t& start) { std::ostringstream oss; clock_t now = clock(); oss << std::setprecision(0) << std::fixed << ((static_cast(now-start) / CLOCKS_PER_SEC) * 1000.0) << " ms"; start = now; return oss.str(); } bool beginswith(string s, string t) { return s.compare(0, t.length(), t)==0; } int main(int argc, char** argv) { string filename; vector includePaths; bool flag_ignoreStdlib = false; bool flag_verbose = false; bool flag_include_stdlib = false; int toplevel_groups = 0; string output_base; string html_header_file; string html_footer_file; string std_lib_dir; if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) { std_lib_dir = string(MZNSTDLIBDIR); } string globals_dir; if (argc < 2) goto error; for (int i=1; i 2) { includePaths.push_back(include.substr(2)+string("/")); } else { i++; if (i==argc) { goto error; } includePaths.push_back(argv[i]+string("/")); } } else if (string(argv[i])==string("--ignore-stdlib")) { flag_ignoreStdlib = true; } else if (string(argv[i])==string("-v") || string(argv[i])==string("--verbose")) { flag_verbose = true; } else if (string(argv[i])=="--stdlib-dir") { i++; if (i==argc) goto error; std_lib_dir = argv[i]; } else if (beginswith(string(argv[i]),"-G")) { string filename(argv[i]); if (filename.length() > 2) { globals_dir = filename.substr(2); } else { i++; if (i==argc) { goto error; } globals_dir = argv[i]; } } else if (string(argv[i])=="--toplevel-groups") { i++; if (i==argc) goto error; toplevel_groups = atoi(argv[i]); } else if (string(argv[i])=="--html-header") { i++; if (i==argc) goto error; html_header_file = string(argv[i]); } else if (string(argv[i])=="--html-footer") { i++; if (i==argc) goto error; html_footer_file = string(argv[i]); } else if (string(argv[i])=="--include-stdlib") { flag_include_stdlib = true; } else if (string(argv[i])=="--globals-dir" || string(argv[i])=="--mzn-globals-dir") { i++; if (i==argc) goto error; globals_dir = argv[i]; } else if (string(argv[i])=="--output-base") { i++; if (i==argc) goto error; output_base = argv[i]; } else { std::string input_file(argv[i]); if (input_file.length()<=4) { std::cerr << "Error: cannot handle file " << input_file << "." << std::endl; goto error; } std::string extension = input_file.substr(input_file.length()-4,string::npos); if (extension == ".mzn") { if (filename=="") { filename = input_file; } else { std::cerr << "Error: Multiple .mzn files given." << std::endl; goto error; } } else if (extension == ".dzn") { std::cerr << "Error: cannot generate documentation for data files." << std::endl; } else { std::cerr << "Error: cannot handle file extension " << extension << "." << std::endl; goto error; } } } if (filename=="") { std::cerr << "Error: no model file given." << std::endl; goto error; } if (std_lib_dir=="") { std::string mypath = FileUtils::progpath(); if (!mypath.empty()) { if (FileUtils::file_exists(mypath+"/share/minizinc/std/builtins.mzn")) { std_lib_dir = mypath+"/share/minizinc"; } else if (FileUtils::file_exists(mypath+"/../share/minizinc/std/builtins.mzn")) { std_lib_dir = mypath+"/../share/minizinc"; } else if (FileUtils::file_exists(mypath+"/../../share/minizinc/std/builtins.mzn")) { std_lib_dir = mypath+"/../../share/minizinc"; } } } if (std_lib_dir=="") { std::cerr << "Error: unknown minizinc standard library directory.\n" << "Specify --stdlib-dir on the command line or set the\n" << "MZN_STDLIB_DIR environment variable.\n"; std::exit(EXIT_FAILURE); } if (globals_dir!="") { includePaths.push_back(std_lib_dir+"/"+globals_dir+"/"); } includePaths.push_back(std_lib_dir+"/std/"); for (unsigned int i=0; i(hs)), std::istreambuf_iterator()); html_header = str; html_header_title = str.find("@TITLE"); } string html_footer; if (!html_footer_file.empty()) { std::ifstream hs(html_footer_file); if (!hs.good()) { std::cerr << "Cannot open HTML footer file " << html_footer_file << "\n"; std::exit(EXIT_FAILURE); } std::string str((std::istreambuf_iterator(hs)), std::istreambuf_iterator()); html_footer = str; } std::stringstream errstream; if (flag_verbose) std::cerr << "Parsing '" << filename << "'" << std::endl; if (Model* m = parse(filename, vector(), includePaths, flag_ignoreStdlib, true, flag_verbose, errstream)) { try { Env env(m); if (flag_verbose) std::cerr << "Done parsing." << std::endl; if (flag_verbose) std::cerr << "Typechecking ..."; vector typeErrors; MiniZinc::typecheck(env, m, typeErrors, true); if (typeErrors.size() > 0) { for (unsigned int i=0; i docs = HtmlPrinter::printHtml(env.envi(),m,basename,toplevel_groups,flag_include_stdlib); for (unsigned int i=0; i(errstream),istreambuf_iterator(),ostreambuf_iterator(std::cerr)); exit(EXIT_FAILURE); } } if (flag_verbose) std::cerr << "Done." << std::endl; return 0; error: std::cerr << "Usage: "<< argv[0] << " [] [-I ] .mzn [.dzn ...]" << std::endl << std::endl << "Options:" << std::endl << " --help, -h\n Print this help message" << std::endl << " --version\n Print version information" << std::endl << " --ignore-stdlib\n Ignore the standard libraries stdlib.mzn and builtins.mzn" << std::endl << " -v, --verbose\n Print progress statements" << std::endl << " --stdlib-dir \n Path to MiniZinc standard library directory" << std::endl << " -G --globals-dir --mzn-globals-dir\n Search for included files in /." << std::endl << " --single-page\n Print entire documentation on a single HTML page." << std::endl << std::endl << "Output options:" << std::endl << std::endl << " --output-base \n Base name for output files" << std::endl ; exit(EXIT_FAILURE); } libminizinc-2.0.11/mzn2fzn.cpp0000644000175000017500000004705512646030173014665 0ustar kaolkaol/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace MiniZinc; using namespace std; std::string stoptime(Timer& start) { std::ostringstream oss; oss << std::setprecision(0) << std::fixed << start.ms() << " ms"; start.reset(); return oss.str(); } bool beginswith(string s, string t) { return s.compare(0, t.length(), t)==0; } int main(int argc, char** argv) { string filename; vector datafiles; vector includePaths; bool flag_ignoreStdlib = false; bool flag_typecheck = true; bool flag_verbose = false; bool flag_newfzn = false; bool flag_optimize = true; bool flag_werror = false; bool flag_statistics = false; bool flag_stdinInput = false; Timer starttime; Timer lasttime; string std_lib_dir; if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) { std_lib_dir = string(MZNSTDLIBDIR); } string globals_dir; bool flag_no_output_ozn = false; string flag_output_base; string flag_output_fzn; string flag_output_ozn; bool flag_output_fzn_stdout = false; bool flag_output_ozn_stdout = false; bool flag_instance_check_only = false; FlatteningOptions fopts; if (argc < 2) goto error; for (int i=1; i 2) { includePaths.push_back(include.substr(2)+string("/")); } else { i++; if (i==argc) { goto error; } includePaths.push_back(argv[i]+string("/")); } } else if (string(argv[i])==string("--ignore-stdlib")) { flag_ignoreStdlib = true; } else if (string(argv[i])==string("--no-typecheck")) { flag_typecheck = false; } else if (string(argv[i])==string("--instance-check-only")) { flag_instance_check_only = true; } else if (string(argv[i])==string("-v") || string(argv[i])==string("--verbose")) { flag_verbose = true; } else if (string(argv[i])==string("--newfzn")) { flag_newfzn = true; } else if (string(argv[i])==string("--no-optimize") || string(argv[i])==string("--no-optimise")) { flag_optimize = false; } else if (string(argv[i])==string("--no-output-ozn") || string(argv[i])==string("-O-")) { flag_no_output_ozn = true; } else if (string(argv[i])=="--output-base") { i++; if (i==argc) goto error; flag_output_base = argv[i]; } else if (beginswith(string(argv[i]),"-o")) { string filename(argv[i]); if (filename.length() > 2) { flag_output_fzn = filename.substr(2); } else { i++; if (i==argc) { goto error; } flag_output_fzn = argv[i]; } } else if (string(argv[i])=="--output-to-file" || string(argv[i])=="--output-fzn-to-file") { i++; if (i==argc) goto error; flag_output_fzn = argv[i]; } else if (string(argv[i])=="--output-ozn-to-file") { i++; if (i==argc) goto error; flag_output_ozn = argv[i]; } else if (string(argv[i])=="--output-to-stdout" || string(argv[i])=="--output-fzn-to-stdout") { flag_output_fzn_stdout = true; } else if (string(argv[i])=="--output-ozn-to-stdout") { flag_output_ozn_stdout = true; } else if (string(argv[i])=="-" || string(argv[i])=="--input-from-stdin") { if (datafiles.size() > 0 || filename != "") goto error; flag_stdinInput = true; } else if (beginswith(string(argv[i]),"-d")) { if (flag_stdinInput) goto error; string filename(argv[i]); string datafile; if (filename.length() > 2) { datafile = filename.substr(2); } else { i++; if (i==argc) { goto error; } datafile = argv[i]; } if (datafile.length()<=4 || datafile.substr(datafile.length()-4,string::npos) != ".dzn") goto error; datafiles.push_back(datafile); } else if (string(argv[i])=="--data") { if (flag_stdinInput) goto error; i++; if (i==argc) { goto error; } string datafile = argv[i]; if (datafile.length()<=4 || datafile.substr(datafile.length()-4,string::npos) != ".dzn") goto error; datafiles.push_back(datafile); } else if (string(argv[i])=="--stdlib-dir") { i++; if (i==argc) goto error; std_lib_dir = argv[i]; } else if (beginswith(string(argv[i]),"-G")) { string filename(argv[i]); if (filename.length() > 2) { globals_dir = filename.substr(2); } else { i++; if (i==argc) { goto error; } globals_dir = argv[i]; } } else if (beginswith(string(argv[i]),"-D")) { if (flag_stdinInput) goto error; string cmddata(argv[i]); if (cmddata.length() > 2) { datafiles.push_back("cmd:/"+cmddata.substr(2)); } else { i++; if (i==argc) { goto error; } datafiles.push_back("cmd:/"+string(argv[i])); } } else if (string(argv[i])=="--cmdline-data") { if (flag_stdinInput) goto error; i++; if (i==argc) { goto error; } datafiles.push_back("cmd:/"+string(argv[i])); } else if (string(argv[i])=="--globals-dir" || string(argv[i])=="--mzn-globals-dir") { i++; if (i==argc) goto error; globals_dir = argv[i]; } else if (string(argv[i])=="-Werror") { flag_werror = true; } else if (string(argv[i])=="-s" || string(argv[i])=="--statistics") { flag_statistics = true; } else { if (flag_stdinInput) goto error; std::string input_file(argv[i]); if (input_file.length()<=4) { std::cerr << "Error: cannot handle file " << input_file << "." << std::endl; goto error; } std::string extension = input_file.substr(input_file.length()-4,string::npos); if (extension == ".mzn") { if (filename=="") { filename = input_file; } else { std::cerr << "Error: Multiple .mzn files given." << std::endl; goto error; } } else if (extension == ".dzn") { datafiles.push_back(input_file); } else { std::cerr << "Error: cannot handle file extension " << extension << "." << std::endl; goto error; } } } if (filename=="" && !flag_stdinInput) { std::cerr << "Error: no model file given." << std::endl; goto error; } if (std_lib_dir=="") { std::string mypath = FileUtils::progpath(); if (!mypath.empty()) { if (FileUtils::file_exists(mypath+"/share/minizinc/std/builtins.mzn")) { std_lib_dir = mypath+"/share/minizinc"; } else if (FileUtils::file_exists(mypath+"/../share/minizinc/std/builtins.mzn")) { std_lib_dir = mypath+"/../share/minizinc"; } else if (FileUtils::file_exists(mypath+"/../../share/minizinc/std/builtins.mzn")) { std_lib_dir = mypath+"/../../share/minizinc"; } } } if (std_lib_dir=="") { std::cerr << "Error: unknown minizinc standard library directory.\n" << "Specify --stdlib-dir on the command line or set the\n" << "MZN_STDLIB_DIR environment variable.\n"; std::exit(EXIT_FAILURE); } if (globals_dir!="") { includePaths.push_back(std_lib_dir+"/"+globals_dir+"/"); } includePaths.push_back(std_lib_dir+"/std/"); for (unsigned int i=0; i(std::cin), istreambuf_iterator()); m = parseFromString(input, filename, includePaths, flag_ignoreStdlib, false, flag_verbose, errstream); } else { m = parse(filename, datafiles, includePaths, flag_ignoreStdlib, false, flag_verbose, errstream); } if (m) { try { if (flag_typecheck) { Env env(m); if (flag_verbose) std::cerr << "Done parsing (" << stoptime(lasttime) << ")" << std::endl; if (flag_verbose) std::cerr << "Typechecking ..."; vector typeErrors; MiniZinc::typecheck(env, m, typeErrors); if (typeErrors.size() > 0) { for (unsigned int i=0; i 0) { exit(EXIT_FAILURE); } env.clearWarnings(); Model* flat = env.flat(); if (flag_verbose) std::cerr << " done (" << stoptime(lasttime) << ", max stack depth " << env.maxCallStack() << ")" << std::endl; if (flag_optimize) { if (flag_verbose) std::cerr << "Optimizing ..."; optimize(env); for (unsigned int i=0; i 0) { exit(EXIT_FAILURE); } if (flag_verbose) std::cerr << " done (" << stoptime(lasttime) << ")" << std::endl; } if (!flag_newfzn) { if (flag_verbose) std::cerr << "Converting to old FlatZinc ..."; oldflatzinc(env); if (flag_verbose) std::cerr << " done (" << stoptime(lasttime) << ")" << std::endl; } else { env.flat()->compact(); env.output()->compact(); } if (flag_statistics) { FlatModelStatistics stats = statistics(env); std::cerr << "Generated FlatZinc statistics:\n"; std::cerr << "Variables: "; bool had_one = false; if (stats.n_bool_vars) { had_one = true; std::cerr << stats.n_bool_vars << " bool"; } if (stats.n_int_vars) { if (had_one) std::cerr << ", "; had_one = true; std::cerr << stats.n_int_vars << " int"; } if (stats.n_float_vars) { if (had_one) std::cerr << ", "; had_one = true; std::cerr << stats.n_float_vars << " float"; } if (stats.n_set_vars) { if (had_one) std::cerr << ", "; had_one = true; std::cerr << stats.n_set_vars << " int"; } if (!had_one) std::cerr << "none"; std::cerr << "\n"; std::cerr << "Constraints: "; had_one = false; if (stats.n_bool_ct) { had_one = true; std::cerr << stats.n_bool_ct << " bool"; } if (stats.n_int_ct) { if (had_one) std::cerr << ", "; had_one = true; std::cerr << stats.n_int_ct << " int"; } if (stats.n_float_ct) { if (had_one) std::cerr << ", "; had_one = true; std::cerr << stats.n_float_ct << " float"; } if (stats.n_set_ct) { if (had_one) std::cerr << ", "; had_one = true; std::cerr << stats.n_set_ct << " int"; } if (!had_one) std::cerr << "none"; std::cerr << "\n"; } if (flag_verbose) std::cerr << "Printing FlatZinc ..."; if (flag_output_fzn_stdout) { Printer p(std::cout,0); p.print(flat); } else { std::ofstream os; os.open(flag_output_fzn.c_str(), ios::out); if (!os.good()) { if (flag_verbose) std::cerr << std::endl; std::cerr << "I/O error: cannot open fzn output file. " << strerror(errno) << "." << std::endl; exit(EXIT_FAILURE); } Printer p(os,0); p.print(flat); os.close(); } if (flag_verbose) std::cerr << " done (" << stoptime(lasttime) << ")" << std::endl; if (!flag_no_output_ozn) { if (flag_verbose) std::cerr << "Printing .ozn ..."; if (flag_output_ozn_stdout) { Printer p(std::cout,0); p.print(env.output()); } else { std::ofstream os; os.open(flag_output_ozn.c_str(), ios::out); if (!os.good()) { if (flag_verbose) std::cerr << std::endl; std::cerr << "I/O error: cannot open ozn output file. " << strerror(errno) << "." << std::endl; exit(EXIT_FAILURE); } Printer p(os,0); p.print(env.output()); os.close(); } if (flag_verbose) std::cerr << " done (" << stoptime(lasttime) << ")" << std::endl; } } } else { // !flag_typecheck Printer p(std::cout); p.print(m); } } catch (LocationException& e) { if (flag_verbose) std::cerr << std::endl; std::cerr << e.loc() << ":" << std::endl; std::cerr << e.what() << ": " << e.msg() << std::endl; exit(EXIT_FAILURE); } catch (Exception& e) { if (flag_verbose) std::cerr << std::endl; std::cerr << e.what() << ": " << e.msg() << std::endl; exit(EXIT_FAILURE); } delete m; } else { if (flag_verbose) std::cerr << std::endl; std::copy(istreambuf_iterator(errstream),istreambuf_iterator(),ostreambuf_iterator(std::cerr)); exit(EXIT_FAILURE); } } if (flag_verbose) { std::cerr << "Done (overall time " << stoptime(starttime) << ", "; size_t mem = GC::maxMem(); if (mem < 1024) std::cerr << "maximum memory " << mem << " bytes"; else if (mem < 1024*1024) std::cerr << "maximum memory " << mem/1024 << " Kbytes"; else std::cerr << "maximum memory " << mem/(1024*1024) << " Mbytes"; std::cerr << ")." << std::endl; } return 0; error: std::cerr << "Usage: "<< argv[0] << " [] [-I ] .mzn [.dzn ...]" << std::endl << std::endl << "Options:" << std::endl << " --help, -h\n Print this help message" << std::endl << " --version\n Print version information" << std::endl << " --ignore-stdlib\n Ignore the standard libraries stdlib.mzn and builtins.mzn" << std::endl << " -v, --verbose\n Print progress statements" << std::endl << " -s, --statistics\n Print statistics" << std::endl << " --instance-check-only\n Check the model instance (including data) for errors, but do not\n convert to FlatZinc." << std::endl << " --no-optimize\n Do not optimize the FlatZinc\n Currently does nothing (only available for compatibility with 1.6)" << std::endl << " -d , --data \n File named contains data used by the model." << std::endl << " -D , --cmdline-data \n Include the given data in the model." << std::endl << " --stdlib-dir \n Path to MiniZinc standard library directory" << std::endl << " -G --globals-dir --mzn-globals-dir\n Search for included files in /." << std::endl << std::endl << "Input/Output options:" << std::endl << " -, --input-from-stdin\n Read model from standard input (no additional .mzn or .dzn files possible)" << std::endl << " --no-output-ozn, -O-\n Do not output ozn file" << std::endl << " --output-base \n Base name for output files" << std::endl << " -o , --output-to-file , --output-fzn-to-file \n Filename for generated FlatZinc output" << std::endl << " --output-ozn-to-file \n Filename for model output specification" << std::endl << " --output-to-stdout, --output-fzn-to-stdout\n Print generated FlatZinc to standard output" << std::endl << " --output-ozn-to-stdout\n Print model output specification to standard output" << std::endl << " -Werror\n Turn warnings into errors" << std::endl ; exit(EXIT_FAILURE); } libminizinc-2.0.11/.gitignore0000644000175000017500000000036012646030173014531 0ustar kaolkaol*.o *~ mzn2fzn solns2out makefile Makefile include/minizinc/parser.tab.hh lib/lexer.yy.cpp lib/parser.tab.cpp core res/ CMakeCache.txt CMakeFiles CMakeScripts cmake_install.cmake install_manifest.txt libminizinc.build libminizinc.xcodeproj libminizinc-2.0.11/share/0000755000175000017500000000000012646030173013644 5ustar kaolkaollibminizinc-2.0.11/share/minizinc/0000755000175000017500000000000012646030173015464 5ustar kaolkaollibminizinc-2.0.11/share/minizinc/g12_lazyfd/0000755000175000017500000000000012646030173017426 5ustar kaolkaollibminizinc-2.0.11/share/minizinc/g12_lazyfd/redefinitions.mzn0000644000175000017500000000334412646030173023022 0ustar kaolkaol% FlatZinc built-in redefinitions for G12/LazyFD. predicate array_bool_element(var int : idx, array[int] of bool : arr, var bool : v) = let { int : N = length(arr), array[1..N] of var bool : tmp = [idx = I | I in 1..N] } in exists(I in 1..N)(tmp[I]) /\ forall(I in 1..N) (tmp[I] -> v = arr[I]); predicate array_var_bool_element(var int : idx, array[int] of var bool : arr, var bool : v) = let { int : N = length(arr), array[1..N] of var bool : tmp = [idx = I | I in 1..N] } in exists(I in 1..N)(tmp[I]) /\ forall(I in 1..N) (tmp[I] -> v = arr[I]); predicate array_bool_xor(array[int] of var bool: bs) = let { int: bs_lower = min(index_set(bs)), int: bs_upper = max(index_set(bs)), int: n = length(bs) } in if n == 1 then bs[bs_lower] else if n == 2 then bs[bs_lower] xor bs[bs_upper] else if n == 3 then bs[bs_lower] = (bs[bs_lower + 1] = bs[bs_upper]) else let { int: cs_lower = bs_lower + 1, int: cs_upper = bs_upper - 1, array [cs_lower..cs_upper] of var bool: cs } in forall(i in cs_lower..cs_upper-1)( cs[i+1] = bs[i+1] xor cs[i] ) /\ (cs[cs_lower] = bs[bs_lower] xor bs[bs_lower + 1]) /\ (bs[bs_upper] xor cs[cs_upper]) endif endif endif; predicate int_abs(var int: a, var int: b) = b >= 0 /\ b >= a /\ b >= -a /\ (b <= a \/ b <= - a); predicate int_mod(var int: a, var int: b, var int: c) = let { int : bnd = max([lb(a), ub(a), -lb(a), -ub(a)]), var -bnd .. bnd : z } in ( b >= 0 -> c >= 0 /\ c < b) /\ ( b <= 0 -> c <= 0 /\ c > b) /\ b * z + c = a; libminizinc-2.0.11/share/minizinc/g12_lazyfd/all_different_int.mzn0000644000175000017500000000175612646030173023635 0ustar kaolkaol%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate all_different_int(array[int] of var int: x) = g12lazy_int_all_different(x); %-----------------------------------------------------------------------------% % The implementation of the all_different constraint in the G12/LazyFD solver. % This should not be called directly, instead the definition above should % be used. predicate g12lazy_int_all_different(array[int] of var int: x); % G12/LazyFD doesn't provide a reified all_different so we use the following % definition if g12lazy_int_all_different is called from a reified context. % predicate g12lazy_int_all_different_reif(array[int] of var int: x, var bool: r) = r <-> forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear/0000755000175000017500000000000012646030173016736 5ustar kaolkaollibminizinc-2.0.11/share/minizinc/linear/redefinitions.mzn0000644000175000017500000004511212646030173022331 0ustar kaolkaol%-----------------------------------------------------------------------------% % FlatZinc built-in redefinitions for linear solvers. % % Sebastian Brand % Gleb Belov Corrected array_var_float_element and float_lin_lt_reif %-----------------------------------------------------------------------------% function var bool: reverse_map(var int: x) = (x==1); function bool: reverse_map(int: x) = (x==1); function var int: bool2int(var bool: x) :: promise_total = let { var 0..1: b2i; constraint (x = reverse_map(b2i)) ::is_reverse_map ; } in b2i; predicate bool_eq(var bool: x, var bool: y) = bool2int(x)==bool2int(y); %-----------------------------------------------------------------------------% % Strict inequality % % Uncomment the following redefinition for FlatZinc MIP solver interfaces that % do not support strict inequality. Note that it does not preserve equivalence % (some solutions of the original problem may become invalid). % predicate float_lt(var float: x, var float: y) = x + 1e-06 <= y; %-----------------------------------------------------------------------------% % % Logic operations % %-----------------------------------------------------------------------------% predicate bool_not(var bool: p, var bool: q) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q) } in x + y = 1; predicate bool_and(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x + y <= z + 1 /\ x + y >= z * 2; % x >= z /\ y >= z; % alternative predicate bool_or(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x + y >= z /\ x + y <= z * 2; % x <= z /\ y <= z; % alternative predicate bool_xor(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x <= y + z /\ y <= x + z /\ z <= x + y /\ x + y + z <= 2; predicate bool_eq_reif(var bool: p, var bool: q, var bool: r) = if is_fixed(q) then % frequent case if fix(q) = true then p = r else bool_not(p,r) endif else let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x + y <= z + 1 /\ x + z <= y + 1 /\ y + z <= x + 1 /\ x + y + z >= 1 endif; predicate bool_ne_reif(var bool: p, var bool: q, var bool: r) = bool_xor(p, q, r); predicate bool_le(var bool: p, var bool: q) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q) } in x <= y; predicate bool_le_reif(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in 1 - x + y >= z /\ 1 - x + y <= z * 2; % 1 - x <= z /\ y <= z; % alternative predicate bool_lt(var bool: p, var bool: q) = not p /\ q; predicate bool_lt_reif(var bool: p, var bool: q, var bool: r) = (not p /\ q) <-> r; %-----------------------------------------------------------------------------% predicate array_bool_or(array[int] of var bool: a, var bool: b) = if is_fixed(b) then % frequent case if fix(b) = true then sum(i in index_set(a))( bool2int(a[i]) ) >= 1 else forall(i in index_set(a))( not a[i] ) endif else let { var 0..1: x = bool2int(b), array[1..length(a)] of var 0..1: c = [ bool2int(a[i]) | i in index_set(a) ] } in sum(c) >= x /\ sum(c) <= x * length(a) endif; predicate array_bool_and(array[int] of var bool: a, var bool: b) = let { var 0..1: x = bool2int(b), array[1..length(a)] of var 0..1: c = [ bool2int(a[i]) | i in index_set(a) ] } in length(a) - sum(c) >= 1 - x /\ length(a) - sum(c) <= (1 - x) * length(a); predicate array_bool_xor(array[int] of var bool: a) = let { var 0..length(a): m } in sum(i in 1..length(a))( bool2int(a[i]) ) = 1 + 2 * m; predicate bool_clause(array[int] of var bool: p, array[int] of var bool: n) = sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1; % predicate array_bool_xor(array[int] of var bool: a) = .. sum(a) is odd .. %-----------------------------------------------------------------------------% % % Linear equations and inequations % %-----------------------------------------------------------------------------% predicate int_le_reif(var int: x, var int: y, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_int_le_if_1(x, y, p) /\ aux_int_gt_if_0(x, y, p); predicate int_lt_reif(var int: x, var int: y, var bool: b) = int_le_reif(x, y - 1, b); predicate int_ne(var int: x, var int: y) = let { var 0..1: p } in aux_int_lt_if_1(x, y, p) /\ aux_int_gt_if_0(x, y, p); predicate int_lin_ne(array[int] of int: c, array[int] of var int: x, int: d) = int_ne(sum(i in index_set(x))( c[i]*x[i] ),d); predicate int_eq_reif(var int: x, var int: y, var bool: b) = aux_int_eq_iff_1(x, y, bool2int(b)); predicate int_ne_reif(var int: x, var int: y, var bool: b) = aux_int_eq_iff_1(x, y, 1 - bool2int(b)); %-----------------------------------------------------------------------------% predicate int_lin_eq_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, bool2int(b)); predicate int_lin_ne_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, 1 - bool2int(b)); predicate int_lin_le_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_int_le_if_1(sum(i in index_set(x))( c[i] * x[i] ), d, p) /\ aux_int_gt_if_0(sum(i in index_set(x))( c[i] * x[i] ), d, p); predicate int_lin_lt_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = int_lin_le_reif(c, x, d - 1, b); %-----------------------------------------------------------------------------% predicate float_le_reif(var float: x, var float: y, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_float_le_if_1(x, y, int2float(p)) /\ aux_float_gt_if_0(x, y, int2float(p)); predicate float_lt_reif(var float: x, var float: y, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_float_lt_if_1(x, y, int2float(p)) /\ aux_float_ge_if_0(x, y, int2float(p)); predicate float_ne(var float: x, var float: y) = let { var 0..1: p } in aux_float_lt_if_1(x, y, int2float(p)) /\ aux_float_gt_if_0(x, y, int2float(p)); predicate float_eq_reif(var float: x, var float: y, var bool: b) = aux_float_eq_iff_1(x, y, int2float(bool2int(b))); predicate float_ne_reif(var float: x, var float: y, var bool: b) = aux_float_eq_iff_1(x, y, 1.0 - int2float(bool2int(b))); %-----------------------------------------------------------------------------% predicate float_lin_eq_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, int2float(bool2int(b))); predicate float_lin_ne_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, 1.0 - int2float(bool2int(b))); predicate float_lin_le_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = let { var 0.0..1.0: p = int2float(bool2int(b)) } in aux_float_le_if_1(sum(i in index_set(x))( c[i] * x[i] ), d, p) /\ aux_float_gt_if_0(sum(i in index_set(x))( c[i] * x[i] ), d, p); predicate float_lin_lt_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = let { var 0.0..1.0: p = int2float(bool2int(b)) } in aux_float_lt_if_1(sum(i in index_set(x))( c[i] * x[i] ), d, p) /\ aux_float_ge_if_0(sum(i in index_set(x))( c[i] * x[i] ), d, p); %-----------------------------------------------------------------------------% % Minimum, maximum, absolute value predicate int_abs(var int: x, var int: z) = let { var 0..1: p } in % z <= x \/ z <= -x aux_int_le_if_1(z, x, p) /\ aux_int_le_if_0(z, -x, p) /\ z >= x /\ z >= -x /\ z >= 0; predicate int_min(var int: x, var int: y, var int: z) = let { var 0..1: p } in % z >= x \/ z >= y aux_int_ge_if_1(z, x, p) /\ aux_int_ge_if_0(z, y, p) /\ z <= x /\ z <= y; predicate int_max(var int: x, var int: y, var int: z) = let { var 0..1: p } in % z <= x \/ z <= y aux_int_le_if_1(z, x, p) /\ aux_int_le_if_0(z, y, p) /\ z >= x /\ z >= y; predicate float_abs(var float: x, var float: z) = let { var 0..1: p } in % z <= x \/ z <= -x aux_float_le_if_1(z, x, int2float(p)) /\ aux_float_le_if_0(z, -x, int2float(p)) /\ z >= x /\ z >= -x /\ z >= 0.0; predicate float_min(var float: x, var float: y, var float: z) = let { var 0..1: p } in % z >= x \/ z >= y aux_float_ge_if_1(z, x, int2float(p)) /\ aux_float_ge_if_0(z, y, int2float(p)) /\ z <= x /\ z <= y; predicate float_max(var float: x, var float: y, var float: z) = let { var 0..1: p } in % z <= x \/ z <= y aux_float_le_if_1(z, x, int2float(p)) /\ aux_float_le_if_0(z, y, int2float(p)) /\ z >= x /\ z >= y; %-----------------------------------------------------------------------------% % Multiplication and division predicate int_div(var int: x, var int: y, var int: q) = let { var 0..max(abs(lb(y)), abs(ub(y))) - 1: r } in aux_int_division_modulo(x,y,q,r); predicate int_mod(var int: x, var int: y, var int: r) = let { int: bx = max(abs(lb(x)), abs(ub(x))); var -bx..bx: q; int: by = max(abs(lb(y)), abs(ub(y))); constraint r in -by..by; } in aux_int_division_modulo(x,y,q,r); predicate aux_int_division_modulo(var int: x, var int: y, var int: q, var int: r) = x = y * q + r /\ let { array[1..2] of var 0..1: p } in % 0 < x -> 0 <= r which is 0 >= x \/ 0 <= r aux_int_le_if_1(x, 0, p[1]) /\ aux_int_ge_if_0(r, 0, p[1]) /\ % x < 0 -> r <= 0 which is x >= 0 \/ r <= 0 aux_int_ge_if_1(x, 0, p[2]) /\ aux_int_le_if_0(r, 0, p[2]) /\ % abs(r) < abs(y) let { var 1.. max(abs(lb(y)), abs(ub(y))): w = abs(y) } in w > r /\ w > -r; predicate int_times(var int: x, var int: y, var int: z) = if card(dom(x)) > card(dom(y)) then int_times(y,x,z) else let { set of int: s = lb(x)..ub(x), set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, array[s] of var min(r)..max(r): ady = array1d(s, [ d*y | d in s ]) } in ady[x] = z endif; %-----------------------------------------------------------------------------% % Array 'element' constraints predicate array_bool_element(var int: x, array[int] of bool: a, var bool: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_var_bool_element(var int: x, array[int] of var bool: a, var bool: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_int_element(var int: x, array[int] of int: a, var int: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_var_int_element(var int: x, array[int] of var int: a, var int: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_float_element(var int: x, array[int] of float: a, var float: z) = let { set of int: ix = index_set(a), array[ix] of var 0..1: x_eq_d } in sum(i in ix)( x_eq_d[i] ) = 1 /\ sum(i in ix)( i * x_eq_d[i] ) = x /\ sum(i in ix)( a[i] * int2float(x_eq_d[i]) ) = z; predicate array_var_float_element(var int: x, array[int] of var float: a, var float: z) = let { set of int: ix = index_set(a), array[ix] of var 0..1: x_eq_d } in sum(i in ix)( x_eq_d[i] ) = 1 /\ sum(i in ix)( i * x_eq_d[i] ) = x /\ forall(i in ix)( % x_eq_d[i] -> a[i] = a2[i] a[i] - z >= (lb(a[i])-ub(z))*int2float(1-x_eq_d[i]) /\ z - a[i] >= (lb(z)-ub(a[i]))*int2float(1-x_eq_d[i]) ); %-----------------------------------------------------------------------------% % Domain constraints % XXX only for a fixed set predicate set_in(var int: x, set of int: s) = if s = min(s)..max(s) then min(s) <= x /\ x <= max(s) else exists(e in s)( x = e ) endif; % XXX only for a fixed set predicate set_in_reif(var int: x, set of int: s, var bool: b) = b <-> exists(i in 1..length([ 0 | e in s where not (e - 1 in s) ]))( let { int: l = [ e | e in s where not (e - 1 in s) ][i], int: r = [ e | e in s where not (e + 1 in s) ][i] } in l <= x /\ x <= r ); % Alternative predicate alt_set_in_reif(var int: x, set of int: s, var bool: b) = b <-> if s = min(s)..max(s) then min(s) <= x /\ x <= max(s) else exists(e in s)( x = e ) endif; %-----------------------------------------------------------------------------% % Auxiliary: equality reified onto a 0/1 variable predicate aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q_458 } in aux_int_lt_if_0(x - p, y, q_458[1]) /\ aux_int_gt_if_0(x + p, y, q_458[2]) /\ sum(q_458) <= 2 - 2*p /\ sum(q_458) <= 1 + p; % Alternative 1 predicate alt_1_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q } in aux_int_lt_if_0(x - p, y, q[1]) /\ aux_int_gt_if_0(x + p, y, q[2]) /\ q[1] <= 1 - p /\ q[2] <= 1 - p /\ sum(q) <= 1 + p; % Alternative 2 predicate alt_2_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q } in aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) /\ aux_int_lt_if_0(x, y, q[1]) /\ aux_int_gt_if_0(x, y, q[2]) /\ sum(q) <= p + 1; predicate aux_float_eq_iff_1(var float: x, var float: y, var float: p) = let { array[1..2] of var 0..1: q } in aux_float_le_if_1(x, y, p) /\ aux_float_ge_if_1(x, y, p) /\ aux_float_lt_if_0(x, y, int2float(q[1])) /\ aux_float_gt_if_0(x, y, int2float(q[2])) /\ int2float(sum(q)) <= 1.0 + p; %-----------------------------------------------------------------------------% % Auxiliary: indicator constraints % p -> x # 0 where p is a 0/1 variable and # is a comparison % Base cases predicate aux_int_le_zero_if_0(var int: x, var int: p) = x <= ub(x) * p; predicate aux_float_le_zero_if_0(var float: x, var float: p) = x <= ub(x) * p; predicate aux_float_lt_zero_if_0(var float: x, var float: p) = let { float: rho = 1e-02 * abs(ub(x)) } % same order of magnitude as ub(x) in x < (ub(x) + rho) * p; % Derived cases predicate aux_int_le_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, p); predicate aux_int_ge_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, p); predicate aux_int_le_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, 1 - p); predicate aux_int_ge_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, 1 - p); predicate aux_int_lt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, p); predicate aux_int_gt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x + 1, p); predicate aux_int_lt_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, 1 - p); predicate aux_float_le_if_0(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(x - y, p); predicate aux_float_ge_if_0(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(y - x, p); predicate aux_float_le_if_1(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(x - y, 1.0 - p); predicate aux_float_ge_if_1(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(y - x, 1.0 - p); predicate aux_float_lt_if_0(var float: x, var float: y, var float: p) = aux_float_lt_zero_if_0(x - y, p); predicate aux_float_gt_if_0(var float: x, var float: y, var float: p) = aux_float_lt_zero_if_0(y - x, p); predicate aux_float_lt_if_1(var float: x, var float: y, var float: p) = aux_float_lt_zero_if_0(x - y, 1.0 - p); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% annotation bool_search(array[int] of var bool: x, ann:a1, ann:a2, ann:a3) = int_search([bool2int(x[i]) | i in index_set(x)],a1,a2,a3); predicate array_int_maximum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_float_maximum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_int_minimum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); predicate array_float_minimum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); mzn_opt_only_range_domains = true; libminizinc-2.0.11/share/minizinc/linear/domain_encodings.mzn0000644000175000017500000000415312646030173022767 0ustar kaolkaol%-----------------------------------------------------------------------------% % Domain encodings %-----------------------------------------------------------------------------% % Linear equality encoding % Single variable: x = d <-> x_eq_d[d] predicate equality_encoding(var int: x, array[int] of var 0..1: x_eq_d) = x in index_set(x_eq_d) /\ sum(d in dom(x))( x_eq_d[d] ) = 1 /\ sum(d in dom(x))( d * x_eq_d[d] ) = x; % Array of variables: x[i] = d <-> x_eq_d[i,d] predicate equality_encoding(array[int] of var int: x, array[int, int] of var 0..1: x_eq_d) = forall(i in index_set(x))( x[i] in index_set_2of2(x_eq_d) /\ sum(d in index_set_2of2(x_eq_d))( x_eq_d[i,d] ) = 1 /\ sum(d in index_set_2of2(x_eq_d))( d * x_eq_d[i,d] ) = x[i] ); function var int: eq_new_var(var int: x, int: i) = if i in dom(x) then let { var 0..1: xi; } in xi else 0 endif; function array[int] of var 0..1: eq_encode(var int: x) ::promise_total = let { array[int] of var 0..1: y = array1d(lb(x)..ub(x),[eq_new_var(x,i) | i in lb(x)..ub(x)]); constraint equality_encoding(x,y); } in y; function array[int] of int: eq_encode(int: x) ::promise_total = array1d(lb(x)..ub(x),[ if i=x then 1 else 0 endif | i in lb(x)..ub(x)]); function array[int,int] of var int: eq_encode(array[int] of var int: x) ::promise_total = let { array[index_set(x),lb_array(x)..ub_array(x)] of var 0..1: y = array2d(index_set(x),lb_array(x)..ub_array(x), [ let { array[int] of var int: xi = eq_encode(x[i]) } in if j in index_set(xi) then xi[j] else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)] ) } in y; function array[int,int] of int: eq_encode(array[int] of int: x) ::promise_total = array2d(index_set(x),lb_array(x)..ub_array(x),[ if j=x[i] then 1 else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)]); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear/inverse.mzn0000644000175000017500000000132412646030173021137 0ustar kaolkaol%-----------------------------------------------------------------------------% % Constrains two arrays of int variables to represent inverse functions. % All the values in each array must be within the index set of the other array. % % Linear version. %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; predicate inverse(array[int] of var int: f, array[int] of var int: g) = let { array[int,int] of var 0..1: map_f = eq_encode(f); array[int,int] of var 0..1: map_g = eq_encode(g); } in forall (i in index_set(f), j in index_set(g)) (map_f[i,j] = map_g[j,i]); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear/all_different_int.mzn0000644000175000017500000000132112646030173023131 0ustar kaolkaol%-----------------------------------------------------------------------------% % 'all_different' constrains an array of objects to be all different. % % Linear version: equality encoding; see e.g. [Refalo, CP 2000] % % For a given d in dom(x), at most one i with x_i = d can exist. %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; predicate all_different_int(array[int] of var int: x) = let { array[int,int] of var 0..1: x_eq_d = eq_encode(x) } in ( forall(d in index_set_2of2(x_eq_d))( sum(i in index_set_1of2(x_eq_d))( x_eq_d[i,d] ) <= 1 ) ); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear/redefinitions-2.0.mzn0000644000175000017500000000035612646030173022627 0ustar kaolkaolpredicate bool_clause_reif(array[int] of var bool: p, array[int] of var bool: n, var bool: c) = c = ( sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1 ); libminizinc-2.0.11/share/minizinc/linear/redefinitions-2.0.2.mzn0000644000175000017500000000147112646030173022766 0ustar kaolkaol% This file contains redefinitions of standard builtins for version 2.0.2 % that can be overridden by solvers. predicate symmetry_breaking_constraint(var bool: b) = b; predicate redundant_constraint(var bool: b) = b; %% Linearized element: just call without shifting predicate array_var_bool_element_nonshifted(var int: idx, array[int] of var bool: x, var bool: c) = array_var_bool_element(idx,x,c); predicate array_var_int_element_nonshifted(var int: idx, array[int] of var int: x, var int: c) = array_var_int_element(idx,x,c); predicate array_var_float_element_nonshifted(var int: idx, array[int] of var float: x, var float: c) = array_var_float_element(idx,x,c); predicate array_var_set_element_nonshifted(var int: idx, array[int] of var set of int: x, var set of int: c) = array_var_set_element(idx,x,c); libminizinc-2.0.11/share/minizinc/linear/table_int.mzn0000644000175000017500000000160612646030173021430 0ustar kaolkaol%-----------------------------------------------------------------------------% % A 'table' constraint table(x, T) represents the constraint x in T where we % consider each row in T to be a tuple and T as a set of tuples. % % Linear version. % % See also the equality encoding of the 'element' constraint. %-----------------------------------------------------------------------------% predicate table_int(array[int] of var int: x, array[int, int] of int: t) = assert(index_set_2of2(t) = index_set(x), "The second dimension of the table must equal the number of " ++ "variables in the first argument", let { set of int: it = index_set_1of2(t), array[it] of var 0..1: lambda } in sum(lambda) = 1 /\ forall(j in index_set(x))( sum(i in it)( t[i,j]*lambda[i] ) = x[j] ) ); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear_new/0000755000175000017500000000000012646030173017607 5ustar kaolkaollibminizinc-2.0.11/share/minizinc/linear_new/subcircuit.mzn0000644000175000017500000000465712646030173022525 0ustar kaolkaolinclude "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a subcircuit where \a x[\p i] = \p j means that \p j is the successor of \p i and \a x[\p i] = \p i means that \p i is not in the circuit. */ %% Linear version predicate subcircuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), array[S] of var 1..n: order, array[S] of var bool: ins = array1d(S,[ x[i] != i | i in S]), var l..u+1: firstin = min([ u+1 + bool2int(ins[i])*(i-u-1) | i in S]), %% ... var S: lastin, var bool: empty = (firstin == u+1), } in alldifferent(x) /\ % NO alldifferent(order) /\ % If the subcircuit is empty then each node points at itself. % (empty <-> forall(i in S)(not ins[i])) /\ % If the subcircuit is non-empty then order numbers the subcircuit. % ((not empty) <-> %% Another way to express minimum. % forall(i in l..u+1)( % i==firstin <-> ins[i] % /\ forall(j in S where j firstin /\ % The lastin node points at firstin. x[lastin] = firstin /\ % And both are in ins[lastin] /\ ins[firstin] /\ % The successor of each node except where it is firstin is % numbered one more than the predecessor. % forall(i in S) ( % (ins[i] /\ x[i] != firstin) -> order[x[i]] = order[i] + 1 % ) /\ %%% MTZ model. Note that INTEGER order vars seem better!: forall (i,j in S where i!=j) ( order[i] - order[j] + n*bool2int( x[i]==j /\ i!=lastin ) % + (n-3)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term % --- strangely enough it is much worse on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn! <= n-1 ) /\ % Each node that is not in is numbered after the lastin node. forall(i in S) ( true % (not ins[i]) <-> (n == order[i]) ) ); predicate subcircuit_reif(array[int] of var int: x, var bool: b) = abort("Reified subcircuit/1 is not supported."); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear_new/redefinitions.mzn0000644000175000017500000013471212646030173023207 0ustar kaolkaol/* % FlatZinc built-in redefinitions for linear solvers. % % AUTHORS % Sebastian Brand % Gleb Belov (2015) % cf. Belov, Tack, Wallace. Updated Linearization Library for MiniZinc 2.0. ModRef Workshop, CP 2015. */ %-----------------------------------------------------------------------------% % TODO. Have some simple basic constraints (better for presolve) + facets as user cuts %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; %-----------------------------------------------------------------------------% %%% Set =true to PRINT TRACING messages for some constraints: opt bool: mzn__my_trace_on = false; %= true; test my_trace(string: msg) ::promise_total = if occurs(mzn__my_trace_on) /\ deopt(mzn__my_trace_on) then trace(msg) else true endif; %-----------------------------------------------------------------------------% % Parameters % -- for unary encoding: maximal domain length to invoke it int: nMZN__UnaryLenMax__ALL=2000; %% can be used by the indiv. cases int: nMZN__UnarySizeMax_intTimes=20; int: nMZN__UnarySizeMax_cumul=2000; int: nMZN__UnarySizeMax_1step_regular=20000; %% network-flow decomp in the regular constraint bool: fMZN__UseIndicators=false; %% Pass on indicator constraints bool: fMZN__IgnoreRedundantCumulative=false; %% ----- NOT WORKING NOW, use redefs_2.0.2.mzn: %%%%% ---- bool: fMZN__IgnoreAllUserRedundant=false; %% ignore all user-spec redundant constr %-----------------------------------------------------------------------------% % Some more detailed parameters int: nMZN__UnaryLenMax_neq = nMZN__UnaryLenMax__ALL; int: nMZN__UnaryLenMax_eq = nMZN__UnaryLenMax__ALL; int: nMZN__UnaryLenMax_setIn = nMZN__UnaryLenMax__ALL; int: nMZN__UnaryLenMax_setInReif = nMZN__UnaryLenMax__ALL; %-----------------------------------------------------------------------------% % Strict inequality % % Uncomment the following redefinition for FlatZinc MIP solver interfaces that % do not support strict inequality. Note that it does not preserve equivalence % (some solutions of the original problem may become invalid). % predicate float_lt(var float: x, var float: y) = x + 1e-06 <= y; %----------------------------- BOOL2INT --------------------------------% function var bool: reverse_map(var int: x) = (x==1); function bool: reverse_map(int: x) = (x==1); function var int: bool2int(var bool: x) :: promise_total = let { var 0..1: b2i; constraint (x = reverse_map(b2i)) ::is_reverse_map ; } in b2i; predicate bool_eq(var bool: x, var bool: y) = bool2int(x)==bool2int(y); %-----------------------------------------------------------------------------% % % Logic operations % Use indicators for reifs TODO % %-----------------------------------------------------------------------------% predicate bool_not(var bool: p, var bool: q) = bool2int(p) + bool2int(q) = 1; predicate bool_and(var bool: p, var bool: q, var bool: r) = my_trace(" bool_and: \(p) /\\ \(q) <-> \(r) \n") /\ if fMZN__UseIndicators then int_lin_le_reif__IND( [-1, -1], [p, q], -2, r) else bool_and__INT(bool2int(p), bool2int(q), bool2int(r)) endif; predicate bool_and__INT(var int: x, var int: y, var int: z) = my_trace(" bool_and__INT: \(x) /\\ \(y) <-> \(z) \n") /\ x + y <= z + 1 /\ %% x + y >= z * 2; % weak x >= z /\ y >= z; % strong predicate bool_or(var bool: p, var bool: q, var bool: r) = my_trace(" bool_or: \(p) \\/ \(q) <-> \(r) \n") /\ if fMZN__UseIndicators then int_lin_le_reif__IND( [-1, -1], [p, q], -1, r) else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in my_trace(" bool_or: 0..1: \(x) \\/ \(y) <-> \(z) \n") /\ x + y >= z /\ % x + y <= z * 2; % weak x <= z /\ y <= z % strong endif; predicate bool_xor(var bool: p, var bool: q, var bool: r) = if fMZN__UseIndicators then int_lin_eq_reif__IND( [1, 1], [p, q], 1, r) else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x <= y + z /\ y <= x + z /\ z <= x + y /\ x + y + z <= 2 endif; predicate bool_eq_reif(var bool: p, var bool: q, var bool: r) = if is_fixed(r) then % frequent case if fix(r) = true then p = q else bool_not(p,q) endif elseif fMZN__UseIndicators then int_lin_eq_reif__IND( [1, -1], [p, q], 0, r) else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x + y <= z + 1 /\ x + z <= y + 1 /\ y + z <= x + 1 /\ x + y + z >= 1 endif; predicate bool_ne_reif(var bool: p, var bool: q, var bool: r) = bool_xor(p, q, r); predicate bool_le(var bool: p, var bool: q) = let { var int: x = bool2int(p), var int: y = bool2int(q) } in my_trace(" bool_le: \(p) <= \(q), , 0..1: \(x) <= \(y) \n") /\ x <= y; predicate bool_le_reif(var bool: p, var bool: q, var bool: r) = if fMZN__UseIndicators then int_lin_le_reif__IND( [1, -1], [p, q], 0, r) else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in my_trace(" bool_le_reif: \(p) le \(q) equiv \(r), integers: \(x) le \(y) equiv \(z) \n") /\ 1 - x + y >= z /\ %% /\ 1 - x + y <= z * 2 not needed 1 - x <= z /\ y <= z % strong endif; predicate bool_lt(var bool: p, var bool: q) = not p /\ q; predicate bool_lt_reif(var bool: p, var bool: q, var bool: r) = my_trace(" bool_lt_reif: \(p) lt \(q) equiv \(r) \n") /\ (not p /\ q) <-> r; %-----------------------------------------------------------------------------% predicate array_bool_or(array[int] of var bool: a, var bool: b) = if is_fixed(b) then % frequent case %%%% TODO: "Cannot partially evaluate let expression" ??????????? % my_trace( " array_bool_or: \(a), \(b) \n") /\ my_trace( " array_bool_or FIXED: " ++ show(index_set(a)) ++ ", val=" ++ show(fix(b)) ++ "\n") /\ if fix(b) = true then sum(i in index_set(a))( bool2int(a[i]) ) >= 1 else forall(i in index_set(a))( not a[i] ) endif else let { var int: x = bool2int(b), array[1..length(a)] of var int: c = [ bool2int(a[i]) | i in index_set(a) ] } in my_trace( " array_bool_or: \(a), \(b), " ++ " array_bool_or(" ++ show(length(a)) ++ "): vars 0..1: \(c), \(x) \n") /\ if fMZN__UseIndicators then int_lin_le_reif__IND( [ -1 | i in index_set(a) ], c, -1, b) else sum(c) >= x /\ % sum(c) <= x * length(a) % weak forall (i in index_set(a)) (x >= c[i]) % strong endif endif; predicate array_bool_and(array[int] of var bool: a, var bool: b) = if false /*is_fixed(b)*/ then % frequent case. Does not work -- BUG TODO %% my_trace( " array_bool_and: \(a), \(b) \n") /\ TODO my_trace( " array_bool_and FIXED: " ++ show(index_set(a)) ++ ", val=" ++ show(fix(b)) ++ "\n") /\ if fix(b) = false then sum(i in index_set(a))( bool2int(a[i]) ) <= length(a)-1 else forall(i in index_set(a))( a[i] ) endif else let { var int: x = bool2int(b), array[1..length(a)] of var int: c = [ bool2int(a[i]) | i in index_set(a) ] } in my_trace( % " array_bool_and: \(a), \(b), " ++ " array_bool_and(" ++ show(length(a)) ++ "): vars 0..1: \(c), \(x) \n") /\ if fMZN__UseIndicators then int_lin_le_reif__IND( [ -1 | i in index_set(a) ], c, -length(a), b) else length(a) - sum(c) >= 1 - x /\ % length(a) - sum(c) <= (1 - x) * length(a); % weak forall (i in index_set(a)) (x <= c[i]) % strong endif endif; % predicate array_bool_xor(array[int] of var bool: a) = .. sum(a) is odd .. predicate array_bool_xor(array[int] of var bool: a) = let { var 0..(length(a)-1) div 2: m, var 1..((length(a)-1) div 2)*2+1: ss = sum(i in index_set(a))( bool2int(a[i]) ) } in ss == 1 + 2 * m; predicate bool_clause(array[int] of var bool: p, array[int] of var bool: n) = my_trace(" bool_clause: \(p), \(n) \n") /\ % my_trace( " bool_clause: " ++ show(index_set(p)) ++ ", " ++ show(index_set(n)) ++ "\n") /\ sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1; predicate bool_lin_eq(array[int] of int: c, array[int] of var bool: x, var int: d) = sum(i in index_set(x))( c[i]*bool2int(x[i]) ) == d; predicate bool_lin_eq_reif(array[int] of int: c, array[int] of var bool: x, int: d, var bool: b) = %% No var int d, sorry my_trace(" bool_lin_eq_reif: \(c), \(x), \(d), \(b) \n") /\ aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*bool2int(x[i]) ), d, bool2int(b)); %-----------------------------------------------------------------------------% % % Linear equations and inequations % Use indicators for reifs TODO % Otherwise and more using unary encoding for reasonable domains % %-----------------------------------------------------------------------------% predicate int_le_reif(var int: x, var int: y, var bool: b) = if ub(x)<=lb(y) then b==true elseif lb(x)>ub(y) then b==false elseif fMZN__UseIndicators then int_lin_le_reif__IND( [1, -1], [x, y], 0, b) else let { var 0..1: p = bool2int(b) % , var int: x_y = x-y } in %% No big difference using the binary decomposition: % my_trace(" int_le_reif( var " ++ show(dom(x)) ++ ", var " ++ show(dom(y)) % ++ ", dom(x-y) = " ++ show(dom(x-y)) % ++ ", var \(b))\n") /\ % if card(dom(x_y))<20 then % let { array[int] of var int: p = eq_encode(x_y) } in % my_trace (" -- by unary: dom(x-y) = " ++ show(dom(x_y)) ++ "\n") /\ % sum ( i in dom(x_y) where i<=0 ) ( p[i] ) == bool2int(b) % else aux_int_le_if_1(x, y, p) /\ aux_int_gt_if_0(x, y, p) % endif endif ; predicate int_lt_reif(var int: x, var int: y, var bool: b) = int_le_reif(x, y - 1, b); predicate int_ne(var int: x, var int: y) = my_trace(" int_ne(var " ++ show(lb(x)) ++ " .. " ++ show(ub(x)) ++ ", var " ++ show(lb(y)) ++ " .. " ++ show(ub(y)) ++ ")\n") /\ int_ne(x-y, 0); % let { var 0..1: p } in % aux_int_lt_if_1(x, y, p) /\ % aux_int_gt_if_0(x, y, p); predicate int_ne(var int: x, int: y) = %% int_eq_reif(x, y, false); my_trace(" int_ne(var " ++ show(lb(x)) ++ " .. " ++ show(ub(x)) ++ ", int " ++ show(y) ++ ")\n") /\ if y in dom(x) then if y==ub(x) then x <= y-1 elseif y==lb(x) then x >= y+1 elseif card(dom(x))0 then if is_fixed(x) then if is_fixed(y) then b <-> fix(x)==fix(y) else int_eq_reif(y, fix(x), b) endif elseif is_fixed(y) then int_eq_reif(x, fix(y), b) else int_eq_reif(x-y, 0, b) %%% aux_int_eq_iff_1(x, y, bool2int(b)) endif else not b endif; predicate int_eq_reif(var int: x, int: y, var bool: b) = if y in dom(x) then my_trace(" int_eq_reif ( x: " ++ if has_bounds(x) then show(dom(x)) else "int" endif ++ ", y=const: " ++ show(y) ++ " )\n") /\ if y==lb(x) then int_lt_reif(y, x, not b) elseif y==ub(x) then int_lt_reif(x, y, not b) elseif card(dom(x))=0 then z==x elseif ub(x)<=0 then z==-x else let { var 0..1: p } in % z <= x \/ z <= -x aux_int_le_if_1(z, x, p) /\ aux_int_le_if_0(z, -x, p) /\ z >= x /\ z >= -x /\ z >= 0 /\ % This is just for preprocessor z <= max([ub(x), -lb(x)]) % And this endif ; predicate int_min(var int: x, var int: y, var int: z) = array_int_minimum(z, [x, y]); predicate int_max(var int: x, var int: y, var int: z) = array_int_maximum(z, [x, y]); predicate float_abs(var float: x, var float: z) = let { var 0..1: p } in % z <= x \/ z <= -x aux_float_le_if_1(z, x, (p)) /\ aux_float_le_if_0(z, -x, (p)) /\ z >= x /\ z >= -x /\ z >= 0.0 /\ % This is just for preprocessor z <= max([ub(x), -lb(x)]); % And this predicate float_min(var float: x, var float: y, var float: z) = array_float_minimum(z, [x, y]); predicate float_max(var float: x, var float: y, var float: z) = array_float_maximum(z, [x, y]); %-----------------------------------------------------------------------------% % Multiplication and division predicate int_div(var int: x, var int: y, var int: q) = let { int: bx = max(abs(lb(x)), abs(ub(x))); constraint -bx<=q /\ q<=bx; int: by = max(abs(lb(y)), abs(ub(y))); var -by+1..by-1: r; } in aux_int_division_modulo(x,y,q,r); predicate int_mod(var int: x, var int: y, var int: r) = let { int: bx = max(abs(lb(x)), abs(ub(x))); var -bx..bx: q; int: by = max(abs(lb(y)), abs(ub(y))); constraint -by+1<=r /\ r<=by-1; } in aux_int_division_modulo(x,y,q,r); predicate aux_int_division_modulo(var int: x, var int: y, var int: q, var int: r) = let { int: bx = max(abs(lb(x)), abs(ub(x))); constraint -bx<=q /\ q<=bx; int: by = max(abs(lb(y)), abs(ub(y))); constraint -by+1<=r /\ r<=by-1; var 0..1: p } in x = y * q + r /\ % 0 <= x -> 0 <= r which is 0 > x \/ 0 <= r aux_int_lt_if_1(x, 0, p) /\ aux_int_ge_if_0(r, 0, p) /\ % x < 0 -> r <= 0 which is x >= 0 \/ r <= 0 aux_int_ge_if_0(x, 0, p) /\ aux_int_le_if_1(r, 0, p) /\ % abs(r) < abs(y) let { var 1.. max(abs(lb(y)), abs(ub(y))): w = abs(y) } in w > r /\ w > -r; %% Can also have int_times(var float, var int) ......... TODO predicate int_times(var int: x, var int: y, var int: z) = if is_fixed(x) then z==fix(x)*y %%%%% Need to use fix() otherwise added to map & nothing happens elseif is_fixed(y) then z==x*fix(y) else if 0..1==dom(x) /\ 0..1==dom(y) then bool_and__INT(x,y,z) elseif card(dom(x))==2 /\ card(dom(y))==2 /\ 0 in dom(x) /\ 0 in dom(y) then let { var 0..1: xn; var 0..1: yn; var 0..1: zn; constraint x=xn*max(dom(x) diff {0}); constraint y=yn*max(dom(y) diff {0}); constraint z=zn*max(dom(x) diff {0})*max(dom(y) diff {0}); } in bool_and__INT(xn,yn,zn) elseif card(dom(x)) * card(dom(y)) > nMZN__UnarySizeMax_intTimes then %% PARAM %% ALSO NO POINT IF <=4. TODO if card(dom(x)) > card(dom(y)) then int_times(y,x,z) else my_trace ( " int_times(x,y,z): dom(x) = " ++ show(dom(x)) ++ " " ) /\ my_trace ( ", dom(y) = " ++ show(dom(y)) ++ "\n" ) /\ let { set of int: s = lb(x)..ub(x), set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, array[s] of var min(r)..max(r): ady = array1d(s, [ d*y | d in s ]) } in ady[x] = z %% use element() endif else int_times_unary(x, { }, y, z) endif endif; %% domx__ can be used to narrow domain... NOT IMPL. predicate int_times_unary(var int: x, set of int: domx__, var int: y, var int: z) = let { set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, %% set of int: domx = if card(domx__)>0 then domx__ else dom(x) endif, array[int, int] of var int: pp=eq_encode(x, y) } in my_trace ( " int_times_unary(\(x),\(y),\(z)): dom(x) = " ++ show(dom(x)) ++ " " ) /\ % my_trace ( ", domx = " ++ show(domx) ++ " " ) /\ my_trace ( ", dom(y) = " ++ show(dom(y)) ++ " " ) /\ z>=min(r) /\ z<=max(r) /\ my_trace ( ", dom(z) = " ++ show(dom(z)) ++ "\n" ) /\ %% after the bounds z==sum(i in index_set_1of2(pp), j in index_set_2of2(pp)) (i * j * pp[i, j]) /\ forall(i in index_set_1of2(pp), j in index_set_2of2(pp) where not ((i*j) in dom(z)) )(pp[i, j]==0) ; predicate int_times_unary__NOFN(var int: x, set of int: domx__, var int: y, var int: z) = let { set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, %% set of int: domx = if card(domx__)>0 then domx__ else dom(x) endif, array[int] of var int: pX = eq_encode(x), array[int] of var int: pY = eq_encode(y), array[int] of int: valX = [ v | v in index_set(pX) ], %% NOT domx. array[int] of int: valY = [ v | v in index_set(pY) ], %% -- according to eq_encode! array[index_set(valX), index_set(valY)] of var 0..1: pp %% both dim 1.. } in if is_fixed(x) \/ is_fixed(y) then z==x*y else my_trace ( " int_times_unary__NOFN(\(x),\(y),\(z)): dom(x) = " ++ show(dom(x)) ++ " " ) /\ % my_trace ( ", domx = " ++ show(domx) ++ " " ) /\ my_trace ( ", dom(y) = " ++ show(dom(y)) ++ " " ) /\ z>=min(r) /\ z<=max(r) /\ my_trace ( ", dom(z) = " ++ show(dom(z)) ++ "\n" ) /\ %% after the bounds sum(pp)==1 /\ z==sum(i in index_set(valX), j in index_set(valY)) (valX[i] * valY[j] * pp[i, j]) /\ forall(i in index_set(valX)) ( pX[valX[i]] == sum(j in index_set(valY))( pp[i, j] ) ) /\ forall(j in index_set(valY)) ( pY[valY[j]] == sum(i in index_set(valX))( pp[i, j] ) ) endif; %-----------------------------------------------------------------------------% % Array 'element' constraints predicate array_bool_element(var int: x, array[int] of bool: a, var bool: z) = array_int_element(x, arrayXd(a, [bool2int(a[i]) | i in index_set(a)]), bool2int(z)); predicate array_var_bool_element(var int: x, array[int] of var bool: a, var bool: z) = array_var_int_element(x, arrayXd(a, [bool2int(a[i]) | i in index_set(a)]), bool2int(z)); predicate array_int_element(var int: x, array[int] of int: a, var int: z) = array_float_element(x, arrayXd(a, [int2float(a[i]) | i in index_set(a)]), int2float(z)); predicate array_var_int_element(var int: x, array[int] of var int: a, var int: z) = %%%% Relate to the float version: array_var_float_element(x, arrayXd(a, [int2float(a[i]) | i in index_set(a)]), int2float(z)); %%%% Simplistic version: %%%% Complete binarization: MEMORY FULL. Need exact domains & sparse encoding predicate array_float_element(var int: i00, array[int] of float: a, var float: z) = let { set of int: ix = index_set(a), constraint i00 in ix } in z >= min(i in dom(i00))(a[i]) /\ z <= max(i in dom(i00))(a[i]) /\ if card(dom(i00))==1 \/ min(i in dom(i00))(a[i])==max(i in dom(i00))(a[i]) then true %%%% z==a[fix(i00)] else let { int: nUBi00 = max(dom(i00)), int: nLBi00 = min(dom(i00)), float: nMinDist = min(i in nLBi00 .. nUBi00-1)(a[i+1]-a[i]), float: nMaxDist = max(i in nLBi00 .. nUBi00-1)(a[i+1]-a[i]), } in if nMinDist == nMaxDist then %% The linear case z == a[nLBi00] + nMinDist*(i00-nLBi00) else let { array[int] of var int: p = eq_encode(i00) %% this needs i00 in ix } in my_trace(" array_float_element(i00, a[], z: dom(i00) = " ++ show(dom(i00)) ++ "\n z in: " ++ show(lb(z)) ++ " .. " ++ show(ub(z)) ++ "\n elements of a in: " ++ show(min(i in dom(i00))(a[i])) ++ " .. " ++ show(max(i in dom(i00))(a[i])) ++ "\n index_set(a) = " ++ show(index_set(a)) ++ "\n index_set(p) = " ++ show(index_set(p)) ++ "\n") /\ assert(dom(i00) subset index_set(p), "", true) /\ sum(i in dom(i00))( a[i] * int2float(p[i]) ) == z %% add more hull? endif endif; predicate array_var_float_element(var int: i00, array[int] of var float: a, var float: z) = let { set of int: ix = index_set(a), constraint i00 in ix, float: minLB=min(i in dom(i00))(lb(a[i])), float: maxUB=max(i in dom(i00))(ub(a[i])) } in z >= minLB /\ z <= maxUB /\ if is_fixed(i00) then z==a[fix(i00)] elseif minLB==maxUB then true else let { array[int] of var int: p = eq_encode(i00), } in my_trace ( " array_var_float_element: i in " ++ show(lb(i00)) ++ ".." ++ show(ub(i00)) ++ "\n LB(a) = " ++ show([lb(a[i]) | i in ix]) ++ "\n UB(a) = " ++ show([ub(a[i]) | i in ix]) ++ ", z in " ++ show(lb(z)) ++ ".." ++ show(ub(z)) ++ "\n") /\ assert(dom(i00) subset index_set(p), "", true) /\ %%% The convexified bounds seem slow for ^2 and ^3 equations: % sum(i in dom(i01))( lb(a[i]) * int2float(p[i]) ) <= z /\ %% convexify lower bounds % sum(i in dom(i01))( ub(a[i]) * int2float(p[i]) ) >= z /\ %% convexify upper bounds forall (i in dom(i00))( aux_float_eq_if_1(z, a[i], p[i]) ) %% Cuts: seems better without? % /\ array_var_float_element__ROOF([ a[i] | i in dom(i01) ], z) % /\ array_var_float_element__ROOF([ -a[i] | i in dom(i01) ], -z) endif ; %%% Facets on the upper surface of the z-a polytope %%% Possible parameter: maximal number of first cuts taken only predicate array_var_float_element__ROOF(array[int] of var float: a, var float: z) = let { set of int: ix = index_set(a), int: n = length(a), % array[int] of float: ALm = [ -lb(a[i]) | i in 1..n], % array[int] of int: srt_lb = sort_by([i | i in 1..n], ALm), %indices of lb sorted down array[int] of float: AU = [ ub(a[i]) | i in 1..n], array[int] of int: srt_ub = sort_by([i | i in 1..n], AU), %indices of ub sorted up array[int] of float: AU_srt_ub = [ub(a[srt_ub[i]]) | i in 1..n], array[int] of float: AL_srt_ub = [lb(a[srt_ub[i]]) | i in 1..n], array[int] of float: MaxLBFrom = [ max(j in index_set(AL_srt_ub) where j>=i)(AL_srt_ub[j]) | i in 1..n ], %% direct, O(n^2) array[int] of float: ULB = [ if 1==i then MaxLBFrom[1] else max([AU_srt_ub[i-1], MaxLBFrom[i]]) endif | i in 1..n ] % array[int] of float: AL_srt = [AL[srt[i]] | i in 1..n], % array[int] of float: AU_srt = [ub(x[srt[i]]) | i in 1..n] } in %%% "ROOF" forall (i in 1..n where ((i= sum(i in index_set(sL))(B[i]*sL[i]) /\ x <= sum(i in index_set(sR))(B[i]*sR[i]) % endif % 1 == sum(e in s)(bool2int( x == e )) % exists(e in s)( x = e ) % let { var 1..card(s): i } in % array_int_element(i, [v | v in s], x) endif; % XXX only for a fixed set predicate set_in_reif(var int: x, set of int: s__, var bool: b) = my_trace(" set_in_reif ( x: " ++ if has_bounds(x) then show(dom(x)) else "int" endif ++ ", s__: " ++ show(s__) ++ " )\n" ) /\ let { set of int: s = if has_bounds(x) then s__ intersect dom(x) else s__ endif, } in ( if dom(x) subset s then b==true elseif card(dom(x) intersect s)==0 then b==false elseif s = min(s)..max(s) then b <-> (min(s) <= x /\ x <= max(s)) else % let { % array[int] of int: sL = [ e | e in s where not (e - 1 in s) ]; % array[int] of int: sR = [ e | e in s where not (e + 1 in s) ]; % array [index_set(sR)] of var 0..1: B; % constraint assert(length(sR)==length(sL), "N of lb and ub of sub-intervals of a set should be equal"); % } in % sum(B) = bool2int(b) %% use indicators % /\ % x >= lb(x) + sum(i in index_set(sL))(B[i]*(sL[i]-lb(x))) % /\ % x <= ub(x) + sum(i in index_set(sR))(B[i]*(sR[i]-ub(x))) aux_int_le_if_1(x, max(s), bool2int(b)) /\ aux_int_ge_if_1(x, min(s), bool2int(b)) /\ if card(dom(x))<=nMZN__UnaryLenMax_setInReif then %% PARAM TODO let { array[int] of var int: p = eq_encode(x); } in sum(i in s intersect dom(x))(p[i]) == bool2int(b) else bool2int(b) == fVarInBigSetOfInt(x, s) endif % bool2int(b) == sum(e in s)(bool2int( x == e )) endif ); % Alternative predicate alt_set_in_reif(var int: x, set of int: s, var bool: b) = b <-> exists(i in 1..length([ 0 | e in s where not (e - 1 in s) ]))( let { int: l = [ e | e in s where not (e - 1 in s) ][i], int: r = [ e | e in s where not (e + 1 in s) ][i] } in l <= x /\ x <= r ); function var int: fVarInBigSetOfInt(var int: x, set of int: s) = let { array[int] of int: sL = [ e | e in s where not (e - 1 in s) ]; array[int] of int: sR = [ e | e in s where not (e + 1 in s) ]; constraint assert(length(sR)==length(sL), "N of lb and ub of sub-intervals of a set should be equal"); } in sum(i in index_set(sL)) (bool2int(x>=sL[i] /\ x<=sR[i])); %% use indicators %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% OTHER SET STUFF, COPIED FROM ../nosets/redefs %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function var set of int: reverse_map(array[int] of var bool: b); function set of int: reverse_map(array[int] of bool: b) ::promise_total = { i | i in index_set(b) where b[i] }; array[int] of var bool: set2bools(var set of int: x) ::promise_total = if is_fixed(x) then set2bools(fix(x)) else let { array[min(ub(x))..max(ub(x))] of var bool: b; constraint forall (i in index_set(b) where not (i in ub(x))) (b[i]=false); constraint (x = reverse_map(b)) :: is_reverse_map; constraint my_trace(" set2bools(\(x)) = \(b) \n") } in b endif; array[int] of var bool: set2bools(var set of int: x, set of int: ubx) ::promise_total = if is_fixed(x) then set2bools(fix(x) intersect ubx) else let { array[min(ubx)..max(ubx)] of var bool: b; constraint forall (i in index_set(b) where not (i in ubx)) (b[i]=false); constraint (x = reverse_map(b)) :: is_reverse_map; constraint my_trace(" set2bools(\(x), \(ubx)) = \(b) \n") } in b endif; array[int] of bool: set2bools(set of int: x) ::promise_total = array1d(min(x)..max(x),[i in x | i in min(x)..max(x)]); array[int] of bool: set2bools(set of int: x, set of int: ubx) ::promise_total = set2bools(x intersect ubx); predicate set_eq(var set of int: x, var set of int: y) = if not has_ub_set(x) /\ not has_ub_set(y) then assert(false, "Cannot determine bounds of set variables") elseif not has_ub_set(x) then set_eq(y,x) else let { set of int: uby = if has_ub_set(y) then ub(y) else ub(x) endif; array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y,uby); } in forall (i in index_set(bx) union index_set(by)) ( if not (i in index_set(bx)) then not by[i] elseif not (i in index_set(by)) then not bx[i] else bx[i]=by[i] endif ) endif; predicate set_eq_reif(var set of int: x, var set of int: y, var bool: b) = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in b <-> forall (i in index_set(bx) union index_set(by)) ( if not (i in index_set(bx)) then not by[i] elseif not (i in index_set(by)) then not bx[i] else bx[i]=by[i] endif ); predicate set_subset(var set of int: x, var set of int: y) = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in forall (i in index_set(bx)) ( if not (i in index_set(by)) then not bx[i] else bx[i] -> by[i] endif ); predicate set_subset_reif(var set of int: x, var set of int: y, var bool: b) = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in b <-> forall (i in index_set(bx)) ( if not (i in index_set(by)) then not bx[i] else bx[i] -> by[i] endif ); function var set of int: set_intersect(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of (index_set(bx) intersect index_set(by)): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in index_set(bz)) ( bz[i] = (bx[i] /\ by[i]) ); } in z; %predicate set_le(var set of int: x, var set of int: y) ::promise_total = % let { % array[int] of var bool: bx = set2bools(x); % array[int] of var bool: by = set2bools(y); % } in function var set of int: set_union(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of (index_set(bx) union index_set(by)): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in index_set(bx) union index_set(by)) ( if (i in index_set(bx)) then if (i in index_set(by)) then bz[i] = (bx[i] \/ by[i]) else bz[i] = bx[i] endif else bz[i] = by[i] endif ); } in z; function var set of int: set_diff(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of (index_set(bx) diff index_set(by)): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in index_set(bz)) ( bz[i] = (bx[i] /\ (not by[i])) ); } in z; function var int: card(var set of int: x) ::promise_total = let { array[int] of var bool: bx = set2bools(x); var 0..length(bx) : c; constraint bool_lin_eq([1 | i in index_set(bx)],bx,c); } in c; predicate set_in(var int: x, var set of int: y) = let { array[int] of var bool: by = set2bools(y); } in by[x]; predicate set_in_reif(var int: x, var set of int: y, var bool: b) = let { array[int] of var bool: by = set2bools(y); } in b <-> by[x]; %function array[int] of var set of int: reverse_map(array[int] of var bool: b); %%%% Use array[int,int] of var bool? %function set of int: reverse_map(array[int] of bool: b) ::promise_total = % { i | i in index_set(b) where b[i] }; % let { % array[min(ub(x))..max(ub(x))] of var bool: b; % constraint forall (i in index_set(b) where not (i in ub(x))) (b[i]=false); % constraint (x = reverse_map(b)) :: is_reverse_map; % } in b function array[int] of var bool: setarray2bools(array[int] of var set of int: x) :: promise_total = if length(x)=0 then [] else set2bools(x[1])++setarray2bools([x[i]|i in 2..length(x)]) endif; %function array[int] of var bool: setarray2bools(array[int] of var set of int: x) % :: promise_total % = let { % array[int] of var bool: b = % if length(x)=0 then [] else % set2bools(x[1])++setarray2bools_I([x[i]|i in 2..length(x)]) % endif; % constraint (x = reverse_map(b)) :: is_reverse_map; % } in b; annotation set_search(array[int] of var set of int: x, ann: a1, ann: a2, ann: a3) = bool_search(setarray2bools(x),a1,a2,a3); %-----------------------------------------------------------------------------% % Auxiliary: equality reified onto a 0/1 variable predicate aux_int_eq_iff_1(var int: x, var int: y, var int: p) = if fMZN__UseIndicators then int_lin_eq_reif__IND([1, -1], [x, y], 0, (p==1)) else let { array[1..2] of var 0..1: q } in % my_trace(" aux_int_eq_iff_1: var " ++ show(dom(x)) % ++ ", var " ++ show(dom(y)) ++ "\n") /\ aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) /\ aux_int_lt_if_0(x, y, q[1]) /\ aux_int_gt_if_0(x, y, q[2]) /\ sum(q) == p + 1 endif; % Alternative 2 predicate aux_int_eq_iff_1__WEAK1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q_458 } in aux_int_lt_if_0(x - p, y, q_458[1]) /\ aux_int_gt_if_0(x + p, y, q_458[2]) /\ sum(q_458) <= 2 - 2*p /\ sum(q_458) <= 1 + p; % Alternative 1 predicate alt_1_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q } in aux_int_lt_if_0(x - p, y, q[1]) /\ aux_int_gt_if_0(x + p, y, q[2]) /\ q[1] <= 1 - p /\ q[2] <= 1 - p /\ sum(q) <= 1 + p; predicate aux_float_eq_iff_1(var float: x, var float: y, var int: p) = %% if fMZN__UseIndicators then ?????? let { array[1..2] of var 0..1: q } in aux_float_le_if_1(x, y, p) /\ aux_float_ge_if_1(x, y, p) /\ aux_float_lt_if_0(x, y, (q[1])) /\ aux_float_gt_if_0(x, y, (q[2])) /\ sum(i in 1..2)((q[i])) == 1 + p; predicate aux_float_eq_if_1(var float: x, var float: y, var int: p) = if fMZN__UseIndicators then aux_float_eq_if_1__IND(x, y, p) else aux_float_le_if_1(x, y, p) /\ aux_float_ge_if_1(x, y, p) endif; %-----------------------------------------------------------------------------% % Auxiliary: indicator constraints % p -> x # 0 where p is a 0/1 variable and # is a comparison % Base cases predicate aux_int_le_zero_if_0(var int: x, var 0..1: p) = % my_trace(" aux_int_le_zero_if_0( \(x), \(p))\n") /\ % if card(dom(x))<20 then % let { array[int] of var int: pp = eq_encode(x) } in % my_trace (" aux_int_le_zero_if_0 by unary: dom(x) = " ++ show(dom(x)) ++ "\n") /\ % sum ( i in dom(x) where i<=0 ) ( pp[i] ) == p % else if fMZN__UseIndicators then aux_int_le_zero_if_0__IND(x, p) else x <= ub(x) * p endif; predicate aux_float_le_zero_if_0(var float: x, var int: p) = if fMZN__UseIndicators then aux_float_le_zero_if_0__IND(x, p) else x <= ub(x) * p endif; predicate aux_float_lt_zero_if_0(var float: x, var int: p) = let { float: rho = 1e-02 * abs(ub(x)) } % same order of magnitude as ub(x) in x < (ub(x) + rho) * p; % Derived cases predicate aux_int_le_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, p); predicate aux_int_ge_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, p); predicate aux_int_le_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, 1 - p); predicate aux_int_ge_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, 1 - p); predicate aux_int_lt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, p); predicate aux_int_gt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x + 1, p); predicate aux_int_lt_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, 1 - p); predicate aux_float_le_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, p); predicate aux_float_ge_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, p); predicate aux_float_le_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, 1 - p); predicate aux_float_ge_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, 1 - p); predicate aux_float_lt_if_0(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(x - y, p); predicate aux_float_gt_if_0(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(y - x, p); predicate aux_float_lt_if_1(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(x - y, 1 - p); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% annotation bool_search(array[int] of var bool: x, ann:a1, ann:a2, ann:a3) = int_search([bool2int(x[i]) | i in index_set(x)],a1,a2,a3); predicate array_float_minimum_I(var float: m, array[int] of var float: x) = let { int: n = length(x), array[1..n] of var 0..1: p, int: iMinUB = arg_min([ub(x[i]) | i in 1..n]), float: MinUB = ub(x[iMinUB]), constraint m >= lb_array(x) /\ m <= MinUB, array[int] of float: AL = [ lb(x[i]) | i in 1..n], array[int] of int: srt = sort_by([i | i in 1..n], AL), %indices of lb in sorted order array[int] of float: AL_srt = [AL[srt[i]] | i in 1..n], array[int] of float: AU_srt = [ub(x[srt[i]]) | i in 1..n], array[int] of float: AM_srt = AL_srt ++ [MinUB] %% -- these are z-levels of extreme points } in assert(index_set(x) == index_set(AL), "array_float_minimum_I: second argument must have index set 1..length()", % my_trace("array_float_minimum_I: " ++ show(lb(m)) ++ " <= m <= " ++ show(ub(m))) /\ % ++ "\n AL = " ++ show(AL) % ++ "\n srt_lb = " ++ show(srt) % ++ "\n AL_srt = " ++ show(AL_srt) % ++ "\n AU_srt = " ++ show(AU_srt) % ++ "\n MinUB = " ++ show(MinUB) % ++ "\n" , 1 == sum(p) /\ forall (i in index_set(x)) ( if lb(x[i])= AM_srt[i] - sum(j in 1..i-1 where AL_srt[j] x_eq_d[d] predicate equality_encoding(var int: x, array[int] of var int: x_eq_d) = x in index_set(x_eq_d) /\ sum(d in dom(x))( x_eq_d[d] ) = 1 /\ sum(d in dom(x))( d * x_eq_d[d] ) = x; % Two variables: x = d /\ y = e <-> x_eq_d[d] /\ y_eq_e[e] /\ xy_eq_de[d, e] predicate equality_encoding(var int: x, var int: y, array[int] of var int: x_eq_d, array[int] of var int: y_eq_e, array[int, int] of var int: xy_eq_de ) = x in index_set(x_eq_d) /\ y in index_set(y_eq_e) /\ index_set(x_eq_d) == index_set_1of2(xy_eq_de) /\ index_set(y_eq_e) == index_set_2of2(xy_eq_de) /\ sum(d in dom(x), e in dom(y))( xy_eq_de[d, e] ) = 1 /\ forall(d in dom(x)) (sum(e in dom(y))( xy_eq_de[d, e] ) = x_eq_d[d]) /\ forall(e in dom(y)) (sum(d in dom(x))( xy_eq_de[d, e] ) = y_eq_e[e]) ; % Array of variables: x[i] = d <-> x_eq_d[i,d] predicate equality_encoding(array[int] of var int: x, array[int, int] of var int: x_eq_d) = forall(i in index_set(x))( x[i] in index_set_2of2(x_eq_d) /\ sum(d in index_set_2of2(x_eq_d))( x_eq_d[i,d] ) = 1 /\ sum(d in index_set_2of2(x_eq_d))( d * x_eq_d[i,d] ) = x[i] ); function var int: eq_new_var(var int: x, int: i) ::promise_total = if i in dom(x) then let { var 0..1: xi; } in xi else 0 endif; function array[int] of var int: eq_encode(var int: x) ::promise_total = let { array[int] of var int: y = array1d(lb(x)..ub(x),[eq_new_var(x,i) | i in lb(x)..ub(x)]); constraint equality_encoding(x,y); constraint if card(dom(x))>200 then trace(" eq_encode: dom(\(x)) = " ++ show(dom(x)) ++ "\n") else true endif; } in y; function array[int] of int: eq_encode(int: x) ::promise_total = array1d(lb(x)..ub(x),[ if i=x then 1 else 0 endif | i in lb(x)..ub(x)]); %%% The same for 2 variables: function var int: eq_new_var(var int: x, int: i, var int: y, int: j) ::promise_total = if i in dom(x) /\ j in dom(y) then let { var 0..1: xi; } in xi else 0 endif; function array[int, int] of var int: eq_encode(var int: x, var int: y) ::promise_total = let { array[int] of var int: pX = eq_encode(x), array[int] of var int: pY = eq_encode(y), array[int, int] of var int: pp = array2d(index_set(pX), index_set(pY), [eq_new_var(x,i,y,j) | i in index_set(pX), j in index_set(pY)]); constraint equality_encoding(x, y, pX, pY, pp); } in pp; function array[int, int] of int: eq_encode(int: x, int: y) ::promise_total = let { constraint if card(dom(x))*card(dom(y))>200 then trace(" eq_encode: dom(\(x)) = " ++ show(dom(x)) ++ ", dom(\(y)) = " ++ show(dom(y)) ++ "\n") else true endif; } in array2d(lb(x)..ub(x), lb(y)..ub(y), [if i==x /\ j==y then 1 else 0 endif | i in lb(x)..ub(x), j in lb(y)..ub(y)]); function array[int,int] of var int: eq_encode(array[int] of var int: x) ::promise_total = let { array[index_set(x),lb_array(x)..ub_array(x)] of var int: y = array2d(index_set(x),lb_array(x)..ub_array(x), [ let { array[int] of var int: xi = eq_encode(x[i]) } in if j in index_set(xi) then xi[j] else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)] ) } in y; function array[int,int] of int: eq_encode(array[int] of int: x) ::promise_total = array2d(index_set(x),lb_array(x)..ub_array(x),[ if j=x[i] then 1 else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)]); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear_new/inverse.mzn0000644000175000017500000000221312646030173022006 0ustar kaolkaol%-----------------------------------------------------------------------------% % Constrains two arrays of int variables to represent inverse functions. % All the values in each array must be within the index set of the other array. % % Linear version. %-----------------------------------------------------------------------------% % include "domain_encodings.mzn"; % predicate inverse(array[int] of var int: f, array[int] of var int: g) = % let { % array[int,int] of var 0..1: map_f = eq_encode(f); % array[int,int] of var 0..1: map_g = eq_encode(g); % } in forall (i in index_set(f), j in index_set(g)) (map_f[i,j] = map_g[j,i]); %-----------------------------------------------------------------------------% %% Now copying the std version, seems a little faster on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn predicate inverse(array[int] of var int: f, array[int] of var int: invf) = forall(i in index_set(f)) ( f[i] in index_set(invf) ) /\ forall(j in index_set(invf)) ( invf[j] in index_set(f) ) /\ forall(i in index_set(f), j in index_set(invf)) ( ((j == f[i]) <-> (i == invf[j])) ); libminizinc-2.0.11/share/minizinc/linear_new/all_different_int.mzn0000644000175000017500000000143712646030173024012 0ustar kaolkaol%-----------------------------------------------------------------------------% % 'all_different' constrains an array of objects to be all different. % % Linear version: equality encoding; see e.g. [Refalo, CP 2000] % % For a given d in dom(x), at most one i with x_i = d can exist. %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; predicate all_different_int(array[int] of var int: x) = let { array[int,int] of var 0..1: x_eq_d = eq_encode(x) } in ( my_trace(" all_different_int: x[" ++ show(index_set(x)) ++ "]\n") /\ forall(d in index_set_2of2(x_eq_d))( sum(i in index_set_1of2(x_eq_d))( x_eq_d[i,d] ) <= 1 ) ); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear_new/redefinitions-2.0.mzn0000644000175000017500000000303712646030173023477 0ustar kaolkaolpredicate bool_clause_reif(array[int] of var bool: p, array[int] of var bool: n, var bool: c) = c = ( sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1 ); predicate array_float_minimum(var float: m, array[int] of var float: x) = if fMZN__UseIndicators then array_float_minimum__IND(m, x) %% transfer to Concert because of prepro else array_float_minimum_I( m, [ x[i] | i in index_set(x)]) endif; predicate array_float_maximum(var float: m, array[int] of var float: x) = if fMZN__UseIndicators then array_float_maximum__IND(m, x) else array_float_minimum_I(-m, [-x[i] | i in index_set(x)]) endif; predicate array_int_minimum(var int: m, array[int] of var int: x) = if fMZN__UseIndicators then array_int_minimum__IND(m, x) else array_float_minimum_I( int2float(m), [ int2float(x[i]) | i in index_set(x)]) endif; predicate array_int_maximum(var int: m, array[int] of var int: x) = if fMZN__UseIndicators then array_int_maximum__IND(m, x) else array_float_minimum_I(-int2float(m), [-int2float(x[i]) | i in index_set(x)]) endif; % predicate array_int_maximum__OLD_SYMMETRIES(var int: m, array[int] of var int: x) = % let { int: l = min(index_set(x)), % int: u = max(index_set(x)), % int: ly = lb_array(x), % int: uy = ub_array(x), % array[l..u] of var ly..uy: y } in % y[l] = x[l] /\ % m = y[u] /\ % forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); libminizinc-2.0.11/share/minizinc/linear_new/lex_lesseq_bool.mzn0000644000175000017500000000652012646030173023517 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_lesseq_bool(array[int] of var bool: x, array[int] of var bool: y) = % if (min(card(index_set(x)), card(index_set(y))) <= 25) then % let { int: size = min(card(index_set(x)), card(index_set(y))); % } in % sum(i in 0..size-1)(pow(2, (size-1-i)) * bool2int(x[i+min(index_set(x))])) % <= sum(i in 0..size-1)(pow(2, (size-1-i)) * bool2int(y[i+min(index_set(y))])) % else let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in b[0] /\ forall(i in 0..size) ( b[i] -> ( ( ( x[lx + i] <= y[ly + i] ) ) /\ % bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) <= 2 /\ % ( b[i] -> ( x[lx + i] < y[ly + i] \/ b[i+1] ) ) % /\ ( bool2int(b[i]) <= bool2int(x[lx + i] < y[ly + i]) + bool2int(b[i+1]) ) /\ % bool2int(b[i]) + (1-bool2int(x[lx + i])) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 % /\ bool2int(b[i]) + bool2int(x[lx + i]) + bool2int(y[ly + i]) + (1-bool2int(b[i+1])) <= 3 %% This guy is dominated by the 1st one above but helps: % /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 ) /\ b[size+1] = (ux-lx <= uy-ly) % endif ; % forall(i in 0..size) ( % ( b[i] == ( x[lx + i] <= y[ly + i] ) ) % /\ % if i < size then % ( b[i] == ( x[lx + i] < y[ly + i] \/ b[i+1] % ) ) else true endif % ); predicate lex_lesseq_bool_reif(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c <-> b[0]) /\ forall(i in 0..size) ( ( b[i] -> ( x[lx + i] <= y[ly + i] ) ) /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) <= 2 /\ ( b[i] -> ( x[lx + i] < y[ly + i] \/ b[i+1] ) ) /\ bool2int(b[i]) + (1-bool2int(x[lx + i])) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + bool2int(y[ly + i]) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 ) /\ b[size+1] = (ux-lx <= uy-ly) % endif ; predicate lex_leq_bool(array[int] of var bool: x, array[int] of var bool: y) = lex_lesseq(x, y); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear_new/CHANGELOG.txt0000644000175000017500000000043112646030173021635 0ustar kaolkaol 2015-07-20 Special handling of array_int_element which is a linear fn. No much diff on ProjPlanning_12_8. [REVERTED] Replaced array_int_element by the old (forall(.. -> ..)) 82s vs 45s on ProjPlanning_12_8libminizinc-2.0.11/share/minizinc/linear_new/regular.mzn0000644000175000017500000001241412646030173022000 0ustar kaolkaol/** @group globals.extensional The sequence of values in array \a x (which must all be in the range 1..\a S) is accepted by the DFA of \a Q states with input 1..\a S and transition function \a d (which maps (1..\a Q, 1..\a S) -> 0..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). We reserve state 0 to be an always failing state. */ predicate regular(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F) = assert(Q > 0, "regular: 'Q' must be greater than zero", assert(S > 0, "regular: 'S' must be greater than zero", assert(index_set_1of2(d) = 1..Q /\ index_set_2of2(d) == 1..S, "regular: the transition function 'd' must be [1..Q,1..S]", assert(forall([d[i, j] in 0..Q | i in 1..Q, j in 1..S]), "regular: transition function 'd' points to states outside 0..Q", % Nb: we need the parentheses around the expression otherwise the % parser thinks it's a generator call! assert((q0 in 1..Q), "regular: start state 'q0' not in 1..Q", assert(F subset 1..Q, "regular: final states in 'F' contain states outside 1..Q", trace(" regular: index_set(x)=" ++ show(index_set(x)) ++ ", dom_array(x)=" ++ show(dom_array(x)) ++ ", dom_array(a)=" ++ show(1..Q) ++ "\n") /\ let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)), int: n = max(index_set(x)) + 1, array[m..n] of var 1..Q: a, constraint a[m] = q0 /\ % Set a[0]. a[n] in F, % Check the final state is in F. constraint forall(i in index_set(x)) ( x[i] in 1..S % Do this in case it's a var. /\ %% trying to eliminate non-reachable states: let { set of int: va_R = { d[va, vx] | va in dom(a[i]), vx in dom(x[i]) } diff { 0 } %% Bug in MZN 2.0.4 } in a[i+1] in va_R ) } in let { constraint forall(i in [n-i | i in 1..length(x)]) ( a[i] in { va | va in dom(a[i]) where exists(vx in dom(x[i]))(d[va, vx] in dom(a[i+1])) } /\ x[i] in { vx | vx in dom(x[i]) where exists(va in dom(a[i]))(d[va, vx] in dom(a[i+1])) } ) } in let { array[int, int] of var int: eq_a=eq_encode(a), array[int, int] of var int: eq_x=eq_encode(x), } in forall(i in index_set(x)) ( let { set of int: va_R = { d[va, vx] | va in dom(a[i]), vx in dom(x[i]) } diff { 0 } %% Bug in MZN 2.0.4 } in my_trace(" S" ++ show(i) ++ ": dom(a[i])=" ++ show(dom(a[i])) ++ ", va_R="++show(va_R) ++ ", index_set_2of2(eq_a) diff va_R=" ++ show(index_set_2of2(eq_a) diff va_R) ++ ", dom(a[i+1])=" ++ show(dom(a[i+1])) ) /\ a[i+1] in va_R /\ forall (va in index_set_2of2(eq_a) diff va_R) (eq_a[i+1, va] == 0) %/\ a[i+1] in min(va_R)..max(va_R) ) /\ trace(" regular -- domains after prop: index_set(x)=" ++ show(index_set(x)) ++ ", dom_array(x)=" ++ show(dom_array(x)) ++ ", dom_array(a)=" ++ show(dom_array(a)) ++ "\n") /\ my_trace("\n") /\ forall(i in index_set(x)) ( % a[i+1] = d[a[i], x[i]] % Determine a[i+1]. if card(dom(a[i]))*card(dom(x[i])) > nMZN__UnarySizeMax_1step_regular then %% Implication decomposition: forall(va in dom(a[i]), vx in dom(x[i]))( if d[va, vx] in dom(a[i+1]) then eq_a[i+1, d[va, vx]] >= eq_a[i, va] + eq_x[i, vx] - 1 %% The only-if part of conj else 1 >= eq_a[i, va] + eq_x[i, vx] endif ) else %% Network-flow decomposition: %% {regularIP07} M.-C. C{\^o}t{\'e}, B.~Gendron, and L.-M. Rousseau. %% \newblock Modeling the regular constraint with integer programming. let { % array[int, int] of set of int: VX_a12 = %% set of x for given a1 that produce a2 % array2d(1..S, 1..Q, [ { vx | vx in 1..S where d[va1, vx]==va2 } | va1 in dom(a[i]), va2 in dom(a[i+1]) ]); array[int, int] of var int: ppAX = eq_encode(a[i], x[i]); } in forall (va2 in dom(a[i+1])) ( eq_a[i+1, va2] = sum(va1 in dom(a[i]), vx in dom(x[i]) where d[va1, vx]==va2) (ppAX[va1, vx]) ) /\ forall(va1 in dom(a[i]), vx in dom(x[i]))( if not (d[va1, vx] in dom(a[i+1])) then ppAX[va1, vx] == 0 else true endif ) endif ) )))))); libminizinc-2.0.11/share/minizinc/linear_new/redefinitions-2.0.2.mzn0000644000175000017500000000150412646030173023634 0ustar kaolkaol% This file contains redefinitions of standard builtins for version 2.0.2 % that can be overridden by solvers. predicate symmetry_breaking_constraint(var bool: b) = b; predicate redundant_constraint(var bool: b) = b; % = true; %% Linearized element: just call without shifting predicate array_var_bool_element_nonshifted(var int: idx, array[int] of var bool: x, var bool: c) = array_var_bool_element(idx,x,c); predicate array_var_int_element_nonshifted(var int: idx, array[int] of var int: x, var int: c) = array_var_int_element(idx,x,c); predicate array_var_float_element_nonshifted(var int: idx, array[int] of var float: x, var float: c) = array_var_float_element(idx,x,c); predicate array_var_set_element_nonshifted(var int: idx, array[int] of var set of int: x, var set of int: c) = array_var_set_element(idx,x,c); libminizinc-2.0.11/share/minizinc/linear_new/cumulative.mzn0000644000175000017500000001025212646030173022513 0ustar kaolkaol/** @group globals.scheduling Requires that a set of tasks given by start times \a s, durations \a d, and resource requirements \a r, never require more than a global resource bound \a b at any one time. Assumptions: - forall \p i, \a d[\p i] >= 0 and \a r[\p i] >= 0 Linear version. */ predicate cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", if mzn_in_redundant_constraint() /\ fMZN__IgnoreRedundantCumulative then true else let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = dom_array( [ s[i] | i in tasks ] ) } in my_trace(" cumul: times = " ++ show(times)) /\ if nMZN__UnarySizeMax_cumul>=card(times)*card(tasks) then %%% -- Mem overflow on rcmsp. PARAMETER? TODO cumulative_time_decomp(s, d, r, b, times) else cumulative_task_decomp(s, d, r, b) endif endif )); %% Can be called with a given set of times: predicate cumulative_set_times(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b, set of int: TIMES01) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = dom_array( [ s[i] | i in tasks ] ) intersect TIMES01 } in if false then %%% 100>=card(times) then %% PARAMETER ? cumulative_time_decomp(s, d, r, b, times) else cumulative_task_decomp(s, d, r, b) endif )); predicate cumulative_time_decomp(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b, set of int: TIMES01) = let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = { i | i in min([ lb(s[i]) | i in tasks ]) .. max([ ub(s[i]) + ub(d[i]) | i in tasks ]) where i in TIMES01 } } in my_trace(" cumul_time: " ++ show(card(tasks)) ++ " tasks, " ++ show(card(times)) ++ " times\n") /\ forall( t in times ) ( b >= sum( i in tasks ) ( if false then %% is_fixed(d[i]) then -- mem overflow on mspsp let { array[int] of var int: p = eq_encode(s[i]) } in %% should be up to 100 sum( t1 in dom(s[i]) where t1>t-d[i] /\ t1<=t ) ( p[t1] ) %% use unary encoding else bool2int( s[i] <= t /\ t < s[i] + d[i] ) endif * r[i] ) ); predicate cumulative_task_decomp(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 } } in trace(" cumul_tasks: " ++ show(card(tasks)) ++ " tasks\n") /\ forall( j in tasks) ( b-r[j] >= sum( i in tasks where i != j /\ lb(s[i])<=ub(s[j]) /\ lb(s[j])= 2*eq_encode(xx[i])[j] + eq_encode(xx[i])[u+1] + eq_encode(xx[u+1])[j] - 1 %% -1 /\ eq_encode(x[i])[j] >= eq_encode(xx[i])[j] /\ eq_encode(x[i])[j] <= eq_encode(xx[i])[j] + eq_encode(xx[i])[u+1] /\ eq_encode(x[i])[j] <= eq_encode(xx[i])[j] + eq_encode(xx[u+1])[j] ) /\ forall( i in S )( eq_encode(x[i])[i] == eq_encode(xx[i])[i] ) ; %% Should include at least 2 nodes if >0? %% xx[n] is dummy predicate subcircuit_wDummy(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), set of int: S__ = S diff {u}, %% the real nodes array[S__] of var 2..n: order, %% constraint order[n]==1, %% fix the dummy %% var bool: empty = (firstin == u+1), no, break 2-cycles with dummy } in alldifferent(x) /\ % NO alldifferent(order) /\ %%% MTZ model. Note that INTEGER order vars seem better!: forall( i in S__, j in dom(x[i]) where i!=j /\ j!=u )( order[i] - order[j] + (n-1)*eq_encode(x[i])[j] % + (n-3)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term % --- strangely enough it is much worse on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn! <= n-2 ) /\ %% Break 2-cycles with dummy: forall( i in S__ )( eq_encode(x[i])[u] + eq_encode(x[u])[i] <= 1 /\ %% Ensure dummy is in: if i in dom(x[i]) then eq_encode(x[i])[i] >= eq_encode(x[u])[u] else true endif ) /\ % Symmetry? Each node that is not in is numbered after the lastin node. forall(i in S) ( true % (not ins[i]) <-> (n == order[i]) ) ; predicate subcircuit_reif(array[int] of var int: x, var bool: b) = abort("Reified subcircuit/1 is not supported."); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear_new/table_int.mzn0000644000175000017500000000160612646030173022301 0ustar kaolkaol%-----------------------------------------------------------------------------% % A 'table' constraint table(x, T) represents the constraint x in T where we % consider each row in T to be a tuple and T as a set of tuples. % % Linear version. % % See also the equality encoding of the 'element' constraint. %-----------------------------------------------------------------------------% predicate table_int(array[int] of var int: x, array[int, int] of int: t) = assert(index_set_2of2(t) = index_set(x), "The second dimension of the table must equal the number of " ++ "variables in the first argument", let { set of int: it = index_set_1of2(t), array[it] of var 0..1: lambda } in sum(lambda) = 1 /\ forall(j in index_set(x))( sum(i in it)( t[i,j]*lambda[i] ) = x[j] ) ); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/linear_new/alldifferent_except_0.mzn0000644000175000017500000000113212646030173024560 0ustar kaolkaol/** @group globals.alldifferent Constrain the array of integers \a vs to be all different except those elements that are assigned the value 0. */ predicate alldifferent_except_0(array[int] of var int: vs) = % forall(i, j in index_set(vs) where i < j) ( % (vs[i] != 0 /\ vs[j] != 0) -> vs[i] != vs[j] % ); let { array[int,int] of var 0..1: x_eq_d = eq_encode(vs) } in ( my_trace(" alldifferent_except_0: x[" ++ show(index_set(vs)) ++ "]\n") /\ forall(d in index_set_2of2(x_eq_d) diff {0})( sum(i in index_set_1of2(x_eq_d))( x_eq_d[i,d] ) <= 1 ) ); libminizinc-2.0.11/share/minizinc/linear_new/circuit.mzn0000644000175000017500000000303012646030173021773 0ustar kaolkaolinclude "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a circuit where \a x[\p i] = \p j means that \p j is the successor of \p i. */ % Linear version. predicate circuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: n = card(S), % array[S] of var 1..n: order array[l+1..l+n-1] of var 2..n: order } in alldifferent(x) /\ forall(i in S)(x[i] != i) /\ % alldifferent(order) /\ % order[l] = 1 /\ % forall(i in l+1..l+n)(order[i] != n -> order[x[i]] = order[i] + 1) /\ % forall(i in l+1..l+n)(order[i] == n -> x[i] = l ) /\ %%% MTZ model. Note that INTEGER order vars seem better!: forall (i,j in l+1..l+n-1 where i!=j /\ j in dom(x[i])) ( order[i] - order[j] + (n-1)* %eq_encode(x[i])[j] bool2int(x[i]==j) % + (n-3)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term % --- strangely enough it is much worse on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn! <= n-2 ) %% much stronger bound & better feasible solution (although initially not so fast), %% less memory, but optimality proof much longer... % /\ forall (i,j in S where i set of 1..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). */ predicate regular_nfa(array[int] of var int: x, int: Q, int: S, array[int,int] of set of int: d, int: q0, set of int: F) = assert(Q > 0, "regular_nfa: 'Q' must be greater than zero", assert(S > 0, "regular_nfa: 'S' must be greater than zero", assert(index_set_1of2(d) = 1..Q /\ index_set_2of2(d) == 1..S, "regular_nfa: the transition function 'd' must be [1..Q,1..S]", assert(forall([d[i, j] subset 1..Q | i in 1..Q, j in 1..S]), "regular_nfa: transition function 'd' points to states outside 1..Q", % Nb: we need the parentheses around the expression otherwise the % parser thinks it's a generator call! assert((q0 in 1..Q), "regular: start state 'q0' not in 1..Q", assert(F subset 1..Q, "regular: final states in 'F' contain states outside 1..Q", let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)), int: n = max(index_set(x)) + 1, array[m..n] of var 1..Q: a } in a[m] = q0 /\ % Set a[0]. forall(i in index_set(x)) ( x[i] in 1..S /\ % Do this in case it's a var. a[i+1] in d[a[i], x[i]] % Determine a[i+1]. ) /\ a[n] in F % Check the final state is in F. )))))) ;libminizinc-2.0.11/share/minizinc/std/table_bool.mzn0000644000175000017500000000274112646030173021112 0ustar kaolkaol%-----------------------------------------------------------------------------% % A table constraint: table(x, t) represents the constraint x in t where we % consider each row in t to be a tuple and t as a set of tuples. %-----------------------------------------------------------------------------% predicate table_bool(array[int] of var bool: x, array[int, int] of bool: t) = assert (index_set_2of2(t) == index_set(x), "The second dimension of the table must equal the number of variables " ++ "in the first argument", let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: lt = min(index_set_1of2(t)), int: ut = max(index_set_1of2(t)), var lt..ut: i, array[l..u, lt..ut] of bool: t_transposed = array2d(l..u, lt..ut, [ t[i,j] | j in l..u, i in lt..ut ]) } in forall(j in l..u) ( % Having the variable index component at the left position % means that the nD-to-1D array translation during Mzn-to-Fzn % will generate at most an offset constraint, instead of a % scaling + offset constraint. % t_transposed[j,i] = x[j] % % t[i,j] = x[j] ) ); predicate table_bool_reif(array[int] of var bool: x, array[int, int] of bool: t, var bool: b) = abort("Reified table/2 for Booleans is not supported."); libminizinc-2.0.11/share/minizinc/std/all_equal_set.mzn0000644000175000017500000000016612646030173021621 0ustar kaolkaolpredicate all_equal_set(array[int] of var set of int: x) = forall(i, j in index_set(x) where i < j) ( x[i] = x[j] ); libminizinc-2.0.11/share/minizinc/std/lex_less_int.mzn0000644000175000017500000000323512646030173021477 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_less_int(array[int] of var int: x, array[int] of var int: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); predicate lex_less_int_reif(array[int] of var int: x, array[int] of var int: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); predicate lex_lt_int(array[int] of var int: x, array[int] of var int: y) = lex_less(x, y); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/atleast.mzn0000644000175000017500000000022412646030173020437 0ustar kaolkaol% The actual definitions are in at_least.mzn. % This file is used to handle the case where users include % "atleast.mzn"; % include "at_least.mzn"; libminizinc-2.0.11/share/minizinc/std/sliding_sum.mzn0000644000175000017500000000105212646030173021317 0ustar kaolkaol/** @group globals Requires that in each subsequence \a vs[\p i], ..., \a vs[\p i + \a seq - 1] the sum of the values belongs to the interval [\a low, \a up]. */ predicate sliding_sum(int: low, int: up, int: seq, array[int] of var int: vs) = let { int: lx = min(index_set(vs)), int: ux = max(index_set(vs)), } in forall (i in lx .. ux - seq + 1) ( let { var int: sum_of_l = sum(j in i..i + seq - 1) (vs[j]) } in low <= sum_of_l /\ sum_of_l <= up ); libminizinc-2.0.11/share/minizinc/std/increasing_set.mzn0000644000175000017500000000057012646030173022003 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate increasing_set(array[int] of var set of int: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.0.11/share/minizinc/std/value_precede_chain_int.mzn0000644000175000017500000000034112646030173023621 0ustar kaolkaolinclude "value_precede.mzn"; predicate value_precede_chain_int(array[int] of int: c, array[int] of var int: x) = forall (i in min(index_set(c)) + 1 .. max(index_set(c))) ( value_precede(c[i - 1], c[i], x) ); libminizinc-2.0.11/share/minizinc/std/element_int.mzn0000644000175000017500000000046212646030173021311 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% predicate element_int(var int: i, array[int] of var int: x, var int: y) = y = x[i]; libminizinc-2.0.11/share/minizinc/std/global_cardinality_fn.mzn0000644000175000017500000000063512646030173023316 0ustar kaolkaolinclude "global_cardinality.mzn"; /** @group globals.counting Returns the number of occurrences of \a cover[\p i] in \a x. */ function array[int] of var int: global_cardinality(array[int] of var int: x, array[int] of int: cover) :: promise_total = let { array[index_set(cover)] of var 0..length(x): counts; constraint global_cardinality(x,cover,counts) } in counts; libminizinc-2.0.11/share/minizinc/std/member_bool.mzn0000644000175000017500000000050212646030173021263 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate member_bool(array[int] of var bool: x, var bool: y) = exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.0.11/share/minizinc/std/subcircuit.mzn0000644000175000017500000000355712646030173021172 0ustar kaolkaolinclude "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a subcircuit where \a x[\p i] = \p j means that \p j is the successor of \p i and \a x[\p i] = \p i means that \p i is not in the circuit. */ predicate subcircuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), array[S] of var 1..n: order, array[S] of var bool: ins = array1d(S,[ x[i] != i | i in S]), var l..u+1: firstin = min([ u+1 + bool2int(ins[i])*(i-u-1) | i in S]), var S: lastin, var bool: empty = (firstin > u), } in alldifferent(x) /\ alldifferent(order) /\ % If the subcircuit is empty then each node points at itself. % (empty -> forall(i in S)(not ins[i])) /\ % If the subcircuit is non-empty then order numbers the subcircuit. % ((not empty) -> % The firstin node is numbered 1. order[firstin] = 1 /\ % The lastin node is greater than firstin. lastin > firstin /\ % The lastin node points at firstin. x[lastin] = firstin /\ % And both are in ins[lastin] /\ ins[firstin] /\ % The successor of each node except where it is firstin is % numbered one more than the predecessor. forall(i in S) ( (ins[i] /\ x[i] != firstin) -> order[x[i]] = order[i] + 1 ) /\ % Each node that is not in is numbered after the lastin node. forall(i in S) ( ins[i] \/ order[lastin] < order[i] ) ); predicate subcircuit_reif(array[int] of var int: x, var bool: b) = abort("Reified subcircuit/1 is not supported."); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/count_eq.mzn0000644000175000017500000000060312646030173020620 0ustar kaolkaol/** @group globals.counting Constrains \a c to be the number of occurrences of \a y in \a x. */ predicate count_eq(array[int] of var int: x, var int: y, var int: c) = c = sum(i in index_set(x)) ( bool2int(x[i] == y) ); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/lex2.mzn0000644000175000017500000000154612646030173017664 0ustar kaolkaolinclude "lex_lesseq.mzn"; /** @group globals.lexicographic Require adjacent rows and adjacent columns in the array \a x to be lexicographically ordered. Adjacent rows and adjacent columns may be equal. */ predicate lex2(array[int, int] of var int: x) = let { int: lbx1 = min(index_set_1of2(x)), int: ubx1 = max(index_set_1of2(x)), int: lbx2 = min(index_set_2of2(x)), int: ubx2 = max(index_set_2of2(x)) } in ( forall(i in lbx1 + 1 .. ubx1) ( lex_lesseq([x[i - 1, j] | j in index_set_2of2(x)], [x[i, j] | j in index_set_2of2(x)] ) ) /\ forall(j in lbx2 + 1 .. ubx2) ( lex_lesseq([x[i, j - 1] | i in index_set_1of2(x)], [x[i, j ] | i in index_set_1of2(x)] ) ) ); libminizinc-2.0.11/share/minizinc/std/strict_lex2.mzn0000644000175000017500000000154612646030173021254 0ustar kaolkaolinclude "lex_less.mzn"; /** @group globals.lexicographic Require adjacent rows and adjacent columns in the array \a x to be lexicographically ordered. Adjacent rows and adjacent columns cannot be equal. */ predicate strict_lex2(array[int, int] of var int: x) = let { int: lbx1 = min(index_set_1of2(x)), int: ubx1 = max(index_set_1of2(x)), int: lbx2 = min(index_set_2of2(x)), int: ubx2 = max(index_set_2of2(x)) } in ( forall(i in lbx1 + 1 .. ubx1) ( lex_less([x[i - 1, j] | j in index_set_2of2(x)], [x[i, j] | j in index_set_2of2(x)] ) ) /\ forall(j in lbx2 + 1 .. ubx2) ( lex_less([x[i, j - 1] | i in index_set_1of2(x)], [x[i, j ] | i in index_set_1of2(x)] ) ) ); libminizinc-2.0.11/share/minizinc/std/range.mzn0000644000175000017500000000137512646030173020106 0ustar kaolkaol/** @group globals Requires that the image of function \a x (represented as an array) on set of values \a s is \a t. ub(\a s) must be a subset of index_set(\a x) otherwise an assertion failure will occur. */ predicate range(array[int] of var int: x, var set of int: s, var set of int: t) = assert(ub(s) subset index_set(x), "range: upper bound of 's' must be a subset of the index set of 'x'", % All values in 's' must map to a value in 't'. forall(i in ub(s)) ( i in s -> x[i] in t ) /\ % All values in 't' must be mapped from a value in 's'. forall(i in ub(t)) ( i in t -> exists(j in ub(s)) ( j in s /\ x[j] == i ) ) ); libminizinc-2.0.11/share/minizinc/std/global_cardinality_closed.mzn0000644000175000017500000000132312646030173024157 0ustar kaolkaol/** @group globals.counting Requires that the number of occurences of \p i in \a x is \a counts[\p i]. The elements of \a x must take their values from \a cover. */ predicate global_cardinality_closed(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts) = assert(index_set(cover) = index_set(counts), "global_cardinality_closed: " ++ "cover and counts must have identical index sets", forall(i in index_set(x))( x[i] in { d | d in cover } ) /\ global_cardinality(x, cover, counts) /\ % Implied constraint length(x) = sum(counts) ); include "global_cardinality.mzn"; libminizinc-2.0.11/share/minizinc/std/comparison_rel_array.mzn0000644000175000017500000000230712646030173023220 0ustar kaolkaol%-----------------------------------------------------------------------------% % Reflect an array of comparison values onto a comparison value variable using % a lexicographic interpretation of the array. The comparison values are % encoded as follows: > | = | < as -1 | 0 | +1. % Uses of this constraint are generated by Cadmium transformations that % simplify ordering constraints on expressions of complex types. %-----------------------------------------------------------------------------% predicate comparison_rel_array(array[int] of var -1..1: rels, var -1..1: rel) = let { int: l = min(index_set(rels)), int: u = max(index_set(rels)), array[l-1..u] of var -1..1: r } in r[l-1] = 0 % initial state (before first array position) is 'equal' /\ forall (i in l..u) ( % new state: as given array at current position if % previous state is 'equal', otherwise previous state % % r[i] = (if r[i-1] = 0 then rels[i] else r[i-1] endif) (r[i-1] = 0 -> r[i] = rels[i]) /\ (r[i-1] != 0 -> r[i] = r[i-1]) ) /\ r[u] = rel; % final state (at last array position) libminizinc-2.0.11/share/minizinc/std/knapsack.mzn0000644000175000017500000000210012646030173020570 0ustar kaolkaol/** @group globals.packing Requires that items are packed in a knapsack with certain weight and profit restrictions. Assumptions: - Weights \a w and profits \a p must be non-negative - \a w, \a p and \a x must have the same index sets @param w: weight of each type of item @param p: profit of each type of item @param x: number of items of each type that are packed @param W: sum of sizes of all items in the knapsack @param P: sum of profits of all items in the knapsack */ predicate knapsack(array[int] of int: w, array[int] of int:p, array[int] of var int:x, var int: W, var int: P) = assert(index_set(w) = index_set(p) /\ index_set(w) = index_set(x), "index set of weights must be equal to index set of profits and index set of items", assert(lb_array(w) >= 0, "weights must be non-negative", assert(lb_array(p) >= 0, "profits must be non-negative", forall (i in index_set(x)) (x[i] >= 0) /\ W >= 0 /\ P >= 0 /\ P = sum(i in index_set(p)) (x[i]*p[i]) /\ W = sum(i in index_set(w)) (x[i]*w[i]) ))); libminizinc-2.0.11/share/minizinc/std/count_fn.mzn0000644000175000017500000000037112646030173020620 0ustar kaolkaolinclude "count.mzn"; /** @group globals.counting Returns the number of occurrences of \a y in \a x. */ function var int: count(array[int] of var int: x, var int: y) ::promise_total = let { var 0..length(x): c; constraint count(x,y,c); } in c; libminizinc-2.0.11/share/minizinc/std/all_different.mzn0000644000175000017500000000115512646030173021604 0ustar kaolkaolinclude "all_different_int.mzn"; include "all_different_set.mzn"; /** @group globals.alldifferent Constrain the array of integers \a x to be all different. */ predicate all_different(array[int] of var int: x) = all_different_int(x); /** @group globals.alldifferent Constrain the array of sets of integers \a x to be all different. */ predicate all_different(array[int] of var set of int: x) = all_different_set(x); % Synonyms for the above. predicate alldifferent(array[int] of var int: x) = all_different_int(x); predicate alldifferent(array[int] of var set of int: x) = all_different_set(x); libminizinc-2.0.11/share/minizinc/std/lex_less_bool.mzn0000644000175000017500000000325012646030173021635 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_less_bool(array[int] of var bool: x, array[int] of var bool: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); predicate lex_less_bool_reif(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); predicate lex_lt_bool(array[int] of var bool: x, array[int] of var bool: y) = lex_less(x, y); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/arg_max.mzn0000644000175000017500000000335012646030173020423 0ustar kaolkaol/** @group globals Returns the index of the maximum value in the array \a x. When breaking ties the least index is returned. */ function var int: arg_max(array[int] of var int: x) = let { constraint length(x) > 0; } in arg_max_total(x); /** @group globals Returns the index of the maximum value in the array \a x. When breaking ties the least index is returned. */ function var int: arg_max(array[int] of var float: x) = let { constraint length(x) > 0; } in arg_max_total(x); function var int: arg_max_total(array[int] of var int: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint maximum_arg_int(x, i); } in i endif; function var int: arg_max_total(array[int] of var float: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint maximum_arg_float(x, i); } in i endif; include "arg_max_int.mzn"; /** @group globals Constrain \a i to be the index of the maximum value in the array \a x. When breaking ties the least index is returned. Assumption: |x| > 0 */ predicate maximum_arg(array[int] of var int: x, var int: i) = maximum_arg_int(x, i); include "arg_max_float.mzn"; /** @group globals Constrain \a i to be the index of the maximum value in the array \a x. When breaking ties the least index is returned. Assumption: |x| > 0 */ predicate maximum_arg(array[int] of var float: x, var int: i) = maximum_arg_float(x, i); libminizinc-2.0.11/share/minizinc/std/among_fn.mzn0000644000175000017500000000044612646030173020574 0ustar kaolkaolinclude "among.mzn"; /** @group globals.counting Returns the number of variables in \a x that take one of the values in \a v. */ function var int: among(array[int] of var int:x, set of int:v) :: promise_total = let { var 0..length(x): n; constraint among(n,x,v); } in n; libminizinc-2.0.11/share/minizinc/std/member_int.mzn0000644000175000017500000000047712646030173021135 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate member_int(array[int] of var int: x, var int: y) = exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.0.11/share/minizinc/std/partition_set.mzn0000644000175000017500000000045312646030173021672 0ustar kaolkaolinclude "all_disjoint.mzn"; /** @group globals Constrains the sets in array \a S to partition the \a universe. */ predicate partition_set(array[int] of var set of int: S, set of int: universe) = all_disjoint(S) /\ universe == array_union(i in index_set(S)) ( S[i] ); libminizinc-2.0.11/share/minizinc/std/at_most1.mzn0000644000175000017500000000052612646030173020536 0ustar kaolkaol/** @group globals.counting Requires that each pair of sets in \a s overlap in at most one element. */ predicate at_most1(array[int] of var set of int: s) = forall(i,j in index_set(s) where i < j) ( card(s[i] intersect s[j]) <= 1 ); % Synonym for the above. predicate atmost1(array[int] of var set of int: s) = at_most1(s); libminizinc-2.0.11/share/minizinc/std/global_cardinality.mzn0000644000175000017500000000105512646030173022630 0ustar kaolkaolinclude "count.mzn"; /** @group globals.counting Requires that the number of occurrences of \a cover[\p i] in \a x is \a counts[\p i]. */ predicate global_cardinality(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts) = assert(index_set(cover) = index_set(counts), "global_cardinality: cover and counts must have identical index sets", forall(i in index_set(cover))( count(x, cover[i], counts[i]) ) /\ % Implied constraint length(x) >= sum(counts) ); libminizinc-2.0.11/share/minizinc/std/value_precede_int.mzn0000644000175000017500000000072712646030173022467 0ustar kaolkaolpredicate value_precede_int(int: s, int: t, array[int] of var int: x) = let { int: imin = min(index_set(x)), int: imax = max(index_set(x)), array[imin..imax+1] of var bool: b } in ( forall (i in imin..imax) (let { var bool: xis = (x[i] == s) } in (xis -> (b[i+1] == true)) /\ ((not xis) -> (b[i] == b[i+1])) /\ ((not b[i]) -> (x[i] != t)) ) /\ b[imin] == false ); libminizinc-2.0.11/share/minizinc/std/lex_greater.mzn0000644000175000017500000000242312646030173021306 0ustar kaolkaolinclude "lex_less.mzn"; /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically greater than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greater(array[int] of var bool: x, array[int] of var bool: y) = lex_less(y, x); /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically greater than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greater(array[int] of var int: x, array[int] of var int: y) = lex_less(y, x); /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically greater than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greater(array[int] of var float: x, array[int] of var float: y) = lex_less(y, x); /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically greater than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greater(array[int] of var set of int: x, array[int] of var set of int: y) = lex_less(y, x); libminizinc-2.0.11/share/minizinc/std/redefinitions.mzn0000644000175000017500000000013512646030173021645 0ustar kaolkaol% This file contains redefinitions of standard builtins that can be overridden % by solvers. libminizinc-2.0.11/share/minizinc/std/decreasing_set.mzn0000644000175000017500000000057012646030173021765 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate decreasing_set(array[int] of var set of int: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.0.11/share/minizinc/std/distribute_fn.mzn0000644000175000017500000000073012646030173021645 0ustar kaolkaolinclude "distribute.mzn"; /** @group globals.counting Returns an array of the number of occurences of \a value[\p i] in \a base. The values in \a value need not be distinct. */ function array[int] of var int: distribute(array[int] of var int: value, array[int] of var int: base) :: promise_total = let { array[index_set(value)] of var 0..length(base): card; constraint distribute(card, value, base); } in card; libminizinc-2.0.11/share/minizinc/std/decreasing_float.mzn0000644000175000017500000000056412646030173022302 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate decreasing_float(array[int] of var float: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.0.11/share/minizinc/std/symmetric_all_different.mzn0000644000175000017500000000052212646030173023675 0ustar kaolkaolinclude "all_different.mzn"; /** @group globals.alldifferent Requires the array of integers \a x to be all different, and for all \p i, \a x[\p i]=j \(\rightarrow\) \a x[\p j]=i. */ predicate symmetric_all_different(array[int] of var int:x) = all_different(x) /\ forall(i, j in index_set(x) where i!=j) (x[i] = j -> x[j] = i); libminizinc-2.0.11/share/minizinc/std/at_most_int.mzn0000644000175000017500000000053412646030173021326 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires at most 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate at_most_int(int: n, array[int] of var int: x, int: v) = sum(i in index_set(x)) ( bool2int(x[i] == v) ) <= n; libminizinc-2.0.11/share/minizinc/std/disjunctive_strict.mzn0000644000175000017500000000124212646030173022722 0ustar kaolkaol/** @group globals.scheduling Requires that a set of tasks given by start times \a s and durations \a d do not overlap in time. Tasks with duration 0 CANNOT be scheduled at any time, but only when no other task is running. Assumptions: - forall \p i, \a d[\p i] >= 0 */ predicate disjunctive_strict(array[int] of var int: s, array[int] of var int: d) = assert(index_set(s) == index_set(d), "disjunctive: the array arguments must have identical index sets", forall (i in index_set(d)) (d[i] >= 0) /\ forall (i,j in index_set(d) where i= n; libminizinc-2.0.11/share/minizinc/std/at_least_int.mzn0000644000175000017500000000053612646030173021456 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires at least 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate at_least_int(int: n, array[int] of var int: x, int: v) = sum(i in index_set(x)) ( bool2int(x[i] == v) ) >= n; libminizinc-2.0.11/share/minizinc/std/count_geq.mzn0000644000175000017500000000064012646030173020770 0ustar kaolkaol/** @group globals.counting Constrains \a c to be greater than or equal to the number of occurrences of \a y in \a x. */ predicate count_geq(array[int] of var int: x, var int: y, var int: c) = c >= sum(i in index_set(x)) ( bool2int(x[i] == y) ); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/lex_lesseq_int.mzn0000644000175000017500000000356112646030173022027 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_lesseq_int(array[int] of var int: x, array[int] of var int: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ if i = size then true else x[lx + i] < y[ly + i] \/ b[i+1] endif ) ); predicate lex_lesseq_int_reif(array[int] of var int: x, array[int] of var int: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ if i = size then true else x[lx + i] < y[ly + i] \/ b[i+1] endif ) ); predicate lex_leq_int(array[int] of var int: x, array[int] of var int: y) = lex_lesseq(x, y); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/diffn_nonstrict.mzn0000644000175000017500000000146512646030173022203 0ustar kaolkaol/** @group globals.packing Constrains rectangles \p i, given by their origins (\a x[\p i], \a y[\p i]) and sizes (\a dx[\p i], \a dy[\p i]), to be non-overlapping. Zero-width rectangles can be packed anywhere. */ predicate diffn_nonstrict(array[int] of var int: x, array[int] of var int: y, array[int] of var int: dx, array[int] of var int: dy) = assert( index_set(x) = index_set(y) /\ index_set(x) = index_set(dx) /\ index_set(x) = index_set(dy), "diffn: index set mismatch", forall(i,j in index_set(x) where i < j)( dx[i] = 0 \/ dx[j] = 0 \/ dy[i]=0 \/ dy[j]=0 \/ x[i] + dx[i] <= x[j] \/ y[i] + dy[i] <= y[j] \/ x[j] + dx[j] <= x[i] \/ y[j] + dy[j] <= y[i] ) ); libminizinc-2.0.11/share/minizinc/std/lex_lesseq_float.mzn0000644000175000017500000000361312646030173022340 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_lesseq_float(array[int] of var float: x, array[int] of var float: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ if i = size then true else x[lx + i] < y[ly + i] \/ b[i+1] endif ) ); predicate lex_lesseq_float_reif(array[int] of var float: x, array[int] of var float: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ if i = size then true else x[lx + i] < y[ly + i] \/ b[i+1] endif ) ); predicate lex_leq_float(array[int] of var float: x, array[int] of var float: y) = lex_lesseq(x, y); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/lex_less_set.mzn0000644000175000017500000000211512646030173021474 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_less_set(array[int] of var set of int: x, array[int] of var set of int: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); predicate lex_lt_set(array[int] of var set of int: x, array[int] of var set of int: y) = lex_less(x, y); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/decreasing_bool.mzn0000644000175000017500000000056212646030173022126 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate decreasing_bool(array[int] of var bool: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.0.11/share/minizinc/std/inverse.mzn0000644000175000017500000000073312646030173020462 0ustar kaolkaol/** @group globals.channeling Constrains two arrays of int variables, \a f and \a invf, to represent inverse functions. All the values in each array must be within the index set of the other array. */ predicate inverse(array[int] of var int: f, array[int] of var int: invf) = forall(i in index_set(f), j in index_set(invf)) ( f[i] in index_set(invf) /\ invf[j] in index_set(f ) /\ (j == f[i] <-> i == invf[j]) ); libminizinc-2.0.11/share/minizinc/std/cumulative_opt.mzn0000644000175000017500000000251712646030173022051 0ustar kaolkaol/** @group globals.scheduling Requires that a set of tasks given by start times \a s, durations \a d, and resource requirements \a r, never require more than a global resource bound \a b at any one time. Start times are optional variables, so that absent tasks do not need to be scheduled. Assumptions: - forall \p i, \a d[\p i] >= 0 and \a r[\p i] >= 0 */ predicate cumulative(array[int] of var opt int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = min([ lb(s[i]) | i in tasks ]) .. max([ ub(s[i]) + ub(d[i]) | i in tasks ]) } in forall( t in times ) ( b >= sum( i in tasks ) ( bool2int( occurs(s[i]) /\ deopt(s[i]) <= t /\ t < deopt(s[i]) + d[i] ) * r[i] ) ) ) ); libminizinc-2.0.11/share/minizinc/std/arg_min_int.mzn0000644000175000017500000000073712646030173021301 0ustar kaolkaolpredicate minimum_arg_int(array[int] of var int: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); int: ly = lb_array(x); int: uy = ub_array(x); array[l..u] of var ly..uy: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == min(x[j],y[j-1]) /\ mi[j] = if y[j-1] <= x[j] then mi[j-1] else j endif ); libminizinc-2.0.11/share/minizinc/std/inverse_set.mzn0000644000175000017500000000114612646030173021334 0ustar kaolkaol/** @group globals.channeling Constrains two arrays of set of int variables, \a f and \a invf, so that a \p j in f[\p i] iff \p i in invf[\p j]. All the values in each array's sets must be within the index set of the other array. */ predicate inverse_set(array[int] of var set of int: f, array[int] of var set of int: invf) = forall(i in index_set(f)) ( f[i] subset index_set(invf) ) /\ forall(j in index_set(invf)) ( invf[j] subset index_set(f) ) /\ forall(i in index_set(f), j in index_set(invf)) ( (j in f[i] <-> i in invf[j]) ); libminizinc-2.0.11/share/minizinc/std/global_cardinality_closed_fn.mzn0000644000175000017500000000077012646030173024647 0ustar kaolkaolinclude "global_cardinality_closed.mzn"; /** @group globals.counting Returns an array with number of occurences of \p i in \a x. The elements of \a x must take their values from \a cover. */ function array[int] of var int: global_cardinality_closed(array[int] of var int: x, array[int] of int: cover) :: promise_total = let { array[index_set(cover)] of var 0..length(x): counts; constraint global_cardinality_closed(x,cover,counts); } in counts; libminizinc-2.0.11/share/minizinc/std/distribute.mzn0000644000175000017500000000117212646030173021163 0ustar kaolkaol/** @group globals.counting Requires that \a card[\p i] is the number of occurences of \a value[\p i] in \a base. The values in \a value need not be distinct. */ predicate distribute(array[int] of var int: card, array[int] of var int: value, array[int] of var int: base) = assert(index_set(card) == index_set(value), "distribute: card and value arrays must have identical index sets", forall (i in index_set(card)) ( card[i] == sum(j in index_set(base)) ( bool2int(value[i] = base[j]) ) ) ); libminizinc-2.0.11/share/minizinc/std/table.mzn0000644000175000017500000000104612646030173020074 0ustar kaolkaolinclude "table_bool.mzn"; include "table_int.mzn"; /** @group globals.extensional Represents the constraint \a x in \a t where we consider each row in \a t to be a tuple and \a t as a set of tuples. */ predicate table(array[int] of var bool: x, array[int, int] of bool: t) = table_bool(x, t); /** @group globals.extensional Represents the constraint \a x in \a t where we consider each row in \a t to be a tuple and \a t as a set of tuples. */ predicate table(array[int] of var int: x, array[int, int] of int: t) = table_int(x, t); libminizinc-2.0.11/share/minizinc/std/at_most.mzn0000644000175000017500000000122312646030173020450 0ustar kaolkaolinclude "at_most_int.mzn"; include "at_most_set.mzn"; /** @group globals.counting Requires at most \a n variables in \a x to take the value \a v. */ predicate at_most(int: n, array[int] of var int: x, int: v) = at_most_int(n, x, v); /** @group globals.counting Requires at most \a n variables in \a x to take the value \a v. */ predicate at_most(int: n, array[int] of var set of int: x, set of int: v) = at_most_set(n, x, v); % Synonyms for the above. predicate atmost(int: n, array[int] of var int: x, int: v) = at_most_int(n, x, v); predicate atmost(int: n, array[int] of var set of int: x, set of int: v) = at_most_set(n, x, v); libminizinc-2.0.11/share/minizinc/std/arg_max_int.mzn0000644000175000017500000000073712646030173021303 0ustar kaolkaolpredicate maximum_arg_int(array[int] of var int: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); int: ly = lb_array(x); int: uy = ub_array(x); array[l..u] of var ly..uy: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == max(x[j],y[j-1]) /\ mi[j] = if y[j-1] >= x[j] then mi[j-1] else j endif ); libminizinc-2.0.11/share/minizinc/std/roots_fn.mzn0000644000175000017500000000047312646030173020641 0ustar kaolkaolinclude "roots.mzn"; /** @group globals Returns \a s such that \a x[\p i] in \a t for all \p i in \a s */ function var set of int: roots(array[int] of var int: x, var set of int: t) :: promise_total = let { var set of index_set(x): s; constraint roots(x,s,t) } in s; libminizinc-2.0.11/share/minizinc/std/all_equal.mzn0000644000175000017500000000061312646030173020743 0ustar kaolkaolinclude "all_equal_int.mzn"; include "all_equal_set.mzn"; /** @group globals.alldifferent Constrain the array of integers \a x to be all equal */ predicate all_equal(array[int] of var int: x) = all_equal_int(x); /** @group globals.alldifferent Constrain the array of sets of integers \a x to be all different */ predicate all_equal(array[int] of var set of int: x) = all_equal_set(x); libminizinc-2.0.11/share/minizinc/std/count_leq.mzn0000644000175000017500000000063512646030173021001 0ustar kaolkaol/** @group globals.counting Constrains \a c to be less than or equal to the number of occurrences of \a y in \a x. */ predicate count_leq(array[int] of var int: x, var int: y, var int: c) = c <= sum(i in index_set(x)) ( bool2int(x[i] == y) ); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/all_different_int.mzn0000644000175000017500000000052212646030173022453 0ustar kaolkaol%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate all_different_int(array[int] of var int: x) = forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); libminizinc-2.0.11/share/minizinc/std/flatzinc_builtins.mzn0000644000175000017500000003403212646030173022531 0ustar kaolkaol%-----------------------------------------------------------------------------% % % FlatZinc builtins % % This section contains declarations for the standard FlatZinc builtins. % They can be redefined by providing a custom redefinitions.mzn in the % solver globals library. % /*** @groupdef flatzinc FlatZinc builtins These are the standard constraints that need to be supported by FlatZinc solvers (or redefined in the redefinitions.mzn file). */ % Integer constraints /** @group flatzinc Constrains \a b to be the absolute value of \a a */ predicate int_abs(var int: a, var int: b); /** @group flatzinc Constrains \a a to be equal to \a b */ predicate int_eq(var int: a, var int: b); /** @group flatzinc Constrains (\a a=\a b) ↔ \a r */ predicate int_eq_reif(var int: a, var int: b, var bool: r); /** @group flatzinc Constrains \a a to be less than or equal to \a b */ predicate int_le(var int: a, var int: b); /** @group flatzinc Constrains (\a a ≤ \a b) ↔ \a r */ predicate int_le_reif(var int: a, var int: b, var bool: r); /** @group flatzinc Constrains \( \a c = \sum_i \a as[i]*\a bs[i] \) */ predicate int_lin_eq(array[int] of int: as, array[int] of var int: bs, int: c); /** @group flatzinc Constrains \( \a r \leftrightarrow (\a c = \sum_i \a as[i]*\a bs[i]) \) */ predicate int_lin_eq_reif(array[int] of int: as, array[int] of var int: bs,int: c, var bool: r); /** @group flatzinc Constrains \( \a c \neq \sum_i \a as[i]*\a bs[i] \) */ predicate int_lin_ne(array[int] of int: as, array[int] of var int: bs, int: c); /** @group flatzinc Constrains \( \a r \leftrightarrow (\a c \neq \sum_i \a as[i]*\a bs[i]) \) */ predicate int_lin_ne_reif(array[int] of int: as, array[int] of var int: bs,int: c, var bool: r); /** @group flatzinc Constrains Σ \a as[\p i]*\a bs[\p i] ≤ \a c */ predicate int_lin_le(array[int] of int: as, array[int] of var int: bs, int: c); /** @group flatzinc Constrains \a r ↔ (Σ \a as[\p i]*\a bs[\p i] ≤ \a c) */ predicate int_lin_le_reif(array[int] of int: as, array[int] of var int: bs,int: c, var bool: r); /** @group flatzinc Constrains \a a ≠ \a b */ predicate int_ne(var int: a, var int: b); /** @group flatzinc \a r ↔ (\a a ≠ \a b) */ predicate int_ne_reif(var int: a, var int: b, var bool: r); /** @group flatzinc Constrains \a a + \a b = \a c */ predicate int_plus(var int: a, var int: b, var int: c); /** @group flatzinc Constrains \a a / \a b = \a c */ predicate int_div(var int: a, var int: b, var int: c); /** @group flatzinc Constrains \a a < \a b */ predicate int_lt(var int: a, var int: b); /** @group flatzinc Constrains \a r ↔ (\a a < \a b) */ predicate int_lt_reif(var int: a, var int: b, var bool: r); /** @group flatzinc Constrains max(\a a, \a b) = \a c */ predicate int_max(var int: a, var int: b, var int: c); /** @group flatzinc Constrains min(\a a, \a b) = \a c */ predicate int_min(var int: a, var int: b, var int: c); /** @group flatzinc Constrains \a a % \a b = \a c */ predicate int_mod(var int: a, var int: b, var int: c); /** @group flatzinc Constrains \a a * \a b = \a c */ predicate int_times(var int: a, var int: b, var int: c); /** @group flatzinc Constrains \a z = \(\a x ^ {\a y}\) */ predicate int_pow(var int: x, var int: y, var int: z); % Set constraints /** @group flatzinc Constrains \a x ∈ \a S */ predicate set_in(var int: x, set of int: S); /** @group flatzinc Constrains \a x ∈ \a S */ predicate set_in(var int: x, var set of int: S); /** @group flatzinc Constrains \a x = |\a S| */ predicate set_card(var set of int: S, var int: x); /** @group flatzinc Constrains \a r ↔ (\a x ∈ \a S) */ predicate set_in_reif(var int: x, set of int: S, var bool: r); /** @group flatzinc Constrains \a r ↔ (\a x ∈ \a S) */ predicate set_in_reif(var int: x, var set of int: S, var bool: r); /** @group flatzinc Constrains \a x ⊆ \a y */ predicate set_subset(var set of int: x, var set of int: y); /** @group flatzinc Constrains \a r ↔ (\a x ⊆ \a y) */ predicate set_subset_reif(var set of int: x, var set of int: y, var bool: r); /** @group flatzinc Constrains \a x ≤ \a y (lexicographic order) */ predicate set_le(var set of int: x, var set of int: y); /** @group flatzinc Constrains \a x < \a y (lexicographic order) */ predicate set_lt(var set of int: x, var set of int: y); /** @group flatzinc Constrains \a x = \a y */ predicate set_eq(var set of int: x, var set of int: y); /** @group flatzinc Constrains \a r ↔ (\a x = \a y) */ predicate set_eq_reif(var set of int: x, var set of int: y, var bool: r); /** @group flatzinc Constrains \a x ≠ \a y */ predicate set_ne(var set of int: x, var set of int: y); /** @group flatzinc Constrains \a r ↔ (\a x ≠ \a y) */ predicate set_ne_reif(var set of int: x, var set of int: y, var bool: r); /** @group flatzinc Constrains \a r = x ∩ \a y */ predicate set_intersect(var set of int: x, var set of int: y, var set of int: r); /** @group flatzinc Constrains \a r = x ∪ \a y */ predicate set_union(var set of int: x, var set of int: y, var set of int: r); /** @group flatzinc Constrains \a r = x − \a y */ predicate set_diff(var set of int: x, var set of int: y, var set of int: r); /** @group flatzinc Constrains \a r to be the symmetric difference of \a x and \a y */ predicate set_symdiff(var set of int: x, var set of int: y, var set of int: r); % Float constraints /** @group flatzinc Constrains \a b to be the absolute value of \a a */ predicate float_abs(var float: a, var float: b); /** @group flatzinc Constrains \a b = acos(\a a) */ predicate float_acos(var float: a, var float: b); /** @group flatzinc Constrains \a b = acosh(\a a) */ predicate float_acosh(var float: a, var float: b); /** @group flatzinc Constrains \a b = asin(\a a) */ predicate float_asin(var float: a, var float: b); /** @group flatzinc Constrains \a b = asinh(\a a) */ predicate float_asinh(var float: a, var float: b); /** @group flatzinc Constrains \a b = atan(\a a) */ predicate float_atan(var float: a, var float: b); /** @group flatzinc Constrains \a b = atanh(\a a) */ predicate float_atanh(var float: a, var float: b); /** @group flatzinc Constrains \a b = cos(\a a) */ predicate float_cos(var float: a, var float: b); /** @group flatzinc Constrains \a b = cosh(\a a) */ predicate float_cosh(var float: a, var float: b); /** @group flatzinc Constrains \a b = exp(\a a) */ predicate float_exp(var float: a, var float: b); /** @group flatzinc Constrains \a b = ln(\a a) */ predicate float_ln(var float: a, var float: b); /** @group flatzinc Constrains \a b = log10(\a a) */ predicate float_log10(var float: a, var float: b); /** @group flatzinc Constrains \a b = log2(\a a) */ predicate float_log2(var float: a, var float: b); /** @group flatzinc Constrains \(\a b = \sqrt{\a a}\) */ predicate float_sqrt(var float: a, var float: b); /** @group flatzinc Constrains \a z = \(\a x ^ {\a y}\) */ predicate float_pow(var float: x, var float: y, var float: z); /** @group flatzinc Constrains \a b = sin(\a a) */ predicate float_sin(var float: a, var float: b); /** @group flatzinc Constrains \a b = sinh(\a a) */ predicate float_sinh(var float: a, var float: b); /** @group flatzinc Constrains \a b = tan(\a a) */ predicate float_tan(var float: a, var float: b); /** @group flatzinc Constrains \a b = tanh(\a a) */ predicate float_tanh(var float: a, var float: b); /** @group flatzinc Constrains \a a = \a b */ predicate float_eq(var float: a, var float: b); /** @group flatzinc Constrains \a r ↔ (\a a = \a b) */ predicate float_eq_reif(var float: a, var float: b, var bool: r); /** @group flatzinc Constrains \a a ≤ \a b */ predicate float_le(var float: a, var float: b); /** @group flatzinc Constrains \a r ↔ (\a a ≤ \a b) */ predicate float_le_reif(var float: a, var float: b, var bool: r); /** @group flatzinc Constrains \a a < \a b */ predicate float_lt(var float: a, var float: b); /** @group flatzinc Constrains \a r ↔ (\a a < \a b) */ predicate float_lt_reif(var float: a, var float: b, var bool: r); /** @group flatzinc Constrains \a a ≠ \a b */ predicate float_ne(var float: a, var float: b); /** @group flatzinc Constrains \a r ↔ (\a a ≠ \a b) */ predicate float_ne_reif(var float: a, var float: b, var bool: r); /** @group flatzinc Constrains \( \a c = \sum_i \a as[i]*\a bs[i] \) */ predicate float_lin_eq(array[int] of float: as, array[int] of var float: bs, float: c); /** @group flatzinc Constrains \( \a r \leftrightarrow (\a c = \sum_i \a as[i]*\a bs[i]) \) */ predicate float_lin_eq_reif(array[int] of float: as, array[int] of var float: bs, float: c, var bool: r); /** @group flatzinc Constrains \( \a c \leq \sum_i \a as[i]*\a bs[i] \) */ predicate float_lin_le(array[int] of float: as, array[int] of var float: bs, float: c); /** @group flatzinc Constrains \( \a r \leftrightarrow (\a c \leq \sum_i \a as[i]*\a bs[i]) \) */ predicate float_lin_le_reif(array[int] of float: as, array[int] of var float: bs, float: c, var bool: r); /** @group flatzinc Constrains \( \a c < \sum_i \a as[i]*\a bs[i] \) */ predicate float_lin_lt(array[int] of float: as, array[int] of var float: bs, float: c); /** @group flatzinc Constrains \( \a r \leftrightarrow (\a c < \sum_i \a as[i]*\a bs[i]) \) */ predicate float_lin_lt_reif(array[int] of float: as, array[int] of var float: bs, float: c, var bool: r); /** @group flatzinc Constrains \( \a c \neq \sum_i \a as[i]*\a bs[i] \) */ predicate float_lin_ne(array[int] of float: as, array[int] of var float: bs, float: c); /** @group flatzinc Constrains \( \a r \leftrightarrow (\a c \neq \sum_i \a as[i]*\a bs[i]) \) */ predicate float_lin_ne_reif(array[int] of float: as, array[int] of var float: bs, float: c, var bool: r); /** @group flatzinc Constrains max(\a a, \a b) = \a c */ predicate float_max(var float: a, var float: b, var float: c); /** @group flatzinc Constrains min(\a a, \a b) = \a c */ predicate float_min(var float: a, var float: b, var float: c); /** @group flatzinc Constrains \a a + \a b = \a c */ predicate float_plus(var float: a, var float: b, var float: c); /** @group flatzinc Constrains \a a * \a b = \a c */ predicate float_times(var float: a, var float: b, var float: c); /** @group flatzinc Constrains \a y=\a x */ predicate int2float(var int: x, var float: y); % Array constraints /** @group flatzinc Constrains \( \a r \leftrightarrow \bigwedge_i \a as[i]\) */ predicate array_bool_and(array[int] of var bool: as, var bool: r); /** @group flatzinc Constrains \( \a r \leftrightarrow \bigvee_i \a as[i]\) */ predicate array_bool_or(array[int] of var bool: as, var bool: r); /** @group flatzinc Constrains \( \a r \leftrightarrow \oplus_i\ \a as[i]\) */ predicate array_bool_xor(array[int] of var bool: as); /** @group flatzinc Constrains \a as[\a b] = \a c */ predicate array_bool_element(var int: b, array[int] of bool: as, var bool: c); /** @group flatzinc Constrains \a as[\a b] = \a c */ predicate array_int_element(var int: b, array[int] of int: as, var int: c); /** @group flatzinc Constrains \a as[\a b] = \a c */ predicate array_float_element(var int: b, array[int] of float: as, var float: c); /** @group flatzinc Constrains \a as[\a b] = \a c */ predicate array_set_element(var int: b, array[int] of set of int: as, var set of int: c); /** @group flatzinc Constrains \a as[\a b] = \a c */ predicate array_var_bool_element(var int: b, array[int] of var bool: as, var bool: c); /** @group flatzinc Constrains \a as[\a b] = \a c */ predicate array_var_int_element(var int: b, array[int] of var int: as, var int: c); /** @group flatzinc Constrains \a as[\a b] = \a c */ predicate array_var_float_element(var int: b, array[int] of var float: as, var float: c); /** @group flatzinc Constrains \a as[\a b] = \a c */ predicate array_var_set_element(var int: b, array[int] of var set of int: as, var set of int: c); /** @group flatzinc Constrains \a m to be the maximum value of the (non-empty) array \a x */ predicate array_int_maximum(var int: m, array[int] of var int: x); /** @group flatzinc Constrains \a m to be the maximum value of the (non-empty) array \a x */ predicate array_float_maximum(var int: m, array[int] of var int: x); /** @group flatzinc Constrains \a m to be the minimum value of the (non-empty) array \a x */ predicate array_int_minimum(var int: m, array[int] of var int: x); /** @group flatzinc Constrains \a m to be the minimum value of the (non-empty) array \a x */ predicate array_float_minimum(var int: m, array[int] of var int: x); % Boolean constraints /** @group flatzinc Constrains \a b ∈ {0,1} and \a a ↔ \a b=1 */ predicate bool2int(var bool: a, var int: b); /** @group flatzinc Constrains \a r ↔ \a a ∧ \a b */ predicate bool_and(var bool: a, var bool: b, var bool: r); /** @group flatzinc Constrains \( \bigvee_i \a as[i] \land \bigvee_j \lnot \a bs[j] \) */ predicate bool_clause(array[int] of var bool: as, array[int] of var bool: bs); /** @group flatzinc Constrains \a a = \a b */ predicate bool_eq(var bool: a, var bool: b); /** @group flatzinc Constrains \a r ↔ (\a a = \a b) */ predicate bool_eq_reif(var bool: a, var bool: b, var bool: r); /** @group flatzinc Constrains \a a ≤ \a b */ predicate bool_le(var bool: a, var bool: b); /** @group flatzinc Constrains \a r ↔ (\a a ≤ \a b) */ predicate bool_le_reif(var bool: a, var bool: b, var bool: r); /** @group flatzinc Constrains \( \a c = \sum_i \a as[i]*\a bs[i] \) */ predicate bool_lin_eq(array[int] of int: as, array[int] of var bool: bs, var int: c); /** @group flatzinc Constrains \( \a c \leq \sum_i \a as[i]*\a bs[i] \) */ predicate bool_lin_le(array[int] of int: as, array[int] of var bool: bs, int: c); /** @group flatzinc Constrains \a a < \a b */ predicate bool_lt(var bool: a, var bool: b); /** @group flatzinc Constrains \a r ↔ (\a a < \a b) */ predicate bool_lt_reif(var bool: a, var bool: b, var bool: r); /** @group flatzinc Constrains \a a ≠ \a b */ predicate bool_not(var bool: a, var bool: b); /** @group flatzinc Constrains \a r ↔ \a a ∨ \a b */ predicate bool_or(var bool: a, var bool: b, var bool: r); /** @group flatzinc Constrains \a r ↔ \a a ⊕ \a b */ predicate bool_xor(var bool: a, var bool: b, var bool: r); /** @group flatzinc Constrains \a a ⊕ \a b */ predicate bool_xor(var bool: a, var bool: b); libminizinc-2.0.11/share/minizinc/std/diffn_k.mzn0000644000175000017500000000251112646030173020403 0ustar kaolkaol/** @group globals.packing Constrains \p k-dimensional boxes to be non-overlapping. For each box \p i and dimension \p j, \a box_posn[\p i, \p j] is the base position of the box in dimension \p j, and \a box_size[\p i, \p j] is the size in that dimension. Boxes whose size is 0 in any dimension still cannot overlap with any other box. */ predicate diffn_k(array[int,int] of var int: box_posn, array[int,int] of var int: box_size) = let { set of int: DIMS= index_set_2of2(box_posn) } in assert(index_set_2of2(box_size) = DIMS /\ index_set_1of2(box_posn) = index_set_1of2(box_size), "diffn: index sets of arguments are incorrect", forall(b1, b2 in index_set_1of2(box_posn) where b1 < b2) (diffn_nonoverlap_k([ box_posn[b1,j] | j in DIMS ], [ box_size[b1,j] | j in DIMS ], [ box_posn[b2,j] | j in DIMS ], [ box_size[b2,j] | j in DIMS ] ) ) ); predicate diffn_nonoverlap_k(array[int] of var int: x1, array[int] of var int: w1, array[int] of var int: x2, array[int] of var int: w2) = exists(j in index_set(x1)) (x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j]); libminizinc-2.0.11/share/minizinc/std/network_flow.mzn0000644000175000017500000000432712646030173021532 0ustar kaolkaol/** @group globals Defines a network flow constraint. @param arc: a directed arc of the flow network. Arc \p i connects node \a arc[\p i,1] to node \a arc[\p i,2]. @param balance: the difference between input and output flow for each node. @param flow: the flow going through each arc. */ predicate network_flow(array[int,1..2] of int: arc, array[int] of int: balance, array[int] of var int: flow) = let { int: source_node = 1; int: sink_node = 2; set of int: ARCS = index_set_1of2(arc); set of int: NODES = index_set(balance); } in assert ( ARCS == index_set(flow) /\ lb_array(arc) >= min(NODES) /\ ub_array(arc) <= max(NODES), "network_flow: wrong sizes of input array parameters", forall (i in NODES) ( sum (j in ARCS where i == arc[j,source_node]) (flow[j]) - sum (j in ARCS where i == arc[j,sink_node]) (flow[j]) = balance[i] ) ); /** @group globals Defines a network flow constraint with cost. @param arc: a directed arc of the flow network. Arc \p i connects node \a arc[\p i,1] to node \a arc[\p i,2]. @param balance: the difference between input and output flow for each node. @param weight: the unit cost of the flow through the arc. @param flow: the flow going through each arc. @param cost: the overall cost of the flow. */ predicate network_flow_cost(array[int,1..2] of int: arc, array[int] of int: balance, array[int] of int: weight, array[int] of var int: flow, var int: cost) = let { int: source_node = 1; int: sink_node = 2; set of int: ARCS = index_set_1of2(arc); set of int: NODES = index_set(balance); } in assert ( ARCS == index_set(flow) /\ ARCS == index_set(weight) /\ lb_array(arc) >= min(NODES) /\ ub_array(arc) <= max(NODES), "network_flow: wrong sizes of input array parameters", cost = sum(i in ARCS) (flow[i] * weight[i]) /\ forall (i in NODES) ( sum (j in ARCS where i == arc[j,source_node]) (flow[j]) - sum (j in ARCS where i == arc[j,sink_node]) (flow[j]) = balance[i] ) ); libminizinc-2.0.11/share/minizinc/std/redefinitions-2.0.mzn0000644000175000017500000000335012646030173022144 0ustar kaolkaol% This file contains redefinitions of standard builtins that can be overridden % by solvers. predicate bool_clause_reif(array[int] of var bool: as, array[int] of var bool: bs, var bool: b) = clause(as,bs++[b]) /\ forall (i in index_set(as)) (as[i] -> b) /\ forall (i in index_set(bs)) (bs[i] \/ b); predicate array_int_maximum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_float_maximum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_int_minimum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); predicate array_float_minimum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); libminizinc-2.0.11/share/minizinc/std/bin_packing_capa.mzn0000644000175000017500000000216612646030173022241 0ustar kaolkaol/** @group globals.packing Requires that each item \p i with weight \a w[\p i], be put into \a bin[\p i] such that the sum of the weights of the items in each bin \p b does not exceed the capacity \a c[\p b]. Assumptions: - forall \p i, \a w[\p i] >=0 - forall \p b, \a c[\p b] >=0 */ predicate bin_packing_capa(array[int] of int: c, array[int] of var int: bin, array[int] of int: w) = assert(index_set(bin) = index_set(w), "bin_packing_capa: the bin and weight arrays must have identical index sets", assert(lb_array(w) >= 0, "bin_packing_capa: the weights must be non-negative", assert(lb_array(c) >= 0, "bin_packing_capa: the capacities must be non-negative", forall( i in index_set(bin) ) ( min(index_set(c)) <= bin[i] /\ bin[i] <= max(index_set(c)) ) /\ forall( b in index_set(c) ) ( c[b] >= sum ( i in index_set(bin) ) ( w[i] * bool2int( bin[i] = b ) ) ) ))); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/member.mzn0000644000175000017500000000157512646030173020263 0ustar kaolkaolinclude "member_bool.mzn"; include "member_float.mzn"; include "member_int.mzn"; include "member_set.mzn"; include "set_member.mzn"; /** @group globals Requires that \a y occurs in the array \a x. */ predicate member(array[int] of var bool: x, var bool: y) = member_bool(x, y); /** @group globals Requires that \a y occurs in the array \a x. */ predicate member(array[int] of var float: x, var float: y) = member_float(x, y); /** @group globals Requires that \a y occurs in the array \a x. */ predicate member(array[int] of var int: x, var int: y) = member_int(x, y); /** @group globals Requires that \a y occurs in the array \a x. */ predicate member(array[int] of var set of int: x, var set of int: y) = member_set(x, y); /** @group globals Requires that \a y occurs in the set \a x. */ predicate member(var set of int: x, var int: y) = set_member(x, y); libminizinc-2.0.11/share/minizinc/std/int_set_channel.mzn0000644000175000017500000000121012646030173022133 0ustar kaolkaol/** @group globals.channeling Requires that array of int variables \a x and array of set variables \a y are related such that (\a x[\p i] = \p j) ↔ (\p i in \a y[\p j]). */ predicate int_set_channel(array[int] of var int: x, array[int] of var set of int: y) = forall(i in index_set(x)) (x[i] in index_set(y)) /\ forall(j in index_set(y)) (y[j] subset index_set(x)) /\ forall(i in index_set(x), j in index_set(y)) (x[i] = j <-> i in y[j]); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/inverse_fn.mzn0000644000175000017500000000050712646030173021144 0ustar kaolkaolinclude "inverse.mzn"; /** @group globals.channeling Given a function \a f represented as an array, return the inverse function. */ function array[int] of var int: inverse(array[int] of var int: f) = let { array[lb_array(f)..ub_array(f)] of var index_set(f): invf; constraint inverse(f,invf); } in invf; libminizinc-2.0.11/share/minizinc/std/lex_less_float.mzn0000644000175000017500000000327012646030173022011 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_less_float(array[int] of var float: x, array[int] of var float: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); predicate lex_less_float_reif(array[int] of var float: x, array[int] of var float: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); predicate lex_lt_float(array[int] of var float: x, array[int] of var float: y) = lex_less(x, y); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/arg_min.mzn0000644000175000017500000000335012646030173020421 0ustar kaolkaol/** @group globals Returns the index of the minimum value in the array \a x. When breaking ties the least index is returned. */ function var int: arg_min(array[int] of var int: x) = let { constraint length(x) > 0; } in arg_min_total(x); /** @group globals Returns the index of the minimum value in the array \a x. When breaking ties the least index is returned. */ function var int: arg_min(array[int] of var float: x) = let { constraint length(x) > 0; } in arg_min_total(x); function var int: arg_min_total(array[int] of var int: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint minimum_arg_int(x, i); } in i endif; function var int: arg_min_total(array[int] of var float: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint minimum_arg_float(x, i); } in i endif; include "arg_min_int.mzn"; /** @group globals Constrain \a i to be the index of the minimum value in the array \a x. When breaking ties the least index is returned. Assumption: |x| > 0 */ predicate minimum_arg(array[int] of var int: x, var int: i) = minimum_arg_int(x, i); include "arg_min_float.mzn"; /** @group globals Constrain \a i to be the index of the minimum value in the array \a x. When breaking ties the least index is returned. Assumption: |x| > 0 */ predicate minimum_arg(array[int] of var float: x, var int: i) = minimum_arg_float(x, i); libminizinc-2.0.11/share/minizinc/std/exactly_int.mzn0000644000175000017500000000053312646030173021330 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires exactly 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate exactly_int(int: n, array[int] of var int: x, int: v) = n == sum(i in index_set(x)) ( bool2int(x[i] == v) ); libminizinc-2.0.11/share/minizinc/std/nvalue_fn.mzn0000644000175000017500000000033512646030173020762 0ustar kaolkaolinclude "nvalue.mzn"; /** @group globals.alldifferent Returns the number of distinct values in \a x. */ function var int: nvalue(array[int] of var int: x) = let { var 0..length(x): n; constraint nvalue(n,x); } in n; libminizinc-2.0.11/share/minizinc/std/disjunctive_strict_opt.mzn0000644000175000017500000000151612646030173023610 0ustar kaolkaol/** @group globals.scheduling Requires that a set of tasks given by start times \a s and durations \a d do not overlap in time. Tasks with duration 0 CANNOT be scheduled at any time, but only when no other task is running. Start times are optional variables, so that absent tasks do not need to be scheduled. Assumptions: - forall \p i, \a d[\p i] >= 0 */ predicate disjunctive_strict(array[int] of var opt int: s, array[int] of var int: d) = assert(index_set(s) == index_set(d), "disjunctive: the array arguments must have identical index sets", forall (i in index_set(d)) (d[i] >= 0) /\ forall (i,j in index_set(d) where i b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ if i = size then true else x[lx + i] < y[ly + i] \/ b[i+1] endif ) ); predicate lex_leq_bool(array[int] of var bool: x, array[int] of var bool: y) = lex_lesseq(x, y); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/count_neq.mzn0000644000175000017500000000062512646030173021002 0ustar kaolkaol/** @group globals.counting Constrains \a c to be not equal to the number of occurrences of \a y in \a x. */ predicate count_neq(array[int] of var int: x, var int: y, var int: c) = c != sum(i in index_set(x)) ( bool2int(x[i] == y) ); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/disjunctive.mzn0000644000175000017500000000145012646030173021333 0ustar kaolkaolinclude "disjunctive_strict.mzn"; /** @group globals.scheduling Requires that a set of tasks given by start times \a s and durations \a d do not overlap in time. Tasks with duration 0 can be scheduled at any time, even in the middle of other tasks. Assumptions: - forall \p i, \a d[\p i] >= 0 */ predicate disjunctive(array[int] of var int: s, array[int] of var int: d) = assert(index_set(s) == index_set(d), "disjunctive: the array arguments must have identical index sets", forall (i in index_set(d)) (d[i] >= 0) /\ if (lb_array(d) > 0) then disjunctive_strict(s,d) else forall (i,j in index_set(d) where i= x[i]); libminizinc-2.0.11/share/minizinc/std/lex_less.mzn0000644000175000017500000000336612646030173020632 0ustar kaolkaolinclude "lex_less_bool.mzn"; include "lex_less_float.mzn"; include "lex_less_int.mzn"; include "lex_less_set.mzn"; /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically less than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_less(array[int] of var bool: x, array[int] of var bool: y) = lex_less_bool(x, y); /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically less than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_less(array[int] of var int: x, array[int] of var int: y) = lex_less_int(x, y); /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically less than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_less(array[int] of var float: x, array[int] of var float: y) = lex_less_float(x, y); /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically less than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_less(array[int] of var set of int: x, array[int] of var set of int: y) = lex_less_set(x, y); % Alternative names for the above. % predicate lex_lt(array[int] of var bool: x, array[int] of var bool: y) = lex_less(x, y); predicate lex_lt(array[int] of var int: x, array[int] of var int: y) = lex_less(x, y); predicate lex_lt(array[int] of var float: x, array[int] of var float: y) = lex_less(x, y); predicate lex_lt(array[int] of var set of int: x, array[int] of var set of int: y) = lex_less(x, y); libminizinc-2.0.11/share/minizinc/std/increasing_bool.mzn0000644000175000017500000000056212646030173022144 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate increasing_bool(array[int] of var bool: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.0.11/share/minizinc/std/element_set.mzn0000644000175000017500000000051012646030173021304 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% predicate element_set(var int: i, array[int] of var set of int: x, var set of int: y) = y = x[i]; libminizinc-2.0.11/share/minizinc/std/exactly.mzn0000644000175000017500000000067112646030173020461 0ustar kaolkaolinclude "exactly_int.mzn"; include "exactly_set.mzn"; /** @group globals.counting Requires exactly \a n variables in \a x to take the value \a v. */ predicate exactly(int: n, array[int] of var int: x, int: v) = exactly_int(n, x, v); /** @group globals.counting Requires exactly \a n variables in \a x to take the value \a v. */ predicate exactly(int: n, array[int] of var set of int: x, set of int: v) = exactly_set(n, x, v); libminizinc-2.0.11/share/minizinc/std/regular.mzn0000644000175000017500000000363412646030173020453 0ustar kaolkaol/** @group globals.extensional The sequence of values in array \a x (which must all be in the range 1..\a S) is accepted by the DFA of \a Q states with input 1..\a S and transition function \a d (which maps (1..\a Q, 1..\a S) -> 0..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). We reserve state 0 to be an always failing state. */ predicate regular(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F) = assert(Q > 0, "regular: 'Q' must be greater than zero", assert(S > 0, "regular: 'S' must be greater than zero", assert(index_set_1of2(d) = 1..Q /\ index_set_2of2(d) == 1..S, "regular: the transition function 'd' must be [1..Q,1..S]", assert(forall([d[i, j] in 0..Q | i in 1..Q, j in 1..S]), "regular: transition function 'd' points to states outside 0..Q", % Nb: we need the parentheses around the expression otherwise the % parser thinks it's a generator call! assert((q0 in 1..Q), "regular: start state 'q0' not in 1..Q", assert(F subset 1..Q, "regular: final states in 'F' contain states outside 1..Q", let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)), int: n = max(index_set(x)) + 1, array[m..n] of var 1..Q: a } in a[m] = q0 /\ % Set a[0]. forall(i in index_set(x)) ( x[i] in 1..S /\ % Do this in case it's a var. a[i+1] = d[a[i], x[i]] % Determine a[i+1]. ) /\ a[n] in F % Check the final state is in F. )))))); libminizinc-2.0.11/share/minizinc/std/lex_lesseq.mzn0000644000175000017500000000345712646030173021161 0ustar kaolkaolinclude "lex_lesseq_bool.mzn"; include "lex_lesseq_float.mzn"; include "lex_lesseq_int.mzn"; include "lex_lesseq_set.mzn"; /** @group globals.lexicographic Requires that the array \a x is lexicographically less than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_lesseq(array[int] of var bool: x, array[int] of var bool: y) = lex_lesseq_bool(x, y); /** @group globals.lexicographic Requires that the array \a x is lexicographically less than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_lesseq(array[int] of var float: x, array[int] of var float: y) = lex_lesseq_float(x, y); /** @group globals.lexicographic Requires that the array \a x is lexicographically less than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_lesseq(array[int] of var int: x, array[int] of var int: y) = lex_lesseq_int(x, y); /** @group globals.lexicographic Requires that the array \a x is lexicographically less than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_lesseq(array[int] of var set of int: x, array[int] of var set of int: y) = lex_lesseq_set(x, y); % Alternative names for the above. % predicate lex_leq(array[int] of var bool: x, array[int] of var bool: y) = lex_lesseq(x, y); predicate lex_leq(array[int] of var int: x, array[int] of var int: y) = lex_lesseq(x, y); predicate lex_leq(array[int] of var float: x, array[int] of var float: y) = lex_lesseq(x, y); predicate lex_leq(array[int] of var set of int: x, array[int] of var set of int: y) = lex_lesseq(x, y); libminizinc-2.0.11/share/minizinc/std/redefinitions-2.0.2.mzn0000644000175000017500000000165412646030173022311 0ustar kaolkaol% This file contains redefinitions of standard builtins for version 2.0.2 % that can be overridden by solvers. predicate symmetry_breaking_constraint(var bool: b) = b; predicate redundant_constraint(var bool: b) = b; predicate array_var_bool_element_nonshifted(var int: idx, array[int] of var bool: x, var bool: c) = array_var_bool_element((idx-(min(index_set(x))-1))::domain,array1d(x),c); predicate array_var_int_element_nonshifted(var int: idx, array[int] of var int: x, var int: c) = array_var_int_element((idx-(min(index_set(x))-1))::domain,array1d(x),c); predicate array_var_float_element_nonshifted(var int: idx, array[int] of var float: x, var float: c) = array_var_float_element((idx-(min(index_set(x))-1))::domain,array1d(x),c); predicate array_var_set_element_nonshifted(var int: idx, array[int] of var set of int: x, var set of int: c) = array_var_set_element((idx-(min(index_set(x))-1))::domain,array1d(x),c); libminizinc-2.0.11/share/minizinc/std/stdlib_new.mzn0000644000175000017500000001017012646030173021135 0ustar kaolkaol%-----------------------------------------------------------------------------% % MiniZinc standard library (Draft for version MiniZinc 2.0) %-----------------------------------------------------------------------------% % This file contains built-in operations that can be expressed in MiniZinc, % and so are not implemented as true built-ins within the compiler. %-----------------------------------------------------------------------------% % % Search annotations % annotation bool_search( array[int] of var bool: vars, ann: select, ann: choice ); annotation int_search( array[int] of var int: vars, ann: select, ann: choice ); annotation set_search( array[int] of var set of int: vars, ann: select, ann: choice, ); annotation float_search( array[int] of var float: vars, float: prec, ann: select, ann: choice ); annotation int_search_all( ann: select, ann: choice ); annotation set_search_all( ann: select, ann: choice ); annotation seq_search(array[int] of ann: s); annotation par_search(array[int] of ann: s); annotation sample_search( ann: select, ann: limit ); annotation backdoor_search( ann: select, float: ratio, ann: limit, array[int] of ann: s ); % Search with limits and restart annotations annotation limit_search(ann: measure, int: value, ann: search); annotation restart_geometric(float: factor, float: value, ann: search); annotation restart_luby(float: factor, float: value, ann: search); % Sequential variable selection strategies annotation seq_vss(array[int] of ann: select); % Multiple domain selection strategies annotation dss(array[int] of ann: choice); % Combine and manipulate variable selection scores annotation weight_score(ann: select, float: weight); annotation sum_score(array[int] of ann: weight_score); % Measures to limit search (e.g., run-time, number of search nodes, fails) annotation measure; %-----------------------------------------------------------------------------% % % Variable selection annotations. % annotation input_order; annotation reverse_input_order; annotation random_order; annotation min_lb; annotation min_ub; annotation max_lb; annotation max_ub; annotation min_dom_size; annotation max_dom_size; annotation min_degree; annotation max_degree; annotation min_lb_regret; annotation max_lb_regret; annotation min_ub_regret; annotation max_ub_regret; annotation min_dom_size_degree; annotation max_dom_size_degree; annotation min_dom_size_weighted_degree; annotation max_dom_size_weighted_degree; annotation min_impact; annotation max_impact; annotation min_activity; annotation max_activity; %-----------------------------------------------------------------------------% % % Domain reduction strategies. % annotation assign_lb; annotation assign_ub; annotation exclude_lb; annotation exclude_ub; annotation assign_mean; annotation exclude_mean; annotation assign_median; annotation exclude_median; annotation assign_random; annotation exclude_random; annotation assign_impact_min; annotation assign_impact_max; annotation exclude_impact_min; annotation exclude_impact_max; annotation assign_activity_min; annotation assign_activity_max; annotation exclude_activity_min; annotation exclude_activity_max; annotation include_min; annotation include_max; annotation exclude_min; annotation exclude_max; annotation enumerate_lb; annotation enumerate_ub; annotation bisect_low; annotation bisect_high; annotation bisect_median_low; annotation bisect_median_high; annotation bisect_random_low; annotation bisect_random_high; annotation bisect_interval_low; annotation bisect_interval_high; annotation bisect_impact_min; annotation bisect_impact_max; annotation bisect_activity_min; annotation bisect_activity_max; %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% % Include solver-specific redefinitions for any FlatZinc built-ins. % include "redefinitions.mzn" %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/bin_packing.mzn0000644000175000017500000000164612646030173021257 0ustar kaolkaol/** @group globals.packing Requires that each item \p i with weight \a w[\p i], be put into \a bin[\p i] such that the sum of the weights of the items in each bin does not exceed the capacity \a c. Assumptions: - forall \p i, \a w[\p i] >=0 - \a c >=0 */ predicate bin_packing(int: c, array[int] of var int: bin, array[int] of int: w) = assert(index_set(bin) == index_set(w), "bin_packing: the bin and weight arrays must have identical index sets", assert(lb_array(w) >= 0, "bin_packing: the weights must be non-negative", assert(c >= 0, "bin_packing: capacity must be non-negative", forall( b in lb_array(bin)..ub_array(bin) ) ( c >= sum ( i in index_set(bin) ) ( w[i] * bool2int( bin[i] == b ) ) ) ))); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/disjunctive_opt.mzn0000644000175000017500000000175012646030173022220 0ustar kaolkaolinclude "disjunctive_strict_opt.mzn"; /** @group globals.scheduling Requires that a set of tasks given by start times \a s and durations \a d do not overlap in time. Tasks with duration 0 can be scheduled at any time, even in the middle of other tasks. Start times are optional variables, so that absent tasks do not need to be scheduled. Assumptions: - forall \p i, \a d[\p i] >= 0 */ predicate disjunctive(array[int] of var opt int: s, array[int] of var int: d) = assert(index_set(s) == index_set(d), "disjunctive: the array arguments must have identical index sets", forall (i in index_set(d)) (d[i] >= 0) /\ if (lb_array(d) > 0) then disjunctive_strict(s,d) else forall (i,j in index_set(d) where i= 0 and \a r[\p i] >= 0 */ predicate cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", if forall(i in index_set(r))(is_fixed(r[i]) /\ fix(r[i]) == 1) /\ is_fixed(b) /\ fix(b) == 1 then if forall(i in index_set(d))(is_fixed(d[i]) /\ fix(d[i]) == 1) then alldifferent(s) else disjunctive(s, d) endif else let { set of int: Tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, int: early = min([ lb(s[i]) | i in Tasks ]), int: late = max([ ub(s[i]) + ub(d[i]) | i in Tasks ]) } in ( if late - early > 5000 then cumulative_task(s, d, r, b) else cumulative_time(s, d, r, b) endif ) endif )); predicate cumulative_time(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = let { set of int: Tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, int: early = min([ lb(s[i]) | i in Tasks ]), int: late = max([ ub(s[i]) + ub(d[i]) | i in Tasks ]) } in ( forall( t in early..late ) ( b >= sum( i in Tasks ) ( bool2int(s[i] <= t /\ t < s[i] + d[i]) * r[i] ) ) ); predicate cumulative_task(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = let { set of int: Tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 } } in ( forall( j in Tasks ) ( b >= r[j] + sum( i in Tasks where i != j ) ( bool2int(s[i] <= s[j] /\ s[j] < s[i] + d[i] ) * r[i] ) ) ); libminizinc-2.0.11/share/minizinc/std/disjoint.mzn0000644000175000017500000000024412646030173020627 0ustar kaolkaol/** @group globals Requires that sets \a s1 and \a s2 do not intersect. */ predicate disjoint(var set of int: s1, var set of int: s2) = s1 intersect s2 == {}; libminizinc-2.0.11/share/minizinc/std/atmost1.mzn0000644000175000017500000000022412646030173020372 0ustar kaolkaol% The actual definitions are in at_most1.mzn. % This file is used to handle the case where users include % "atmost1.mzn"; % include "at_most1.mzn"; libminizinc-2.0.11/share/minizinc/std/at_most_set.mzn0000644000175000017500000000055212646030173021327 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires at most 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate at_most_set(int: n, array[int] of var set of int: x, set of int: v) = sum(i in index_set(x)) ( bool2int(x[i] == v) ) <= n; libminizinc-2.0.11/share/minizinc/std/value_precede.mzn0000644000175000017500000000135112646030173021607 0ustar kaolkaolinclude "value_precede_int.mzn"; include "value_precede_set.mzn"; /** @group globals.lexicographic Requires that \a s precede \a t in the array \a x. Precedence means that if any element of \a x is equal to \a t, then another element of \a x with a lower index is equal to \a s. */ predicate value_precede(int: s, int: t, array[int] of var int: x) = value_precede_int(s, t, x); /** @group globals.lexicographic Requires that \a s precede \a t in the array \a x. Precedence means that if an element of \a x contains \a t but not \a s, then another element of \a x with lower index contains \a s but not \a t. */ predicate value_precede(int: s, int: t, array[int] of var set of int: x) = value_precede_set(s, t, x); libminizinc-2.0.11/share/minizinc/std/maximum.mzn0000644000175000017500000000143312646030173020462 0ustar kaolkaol/** @group globals Constrains \a m to be the maximum of the values in \a x. Assumptions: |\a x| > 0. */ predicate maximum(var int: m, array[int] of var int: x) = array_int_maximum(m, x); /** @group globals Constrains \a m to be the maximum of the values in \a x. Assumptions: |\a x| > 0. */ predicate maximum(var float: m, array[int] of var float: x) = array_float_maximum(m, x); % XXX: currently doesn't work: same problem as 'minimum' above. %predicate maximum(var set of int: m, array[int] of var set of int: x) = % let { int: l = min(index_set(x)), % int: u = max(index_set(x)), % set of int: uy = ub(x), % array[l..u] of var set of uy: y } in % y[l] = x[l] /\ % m = y[u] /\ % forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); libminizinc-2.0.11/share/minizinc/std/all_disjoint.mzn0000644000175000017500000000040512646030173021456 0ustar kaolkaol/** @group globals.alldifferent Constrain the array of sets of integers \a S to be pairwise disjoint. */ predicate all_disjoint(array[int] of var set of int: S) = forall(i,j in index_set(S) where i < j) ( disjoint(S[i], S[j]) ); include "disjoint.mzn"; libminizinc-2.0.11/share/minizinc/std/lex_greatereq.mzn0000644000175000017500000000243512646030173021637 0ustar kaolkaolinclude "lex_lesseq.mzn"; /** @group globals.lexicographic Requires that the array \a x is lexicographically greater than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greatereq(array[int] of var bool: x, array[int] of var bool: y) = lex_lesseq(y, x); /** @group globals.lexicographic Requires that the array \a x is lexicographically greater than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greatereq(array[int] of var int: x, array[int] of var int: y) = lex_lesseq(y, x); /** @group globals.lexicographic Requires that the array \a x is lexicographically greater than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greatereq(array[int] of var float: x, array[int] of var float: y) = lex_lesseq(y, x); /** @group globals.lexicographic Requires that the array \a x is lexicographically greater than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greatereq(array[int] of var set of int: x, array[int] of var set of int: y) = lex_lesseq(y, x); libminizinc-2.0.11/share/minizinc/std/stdlib.mzn0000644000175000017500000004763412646030173020303 0ustar kaolkaol%-----------------------------------------------------------------------------% % MiniZinc standard library. %-----------------------------------------------------------------------------% % This file contains declarations of all functions, predicates and annotations % available in the base MiniZinc language. /*** @groupdef MAIN The MiniZinc library */ /*** @groupdef annotations Annotations These annotations control evaluation and solving behaviour. */ /*** @groupdef annotations.general General annotations */ /** @group annotations.general Declare function as total, i.e. it does not put any constraints on its arguments. */ annotation promise_total; /** @group annotations.general Declare the annotated variable as being functionally defined. This annotation is introduced into FlatZinc code by the compiler. */ annotation is_defined_var; /** @group annotations.general Declare a variable as being introduced by the compiler. */ annotation var_is_introduced; /** @group annotations.general Declare variable: \a c as being functionally defined by the annotated constraint. This annotation is introduced into FlatZinc code by the compiler. */ annotation defines_var(var $t: c); /** @group annotations.general Declare that the annotated array should be printed by the solver with the given index sets \a a. This annotation is introduced into FlatZinc code by the compiler. */ annotation output_array(array[$u] of set of int:a); /** @group annotations.general Declare that the annotated variable should be printed by the solver. This annotation is introduced into FlatZinc code by the compiler. */ annotation output_var; /** @group annotations.general Declare that the annotated expression is used to map an expression back from FlatZinc to MiniZinc. */ annotation is_reverse_map; /** @group annotations.general Document the function or variable declaration item with the string \a s. */ annotation doc_comment(string: s); /*** @groupdef annotations.prop Propagation strength annotations */ /** @group annotations.prop Annotate a constraint to use domain propagation */ annotation domain; /** @group annotations.prop Annotate a constraint to use bounds propagation */ annotation bounds; /*** @groupdef annotations.search Search annotations */ /** @group annotations.search Sequentially perform the searches specified in array \a s */ annotation seq_search(array[int] of ann: s); /** @group annotations.search Specify search on variables \a x, with variable selection strategy \a select, value choice strategy \a choice, and exploration strategy \a explore. */ annotation int_search( array[int] of var int: x, ann: select, ann: choice, ann: explore, ); /** @group annotations.search Specify search on variables \a x, with variable selection strategy \a select, value choice strategy \a choice, and exploration strategy \a explore. */ annotation bool_search( array[int] of var bool: x, ann: select, ann: choice, ann: explore ); /** @group annotations.search Specify search on variables \a x, with precision \a prec, variable selection strategy \a select, value choice strategy \a choice, and exploration strategy \a explore. */ annotation float_search( array[int] of var float: x, float: prec, ann: select, ann: choice, ann: explore ); /** @group annotations.search Specify search on variables \a x, with variable selection strategy \a select, value choice strategy \a choice, and exploration strategy \a explore. */ annotation set_search( array[int] of var set of int: x, ann: select, ann: choice, ann: explore ); /*** @groupdef annotations.search.varsel Variable selection annotations */ /** @group annotations.search.varsel Search variables in the given order */ annotation input_order; /** @group annotations.search.varsel Choose the variable with the smallest domain */ annotation first_fail; /** @group annotations.search.varsel Choose the variable with the largest domain */ annotation anti_first_fail; /** @group annotations.search.varsel Choose the variable with the smallest value in its domain */ annotation smallest; /** @group annotations.search.varsel Choose the variable with the largest value in its domain */ annotation largest; /** @group annotations.search.varsel Choose the variable with the largest number of attached constraints */ annotation occurrence; /** @group annotations.search.varsel Choose the variable with the smallest domain, breaking ties using the number of attached constraints */ annotation most_constrained; /** @group annotations.search.varsel Choose the variable with largest difference between the two smallest values in its domain */ annotation max_regret; /** @group annotations.search.varsel Choose the variable with largest domain, divided by the number of attached constraints weighted by how often they have caused failure */ annotation dom_w_deg; /** @group annotations.search.varsel Choose the variable with the highest impact so far during the search */ annotation impact; /*** @groupdef annotations.search.choice Value choice annotations */ /** @group annotations.search.choice Assign values in ascending order */ annotation indomain; /** @group annotations.search.choice Assign the smallest value in the domain */ annotation indomain_min; /** @group annotations.search.choice Assign the largest value in the domain */ annotation indomain_max; /** @group annotations.search.choice Assign the value in the domain closest to the mean of its current bounds */ annotation indomain_middle; /** @group annotations.search.choice Assign the middle value in the domain */ annotation indomain_median; /** @group annotations.search.choice Assign a random value from the domain */ annotation indomain_random; /** @group annotations.search.choice Bisect the domain, excluding the upper half first */ annotation indomain_split; /** @group annotations.search.choice Bisect the domain, randomly selecting which half to exclude first */ annotation indomain_split_random; /** @group annotations.search.choice Bisect the domain, excluding the lower half first */ annotation indomain_reverse_split; /** @group annotations.search.choice If the domain consists of several contiguous intervals, reduce the domain to the first interval. Otherwise bisect the domain. */ annotation indomain_interval; /** @group annotations.search.choice Exclude the smallest value from the domain */ annotation outdomain_min; /** @group annotations.search.choice Exclude the largest value from the domain */ annotation outdomain_max; /** @group annotations.search.choice Exclude the middle value from the domain */ annotation outdomain_median; /** @group annotations.search.choice Exclude a random value from the domain */ annotation outdomain_random; /*** @groupdef annotations.search.explore Exploration strategy annotations */ /** @group annotations.search.explore Perform a complete search */ annotation complete; /*** @groupdef optiontypes Option type support These functions and predicates implement the standard library for working with option types. Note that option type support is still incomplete. */ /** @group optiontypes Return value of \a x if \a x is not absent. Aborts when evaluated on absent value. */ function $T: deopt(opt $T: x); /** @group optiontypes Return value \a x unchanged (since \a x is guaranteed to be non-optional). */ function var $T: deopt(var $T: x) = x; /** @group optiontypes Test if \a x is not absent (always returns true) */ test occurs(var $T: x) = true; /** @group optiontypes Test if \a x is not absent */ test occurs(opt $T: x); /** @group optiontypes Test if \a x is absent (always returns false) */ test absent(var $T: x) = false; /** @group optiontypes Test if \a x is absent */ test absent(opt $T: x) = not occurs(x); /*** @groupdef optiontypes.bool Option type support for Booleans */ /** @group optiontypes.bool True iff \a x is not absent */ function var bool : occurs(var opt bool: x) ::promise_total = let { var bool : b = occurs_internal(x); var bool : dx = deopt_internal(x); constraint (x = reverse_map(b,dx)) :: is_reverse_map; } in b; /** @group optiontypes.bool Return value of \a x (assumes that \a x is not absent) */ function var bool : deopt(var opt bool : x) ::promise_total = let { var bool : b = occurs_internal(x); var bool : dx = deopt_internal(x); constraint (x = reverse_map(b,dx)) :: is_reverse_map; } in dx; /** @group optiontypes.bool True iff \a x is absent */ predicate absent(var opt bool: x) = not occurs(x); function var bool: occurs_internal(var opt bool: x) ::promise_total = let { var bool : b; } in b; function var bool : deopt_internal(var opt bool : x) ::promise_total = let { var bool: y } in y; function var opt bool: reverse_map(var bool: occ, var bool: d); function opt bool: reverse_map(bool: occ, bool: d) ::promise_total = if occ then d else <> endif; /** @group optiontypes.bool True iff both \a b0 and \a b1 are absent or both are present and have the same value. */ predicate bool_eq(var opt bool: b0, var opt bool: b1) = (absent(b0) /\ absent(b1)) \/ (occurs(b0) /\ occurs(b1) /\ deopt(b0)=deopt(b1)); /** @group optiontypes.bool True iff \a b0 occurs and is equal to \a b1 */ predicate bool_eq(var opt bool: b0, var bool: b1) = occurs(b0) /\ deopt(b0)=b1; /** @group optiontypes.bool True iff \a b1 occurs and is equal to \a b0 */ predicate bool_eq(var bool: b0, var opt bool: b1) = occurs(b1) /\ deopt(b1)=b0; /** @group optiontypes.bool True iff for any \p i, \a x[i] is absent or true */ predicate forall (array[int] of var opt bool: x) = forall ([absent(x[i]) \/ deopt(x[i]) | i in index_set(x)]); /** @group optiontypes.bool True iff for at least one \p i, \a x[i] occurs and is true */ predicate exists (array[int] of var opt bool: x) = exists ([occurs(x[i]) /\ deopt(x[i]) | i in index_set(x)]); /** @group optiontypes.bool True iff \a x is absent or false */ function var bool: 'not'(var opt bool: x) = absent(x) \/ not deopt(x); /** @group optiontypes.bool Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt bool: element(var opt int: idx, array[int] of var bool: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.bool Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt bool: element(var opt int: idx1, var opt int: idx2, array[int,int] of var bool: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /** @group optiontypes.bool Return \a x[\a idx] */ function var opt bool: element(var int: idx, array[int] of var opt bool: x) = let { var opt bool: r; constraint occurs(r) = element(idx,array1d(index_set(x),[occurs(x[i]) | i in index_set(x)])); constraint deopt(r) = element(idx,array1d(index_set(x),[deopt(x[i]) | i in index_set(x)])); } in r; /** @group optiontypes.bool Return \a x[\a idx1, \a idx2] */ function var opt bool: element(var int: idx1, var int: idx2, array[int,int] of var opt bool: x) = let { var opt bool: r; constraint occurs(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[occurs(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); constraint deopt(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[deopt(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); } in r; /** @group optiontypes.bool Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt bool: element(var opt int: idx, array[int] of var opt bool: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.bool Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt bool: element(var opt int: idx1, var opt int: idx2, array[int,int] of var opt bool: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /*** @groupdef optiontypes.int Option type support for integers */ /** @group optiontypes.int True iff \a x is not absent */ function var bool : occurs(var opt int : x) ::promise_total = let { var bool : b = occurs_internal(x); var int : dx = deopt_internal(x); constraint (x = reverse_map(b,dx)) :: is_reverse_map; } in b; /** @group optiontypes.bool Return value of \a x (assumes that \a x is not absent) */ function var int : deopt(var opt int : x) ::promise_total = let { var bool : b = occurs_internal(x); var int : dx = deopt_internal(x); constraint (x = reverse_map(b,dx)) :: is_reverse_map; } in dx; /** @group optiontypes.bool True iff \a x is absent */ function var bool: absent(var opt int: x) ::promise_total = not occurs(x); function var bool: occurs_internal(var opt int: x) ::promise_total = let { var bool : b; } in b; function var int : deopt_internal(var opt int : x) ::promise_total = let { var lb(x)..ub(x): y } in y; function var opt int: reverse_map(var bool: occ, var int: d); function opt int: reverse_map(bool: occ, int: d) ::promise_total = if occ then d else <> endif; /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than the value of \a y. */ function var bool: '>'(var opt int: x, var opt int: y) = absent(x) \/ absent(y) \/ deopt(x) > deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than or equal to the value of \a y. */ function var bool: '>='(var opt int: x, var opt int: y) = absent(x) \/ absent(y) \/ deopt(x) >= deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than the value of \a y. */ function var bool: '<'(var opt int: x, var opt int: y) = absent(x) \/ absent(y) \/ deopt(x) < deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than or equal to the value of \a y. */ function var bool: '<='(var opt int: x, var opt int: y) = absent(x) \/ absent(y) \/ deopt(x) <= deopt(y); /** @group optiontypes.int Return minimum of elements in \a x that are not absent, or absent if all elements in \a x are absent. */ function var opt int: min(array[int] of var opt int: x) ::promise_total = let { var opt lb_array(x)..ub_array(x): m; int: xmax = ub_array(x); constraint occurs(m) <-> exists (i in index_set(x)) (occurs(x[i])); constraint occurs(m) -> deopt(m) = min([if occurs(xi) then deopt(xi) else xmax endif | xi in x]); } in m; /** @group optiontypes.int Return maximum of elements in \a x that are not absent, or absent if all elements in \a x are absent. */ function var opt int: max(array[int] of var opt int: x) ::promise_total = let { var opt lb_array(x)..ub_array(x): m; int: xmin = lb_array(x); constraint occurs(m) <-> exists (i in index_set(x)) (occurs(x[i])); constraint occurs(m) -> deopt(m) = max([if occurs(xi) then deopt(xi) else xmin endif | xi in x]); } in m; /** @group optiontypes.int Weak addition. Return sum of \a x and \a y if both are present, otherwise return absent. */ function var opt int: '~+'(var opt int: x, var opt int: y) ::promise_total = let { int: l = if lb(x)=-infinity \/ lb(y)=-infinity then -infinity else lb(x)+lb(y) endif; int: u = if ub(x)=infinity \/ ub(y)=infinity then infinity else ub(x)+ub(y) endif; var opt l..u: result; constraint absent(x) \/ absent(y) -> result = <>; constraint absent(x) \/ absent(y) \/ result = deopt(x)+deopt(y); } in result; /** @group optiontypes.int Weak subtraction. Return difference of \a x and \a y if both are present, otherwise return absent. */ function var opt int: '~-'(var opt int: x, var opt int: y) ::promise_total = let { int: l = if lb(x)=-infinity \/ ub(y)=infinity then -infinity else lb(x)-ub(y) endif; int: u = if ub(x)=infinity \/ lb(y)=-infinity then infinity else ub(x)-lb(y) endif; var opt l..u: result; constraint absent(x) \/ absent(y) -> result = <>; constraint absent(x) \/ absent(y) \/ result = deopt(x)-deopt(y); } in result; /** @group optiontypes.int Weak multiplication. Return product of \a x and \a y if both are present, otherwise return absent. */ function var opt int: '~*'(var opt int: x, var opt int: y) ::promise_total = if absent(x) \/ absent(y) then <> else deopt(x)*deopt(y) endif; /** @group optiontypes.int Weak equality. True if either \a x or \a y are absent, or present and equal.*/ function var bool: '~='(var opt int: x, var opt int: y) ::promise_total = absent(x) \/ absent(y) \/ deopt(x)=deopt(y); /** @group optiontypes.int Return optional 0/1 integer that is absent iff \a x is absent, and 1 iff \a x occurs and is true. */ function var opt int: bool2int(var opt bool: x) ::promise_total = let { var opt 0..1: xi; constraint absent(xi)=absent(x); constraint deopt(xi)=bool2int(deopt(x)); } in xi; /** @group optiontypes.int True iff both \a x and \a y are absent or both are present and have the same value. */ predicate int_eq(var opt int: x, var opt int: y) = (absent(x) /\ absent(y)) \/ (occurs(x) /\ occurs(y) /\ deopt(x)=deopt(y)); /** @group optiontypes.int True iff only one of \a x and \a y is absent or both are present and have different values. */ predicate int_ne(var opt int : x, var opt int : y) = (absent(x) != absent(y)) \/ (occurs(x) /\ occurs(y) /\ deopt(x)!=deopt(y)); /** @group optiontypes.int Return sum of non-absent elements of \a x. */ function var int: sum(array[int] of var opt int: x) = sum (i in index_set(x)) (let { var int: dx = deopt(x[i]) } in if occurs(x[i]) then dx else 0 endif); /** @group optiontypes.int Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt int: element(var opt int: idx, array[int] of var int: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.int Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt int: element(var opt int: idx1, var opt int: idx2, array[int,int] of var int: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /** @group optiontypes.int Return \a x[\a idx] */ function var opt int: element(var int: idx, array[int] of var opt int: x) = let { var opt int: r; constraint occurs(r) = element(idx,array1d(index_set(x),[occurs(x[i]) | i in index_set(x)])); constraint deopt(r) = element(idx,array1d(index_set(x),[deopt(x[i]) | i in index_set(x)])); } in r; /** @group optiontypes.int Return \a x[\a idx1, \a idx2] */ function var opt int: element(var int: idx1, var int: idx2, array[int,int] of var opt int: x) = let { var opt int: r; constraint occurs(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[occurs(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); constraint deopt(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[deopt(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); } in r; /** @group optiontypes.int Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt int: element(var opt int: idx, array[int] of var opt int: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.int Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt int: element(var opt int: idx1, var opt int: idx2, array[int,int] of var opt int: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /*** @groupdef options Compiler options */ /*** @group options Whether to only generate domains that are contiguous ranges */ opt bool: mzn_opt_only_range_domains; /*** @group options Check whether to only generate domains that are contiguous ranges */ test mzn_check_only_range_domains() = if absent(mzn_opt_only_range_domains) then false else deopt(mzn_opt_only_range_domains) endif; include "builtins.mzn"; libminizinc-2.0.11/share/minizinc/std/globals.mzn0000644000175000017500000000565212646030173020437 0ustar kaolkaol/*** @groupdef globals Global constraints These constraints represent high-level modelling abstractions, for which many solvers implement special, efficient inference algorithms. */ /*** @groupdef globals.alldifferent All-Different and related constraints @groupdef globals.lexicographic Lexicographic constraints @groupdef globals.sort Sorting constraints @groupdef globals.channeling Channeling constraints @groupdef globals.counting Counting constraints @groupdef globals.packing Packing constraints @groupdef globals.scheduling Scheduling constraints @groupdef globals.extensional Extensional constraints (table, regular etc.) */ include "all_different.mzn"; include "alldifferent_except_0.mzn"; include "all_disjoint.mzn"; include "all_equal.mzn"; include "alternative.mzn"; include "among.mzn"; include "among_fn.mzn"; include "arg_sort.mzn"; include "arg_min.mzn"; include "arg_max.mzn"; include "at_least.mzn"; include "at_most.mzn"; include "at_most1.mzn"; include "bin_packing.mzn"; include "bin_packing_capa.mzn"; include "bin_packing_load.mzn"; include "bin_packing_load_fn.mzn"; include "circuit.mzn"; include "count.mzn"; include "count_fn.mzn"; include "count_eq.mzn"; include "count_neq.mzn"; include "count_geq.mzn"; include "count_gt.mzn"; include "count_leq.mzn"; include "count_lt.mzn"; include "cumulative.mzn"; include "cumulative_opt.mzn"; include "decreasing.mzn"; include "diffn.mzn"; include "diffn_nonstrict.mzn"; include "diffn_k.mzn"; include "diffn_nonstrict_k.mzn"; include "disjoint.mzn"; include "disjunctive.mzn"; include "disjunctive_strict.mzn"; include "disjunctive_opt.mzn"; include "disjunctive_strict_opt.mzn"; include "distribute.mzn"; include "distribute_fn.mzn"; include "element.mzn"; include "exactly.mzn"; include "geost.mzn"; include "global_cardinality.mzn"; include "global_cardinality_fn.mzn"; include "global_cardinality_closed.mzn"; include "global_cardinality_closed_fn.mzn"; include "global_cardinality_low_up.mzn"; include "global_cardinality_low_up_closed.mzn"; include "increasing.mzn"; include "int_set_channel.mzn"; include "inverse.mzn"; include "inverse_fn.mzn"; include "inverse_set.mzn"; include "knapsack.mzn"; include "lex_greater.mzn"; include "lex_greatereq.mzn"; include "lex_lesseq.mzn"; include "lex_less.mzn"; include "lex2.mzn"; include "link_set_to_booleans.mzn"; include "maximum.mzn"; include "member.mzn"; include "minimum.mzn"; include "network_flow.mzn"; include "nvalue.mzn"; include "nvalue_fn.mzn"; include "partition_set.mzn"; include "range.mzn"; include "range_fn.mzn"; include "regular.mzn"; include "regular_nfa.mzn"; include "roots.mzn"; include "roots_fn.mzn"; include "sliding_sum.mzn"; include "sort.mzn"; include "sort_fn.mzn"; include "span.mzn"; include "strict_lex2.mzn"; include "subcircuit.mzn"; include "sum_pred.mzn"; include "symmetric_all_different.mzn"; include "table.mzn"; include "value_precede.mzn"; include "value_precede_chain.mzn"; libminizinc-2.0.11/share/minizinc/std/member_float.mzn0000644000175000017500000000050512646030173021440 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate member_float(array[int] of var float: x, var float: y) = exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.0.11/share/minizinc/std/count_gt.mzn0000644000175000017500000000063312646030173020630 0ustar kaolkaol/** @group globals.counting Constrains \a c to be strictly greater than the number of occurrences of \a y in \a x. */ predicate count_gt(array[int] of var int: x, var int: y, var int: c) = c > sum(i in index_set(x)) ( bool2int(x[i] == y) ); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/sort.mzn0000644000175000017500000000131312646030173017771 0ustar kaolkaolinclude "alldifferent.mzn"; include "increasing.mzn"; /** @group globals.sort Requires that the multiset of values in \a x are the same as the multiset of values in \a y but \a y is in sorted order. */ predicate sort(array[int] of var int: x, array[int] of var int: y) = assert(card(index_set(x)) == card(index_set(y)), "sort: x and y must be same sized arrays", let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), array[lx..ux] of var ly..uy: p } in forall(i in index_set(x)) ( y[p[i]] == x[i] ) /\ alldifferent(p) /\ increasing(y) ); libminizinc-2.0.11/share/minizinc/std/decreasing.mzn0000644000175000017500000000152112646030173021107 0ustar kaolkaolinclude "decreasing_bool.mzn"; include "decreasing_float.mzn"; include "decreasing_int.mzn"; include "decreasing_set.mzn"; /** @group globals.sort Requires that the array \a x is in decreasing order (duplicates are allowed). */ predicate decreasing(array[int] of var bool: x) = decreasing_bool(x); /** @group globals.sort Requires that the array \a x is in decreasing order (duplicates are allowed). */ predicate decreasing(array[int] of var float: x) = decreasing_float(x); /** @group globals.sort Requires that the array \a x is in decreasing order (duplicates are allowed). */ predicate decreasing(array[int] of var int: x) = decreasing_int(x); /** @group globals.sort Requires that the array \a x is in decreasing order (duplicates are allowed). */ predicate decreasing(array[int] of var set of int: x) = decreasing_set(x); libminizinc-2.0.11/share/minizinc/std/set_member.mzn0000644000175000017500000000043012646030173021123 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate set_member(var set of int: x, var int: y) = y in x; libminizinc-2.0.11/share/minizinc/std/among.mzn0000644000175000017500000000035612646030173020111 0ustar kaolkaol/** @group globals.counting Requires exactly \a n variables in \a x to take one of the values in \a v. */ predicate among(var int: n, array[int] of var int: x, set of int: v) = n == sum(i in index_set(x)) ( bool2int(x[i] in v) ); libminizinc-2.0.11/share/minizinc/std/increasing.mzn0000644000175000017500000000152112646030173021125 0ustar kaolkaolinclude "increasing_bool.mzn"; include "increasing_float.mzn"; include "increasing_int.mzn"; include "increasing_set.mzn"; /** @group globals.sort Requires that the array \a x is in increasing order (duplicates are allowed). */ predicate increasing(array[int] of var bool: x) = increasing_bool(x); /** @group globals.sort Requires that the array \a x is in increasing order (duplicates are allowed). */ predicate increasing(array[int] of var float: x) = increasing_float(x); /** @group globals.sort Requires that the array \a x is in increasing order (duplicates are allowed). */ predicate increasing(array[int] of var int: x) = increasing_int(x); /** @group globals.sort Requires that the array \a x is in increasing order (duplicates are allowed). */ predicate increasing(array[int] of var set of int: x) = increasing_set(x); libminizinc-2.0.11/share/minizinc/std/sum_pred.mzn0000644000175000017500000000070412646030173020623 0ustar kaolkaol/** @group globals Requires that the sum of \a cs[\p i1]..\a cs[\p iN] equals \a s, where \p i1..\p iN are the elements of the \a i th set in \a sets. Nb: not called 'sum' as in the constraints catalog because 'sum' is a MiniZinc built-in function. */ predicate sum_pred(var int: i, array[int] of set of int: sets, array[int] of int: cs, var int: s) = s == sum(j in index_set(cs)) ( bool2int(j in sets[i]) * cs[j] ); libminizinc-2.0.11/share/minizinc/std/minimum.mzn0000644000175000017500000000152712646030173020464 0ustar kaolkaol/** @group globals Constrains \a m to be the minimum of the values in \a x. Assumptions: |\a x| > 0. */ predicate minimum(var float: m, array[int] of var float: x) = array_float_minimum(m, x); /** @group globals Constrains \a m to be the minimum of the values in \a x. Assumptions: |\a x| > 0. */ predicate minimum(var int: m, array[int] of var int: x) = array_int_minimum(m, x); % XXX: currently doesn't work: 'uy' is used as a type but that isn't % allowed because it's not a global variable. %predicate minimum(var set of int: m, array[int] of var set of int: x) = % let { int: l = min(index_set(x)), % int: u = max(index_set(x)), % set of int: uy = ub(x), % array[l..u] of var set of uy: y } in % y[l] = x[l] /\ % m = y[u] /\ % forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); libminizinc-2.0.11/share/minizinc/std/arg_sort_int.mzn0000644000175000017500000000057612646030173021506 0ustar kaolkaolinclude "alldifferent.mzn"; predicate arg_sort_int(array[int] of var int:x, array[int] of var int:p) = assert(index_set(p) = 1..length(x), "arg_sort_int: second argument must have index 1..length(first argument)", alldifferent(p) /\ forall(j in 1..length(x)-1) (x[p[j]] <= x[p[j+1]] /\ (x[p[j]] == x[p[j+1]] -> p[j] < p[j+1])) ); libminizinc-2.0.11/share/minizinc/std/count.mzn0000644000175000017500000000032712646030173020136 0ustar kaolkaolinclude "count_eq.mzn"; /** @group globals.counting Constrains \a c to be the number of occurrences of \a y in \a x. */ predicate count(array[int] of var int: x, var int: y, var int: c) = count_eq(x, y, c); libminizinc-2.0.11/share/minizinc/std/sort_fn.mzn0000644000175000017500000000053112646030173020455 0ustar kaolkaolinclude "sort.mzn"; /** @group globals.sort Return a multiset of values that is the same as the multiset of values in \a x but in sorted order. */ function array[int] of var int: sort(array[int] of var int: x) ::promise_total = let { array[1..length(x)] of var lb_array(x)..ub_array(x): y; constraint sort(x,y); } in y; libminizinc-2.0.11/share/minizinc/std/all_different_set.mzn0000644000175000017500000000053112646030173022454 0ustar kaolkaol%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate all_different_set(array[int] of var set of int: x) = forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); libminizinc-2.0.11/share/minizinc/std/arg_max_float.mzn0000644000175000017500000000074712646030173021617 0ustar kaolkaolpredicate maximum_arg_float(array[int] of var float: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); float: ly = lb_array(x); float: uy = ub_array(x); array[l..u] of var ly..uy: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == max(x[j],y[j-1]) /\ mi[j] = if y[j-1] >= x[j] then mi[j-1] else j endif ); libminizinc-2.0.11/share/minizinc/std/arg_min_float.mzn0000644000175000017500000000074712646030173021615 0ustar kaolkaolpredicate minimum_arg_float(array[int] of var float: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); float: ly = lb_array(x); float: uy = ub_array(x); array[l..u] of var ly..uy: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == min(x[j],y[j-1]) /\ mi[j] = if y[j-1] <= x[j] then mi[j-1] else j endif ); libminizinc-2.0.11/share/minizinc/std/increasing_float.mzn0000644000175000017500000000056412646030173022320 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate increasing_float(array[int] of var float: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.0.11/share/minizinc/std/all_equal_int.mzn0000644000175000017500000000015712646030173021620 0ustar kaolkaolpredicate all_equal_int(array[int] of var int: x) = forall(i, j in index_set(x) where i < j) ( x[i] = x[j] ); libminizinc-2.0.11/share/minizinc/std/value_precede_chain_set.mzn0000644000175000017500000000035012646030173023622 0ustar kaolkaolinclude "value_precede.mzn"; predicate value_precede_chain_set(array[int] of int: c, array[int] of var set of int: x) = forall (i in min(index_set(c)) + 1 .. max(index_set(c))) ( value_precede(c[i - 1], c[i], x) ); libminizinc-2.0.11/share/minizinc/std/at_least.mzn0000644000175000017500000000123712646030173020603 0ustar kaolkaolinclude "at_least_int.mzn"; include "at_least_set.mzn"; /** @group globals.counting Requires at least \a n variables in \a x to take the value \a v. */ predicate at_least(int: n, array[int] of var int: x, int: v) = at_least_int(n, x, v); /** @group globals.counting Requires at least \a n variables in \a x to take the value \a v. */ predicate at_least(int: n, array[int] of var set of int: x, set of int: v) = at_least_set(n, x, v); % Synonyms for the above. predicate atleast(int: n, array[int] of var int: x, int: v) = at_least_int(n, x, v); predicate atleast(int: n, array[int] of var set of int: x, set of int: v) = at_least_set(n, x, v); libminizinc-2.0.11/share/minizinc/std/exactly_set.mzn0000644000175000017500000000055212646030173021332 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires exactly 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate exactly_set(int: n, array[int] of var set of int: x, set of int: v) = n == sum(i in index_set(x)) ( bool2int(x[i] == v) ); libminizinc-2.0.11/share/minizinc/std/roots.mzn0000644000175000017500000000106512646030173020154 0ustar kaolkaol/** @group globals Requires that \a x[\p i] in \a t for all \p i in \a s */ predicate roots(array[int] of var int: x, var set of int: s, var set of int: t) = assert(ub(s) subset index_set(x), "roots: upper bound of 's' must be a subset of the index set of 'x'", % All values in 's' must map to a value in 't'. forall(i in ub(s)) ( i in s -> x[i] in t ) /\ forall(i in ub(t)) ( i in t -> forall(j in index_set(x)) (x[j] = i -> j in s ) ) ); libminizinc-2.0.11/share/minizinc/std/increasing_int.mzn0000644000175000017500000000056112646030173022002 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate increasing_int(array[int] of var int: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.0.11/share/minizinc/std/count_lt.mzn0000644000175000017500000000063012646030173020632 0ustar kaolkaol/** @group globals.counting Constrains \a c to be strictly less than the number of occurrences of \a y in \a x. */ predicate count_lt(array[int] of var int: x, var int: y, var int: c) = c < sum(i in index_set(x)) ( bool2int(x[i] == y) ); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/diffn.mzn0000644000175000017500000000147612646030173020102 0ustar kaolkaol/** @group globals.packing Constrains rectangles \p i, given by their origins (\a x[\p i], \a y[\p i]) and sizes (\a dx[\p i], \a dy[\p i]), to be non-overlapping. Zero-width rectangles can still not overlap with any other rectangle. */ predicate diffn(array[int] of var int: x, array[int] of var int: y, array[int] of var int: dx, array[int] of var int: dy) = assert( index_set(x) = index_set(y) /\ index_set(x) = index_set(dx) /\ index_set(x) = index_set(dy), "diffn: index set mismatch", forall(i,j in index_set(x) where i < j)( x[i] + dx[i] <= x[j] \/ y[i] + dy[i] <= y[j] \/ x[j] + dx[j] <= x[i] \/ y[j] + dy[j] <= y[i] ) ); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/alldifferent.mzn0000644000175000017500000000024312646030173021442 0ustar kaolkaol% The actual definitions are in all_different.mzn. % This file is used to handle the case where users include % "alldifferent.mzn"; % include "all_different.mzn"; libminizinc-2.0.11/share/minizinc/std/global_cardinality_low_up.mzn0000644000175000017500000000106612646030173024217 0ustar kaolkaol/** @group globals.counting Requires that for all \p i, the value \a cover[\p i] appears at least \a lbound[\p i] and at most \a ubound[\p i] times in the array \a x. */ predicate global_cardinality_low_up(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound) = forall(i in index_set(cover)) ( sum(j in index_set(x)) ( bool2int(x[j] = cover[i]) ) in lbound[i]..ubound[i] ); libminizinc-2.0.11/share/minizinc/std/geost.mzn0000644000175000017500000002213112646030173020124 0ustar kaolkaol/** @group globals.packing A global non-overlap constraint for \a k dimensional objects. It enforces that no two objects overlap. @param k: the number of dimensions @param rect_size: the size of each box in \a k dimensios @param rect_offset: the offset of each box from the base position in \a k dimensions @param shape: the set of rectangles defining the \p i-th shape. Assumption: Each pair of boxes in a shape must not overlap. @param x: the base position of each object. \a x[\p i,\p j] is the position of object \p i in. dimension \p j. @param kind: the shape used by each object. */ predicate geost( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind ) = assert( % Some sanity checks index_set_1of2( rect_size ) = index_set_1of2(rect_offset) /\ index_set_2of2( rect_size ) = 1..k /\ index_set_2of2( rect_offset ) = 1..k /\ index_set( shape ) = 1..length(shape) /\ index_set_1of2( x ) = index_set(kind) /\ index_set_2of2( x ) = 1..k /\ forall(i in index_set(shape))( shape[i] subset index_set_1of2(rect_size) ), % Error message "geost: index sets of arguments are incorrect", assert( % More sanity checks forall(i in index_set(shape))(card(shape[i]) > 0), % Error message "geost: sets in shape must be non-empty", % A few useful definitions let { set of int: DIMS = 1..k; set of int: SHAPES = 1..length(shape); set of int: OBJECTS = index_set(kind); } in % Testing whether the rectangle for each shape are not overlapping forall(s in SHAPES)( forall(r1, r2 in shape[s] where r1 < r2)( assert( geost_nonoverlap_k( [ rect_offset[ r1, j] | j in DIMS ], [ rect_size[ r1, j] | j in DIMS ], [ rect_offset[ r2, j] | j in DIMS ], [ rect_offset[ r2, j] | j in DIMS ] ), "geost: rectangles " ++ show(r1) ++ " and " ++ show(r2) ++ " in shape " ++ show(s) ++ " overlap!" ) ) ) /\ % Posting the geost constraint as decomposition forall(o1, o2 in OBJECTS where o1 < o2)( forall(s1 in dom(kind[o1]), s2 in dom(kind[o2]))( (kind[o1] = s1 /\ kind[o2] = s2 -> forall(r1 in shape[s1], r2 in shape[s2])( geost_nonoverlap_k( [ x[o1,j] + rect_offset[r1,j] | j in DIMS ], [ rect_size[r1,j] | j in DIMS ], [ x[o2,j] + rect_offset[r2,j] | j in DIMS ], [ rect_size[r2,j] | j in DIMS ] ) ) ) ) ) )); % End assert statements /** @group globals.packing A global non-overlap constraint for \a k dimensional objects. It enforces that no two objects overlap, and that all objects fit within a global \a k dimensional bounding box. @param k: the number of dimensions @param rect_size: the size of each box in \a k dimensios @param rect_offset: the offset of each box from the base position in \a k dimensions @param shape: the set of rectangles defining the \p i-th shape. Assumption: Each pair of boxes in a shape must not overlap. @param x: the base position of each object. \a x[\p i,\p j] is the position of object \p i in dimension \p j. @param kind: the shape used by each object. @param l: is an array of lower bounds, \a l[\p i] is the minimum bounding box for all objects in dimension \p i. @param u: is an array of upper bounds, \a u[\p i] is the maximum bounding box for all objects in dimension \p i. */ predicate geost_bb( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind , array[int ] of var int : l , array[int ] of var int : u ) = assert( % Sanity check index_set(l) = 1..k /\ index_set(u) = 1..k, % Error message "geost_bb: index set of bounds arrays is not 1.." ++ show(k), % Two useful definitions let { set of int: DIMS = 1..k; set of int: OBJECTS = index_set(kind); } in % Posting the geost constraint geost(k, rect_size, rect_offset, shape, x, kind) /\ % Posting the bounding box constraints forall(o in OBJECTS)( forall(s in dom(kind[o]))( (kind[o] = s -> forall(r in shape[s], j in DIMS)( x[o,j] + rect_offset[r,j] >= l[j] /\ x[o,j] + rect_offset[r,j] + rect_size[r,j] <= u[j] ) ) ) ) ); /** @group globals.packing A global non-overlap constraint for \a k dimensional objects. It enforces that no two objects overlap, and that all objects fit within a global \a k dimensional bounding box. In addition, it enforces that the bounding box is the smallest one containing all objects, i.e., each of the \a 2k boundaries is touched by at least by one object. @param k: the number of dimensions @param rect_size: the size of each box in \a k dimensios @param rect_offset: the offset of each box from the base position in \a k dimensions @param shape: the set of rectangles defining the \p i-th shape. Assumption: Each pair of boxes in a shape must not overlap. @param x: the base position of each object. \a x[\p i,\p j] is the position of object \p i in dimension \p j. @param kind: the shape used by each object. @param l: is an array of lower bounds, \a l[\p i] is the minimum bounding box for all objects in dimension \p i. @param u: is an array of upper bounds, \a u[\p i] is the maximum bounding box for all objects in dimension \p i. */ predicate geost_smallest_bb( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind , array[int ] of var int : l , array[int ] of var int : u ) = % Two useful definitions let { set of int: DIMS = 1..k; set of int: OBJECTS = index_set(kind); } in ( % Posting the geost constraint geost_bb(k, rect_size, rect_offset, shape, x, kind, l, u) /\ % Posting the smallest bounding box constraints forall(j in DIMS)( % Lower boundary exists(o in OBJECTS, s in dom(kind[o]))( kind[o] = s /\ exists(r in shape[s])( x[o,j] + rect_offset[r,j] == l[j] ) ) /\ % Upper boundary exists(o in OBJECTS, s in dom(kind[o]))( kind[o] = s /\ exists(r in shape[s])( x[o,j] + rect_offset[r,j] + rect_size[r,j] == u[j] ) ) ) ); predicate geost_nonoverlap_k( array[int] of var int : x1, array[int] of int : w1, array[int] of var int : x2, array[int] of int : w2 ) = assert( % Some sanity checks index_set( x1 ) = index_set( w1 ) /\ index_set( x1 ) = index_set( x2 ) /\ index_set( x1 ) = index_set( w2 ), % Error message "geost_nonoverlap_k: index sets of arguments do not match", % Non-overlap constraint exists(j in index_set(x1))( x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j] ) ); test geost_nonoverlap_k( array[int] of int: x1, array[int] of int: w1, array[int] of int: x2, array[int] of int: w2 ) = assert( % Some sanity checks index_set( x1 ) = index_set( w1 ) /\ index_set( x1 ) = index_set( x2 ) /\ index_set( x1 ) = index_set( w2 ), % Error message "geost_nonoverlap_k: index sets of arguments do not match", % Non-overlap test exists(j in index_set(x1))( x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j] ) ); libminizinc-2.0.11/share/minizinc/std/builtins.mzn0000644000175000017500000026071012646030173020643 0ustar kaolkaolinclude "flatzinc_builtins.mzn"; /*** @groupdef builtins Builtins These functions and predicates define built-in operations of the MiniZinc language. */ /*** @groupdef builtins.compare Comparison Builtins These builtins implement comparison operations. */ /** @group builtins.compare Return if \a x is less than \a y */ function bool: '<'( $T: x, $T: y); /** @group builtins.compare Return if \a x is less than \a y */ function var bool: '<'(var $T: x,var $T: y); /** @group builtins.compare Return if \a x is greater than \a y */ function bool: '>'( $T: x, $T: y); /** @group builtins.compare Return if \a x is greater than \a y */ function var bool: '>'(var $T: x,var $T: y); /** @group builtins.compare Return if \a x is less than or equal to \a y */ function bool: '<='( $T: x, $T: y); /** @group builtins.compare Return if \a x is less than or equal to \a y */ function var bool: '<='(var $T: x, var $T: y); /** @group builtins.compare Return if \a x is greater than or equal to \a y */ function bool: '>='( $T: x, $T: y); /** @group builtins.compare Return if \a x is greater than or equal to \a y */ function var bool: '>='(var $T: x,var $T: y); /** @group builtins.compare Return if \a x is equal to \a y */ function bool: '='( $T: x, $T: y); /** @group builtins.compare Return if \a x is equal to \a y */ function bool: '='(opt $T: x, opt $T: y); /** @group builtins.compare Return if \a x is equal to \a y */ function var bool: '='(var $T: x,var $T: y); /** @group builtins.compare Return if \a x is equal to \a y */ function var bool: '='(var opt $T: x,var opt $T: y); /** @group builtins.compare Return if \a x is not equal to \a y */ function bool: '!='( $T: x, $T: y); /** @group builtins.compare Return if \a x is not equal to \a y */ function var bool: '!='(var $T: x, var $T: y); /** @group builtins.compare Return if array \a x is lexicographically smaller than array \a y */ function bool: '<'(array[$U] of $T: x,array[$U] of $T: y); /** @group builtins.compare Return if array \a x is lexicographically smaller than array \a y */ function var bool: '<'(array[$U] of var $T: x,array[$U] of var $T: y); /** @group builtins.compare Return if array \a x is lexicographically greater than array \a y */ function bool: '>'(array[$U] of $T: x,array[$U] of $T: y); /** @group builtins.compare Return if array \a x is lexicographically greater than array \a y */ function var bool: '>'(array[$U] of var $T: x,array[$U] of var $T: y); /** @group builtins.compare Return if array \a x is lexicographically smaller than or equal to array \a y */ function bool: '<='(array[$U] of $T: x,array[$U] of $T: y); /** @group builtins.compare Return if array \a x is lexicographically smaller than or equal to array \a y */ function var bool: '<='(array[$U] of var $T: x,array[$U] of var $T: y); /** @group builtins.compare Return if array \a x is lexicographically greater than or equal to array \a y */ function bool: '>='(array[$U] of $T: x,array[$U] of $T: y); function var bool: '>='(array[$U] of var $T: x,array[$U] of var $T: y); /** @group builtins.compare Return if array \a x is equal to array \a y */ function bool: '='(array[$T] of int: x,array[$T] of int: y) = let { array[int] of int: xx = array1d(x); array[int] of int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function var bool: '='(array[$T] of var int: x,array[$T] of var int: y) = let { array[int] of var int: xx = array1d(x); array[int] of var int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function bool: '='(array[$T] of bool: x,array[$T] of bool: y) = let { array[int] of bool: xx = array1d(x); array[int] of bool: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function var bool: '='(array[$T] of var bool: x,array[$T] of var bool: y) = let { array[int] of var bool: xx = array1d(x); array[int] of var bool: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function bool: '='(array[$T] of set of int: x,array[$T] of set of int: y) = let { array[int] of set of int: xx = array1d(x); array[int] of set of int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function var bool: '='(array[$T] of var set of int: x,array[$T] of var set of int: y) = let { array[int] of var set of int: xx = array1d(x); array[int] of var set of int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function bool: '='(array[$T] of float: x,array[$T] of float: y) = let { array[int] of float: xx = array1d(x); array[int] of float: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function var bool: '='(array[$T] of var float: x,array[$T] of var float: y) = let { array[int] of var float: xx = array1d(x); array[int] of var float: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function bool: '!='(array[$U] of $T: x,array[$U] of $T: y); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function var bool: '!='(array[$U] of var $T: x,array[$U] of var $T: y); /*** @groupdef builtins.arithmetic Arithmetic Builtins These builtins implement arithmetic operations. */ /** @group builtins.arithmetic Return \a x + \a y */ function int: '+'( int: x, int: y); /** @group builtins.arithmetic Return \a x + \a y */ function var int: '+'(var int: x, var int: y); /** @group builtins.arithmetic Return \a x + \a y */ function float: '+'( float: x, float: y); /** @group builtins.arithmetic Return \a x + \a y */ function var float: '+'(var float: x,var float: y); /** @group builtins.arithmetic Return \a x - \a y */ function int: '-'( int: x, int: y); /** @group builtins.arithmetic Return \a x - \a y */ function var int: '-'(var int: x, var int: y); /** @group builtins.arithmetic Return \a x - \a y */ function float: '-'( float: x, float: y); /** @group builtins.arithmetic Return \a x - \a y */ function var float: '-'(var float: x,var float: y); /** @group builtins.arithmetic Return \a x * \a y */ function int: '*'( int: x, int: y); /** @group builtins.arithmetic Return \a x * \a y */ function var int: '*'(var int: x, var int: y); /** @group builtins.arithmetic Return \a x * \a y */ function float: '*'( float: x, float: y); /** @group builtins.arithmetic Return \a x * \a y */ function var float: '*'(var float: x,var float: y); /** @group builtins.arithmetic Return negative \a x */ function int: '-'( int: x); /** @group builtins.arithmetic Return negative \a x */ function var int: '-'(var int: x); /** @group builtins.arithmetic Return negative \a x */ function float: '-'( float: x); /** @group builtins.arithmetic Return negative \a x */ function var float: '-'(var float: x); /** @group builtins.arithmetic Return result of integer division \a x / \a y */ function int: 'div'(int: x,int: y); /** @group builtins.arithmetic Return result of integer division \a x / \a y */ function var int: 'div'(var int: x,var int: y) = if mzn_in_root_context(y) \/ not (0 in dom(y)) then div_t(x,y) else let { constraint y != 0 } in div_mt(x,y) endif; /** @group builtins.arithmetic Return remainder of integer division \a x % \a y */ function int: 'mod'(int: x,int: y); /** @group builtins.arithmetic Return remainder of integer division \a x % \a y */ function var int: 'mod'(var int: x,var int: y) = if mzn_in_root_context(y) \/ not (0 in dom(y)) then mod_t(x,y) else let { constraint y != 0 } in mod_mt(x,y) endif; /** @group builtins.arithmetic Return result of floating point division \a x / \a y */ function float: '/'( float: x, float: y); /** @group builtins.arithmetic Return result of floating point division \a x / \a y */ function var float: '/'(var float: x,var float: y); /** @group builtins.arithmetic Return sum of elements in array \a x */ function int: sum(array[$T] of int: x); /** @group builtins.arithmetic Return sum of elements in array \a x */ function var int: sum(array[$T] of var int: x); /** @group builtins.arithmetic Return sum of elements in array \a x */ function float: sum(array[$T] of float: x); /** @group builtins.arithmetic Return sum of elements in array \a x */ function var float: sum(array[$T] of var float: x); /** @group builtins.arithmetic Return product of elements in array \a x */ function int: product(array[$T] of int: x); /** @group builtins.arithmetic Return product of elements in array \a x */ function var int: product(array[$T] of var int: x) = product_rec(array1d(x)); /** @group builtins.arithmetic Return product of elements in array \a x */ function float: product(array[$T] of float: x); /** @group builtins.arithmetic Return product of elements in array \a x */ function var float: product(array[$T] of var float: x) = product_rec(array1d(x)); /** @group builtins.arithmetic Return minimum of \a x and \a y */ function $T: min( $T: x, $T: y); /** @group builtins.arithmetic Return minimum of elements in array \a x */ function $T: min(array[$U] of par $T: x); /** @group builtins.arithmetic Return maximum of \a x and \a y */ function $T: max( $T: x, $T: y); /** @group builtins.arithmetic Return maximum of elements in array \a x */ function $T: max(array[$U] of $T: x); /** @group builtins.arithmetic Return minimum of elements in set \a x */ function int: min(set of int: x); /** @group builtins.arithmetic Return maximum of elements in set \a x */ function int: max(set of int: x); /** @group builtins.arithmetic Return maximum of \a x and \a y */ function var int: max(var int: x, var int: y) :: promise_total = let { var max(lb(x),lb(y))..max(ub(x),ub(y)): m; constraint int_max(x,y,m); } in m; /** @group builtins.arithmetic Return maximum of elements in array \a x */ function var int: max(array[$U] of var int: x) = let { array[int] of var int: xx = array1d(x); constraint length(x) >= 1; } in max_t(xx); /** @group builtins.arithmetic Return minimum of \a x and \a y */ function var int: min(var int: x, var int: y) :: promise_total = let { var min(lb(x),lb(y))..min(ub(x),ub(y)): m; constraint int_min(x,y,m); } in m; /** @group builtins.arithmetic Return minimum of elements in array \a x */ function var int: min(array[$U] of var int: x) = let { array[int] of var int: xx = array1d(x); constraint length(x) >= 1; } in min_t(xx); % Floating point min and max % TODO: add bounds reasoning /** @group builtins.arithmetic Return maximum of \a x and \a y */ function var float: max(var float: x, var float: y) :: promise_total = let { var float: m; constraint float_max(x,y,m); } in m; /** @group builtins.arithmetic Return maximum of elements in array \a x */ function var float: max(array[$U] of var float: x) = let { array[int] of var float: xx = array1d(x); constraint length(x) >= 1; } in max_t(xx); /** @group builtins.arithmetic Return minimum of \a x and \a y */ function var float: min(var float: x, var float: y) :: promise_total = let { var float: m; constraint float_min(x,y,m); } in m; /** @group builtins.arithmetic Return minimum of elements in array \a x */ function var float: min(array[$U] of var float: x) = let { array[int] of var float: xx = array1d(x); constraint length(x) >= 1; } in min_t(xx); /** @group builtins.arithmetic Return index of minimum of elements in array \a x */ function int: arg_min(array[int] of int: x); /** @group builtins.arithmetic Return index of minimum of elements in array \a x */ function int: arg_min(array[int] of float: x); /** @group builtins.arithmetic Return index of maximum of elements in array \a x */ function int: arg_max(array[int] of int: x); /** @group builtins.arithmetic Return index of maximum of elements in array \a x */ function int: arg_max(array[int] of float: x); /** @group builtins.arithmetic Return absolute value of \a x */ function int: abs(int: x); /** @group builtins.arithmetic Return absolute value of \a x */ function var int: abs(var int: x) :: promise_total = if has_bounds(x) /\ lb(x) >= 0 then x else let { var 0..max(-lb(x),ub(x)): m; constraint int_abs(x,m); } in m endif; /** @group builtins.arithmetic Return absolute value of \a x */ function float: abs(float: x); /** @group builtins.arithmetic Return absolute value of \a x */ function var float: abs(var float: x) :: promise_total = if has_bounds(x) /\ lb(x)>=0.0 then x else let { var 0.0..max(-lb(x),ub(x)): m; constraint float_abs(x,m); } in m endif; /** @group builtins.arithmetic Return \(\sqrt{\a x}\) */ function float: sqrt(float: x); /** @group builtins.arithmetic Return \(\sqrt{\a x}\) */ function var float: sqrt(var float: x) = let { constraint x >= 0.0; } in sqrt_t(x); function var float: sqrt_t(var float: x) ::promise_total = let { var float: r; var float: xx; constraint x < 0.0 -> xx = 1.0; constraint x < 0.0 \/ xx = x; constraint float_sqrt(xx,r); } in r; /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function int: pow(int: x, int: y); /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function var int: pow(var int: x, var int: y) = let { int: yy = if is_fixed(y) then fix(y) else -1 endif; } in if yy = 0 then 1 elseif yy = 1 then x elseif yy = 2 then x*x else let { var int: r; constraint int_pow(x,y,r); } in r endif; /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function float: pow(float: x, float: y); /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function var float: pow(var float: x, var float: y) = let { float: yy = if is_fixed(y) then fix(y) else -1.0 endif } in if yy = 0.0 then 1.0 elseif yy = 1.0 then x elseif yy = 2.0 then x*x else let { var float: r; constraint float_pow(x,y,r); } in r endif; /*** @groupdef builtins.explog Exponential and logarithmic builtins These builtins implement exponential and logarithmic functions. */ /** @group builtins.explog Return \(e ^ {\a x}\) */ function float: exp(float: x); /** @group builtins.explog Return \(e ^ {\a x}\) */ function var float: exp(var float: x) ::promise_total = let { var float: r; constraint float_exp(x,r); } in r; /** @group builtins.explog Return \(\ln \a x\) */ function float: ln(float: x); /** @group builtins.explog Return \(\ln \a x\) */ function var float: ln(var float: x) ::promise_total = let { var float: r; constraint float_ln(x,r); } in r; /** @group builtins.explog Return \(\log_{10} \a x\) */ function float: log10(float: x); /** @group builtins.explog Return \(\log_{10} \a x\) */ function var float: log10(var float: x) ::promise_total = let { var float: r; constraint float_log10(x,r); } in r; /** @group builtins.explog Return \(\log_{2} \a x\) */ function float: log2(float: x); /** @group builtins.explog Return \(\log_{2} \a x\) */ function var float: log2(var float: x) ::promise_total = let { var float: r; constraint float_log2(x,r); } in r; /** @group builtins.explog Return \(\log_{\a x} \a y\) */ function float: log(float: x, float: y); /*** @groupdef builtins.trigonometric Trigonometric functions These builtins implement the standard trigonometric functions. */ /** @group builtins.trigonometric Return \(\sin \a x\) */ function float: sin(float: x); /** @group builtins.trigonometric Return \(\sin \a x\) */ function var float: sin(var float: x) ::promise_total = let { var -1.0..1.0: r; constraint float_sin(x,r); } in r; /** @group builtins.trigonometric Return \(\cos \a x\) */ function float: cos(float: x); /** @group builtins.trigonometric Return \(\cos \a x\) */ function var float: cos(var float: x) ::promise_total = let { var -1.0..1.0: r; constraint float_cos(x,r); } in r; /** @group builtins.trigonometric Return \(\tan \a x\) */ function float: tan(float: x); /** @group builtins.trigonometric Return \(\tan \a x\) */ function var float: tan(var float: x) ::promise_total = let { var float: r; constraint float_tan(x,r); } in r; /** @group builtins.trigonometric Return \(\mbox{asin}\ \a x\) */ function float: asin(float: x); /** @group builtins.trigonometric Return \(\mbox{asin}\ \a x\) */ function var float: asin(var float: x) ::promise_total = let { var float: r; constraint float_asin(x,r); } in r; /** @group builtins.trigonometric Return \(\mbox{acos}\ \a x\) */ function float: acos(float: x); /** @group builtins.trigonometric Return \(\mbox{acos}\ \a x\) */ function var float: acos(var float: x) ::promise_total = let { var float: r; constraint float_acos(x,r); } in r; /** @group builtins.trigonometric Return \(\mbox{atan}\ \a x\) */ function float: atan(float: x); /** @group builtins.trigonometric Return \(\mbox{atan}\ \a x\) */ function var float: atan(var float: x) ::promise_total = let { var float: r; constraint float_atan(x,r); } in r; /** @group builtins.trigonometric Return \(\sinh \a x\) */ function float: sinh(float: x); /** @group builtins.trigonometric Return \(\sinh \a x\) */ function var float: sinh(var float: x) ::promise_total = let { var float: r; constraint float_sinh(x,r); } in r; /** @group builtins.trigonometric Return \(\cosh \a x\) */ function float: cosh(float: x); /** @group builtins.trigonometric Return \(\cosh \a x\) */ function var float: cosh(var float: x) ::promise_total = let { var float: r; constraint float_cosh(x,r); } in r; /** @group builtins.trigonometric Return \(\tanh \a x\) */ function float: tanh(float: x); /** @group builtins.trigonometric Return \(\tanh \a x\) */ function var float: tanh(var float: x) ::promise_total = let { var float: r; constraint float_tanh(x,r); } in r; /** @group builtins.trigonometric Return \(\mbox{asinh}\ \a x\) */ function float: asinh(float: x); /** @group builtins.trigonometric Return \(\mbox{asinh}\ \a x\) */ function var float: asinh(var float: x) ::promise_total = let { var float: r; constraint float_asinh(x,r); } in r; /** @group builtins.trigonometric Return \(\mbox{acosh}\ \a x\) */ function float: acosh(float: x); /** @group builtins.trigonometric Return \(\mbox{acosh}\ \a x\) */ function var float: acosh(var float: x) ::promise_total = let { var float: r; constraint float_acosh(x,r); } in r; /** @group builtins.trigonometric Return \(\mbox{atanh}\ \a x\) */ function float: atanh(float: x); /** @group builtins.trigonometric Return \(\mbox{atanh}\ \a x\) */ function var float: atanh(var float: x) ::promise_total = let { var float: r; constraint float_atanh(x,r); } in r; /*** @groupdef builtins.logic Logical operations Logical operations are the standard operators of Boolean logic. */ /** @group builtins.logic Return truth value of \a x ∧ \a y */ function bool: '/\'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x ∧ \a y */ function var bool: '/\'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a x ∨ \a y */ function bool: '\/'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x ∨ \a y */ function var bool: '\/'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a x implies \a y */ function bool: '->'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x implies \a y */ function var bool: '->'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a y implies \a x */ function bool: '<-'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a y implies \a x */ function var bool: '<-'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a x if-and-only-if \a y */ function bool: '<->'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x if-and-only-if \a y */ function var bool: '<->'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a x xor \a y */ function bool: 'xor'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x xor \a y */ function var bool: 'xor'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of the negation of \a x */ function bool: 'not'( bool: x); /** @group builtins.logic Return truth value of the negation of \a x */ function var bool: 'not'(var bool: x); /** @group builtins.logic Return truth value of \(\bigwedge_i \a x[i]\) */ function bool: forall(array[$T] of bool: x); /** @group builtins.logic Return truth value of \(\bigwedge_i \a x[i]\) */ function var bool: forall(array[$T] of var bool: x); /** @group builtins.logic Return truth value of \(\bigvee_i \a x[i]\) */ function bool: exists(array[$T] of bool: x); /** @group builtins.logic Return truth value of \(\bigvee_i \a x[i]\) */ function var bool: exists(array[$T] of var bool: x); /** @group builtins.logic Return truth value of \(\oplus_i \a x[i]\) */ function bool: xorall(array[$T] of bool: x); /** @group builtins.logic Return truth value of \(\oplus_i \a x[i]\) */ function var bool: xorall(array[$T] of var bool: x) = array_bool_xor(array1d(x)); /** @group builtins.logic Return truth value of \(\text{true}\oplus (\oplus_i \a x[i])\) */ function bool: iffall(array[$T] of bool: x); /** @group builtins.logic Return truth value of \(\text{true}\oplus (\oplus_i \a x[i])\) */ function var bool: iffall(array[$T] of var bool: x) = array_bool_xor(array1d(x)++[true]); /** @group builtins.logic Return truth value of \((\bigvee_i \a x[i]) \lor (\bigvee_j \lnot \a y[j])\) */ function var bool: clause(array[$T] of var bool: x, array[$T] of var bool: y); /** @group builtins.logic Return truth value of \((\bigvee_i \a x[i]) \lor (\bigvee_j \lnot \a y[j])\) */ function var bool: clause(array[$T] of bool: x, array[$T] of bool: y); /*** @groupdef builtins.set Set operations These functions implement the basic operations on sets. */ /** @group builtins.set Test if \a x is an element of the set \a y */ function bool: 'in'( int: x, set of int: y); /** @group builtins.set \a x is an element of the set \a y */ function var bool: 'in'(var int: x, var set of int: y); /** @group builtins.set Test if \a x is a subset of \a y */ function bool: 'subset'( set of $T: x, set of $T: y); /** @group builtins.set \a x is a subset of \a y */ function var bool: 'subset'(var set of int: x, var set of int: y); /** @group builtins.set Test if \a x is a superset of \a y */ function bool: 'superset'( set of $T: x, set of $T: y); /** @group builtins.set \a x is a superset of \a y */ function var bool: 'superset'(var set of int: x, var set of int: y); /** @group builtins.set Return the union of sets \a x and \a y */ function set of $T: 'union'( set of $T: x, set of $T: y); /** @group builtins.set Return the union of sets \a x and \a y */ function var set of int: 'union'(var set of int: x, var set of int: y); /** @group builtins.set Return the intersection of sets \a x and \a y */ function set of $T: 'intersect'( set of $T: x, set of $T: y); /** @group builtins.set Return the intersection of sets \a x and \a y */ function var set of int: 'intersect'(var set of int: x, var set of int: y); /** @group builtins.set Return the set difference of sets \a x − \a y */ function set of $T: 'diff'( set of $T: x, set of $T: y); /** @group builtins.set Return the set difference of sets \a x − \a y */ function var set of int: 'diff'(var set of int: x, var set of int: y); /** @group builtins.set Return the symmetric set difference of sets \a x and \a y */ function set of $T: 'symdiff'( set of $T: x, set of $T: y); /** @group builtins.set Return the symmetric set difference of sets \a x and \a y */ function var set of int: 'symdiff'(var set of int: x, var set of int: y); /** @group builtins.set Return the set \(\{\a a,\ldots,\a b\}\) */ function set of int: '..'(int: a,int: b); /** @group builtins.set Return the set \(\{\a a,\ldots,\a b\}\) */ function set of float: '..'(float: a,float: b); function var set of int: '..'(var int: a, var int: b) ::promise_total = let { var set of min(lb(a),lb(b))..max(ub(a),ub(b)): s; constraint forall (i in ub(s)) (i in s <-> (a <= i /\ i <= b)); } in s; /** @group builtins.set Return the cardinality of the set \a x */ function int: card( set of $T: x); /** @group builtins.set Return the cardinality of the set \a x */ function var int: card(var set of int: x); /** @group builtins.set Return the union of the sets in array \a x */ function set of $U: array_union(array[$T] of set of $U: x); /** @group builtins.set Return the union of the sets in array \a x */ function var set of int: array_union(array[$T] of var set of int: x) = array_union_rec(array1d(x)); /** @group builtins.set Return the intersection of the sets in array \a x */ function set of $U: array_intersect(array[$T] of set of $U: x); function var set of int: array_intersect(array[$T] of var set of int: x) = array_intersect_rec(array1d(x)); /*** @groupdef builtins.array Array operations These functions implement the basic operations on arrays. */ /** @group builtins.array Return the concatenation of arrays \a x and \a y */ function array[int] of $T: '++'(array[int] of $T: x, array[int] of $T: y); /** @group builtins.array Return the concatenation of arrays \a x and \a y */ function array[int] of var $T: '++'(array[int] of var $T: x, array[int] of var $T: y); /** @group builtins.array Return the concatenation of arrays \a x and \a y */ function array[int] of var opt $T: '++'(array[int] of var opt $T: x, array[int] of var opt $T: y); /** @group builtins.array Return the length of array \a x Note that the length is defined as the number of elements in the array, regardless of its dimensionality. */ function int: length(array[$T] of var opt $U: x); /** @group builtins.array Return the array \a x in reverse order The resulting array has the same index set as \a x. */ function array[int] of $T: reverse(array[int] of $T: x) = let { int: l = max(index_set(x))+min(index_set(x)) } in array1d(index_set(x),[x[l-i] | i in index_set(x)]); /** @group builtins.array Return the array \a x in reverse order The resulting array has the same index set as \a x. */ function array[int] of var $T: reverse(array[int] of var $T: x) = let { int: l = max(index_set(x))+min(index_set(x)) } in array1d(index_set(x),[x[l-i] | i in index_set(x)]); /** @group builtins.array Return the array \a x in reverse order The resulting array has the same index set as \a x. */ function array[int] of var opt $T: reverse(array[int] of var opt $T: x) = let { int: l = max(index_set(x))+min(index_set(x)) } in array1d(index_set(x),[x[l-i] | i in index_set(x)]); /** @group builtins.array Test if \a x and \a y have the same index sets */ test index_sets_agree(array[$T] of var opt $U: x, array[$T] of var opt $W: y); /** @group builtins.array Return index set of one-dimensional array \a x */ function set of int: index_set(array[int] of var opt $U: x); /** @group builtins.array Return index set of first dimension of two-dimensional array \a x */ function set of int: index_set_1of2(array[int,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of two-dimensional array \a x */ function set of int: index_set_2of2(array[int,int] of var opt $U: x); /** @group builtins.array Return index set of first dimension of 3-dimensional array \a x */ function set of int: index_set_1of3(array[int,int,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of 3-dimensional array \a x */ function set of int: index_set_2of3(array[int,int,int] of var opt $U: x); /** @group builtins.array Return index set of third dimension of 3-dimensional array \a x */ function set of int: index_set_3of3(array[int,int,int] of var opt $U: x); /** @group builtins.array Return index set of first dimension of 4-dimensional array \a x */ function set of int: index_set_1of4(array[int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of 4-dimensional array \a x */ function set of int: index_set_2of4(array[int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of third dimension of 4-dimensional array \a x */ function set of int: index_set_3of4(array[int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of fourth dimension of 4-dimensional array \a x */ function set of int: index_set_4of4(array[int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of first dimension of 5-dimensional array \a x */ function set of int: index_set_1of5(array[int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of 5-dimensional array \a x */ function set of int: index_set_2of5(array[int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of third dimension of 5-dimensional array \a x */ function set of int: index_set_3of5(array[int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of fourth dimension of 5-dimensional array \a x */ function set of int: index_set_4of5(array[int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of fifth dimension of 5-dimensional array \a x */ function set of int: index_set_5of5(array[int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of first dimension of 6-dimensional array \a x */ function set of int: index_set_1of6(array[int,int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of 6-dimensional array \a x */ function set of int: index_set_2of6(array[int,int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of third dimension of 6-dimensional array \a x */ function set of int: index_set_3of6(array[int,int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of fourth dimension of 6-dimensional array \a x */ function set of int: index_set_4of6(array[int,int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of fifth dimension of 6-dimensional array \a x */ function set of int: index_set_5of6(array[int,int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of sixth dimension of 6-dimensional array \a x */ function set of int: index_set_6of6(array[int,int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return array \a x coerced to index set 1..length(\a x) */ function array[int] of $V: array1d(array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to index set 1..length(\a x) */ function array[int] of var $V: array1d(array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to index set 1..length(\a x) */ function array[int] of var opt $V: array1d(array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to one-dimensional array with index set \a S */ function array[int] of $V: array1d(set of int: S, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to one-dimensional array with index set \a S */ function array[int] of var $V: array1d(set of int: S, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to one-dimensional array with index set \a S */ function array[int] of var opt $V: array1d(set of int: S, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to two-dimensional array with index sets \a S1 and \a S2 */ function array[int,int] of $V: array2d(set of int: S1, set of int: S2, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to two-dimensional array with index sets \a S1 and \a S2 */ function array[int,int] of var $V: array2d(set of int: S1, set of int: S2, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to two-dimensional array with index sets \a S1 and \a S2 */ function array[int,int] of var opt $V: array2d(set of int: S1, set of int: S2, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to three-dimensional array with index sets \a S1, \a S2 and \a S3 */ function array[int,int,int] of $V: array3d(set of int: S1, set of int: S2, set of int: S3, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to three-dimensional array with index sets \a S1, \a S2 and \a S3 */ function array[int,int,int] of var $V: array3d(set of int: S1, set of int: S2, set of int: S3, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to three-dimensional array with index sets \a S1, \a S2 and \a S3 */ function array[int,int,int] of var opt $V: array3d(set of int: S1, set of int: S2, set of int: S3, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to 4-dimensional array with index sets \a S1, \a S2, \a S3 and \a S4 */ function array[int,int,int,int] of $V: array4d(set of int: S1, set of int: S2, set of int: S3, set of int: S4, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to 4-dimensional array with index sets \a S1, \a S2, \a S3 and \a S4 */ function array[int,int,int,int] of var $V: array4d(set of int: S1, set of int: S2, set of int: S3, set of int: S4, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to 4-dimensional array with index sets \a S1, \a S2, \a S3 and \a S4 */ function array[int,int,int,int] of var opt $V: array4d(set of int: S1, set of int: S2, set of int: S3, set of int: S4, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to 5-dimensional array with index sets \a S1, \a S2, \a S3, \a S4 and \a S5 */ function array[int,int,int,int,int] of $V: array5d(set of int: S1, set of int: S2, set of int: S3, set of int: S4, set of int: S5, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to 5-dimensional array with index sets \a S1, \a S2, \a S3, \a S4 and \a S5 */ function array[int,int,int,int,int] of var $V: array5d(set of int: S1, set of int: S2, set of int: S3, set of int: S4, set of int: S5, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to 5-dimensional array with index sets \a S1, \a S2, \a S3, \a S4 and \a S5 */ function array[int,int,int,int,int] of var opt $V: array5d(set of int: S1, set of int: S2, set of int: S3, set of int: S4, set of int: S5, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to 6-dimensional array with index sets \a S1, \a S2, \a S3, \a S4, \a S5 and \a S6 */ function array[int,int,int,int,int,int] of $V: array6d(set of int: S1, set of int: S2, set of int: S3, set of int: S4, set of int: S5, set of int: S6, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to 6-dimensional array with index sets \a S1, \a S2, \a S3, \a S4, \a S5 and \a S6 */ function array[int,int,int,int,int,int] of var $V: array6d(set of int: S1, set of int: S2, set of int: S3, set of int: S4, set of int: S5, set of int: S6, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to 6-dimensional array with index sets \a S1, \a S2, \a S3, \a S4, \a S5 and \a S6 */ function array[int,int,int,int,int,int] of var opt $V: array6d(set of int: S1, set of int: S2, set of int: S3, set of int: S4, set of int: S5, set of int: S6, array[$U] of var opt $V: x); /** @group builtins.array Return array \a y coerced to array with same number of dimensions and same index sets as array \a x */ function array[$T] of $V: arrayXd(array[$T] of var opt $X: x, array[$U] of $V: y); /** @group builtins.array Return array \a y coerced to array with same number of dimensions and same index sets as array \a x */ function array[$T] of var $V: arrayXd(array[$T] of var opt $X: x, array[$U] of var $V: y); /** @group builtins.array Return array \a y coerced to array with same number of dimensions and same index sets as array \a x */ function array[$T] of var opt $V: arrayXd(array[$T] of var opt $X: x, array[$U] of var opt $V: y); /** @group builtins.array Return row \a r of array \a x */ function array[int] of $T: row(array[int, int] of $T: x, int: r) = array1d(index_set_2of2(x), [x[r,i] | i in index_set_2of2(x)]); /** @group builtins.array Return row \a r of array \a x */ function array[int] of var $T: row(array[int, int] of var $T: x, int: r) = array1d(index_set_2of2(x), [x[r,i] | i in index_set_2of2(x)]); /** @group builtins.array Return row \a r of array \a x */ function array[int] of var opt $T: row(array[int, int] of var opt $T: x, int: r) = array1d(index_set_2of2(x), [x[r,i] | i in index_set_2of2(x)]); /** @group builtins.array Return column \a c of array \a x */ function array[int] of $T: col(array[int,int] of $T: x, int: c) = array1d(index_set_1of2(x), [x[i,c] | i in index_set_1of2(x)]); /** @group builtins.array Return column \a c of array \a x */ function array[int] of var $T: col(array[int,int] of var $T: x, int: c) = array1d(index_set_1of2(x), [x[i,c] | i in index_set_1of2(x)]); /** @group builtins.array Return column \a c of array \a x */ function array[int] of var opt $T: col(array[int,int] of var opt $T: x, int: c) = array1d(index_set_1of2(x), [x[i,c] | i in index_set_1of2(x)]); /** @group builtins.array Test if \a i is in the index set of \a x */ test has_index(int: i, array[int] of var opt $T: x) = i in index_set(x); /** @group builtins.array Test if \a e is an element of array \a x */ test has_element($T: e, array[int] of $T: x) = exists (i in index_set(x)) (x[i]=e); /** @group builtins.array Test if \a e is an element of array \a x */ predicate has_element($T: e, array[int] of var opt $T: x) = exists (i in index_set(x)) (x[i]=e); /*** @groupdef builtins.sort Array sorting operations */ /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[int] of var opt $T: sort_by(array[int] of var opt $T: x, array[int] of int: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[int] of var $T: sort_by(array[int] of var $T: x, array[int] of int: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[int] of $T: sort_by(array[int] of $T: x, array[int] of int: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[int] of var opt $T: sort_by(array[int] of var opt $T: x, array[int] of float: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[int] of var $T: sort_by(array[int] of var $T: x, array[int] of float: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[int] of $T: sort_by(array[int] of $T: x, array[int] of float: y); /** @group builtins.sort Return values from array \a x sorted in non-decreasing order */ function array[int] of int: sort(array[int] of int: x); /** @group builtins.sort Return values from array \a x sorted in non-decreasing order */ function array[int] of float: sort(array[int] of float: x); /** @group builtins.sort Return values from array \a x sorted in non-decreasing order */ function array[int] of bool: sort(array[int] of bool: x); /** @group builtins.sort Returns the permutation \a p which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ function array[int] of int: arg_sort(array[int] of int:x) = sort_by([i | i in index_set(x)], x); /** @group builtins.sort Returns the permutation \a p which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ function array[int] of int: arg_sort(array[int] of float:x) = sort_by([i | i in index_set(x)], x); /*** @groupdef builtins.coercion Coercions These functions implement coercions, or channeling, between different types. */ /** @group builtins.coercion Return \( \lceil{ \a x} \rceil \) */ function int: ceil(float: x); /** @group builtins.coercion Return \( \lfloor{ \a x} \rfloor \) */ function int: floor(float: x); /** @group builtins.coercion Return \a x rounded to nearest integer */ function int: round(float: x); /** @group builtins.coercion Return Boolean \a b coerced to an integer */ function int: bool2int(bool: b); /** @group builtins.coercion Return Boolean \a b coerced to a float */ function float: bool2float(bool: b) = if b then 1.0 else 0.0 endif; /** @group builtins.coercion Return array of Booleans \a x coerced to an array of floats */ function array[$T] of float: bool2float(array[$T] of bool: x) ::promise_total = let { array[int] of bool: xx = array1d(x) } in arrayXd(x,[bool2float(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of Booleans \a x coerced to an array of floats */ function array[$T] of var float: bool2float(array[$T] of var bool: x) ::promise_total = let { array[int] of var bool: xx = array1d(x) } in arrayXd(x,[bool2float(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return Boolean \a b coerced to an integer */ function var int: bool2int(var bool: b); /** @group builtins.coercion Return array of Booleans \a b coerced to an array of integers */ function array[int] of var int: bool2int(array[int] of var bool: b); /** @group builtins.coercion Return Boolean \a b coerced to a float */ function var float: bool2float(var bool: b) = int2float(bool2int(b)); /** @group builtins.coercion Return integer \a x coerced to a float */ function float: int2float(int: x); /** @group builtins.coercion Return integer \a x coerced to a float */ function var float: int2float(var int: x) ::promise_total = let { var int2float(lb(x))..int2float(ub(x)): y; constraint int2float(x,y); } in y; function set of int: bool2int(set of bool: b) = if b={false,true} then {0,1} elseif b={false} then {0} elseif b={true} then {1} else {} endif; /** @group builtins.coercion Return array of Booleans \a x coerced to an array of integers */ function array[$T] of int: bool2int(array[$T] of bool: x) ::promise_total = let { array[int] of bool: xx = array1d(x) } in arrayXd(x,[bool2int(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of sets of Booleans \a x coerced to an array of sets of integers */ function array[$T] of set of int: bool2int(array[$T] of set of bool: x) ::promise_total = let { array[int] of set of bool: xx = array1d(x) } in arrayXd(x,[bool2int(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of Booleans \a x coerced to an array of integers */ function array[$T] of var int: bool2int(array[$T] of var bool: x) ::promise_total = let { array[int] of var bool: xx = array1d(x) } in arrayXd(x,[bool2int(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of Booleans \a x coerced to an array of integers */ function array[$T] of var opt int: bool2int(array[$T] of var opt bool: x) ::promise_total = let { array[int] of var opt bool: xx = array1d(x) } in arrayXd(x,[bool2int(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of integers \a x coerced to an array of floats */ function array[$T] of float: int2float(array[$T] of int: x) ::promise_total = let { array[int] of int: xx = array1d(x) } in arrayXd(x,[int2float(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of integers \a x coerced to an array of floats */ function array[$T] of var float: int2float(array[$T] of var int: x) ::promise_total = let { array[int] of var int: xx = array1d(x) } in arrayXd(x,[int2float(xx[i]) | i in index_set(xx)]); % Only supported for set of int: % function array[int] of $T: set2array(set of $T); /** @group builtins.coercion Return a set of integers \a x coerced to an array of integers */ function array[int] of int: set2array(set of int: x); /*** @groupdef builtins.string String operations These functions implement operations on strings. */ /** @group builtins.string Convert \a x into a string */ function string: show(var opt set of $T: x); /** @group builtins.string Convert \a x into a string */ function string: show(var opt $T: x); /** @group builtins.string Convert \a x into a string */ function string: show(array[$U] of var opt $T: x); /** @group builtins.string Formatted to-string conversion for integers Converts the integer \a x into a string right justified by the number of characters given by \a w, or left justified if \a w is negative. */ function string: show_int(int: w, var int: x); /** @group builtins.string Formatted to-string conversion for floats. Converts the float \a x into a string right justified by the number of characters given by \a w, or left justified if \a w is negative. The number of digits to appear after the decimal point is given by \a p. It is a run-time error for \a p to be negative. */ function string: show_float(int: w, int: p, var float: x); /** @group builtins.string Convert two-dimensional array \a x into a string */ function string: show2d(array[int,int] of var opt $T: x) = let { int: rows=card(index_set_1of2(x)); int: cols=card(index_set_2of2(x)); array[int] of string: s = [show(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)]; int: max_length = max([string_length(s[i]) | i in index_set(s)]) } in "[| "++ concat([format(max_length,s[(i-1)*cols+j])++ if j= l /\ ub(x) <= u then true else x >= l /\ x <= u endif; test var_dom(float:x, float: l, float: u) = x >= l /\ x <= u; predicate var_dom(array[$T] of var set of int: x, set of int: d) = let { array[int] of var set of int: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],d)); predicate var_dom(array[$T] of var int: x, set of int: d) = let { array[int] of var int: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],d)); predicate var_dom(array[$T] of var float: x, float: l, float: u) = let { array[int] of var float: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],l,u)); test var_dom(array[$T] of set of int: x, set of int: d) = let { array[int] of set of int: xx = array1d(x) } in forall (i in index_set(xx)) (xx[i] subset d); test var_dom(array[$T] of int: x, set of int: d) = let { array[int] of int: xx = array1d(x) } in forall (i in index_set(xx)) (xx[i] in d); test var_dom(array[$T] of float: x, float: l, float: u) = let { array[int] of float: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],l,u)); function var set of int: array2set(array[int] of var int: x) ::promise_total = let { var set of int: y = array_union([ let { var set of dom(x[i]): s; constraint x[i] in s /\ card(s)=1; } in s | i in index_set(x)]); } in y; function set of int: array2set(array[int] of int: x) = { x[i] | i in index_set(x) }; predicate array_var_int_element(var int: x, array[int] of int: y, var int: z) = array_int_element(x,y,z); predicate array_var_bool_element(var int: x, array[int] of bool: y, var bool: z) = array_bool_element(x,y,z); predicate array_var_float_element(var int: x, array[int] of float: y, var float: z) = array_float_element(x,y,z); predicate array_var_set_element(var int: x, array[int] of set of int: y, var set of int: z) = array_set_element(x,y,z); predicate bool_xor_reif(var bool: a, var bool: b, var bool: c) = bool_xor(a,b,c); predicate xorall_reif(array[int] of var bool: b, var bool: c) = xorall([not c]++b); function var int: lin_exp(array[int] of int, array[int] of var int, int); function var float: lin_exp(array[int] of float, array[int] of var float, float); test mzn_in_root_context(var $T); test mzn_in_redundant_constraint(); %-----------------------------------------------------------------------------% % % Element constraint implementations % % MiniZinc compiles element constraints using a series of intermediate % functions that test whether the constraint is total and perform array slicing % for multi-dimensional element constraints. % %%%%%%%%%%%%%%%%%%% % Element on ints function var int: element_t(var int: idx, array[int] of var int: x) :: promise_total = let { var dom_bounds_array(x): r ::is_defined_var; constraint idx in index_set(x); constraint array_var_int_element_nonshifted(idx,x,r) ::defines_var(r); } in r; function var int: element_mt(var int: idx, array[int] of var int: x) :: promise_total = let { var lb_array(x)..ub_array(x): r ::is_defined_var; var min(index_set(x))..max(index_set(x)): idx2; constraint idx in index_set(x) -> idx2=idx; constraint idx in index_set(x) \/ idx2=min(index_set(x)); constraint array_var_int_element_nonshifted(idx2,x,r) ::defines_var(r); } in r; function var int: element(var int: idx, array[int] of var int: x) = if mzn_in_root_context(idx) \/ (has_bounds(idx) /\ lb(idx) >= min(index_set(x)) /\ ub(idx) <= max(index_set(x))) then element_t(idx,x) else let { constraint idx in index_set(x) } in element_mt(idx,x) endif; function var int: element(var int: idx1, var int: idx2, array[int,int] of var int: x) = let { int: dim = card(index_set_2of2(x)); int: min_flat = min(index_set_1of2(x))*dim+min(index_set_2of2(x))-1; } in if mzn_in_root_context(idx1) \/ ((has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of2(x)) /\ ub(idx1) <= max(index_set_1of2(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of2(x)) /\ ub(idx2) <= max(index_set_2of2(x)))) then element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) else let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_mt( (idx1*dim+idx2-min_flat)::domain, array1d(x)) endif; function var int: element(var int: idx1, var int: idx2, var int: idx3, array[int,int,int] of var int: x) = let { int: dim2 = card(index_set_2of3(x)); int: dim3 = card(index_set_3of3(x)); int: min = min(index_set_1of3(x))*dim2*dim3+ min(index_set_2of3(x))*dim3+ min(index_set_3of3(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of3(x)) /\ ub(idx1) <= max(index_set_1of3(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of3(x)) /\ ub(idx2) <= max(index_set_2of3(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of3(x)) /\ ub(idx3) <= max(index_set_3of3(x)))) then element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_mt( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) endif; function var int: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, array[int,int,int,int] of var int: x) = let { int: dim2 = card(index_set_2of4(x)); int: dim3 = card(index_set_3of4(x)); int: dim4 = card(index_set_4of4(x)); int: min = min(index_set_1of4(x))*dim2*dim3*dim4+ min(index_set_2of4(x))*dim3*dim4+ min(index_set_3of4(x))*dim4+ min(index_set_4of4(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of4(x)) /\ ub(idx1) <= max(index_set_1of4(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of4(x)) /\ ub(idx2) <= max(index_set_2of4(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of4(x)) /\ ub(idx3) <= max(index_set_3of4(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of4(x)) /\ ub(idx4) <= max(index_set_4of4(x))) ) then element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_mt( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) endif; %%%%%%%%%%%%%%%%%%% % Element on floats function var float: element_t(var int: idx, array[int] of var float: x) :: promise_total = let { var lb_array(x)..ub_array(x): r ::is_defined_var; constraint idx in index_set(x); constraint array_var_float_element_nonshifted(idx,x,r) ::defines_var(r); } in r; function var float: element_mt(var int: idx, array[int] of var float: x) :: promise_total = let { var lb_array(x)..ub_array(x): r ::is_defined_var; var min(index_set(x))..max(index_set(x)): idx2; constraint idx in index_set(x) -> idx2=idx; constraint idx in index_set(x) \/ idx2=min(index_set(x)); constraint array_var_float_element_nonshifted(idx2,x,r) ::defines_var(r); } in r; function var float: element(var int: idx, array[int] of var float: x) = if mzn_in_root_context(idx) \/ (has_bounds(idx) /\ lb(idx) >= min(index_set(x)) /\ ub(idx) <= max(index_set(x))) then element_t(idx,x) else let { constraint idx in index_set(x) } in element_mt(idx,x) endif; function var float: element(var int: idx1, var int: idx2, array[int,int] of var float: x) = let { int: dim = card(index_set_2of2(x)); int: min_flat = min(index_set_1of2(x))*dim+min(index_set_2of2(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of2(x)) /\ ub(idx1) <= max(index_set_1of2(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of2(x)) /\ ub(idx2) <= max(index_set_2of2(x))) ) then element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) else let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_mt( (idx1*dim+idx2-min_flat)::domain, array1d(x)) endif; function var float: element(var int: idx1, var int: idx2, var int: idx3, array[int,int,int] of var float: x) = let { int: dim2 = card(index_set_2of3(x)); int: dim3 = card(index_set_3of3(x)); int: min = min(index_set_1of3(x))*dim2*dim3+ min(index_set_2of3(x))*dim3+ min(index_set_3of3(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of3(x)) /\ ub(idx1) <= max(index_set_1of3(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of3(x)) /\ ub(idx2) <= max(index_set_2of3(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of3(x)) /\ ub(idx3) <= max(index_set_3of3(x))) ) then element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_mt( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) endif; function var float: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, array[int,int,int,int] of var float: x) = let { int: dim2 = card(index_set_2of4(x)); int: dim3 = card(index_set_3of4(x)); int: dim4 = card(index_set_4of4(x)); int: min = min(index_set_1of4(x))*dim2*dim3*dim4+ min(index_set_2of4(x))*dim3*dim4+ min(index_set_3of4(x))*dim4+ min(index_set_4of4(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of4(x)) /\ ub(idx1) <= max(index_set_1of4(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of4(x)) /\ ub(idx2) <= max(index_set_2of4(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of4(x)) /\ ub(idx3) <= max(index_set_3of4(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of4(x)) /\ ub(idx4) <= max(index_set_4of4(x))) ) then element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_mt( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) endif; %%%%%%%%%%%%%%%%% % Element on sets function var set of int: element_t(var int: idx, array[int] of var set of int: x) :: promise_total = let { var set of min(ub_array(x))..max(ub_array(x)): r ::is_defined_var; constraint idx in index_set(x); constraint array_var_set_element_nonshifted(idx,x,r) ::defines_var(r); } in r; function var set of int: element_mt(var int: idx, array[int] of var set of int: x) :: promise_total = let { var set of min(ub_array(x))..max(ub_array(x)): r ::is_defined_var; var min(index_set(x))..max(index_set(x)): idx2; constraint idx in index_set(x) -> idx2=idx; constraint idx in index_set(x) \/ idx2=min(index_set(x)); constraint array_var_set_element_nonshifted(idx2,x,r) ::defines_var(r); } in r; function var set of int: element(var int: idx, array[int] of var set of int: x) = if mzn_in_root_context(idx) \/ (has_bounds(idx) /\ lb(idx) >= min(index_set(x)) /\ ub(idx) <= max(index_set(x))) then element_t(idx,x) else let { constraint idx in index_set(x) } in element_mt(idx,x) endif; function var set of int: element(var int: idx1, var int: idx2, array[int,int] of var set of int: x) = let { int: dim = card(index_set_2of2(x)); int: min_flat = min(index_set_1of2(x))*dim+min(index_set_2of2(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of2(x)) /\ ub(idx1) <= max(index_set_1of2(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of2(x)) /\ ub(idx2) <= max(index_set_2of2(x))) ) then element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) else let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_mt( (idx1*dim+idx2-min_flat)::domain, array1d(x)) endif; function var set of int: element(var int: idx1, var int: idx2, var int: idx3, array[int,int,int] of var set of int: x) = let { int: dim2 = card(index_set_2of3(x)); int: dim3 = card(index_set_3of3(x)); int: min = min(index_set_1of3(x))*dim2*dim3+ min(index_set_2of3(x))*dim3+ min(index_set_3of3(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of3(x)) /\ ub(idx1) <= max(index_set_1of3(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of3(x)) /\ ub(idx2) <= max(index_set_2of3(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of3(x)) /\ ub(idx3) <= max(index_set_3of3(x))) ) then element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_mt( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) endif; function var set of int: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, array[int,int,int,int] of var set of int: x) = let { int: dim2 = card(index_set_2of4(x)); int: dim3 = card(index_set_3of4(x)); int: dim4 = card(index_set_4of4(x)); int: min = min(index_set_1of4(x))*dim2*dim3*dim4+ min(index_set_2of4(x))*dim3*dim4+ min(index_set_3of4(x))*dim4+ min(index_set_4of4(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of4(x)) /\ ub(idx1) <= max(index_set_1of4(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of4(x)) /\ ub(idx2) <= max(index_set_2of4(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of4(x)) /\ ub(idx3) <= max(index_set_3of4(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of4(x)) /\ ub(idx4) <= max(index_set_4of4(x))) ) then element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_mt( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) endif; %%%%%%%%%%%%%%%%%% % Element on bools function var bool: element_t(var int: idx, array[int] of var bool: x) :: promise_total = let { var bool: r ::is_defined_var; constraint idx in index_set(x); constraint array_var_bool_element_nonshifted(idx,x,r) ::defines_var(r); } in r; function var bool: element_mt(var int: idx, array[int] of var bool: x) :: promise_total = let { var bool: r ::is_defined_var; var min(index_set(x))..max(index_set(x)): idx2; constraint idx in index_set(x) -> idx2=idx; constraint idx in index_set(x) \/ idx2=min(index_set(x)); constraint array_var_bool_element_nonshifted(idx2,x,r) ::defines_var(r); } in r; function var bool: element(var int: idx, array[int] of var bool: x) = if mzn_in_root_context(idx) \/ (has_bounds(idx) /\ lb(idx) >= min(index_set(x)) /\ ub(idx) <= max(index_set(x))) then element_t(idx,x) else idx in index_set(x) /\ element_mt(idx,x) endif; function var bool: element(var int: idx1, var int: idx2, array[int,int] of var bool: x) = let { int: dim = card(index_set_2of2(x)); int: min_flat = min(index_set_1of2(x))*dim+min(index_set_2of2(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of2(x)) /\ ub(idx1) <= max(index_set_1of2(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of2(x)) /\ ub(idx2) <= max(index_set_2of2(x))) ) then element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) else let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_mt( (idx1*dim+idx2-min_flat)::domain, array1d(x)) endif; function var bool: element(var int: idx1, var int: idx2, var int: idx3, array[int,int,int] of var bool: x) = let { int: dim2 = card(index_set_2of3(x)); int: dim3 = card(index_set_3of3(x)); int: min = min(index_set_1of3(x))*dim2*dim3+ min(index_set_2of3(x))*dim3+ min(index_set_3of3(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of3(x)) /\ ub(idx1) <= max(index_set_1of3(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of3(x)) /\ ub(idx2) <= max(index_set_2of3(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of3(x)) /\ ub(idx3) <= max(index_set_3of3(x))) ) then element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_mt( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) endif; function var bool: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, array[int,int,int,int] of var bool: x) = let { int: dim2 = card(index_set_2of4(x)); int: dim3 = card(index_set_3of4(x)); int: dim4 = card(index_set_4of4(x)); int: min = min(index_set_1of4(x))*dim2*dim3*dim4+ min(index_set_2of4(x))*dim3*dim4+ min(index_set_3of4(x))*dim4+ min(index_set_4of4(x))-1; } in if mzn_in_root_context(idx1) \/ ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of4(x)) /\ ub(idx1) <= max(index_set_1of4(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of4(x)) /\ ub(idx2) <= max(index_set_2of4(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of4(x)) /\ ub(idx3) <= max(index_set_3of4(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of4(x)) /\ ub(idx4) <= max(index_set_4of4(x))) ) then element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_mt( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) endif; %-----------------------------------------------------------------------------% % % Internal functions for implementing div, mod etc function set of int:compute_div_bounds(var int: x, var int: y); function var int: div_t(var int: x, var int: y) :: promise_total = let { var (compute_div_bounds(x,y)): z ::is_defined_var; constraint y != 0; constraint int_div(x,y,z) ::defines_var(z); } in z; function var int: div_mt(var int: x, var int: y) :: promise_total = let { var ((dom(y) diff {0}) union {1}): yy = if y=0 then 1 else y endif; } in div_t(x,yy); function var int: mod_t(var int: x, var int: y) :: promise_total = let { var -(max(ub(y),-lb(y)))..max(ub(y),-lb(y)): z; constraint y != 0; constraint int_mod(x,y,z); } in z; function var int: mod_mt(var int: x, var int: y) :: promise_total = let { var {1} union dom(y): yy = if y=0 then 1 else y endif; } in mod_t(x,yy); function var int: product_rec(array[int] of var int: x) = if length(x)=0 then 1 elseif length(x)=1 then x[min(index_set(x))] else x[min(index_set(x))]* product_rec([x[i] | i in min(index_set(x))+1..max(index_set(x))]) endif; function var float: product_rec(array[int] of var float: x) = if length(x)=0 then 1.0 elseif length(x)=1 then x[min(index_set(x))] else x[min(index_set(x))]* product_rec([x[i] | i in min(index_set(x))+1..max(index_set(x))]) endif; function var int: max_t(array[int] of var int: x) :: promise_total = if length(x)=0 then 0 elseif length(x)=1 then x[min(index_set(x))] elseif length(x)=2 then max(x[1],x[2]) else let { var lb_array(x)..ub_array(x): m; constraint array_int_maximum(m,x); } in m endif; function var int: min_t(array[int] of var int: x) :: promise_total = if length(x)=0 then 0 elseif length(x)=1 then x[1] elseif length(x)=2 then min(x[1],x[2]) else let { var lb_array(x)..ub_array(x): m; constraint array_int_minimum(m,x); } in m endif; function var float: max_t(array[int] of var float: x) :: promise_total = if length(x)=0 then 0.0 elseif length(x)=1 then x[min(index_set(x))] elseif length(x)=2 then min(x[1],x[2]) else let { var float: m; constraint array_float_maximum(m,x); } in m endif; function var float: min_t(array[int] of var float: x) :: promise_total = if length(x)=0 then 0.0 elseif length(x)=1 then x[1] elseif length(x)=2 then min(x[1],x[2]) else let { var float: m; constraint array_float_minimum(m,x); } in m endif; function var set of int: array_union_rec(array[int] of var set of int: x) = if length(x)=0 then {} elseif length(x)=1 then x[min(index_set(x))] else x[min(index_set(x))] union array_union_rec([x[i] | i in min(index_set(x))+1..max(index_set(x))]) endif; function var set of int: array_intersect_rec(array[int] of var set of int: x) = if length(x)=0 then {} elseif length(x)=1 then x[min(index_set(x))] else x[min(index_set(x))] intersect array_intersect_rec([x[i] | i in min(index_set(x))+1..max(index_set(x))]) endif; /*** @groupdef builtins.random Random Number Generator builtins These functions implement random number generators from different probability distributions. */ /** @group builtins.random Return a sample from the normal distribution defined by \(\a mean, \a std\) */ function float: normal(float: mean, float: std); /** @group builtins.random Return a sample from the normal distribution defined by \(\a mean, \a std\) */ function float: normal(int: mean, float: std); /** @group builtins.random Return a sample from the uniform distribution defined by \(\a lowerbound, \a upperbound\) */ function float: uniform(float: lowerbound, float: upperbound); /** @group builtins.random Return a sample from the uniform distribution defined by \(\a lowerbound, \a upperbound\) */ function int: uniform(int: lowerbound, int: upperbound); /** @group builtins.random Return a sample from the poisson distribution defined by \a mean */ function int: poisson(float: mean); /** @group builtins.random Return a sample from the poisson distribution defined by an integer \a mean */ function int: poisson(int: mean); /** @group builtins.random Return a sample from the gamma distribution defined by \(\a alpha, \a beta\) */ function float: gamma(float: alpha, float: beta); /** @group builtins.random Return a sample from the gamma distribution defined by \(\a alpha, \a beta\) */ function float: gamma(int: alpha, float: beta); /** @group builtins.random Return a sample from the Weibull distribution defined by \(\a shape, \a scale\) */ function float: weibull(float: shape, float: scale); /** @group builtins.random Return a sample from the Weibull distribution defined by \(\a shape, \a scale\) */ function float: weibull(int: shape, float: scale); /** @group builtins.random Return a sample from the exponential distribution defined by \(\a lambda\) */ function float: exponential(int: lambda); /** @group builtins.random Return a sample from the exponential distribution defined by \(\a lambda\) */ function float: exponential(float: lambda); /** @group builtins.random Return a sample from the lognormal distribution defined by \(\a mean, \a std\) */ function float: lognormal(float: mean, float: std); /** @group builtins.random Return a sample from the lognormal distribution defined by \(\a mean, \a std\) */ function float: lognormal(int: mean, float: std); /** @group builtins.random Return a sample from the chi-squared distribution defined by the degree of freedom \(\a n\) */ function float: chisquared(int: n); /** @group builtins.random Return a sample from the chi-squared distribution defined by the degree of freedom \(\a n\) */ function float: chisquared(float: n); /** @group builtins.random Return a sample from the cauchy distribution defined by \(\a mean, \a scale\) */ function float: cauchy(float: mean, float: scale); /** @group builtins.random Return a sample from the cauchy distribution defined by \(\a mean, \a scale\) */ function float: cauchy(int: mean, float: scale); /** @group builtins.random Return a sample from the Fisher-Snedecor F-distribution defined by the degrees of freedom \(\a d1, \a d2\) */ function float: fdistribution(float: d1, float: d2); /** @group builtins.random Return a sample from the Fisher-Snedecor F-distribution defined by the degrees of freedom \(\a d1, \a d2\) */ function float: fdistribution(int: d1, int: d2); /** @group builtins.random Return a sample from the student's t-distribution defined by the sample size \(\a n\) */ function float: tdistribution(float: n); /** @group builtins.random Return a sample from the student's t-distribution defined by the sample size \(\a n\) */ function float: tdistribution(int: n); /** @group builtins.random Return a sample from the discrete distribution defined by the array of weights \(\a weights\) that assigns a weight to each integer starting from zero */ function int: discrete_distribution(array[int] of int: weights); /** @group builtins.random Return a boolean sample from the Bernoulli distribution defined by probability \(\a p\) */ function bool: bernoulli(float: p); /** @group builtins.random Return a sample from the binomial distribution defined by sample number \a t and probability \a p */ function int: binomial(int: t, float: p); /*** @groupdef builtins.special Special constraints These predicates allow users to mark constraints as e.g. symmetry breaking or redundant, so that solvers can choose to implement them differently. We cannot easily use annotations for this purpose, since annotations are propagated to all constraints in a decomposition, which may be incorrect for redundant or symmetry breaking constraints in the presence of common subexpression elimination (CSE). */ /** @group builtins.special Mark \a b as a symmetry breaking constraint */ predicate symmetry_breaking_constraint(var bool: b); /** @group builtins.special Mark \a b as a redundant constraint */ predicate redundant_constraint(var bool: b); /** @group builtins.special Mark \a b as an implied constraint (synonym for redundant_constraint) */ predicate implied_constraint(var bool: b) = redundant_constraint(b); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% % Include solver-specific redefinitions for any FlatZinc built-ins. % include "redefinitions.mzn"; include "redefinitions-2.0.mzn"; include "redefinitions-2.0.2.mzn"; %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/value_precede_chain.mzn0000644000175000017500000000156212646030173022755 0ustar kaolkaolinclude "value_precede_chain_int.mzn"; include "value_precede_chain_set.mzn"; /** @group globals.lexicographic Requires that \a c[\p i] precedes \a c[\p i +1] in the array \a x. Precedence means that if any element of \a x is equal to \a \a c[\p i +1], then another element of \a x with a lower index is equal to \a \a c[\p i]. */ predicate value_precede_chain(array[int] of int: c, array[int] of var int: x) = value_precede_chain_int(c, x); /** @group globals.lexicographic Requires that \a c[\p i] precedes \a c[\p i +1] in the array \a x. Precedence means that if an element of \a x contains \a \a c[\p i +1] but not \a \a c[\p i], then another element of \a x with lower index contains \a \a c[\p i] but not \a \a c[\p i +1]. */ predicate value_precede_chain(array[int] of int: c, array[int] of var set of int: x) = value_precede_chain_set(c, x); libminizinc-2.0.11/share/minizinc/std/member_set.mzn0000644000175000017500000000051512646030173021127 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate member_set(array[int] of var set of int: x, var set of int: y) = exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.0.11/share/minizinc/std/arg_sort_float.mzn0000644000175000017500000000060612646030173022013 0ustar kaolkaolinclude "alldifferent.mzn"; predicate arg_sort_float(array[int] of var float:x, array[int] of var int:p) = assert(index_set(p) = 1..length(x), "arg_sort_float: second argument must have index 1..length(first argument)", alldifferent(p) /\ forall(j in 1..length(x)-1) (x[p[j]] <= x[p[j+1]] /\ (x[p[j]] == x[p[j+1]] -> p[j] < p[j+1])) ); libminizinc-2.0.11/share/minizinc/std/nvalue.mzn0000644000175000017500000000051212646030173020274 0ustar kaolkaol/** @group globals.alldifferent Requires that the number of distinct values in \a x is \a n. */ predicate nvalue(var int: n, array[int] of var int: x) = let { int: lx = lb_array(x), int: ux = ub_array(x), } in n == sum(j in lx..ux) ( bool2int(exists(i in index_set(x)) ( x[i] = j )) ); libminizinc-2.0.11/share/minizinc/std/lex_lesseq_set.mzn0000644000175000017500000000227212646030173022026 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_lesseq_set(array[int] of var set of int: x, array[int] of var set of int: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ if i = size then true else x[lx + i] < y[ly + i] \/ b[i+1] endif ) ); predicate lex_leq_set(array[int] of var set of int: x, array[int] of var set of int: y) = lex_lesseq(x, y); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/global_cardinality_low_up_closed.mzn0000644000175000017500000000134312646030173025546 0ustar kaolkaol/** @group globals.counting Requires that for all \p i, the value \a cover[\p i] appears at least \a lbound[\p i] and at most \a ubound[\p i] times in the array \a x. The elements of \a x must take their values from \a cover. */ predicate global_cardinality_low_up_closed(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound) = forall(i in index_set(x))( x[i] in { d | d in array2set(cover) } ) /\ global_cardinality_low_up(x, cover, lbound, ubound) /\ % Implied condition length(x) in sum(lbound)..sum(ubound); include "global_cardinality_low_up.mzn"; libminizinc-2.0.11/share/minizinc/std/diffn_nonstrict_k.mzn0000644000175000017500000000267612646030173022522 0ustar kaolkaol/** @group globals.packing Constrains \p k-dimensional boxes to be non-overlapping. For each box \p i and dimension \p j, \a box_posn[\p i, \p j] is the base position of the box in dimension \p j, and \a box_size[\p i, \p j] is the size in that dimension. Boxes whose size is 0 in at least one dimension can be packed anywhere. */ predicate diffn_nonstrict_k(array[int,int] of var int: box_posn, array[int,int] of var int: box_size) = let { set of int: DIMS= index_set_2of2(box_posn) } in assert(index_set_2of2(box_size) = DIMS /\ index_set_1of2(box_posn) = index_set_1of2(box_size), "diffn: index sets of arguments are incorrect", forall(b1, b2 in index_set_1of2(box_posn) where b1 < b2) (diffn_nonstrict_nonoverlap_k([ box_posn[b1,j] | j in DIMS ], [ box_size[b1,j] | j in DIMS ], [ box_posn[b2,j] | j in DIMS ], [ box_size[b2,j] | j in DIMS ] ) ) ); predicate diffn_nonstrict_nonoverlap_k(array[int] of var int: x1, array[int] of var int: w1, array[int] of var int: x2, array[int] of var int: w2) = exists(j in index_set(x1)) (w1[j] = 0 \/ w2[j] = 0 \/ x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j]); libminizinc-2.0.11/share/minizinc/std/table_int.mzn0000644000175000017500000001127412646030173020752 0ustar kaolkaol%-----------------------------------------------------------------------------% % A table constraint table(x, t) represents the constraint x in t where we % consider each row in t to be a tuple and t as a set of tuples. %-----------------------------------------------------------------------------% predicate table_int(array[int] of var int: x, array[int, int] of int: t) = assert (index_set_2of2(t) == index_set(x), "The second dimension of the table must equal the number of variables " ++ "in the first argument", let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: lt = min(index_set_1of2(t)), int: ut = max(index_set_1of2(t)), var lt..ut: i, array[l..u, lt..ut] of int: t_transposed = array2d(l..u, lt..ut, [ t[i,j] | j in l..u, i in lt..ut ]) } in forall(j in l..u) ( % Having the variable index component at the left position % means that the nD-to-1D array translation during Mzn-to-Fzn % will generate at most an offset constraint, instead of a % scaling + offset constraint. % t_transposed[j,i] = x[j] % % t[i,j] = x[j] ) ); %-----------------------------------------------------------------------------% % Reified version % % We only support special cases of a few variables. % % The approach is to add the Boolean variable to the list of variables and % create an extended table. The extended table covers all combinations of % assignments to the original variables, and every entry in it is padded with a % value that depends on whether that entry occurs in the original table. % % For example, the original table constraint % % x y % --- % 2 3 % 5 8 % 4 1 % % reified with a Boolean b is turned into a table constraint of the form % % x y b % --------- % 2 3 true % 5 8 true % 4 1 true % ... false % ... false % for all other pairs (x,y) % ... false % predicate table_int_reif(array[int] of var int: x, array[int, int] of int: t, var bool: b) = let { int: n_vars = length(x) } in assert(n_vars in 1..5, "'table' constraints in a reified context " ++ "are only supported for 1..5 variables.", if n_vars = 1 then x[1] in { t[it,1] | it in index_set_1of2(t) } <-> b else let { set of int: ix = index_set(x), set of int: full_size = 1..product(i in ix)( dom_size(x[i]) ), array[full_size, 1..n_vars + 1] of int: t_b = array2d(full_size, 1..n_vars + 1, if n_vars = 2 then [ let { array[ix] of int: tpl = [i1,i2] } in (tpl ++ [bool2int(aux_is_in_table(tpl,t))])[p] | i1 in dom(x[1]), i2 in dom(x[2]), p in 1..n_vars + 1 ] else if n_vars = 3 then [ let { array[ix] of int: tpl = [i1,i2,i3] } in (tpl ++ [bool2int(aux_is_in_table(tpl,t))])[p] | i1 in dom(x[1]), i2 in dom(x[2]), i3 in dom(x[3]), p in 1..n_vars + 1 ] else if n_vars = 4 then [ let { array[ix] of int: tpl = [i1,i2,i3,i4] } in (tpl ++ [bool2int(aux_is_in_table(tpl,t))])[p] | i1 in dom(x[1]), i2 in dom(x[2]), i3 in dom(x[3]), i4 in dom(x[4]), p in 1..n_vars + 1 ] else % if n_vars = 5 then [ let { array[ix] of int: tpl = [i1,i2,i3,i4,i5] } in (tpl ++ [bool2int(aux_is_in_table(tpl,t))])[p] | i1 in dom(x[1]), i2 in dom(x[2]), i3 in dom(x[3]), i4 in dom(x[4]), i5 in dom(x[5]), p in 1..n_vars + 1 ] endif endif endif ) } in table_int(x ++ [bool2int(b)], t_b) endif ); test aux_is_in_table(array[int] of int: e, array[int, int] of int: t) = exists(i in index_set_1of2(t))( forall(j in index_set(e))( t[i,j] = e[j] ) ); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/element.mzn0000644000175000017500000000135412646030173020440 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% include "element_bool.mzn"; include "element_float.mzn"; include "element_int.mzn"; include "element_set.mzn"; predicate element(var int: i, array[int] of var bool: x, var bool: y) = element_bool(i, x, y); predicate element(var int: i, array[int] of var float: x, var float: y) = element_float(i, x, y); predicate element(var int: i, array[int] of var int: x, var int: y) = element_int(i, x, y); predicate element(var int: i, array[int] of var set of int: x, var set of int: y) = element_set(i, x, y); libminizinc-2.0.11/share/minizinc/std/alldifferent_except_0.mzn0000644000175000017500000000050012646030173023225 0ustar kaolkaol/** @group globals.alldifferent Constrain the array of integers \a vs to be all different except those elements that are assigned the value 0. */ predicate alldifferent_except_0(array[int] of var int: vs) = forall(i, j in index_set(vs) where i < j) ( (vs[i] != 0 /\ vs[j] != 0) -> vs[i] != vs[j] ); libminizinc-2.0.11/share/minizinc/std/range_fn.mzn0000644000175000017500000000064512646030173020570 0ustar kaolkaolinclude "range.mzn"; /** @group globals Returns the image of function \a x (represented as an array) on set of values \a s. ub(\a s) must be a subset of index_set(\a x) otherwise an assertion failure will occur. */ function var set of int: range(array[int] of var int: x, var set of int: s) ::promise_total = let { var set of lb_array(x)..ub_array(x): t; constraint range(x,s,t); } in t; libminizinc-2.0.11/share/minizinc/std/bin_packing_load_fn.mzn0000644000175000017500000000112712646030173022733 0ustar kaolkaolinclude "bin_packing_load.mzn"; /** @group globals.packing Returns the load of each bin resulting from packing each item \p i with weight \a w[\p i] into \a bin[\p i], where the load is defined as the sum of the weights of the items in each bin. Assumptions: - forall \p i, \a w[\p i] >=0 */ function array[int] of var int: bin_packing_load(array[int] of var int: bin, array[int] of int: w) :: promise_total = let { array[dom_bounds_array(bin)] of var 0..sum(w): load; constraint bin_packing_load(load,bin,w); } in load; libminizinc-2.0.11/share/minizinc/std/bin_packing_load.mzn0000644000175000017500000000202212646030173022243 0ustar kaolkaol/** @group globals.packing Requires that each item \p i with weight \a w[\p i], be put into \a bin[\p i] such that the sum of the weights of the items in each bin \p b is equal to \a load[\p b]. Assumptions: - forall \p i, \a w[\p i] >=0 */ predicate bin_packing_load(array[int] of var int: load, array[int] of var int: bin, array[int] of int: w) = assert(index_set(bin) == index_set(w), "bin_packing_load: the bin and weight arrays must have identical index sets", assert(lb_array(w) >= 0, "bin_packing_load: the weights must be non-negative", sum(load) = sum(w) /\ forall( i in index_set(bin) ) ( min(index_set(load)) <= bin[i] /\ bin[i] <= max(index_set(load)) ) /\ forall( b in index_set(load) ) ( load[b] = sum ( i in index_set(bin) ) ( w[i] * bool2int( bin[i] = b ) ) ) )); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/span.mzn0000644000175000017500000000121212646030173017741 0ustar kaolkaol/** @group globals.scheduling Span constraint for optional tasks. Task (\a s0,\a d0) spans the optional tasks (\a s[\p i],\a d[\p i]) in the array arguments. */ predicate span(var opt int: s0, var int: d0, array[int] of var opt int: s, array[int] of var int: d) = assert(index_set(s) = index_set(d), "span: index sets of third and fourth argument must be identical", (occurs(s0) <-> exists(i in index_set(s))(occurs(s[i]))) /\ s0 = min(s) /\ (absent(s0) -> d0 = 0) /\ s0 ~+ d0 = max([s[i] ~+ d[i] | i in index_set(s)]) ); libminizinc-2.0.11/share/minizinc/std/element_bool.mzn0000644000175000017500000000046512646030173021455 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% predicate element_bool(var int: i, array[int] of var bool: x, var bool: y) = y = x[i]; libminizinc-2.0.11/share/minizinc/std/element_float.mzn0000644000175000017500000000047012646030173021623 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% predicate element_float(var int: i, array[int] of var float: x, var float: y) = y = x[i]; libminizinc-2.0.11/share/minizinc/std/atmost.mzn0000644000175000017500000000022012646030173020305 0ustar kaolkaol% The actual definitions are in atmost.mzn. % This file is used to handle the case where users include % "atmost.mzn"; % include "at_most.mzn"; libminizinc-2.0.11/share/minizinc/std/circuit.mzn0000644000175000017500000000152112646030173020445 0ustar kaolkaolinclude "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a circuit where \a x[\p i] = \p j means that \p j is the successor of \p i. */ predicate circuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: n = card(S), array[S] of var 1..n: order } in alldifferent(x) /\ alldifferent(order) /\ forall(i in S)(x[i] != i) /\ order[l] = 1 /\ forall(i in S)(order[i] != n -> order[x[i]] = order[i] + 1) /\ forall(i in S)(order[i] == n -> x[i] = l ); predicate circuit_reif(array[int] of var int: x, var bool: b) = abort("Reified circuit/1 is not supported."); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/std/arg_sort.mzn0000644000175000017500000000467012646030173020633 0ustar kaolkaol/** @group globals.sort Returns the permutation \a p which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ function array[int] of var int: arg_sort(array[int] of var int:x) :: promise_total = if length(x) = 0 then [] else let { int: l = min(index_set(x)); int: u = max(index_set(x)); array[1..u-l+1] of var l..u: p; constraint arg_sort_int(x,p); } in p endif; /** @group globals.sort Returns the permutation \a p which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ function array[int] of int: arg_sort(array[int] of int:x); /** @group globals.sort Returns the permutation \a p which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ function array[int] of var int: arg_sort(array[int] of var float:x) :: promise_total = if length(x) = 0 then [] else let { int: l = min(index_set(x)); int: u = max(index_set(x)); array[1..u-l+1] of var l..u: p; constraint arg_sort_float(x,p); } in p endif; /** @group globals.sort Constrains \a p to be the permutation which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ predicate arg_sort(array[int] of var int:x, array[int] of var int:p) = arg_sort_int(x,p); /** @group globals.sort Constrains \a p to be the permutation which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ predicate arg_sort(array[int] of var float:x, array[int] of var int:p) = arg_sort_float(x,p); include "arg_sort_int.mzn"; include "arg_sort_float.mzn"; libminizinc-2.0.11/share/minizinc/std/value_precede_set.mzn0000644000175000017500000000101212646030173022454 0ustar kaolkaolpredicate value_precede_set(int: s, int: t, array[int] of var set of int: x) = let { int: imin = min(index_set(x)), int: imax = max(index_set(x)), array[imin..imax + 1] of var bool: b } in ( forall (i in imin..imax) (let { var bool: xis = (s in x[i] /\ not (t in x[i])) } in (xis -> (b[i + 1] == true)) /\ ((not xis) -> (b[i] == b[i + 1])) /\ ((not b[i]) -> (s in x[i] \/ not (t in x[i]))) ) /\ b[imin] == false ); libminizinc-2.0.11/share/minizinc/std/link_set_to_booleans.mzn0000644000175000017500000000076712646030173023212 0ustar kaolkaol/** @group globals.channeling Constrain the array of Booleans \a b to be a representation of the set \a s: \p i in \a s ↔ \a b[\p i]. The index set of \a b must be a superset of the possible values of \a s. */ predicate link_set_to_booleans(var set of int: s, array[int] of var bool: b) = assert(ub(s) subset index_set(b), "link_set_to_booleans: the index set of b must be a superset of the possible values of s", forall(i in index_set(b)) ( b[i] <-> i in s ) ); libminizinc-2.0.11/share/minizinc/nosets/0000755000175000017500000000000012646030173016777 5ustar kaolkaollibminizinc-2.0.11/share/minizinc/nosets/redefinitions.mzn0000644000175000017500000001127612646030173022376 0ustar kaolkaolfunction var set of int: reverse_map(array[int] of var bool: b); function set of int: reverse_map(array[int] of bool: b) ::promise_total = { i | i in index_set(b) where b[i] }; array[int] of var bool: set2bools(var set of int: x) ::promise_total = if is_fixed(x) then set2bools(fix(x)) else let { array[min(ub(x))..max(ub(x))] of var bool: b; constraint forall (i in index_set(b) where not (i in ub(x))) (b[i]=false); constraint (x = reverse_map(b)) :: is_reverse_map; } in b endif; array[int] of var bool: set2bools(var set of int: x, set of int: ubx) ::promise_total = if is_fixed(x) then set2bools(fix(x) intersect ubx) else let { array[min(ubx)..max(ubx)] of var bool: b; constraint forall (i in index_set(b) where not (i in ubx)) (b[i]=false); constraint (x = reverse_map(b)) :: is_reverse_map; } in b endif; array[int] of bool: set2bools(set of int: x) ::promise_total = array1d(min(x)..max(x),[i in x | i in min(x)..max(x)]); array[int] of bool: set2bools(set of int: x, set of int: ubx) ::promise_total = set2bools(x intersect ubx); predicate set_eq(var set of int: x, var set of int: y) = if not has_ub_set(x) /\ not has_ub_set(y) then assert(false, "Cannot determine bounds of set variables") elseif not has_ub_set(x) then set_eq(y,x) else let { set of int: uby = if has_ub_set(y) then ub(y) else ub(x) endif; array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y,uby); } in forall (i in index_set(bx) union index_set(by)) ( if not (i in index_set(bx)) then not by[i] elseif not (i in index_set(by)) then not bx[i] else bx[i]=by[i] endif ) endif; predicate set_eq_reif(var set of int: x, var set of int: y, var bool: b) = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in b <-> forall (i in index_set(bx) union index_set(by)) ( if not (i in index_set(bx)) then not by[i] elseif not (i in index_set(by)) then not bx[i] else bx[i]=by[i] endif ); predicate set_subset(var set of int: x, var set of int: y) = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in forall (i in index_set(bx)) ( if not (i in index_set(by)) then not bx[i] else bx[i] -> by[i] endif ); predicate set_subset_reif(var set of int: x, var set of int: y, var bool: b) = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in b <-> forall (i in index_set(bx)) ( if not (i in index_set(by)) then not bx[i] else bx[i] -> by[i] endif ); function var set of int: set_intersect(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of (index_set(bx) intersect index_set(by)): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in index_set(bz)) ( bz[i] = (bx[i] /\ by[i]) ); } in z; function var set of int: set_union(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of (index_set(bx) union index_set(by)): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in index_set(bx) union index_set(by)) ( if (i in index_set(bx)) then if (i in index_set(by)) then bz[i] = (bx[i] \/ by[i]) else bz[i] = bx[i] endif else bz[i] = by[i] endif ); } in z; function var set of int: set_diff(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of (index_set(bx) diff index_set(by)): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in index_set(bz)) ( bz[i] = (bx[i] /\ (not by[i])) ); } in z; function var int: card(var set of int: x) ::promise_total = let { array[int] of var bool: bx = set2bools(x); var 0..length(bx) : c; constraint bool_lin_eq([1 | i in index_set(bx)],bx,c); } in c; predicate set_in(var int: x, var set of int: y) = let { array[int] of var bool: by = set2bools(y); } in by[x]; predicate set_in_reif(var int: x, var set of int: y, var bool: b) = let { array[int] of var bool: by = set2bools(y); } in b <-> by[x]; function array[int] of var bool: setarray2bools(array[int] of var set of int: x) = if length(x)=0 then [] else set2bools(x[1])++setarray2bools([x[i]|i in 2..length(x)]) endif; annotation set_search(array[int] of var set of int: x, ann: a1, ann: a2, ann: a3) = bool_search(setarray2bools(x),a1,a2,a3); libminizinc-2.0.11/share/minizinc/g12_fd/0000755000175000017500000000000012646030173016526 5ustar kaolkaollibminizinc-2.0.11/share/minizinc/g12_fd/all_different_int.mzn0000644000175000017500000000173712646030173022734 0ustar kaolkaol%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate all_different_int(array[int] of var int: x) = g12fd_int_all_different(x); %-----------------------------------------------------------------------------% % The implementation of the all_different constraint in the G12/FD solver. % This should not be called directly, instead the definition above should % be used. predicate g12fd_int_all_different(array[int] of var int: x); % G12/FD doesn't provide a reified all_different so we use the following % definition if g12fd_int_all_different is called from a reified context. % predicate g12fd_int_all_different_reif(array[int] of var int: x, var bool: r) = r <-> forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/g12_fd/cumulative.mzn0000644000175000017500000000316212646030173021434 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that a set of tasks given by start times 's', durations 'd', and % resource requirements 'r', never require more than a global resource bound % 'b' at any one time. % Assumptions: % - forall i, d[i] >= 0 and r[i] >= 0 %-----------------------------------------------------------------------------% predicate cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", g12fd_cumulative(s, d, r, b))); %-----------------------------------------------------------------------------% % Optional parameters that can be used with the built-in G12/FD cumulative % constraint. % annotation energy_feasibility_check; annotation edge_finding_filtering; annotation ext_edge_finding_filtering; annotation histogram_filtering; annotation idempotent; %-----------------------------------------------------------------------------% % The implementation of the cumulative constraint in the G12/FD solver. % This should not be called directly, instead the definition above should % be used. predicate g12fd_cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b); %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/minizinc/g12_fd/global_cardinality_low_up.mzn0000644000175000017500000000231112646030173024461 0ustar kaolkaol%-----------------------------------------------------------------------------% % Requires that for all 'i', the value 'cover[i]' appears at least 'lbound[i]' % and at most 'ubound[i]' times in the array 'x'. %-----------------------------------------------------------------------------% predicate global_cardinality_low_up(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound) = g12fd_global_cardinality_open(x, cover, lbound, ubound); %-----------------------------------------------------------------------------% % The implementation in the G12/FD solver. This should not be called directly; % instead the definition above should be used. predicate g12fd_global_cardinality_open(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.0.11/share/examples/0000755000175000017500000000000012646030173015462 5ustar kaolkaollibminizinc-2.0.11/share/examples/option_types/0000755000175000017500000000000012646030173020216 5ustar kaolkaollibminizinc-2.0.11/share/examples/option_types/compatible_assignment_opt.mzn0000644000175000017500000000267712646030173026211 0ustar kaolkaolint: n; set of int: W = 1..n; int: m; set of int: T = 1..2*m; array[W,T] of int: profit; array[W,W] of bool: compatible; array[W] of var T: task; array[T] of var opt W: worker; include "inverse.mzn"; constraint inverse(task,worker); constraint forall(t in T where t != max(T)) (compatible[worker[t],worker[t+1]]); var int: obj = sum(w in W)(profit[w,task[w]]); solve maximize obj; output [ if fix(occurs(worker[t])) then show(worker[t]) else " " endif ++ " " | t in T ] ++ [ show(task), "\n" ] ++ [ "Profit: ", show(obj), "\n"] ; predicate inverse(array[int] of var opt int: f, array[int] of var opt int: g) = forall(i in index_set(f), j in index_set(g)) ( (occurs(f[i]) /\ deopt(f[i]) = j) <-> (occurs(g[j]) /\ deopt(g[j]) = i)); n = 7; m = 4; profit = [| 1,4,6,8, 8,4,3,4 | 3,5,2,4, 9,5,8,2 | 2,8,3,5, 6,3,7,1 | 2,5,3,4, 8,6,1,3 | 3,4,4,4, 6,6,6,3 | 2,2,1,2, 4,3,3,1 | 2,6,5,3, 3,3,3,3 |]; compatible = [| false, false, true, true, false, false, true | false, false, true, true, false, true, false | true, false, false, true, true, false, true | true, true, true, false, true, false, false | false, false, true, true, false, true, true | false, true, false, false, true, false, true | true, false, true, false, true, true, false |]; libminizinc-2.0.11/share/examples/option_types/extended_comprehensions.mzn0000644000175000017500000000034212646030173025657 0ustar kaolkaol% Comprehensions can now range over var sets array[int] of int: z = [2,3,5,7,11]; var set of 1..5: y; % This used to be illegal in MiniZinc 1.6 var int: x = sum (i in y) (z[i]); solve satisfy; output [show(x)," ",show(y)]; libminizinc-2.0.11/share/examples/option_types/fjsp.mzn0000644000175000017500000001603512646030173021713 0ustar kaolkaol%-----------------------------------------------------------------------------% % vim: ts=4 sw=4 et wm=0 tw=0 %-----------------------------------------------------------------------------% % Copyright (C) 2013 National ICT Australia. % See the file COPYING for license information. %-----------------------------------------------------------------------------% % % Author(s): % Andreas Schutt % %-----------------------------------------------------------------------------% % Flexible Job Shop Scheduling % % Flexible Job Shop Scheduling (FJSS) is more general version of Job Shop % Scheduling in which some tasks can be run an alternative machines. The goal % is to find a feasible schedule minimising the makespan. % %-----------------------------------------------------------------------------% % This model uses option types. The weak <= and = predicates should become part % of the standard library. %-----------------------------------------------------------------------------% % Parameters int: no_mach; % Number of machines int: no_jobs; % Number of jobs int: no_task; % Number of total tasks int: no_optt; % Number of total optional tasks set of int: Mach = 1..no_mach; set of int: Jobs = 1..no_jobs; set of int: Tasks = 1..no_task; set of int: OptTs = 1..no_optt; array [Jobs] of set of int: tasks; array [Tasks] of set of int: optts; array [OptTs] of int: optt_mach; array [OptTs] of int: optt_dur; array [Jobs] of int: last_task = [ max(tasks[j]) | j in Jobs ]; %-----------------------------------------------------------------------------% % Additional derived parameters for tasks % "Short cut" from a task to its job % array [Tasks] of int: task_job = [ min(j in Jobs where t in tasks[j])(j) | t in Tasks ]; % Earliest start times of tasks % array [Tasks] of int: task_mins = [ sum(k in tasks[task_job[t]])(if k < t then task_mind[k] else 0 endif) | t in Tasks ]; % Latest start times of tasks % array [Tasks] of int: task_maxs = [ t_max - sum(k in tasks[task_job[t]])(if k < t then 0 else task_mind[k] endif) | t in Tasks ]; % Minimal durations of tasks % array [Tasks] of int: task_mind = [ min(o in optts[t])(optt_dur[o]) | t in Tasks ]; % Maximal durations of tasks % array [Tasks] of int: task_maxd = [ max(o in optts[t])(optt_dur[o]) | t in Tasks ]; % Additional deirved parameters for optional tasks % array [OptTs] of int: optt_task = [ min(t in Tasks where o in optts[t])(t) | o in OptTs ]; int: min_dur = min(optt_dur); int: max_dur = max(optt_dur); set of int: Durs = min_dur..max_dur; % Parameters related to the planning horizon % int: t_max = sum(t in Tasks)(max(o in optts[t])(optt_dur[o])); set of int: Times = 0..t_max; %-----------------------------------------------------------------------------% % Variables % Start time variables for tasks % array [Tasks] of var Times: start = [ let { var task_mins[t]..task_maxs[t]: s } in s | t in Tasks ]; % Duration variables for tasks % array [Tasks] of var Durs: dur = [ if task_mind[t] = task_maxd[t] then task_mind[t] else let { var task_mind[t]..task_maxd[t]: d } in d endif | t in Tasks ]; % Variables whether an optional task is executed % array [OptTs] of var opt Times: optt_s = [ let { var opt task_mins[optt_task[o]]..task_maxs[optt_task[o]]: s } in s | o in OptTs ]; var Times: objective ::output_var; %-----------------------------------------------------------------------------% % Constraints % Precedence relations % constraint forall(j in Jobs, i in tasks[j] where i < last_task[j])( start[i] + dur[i] <= start[i + 1] ); % Optional tasks' constraints % constraint forall(t in Tasks)( alternative(start[t], dur[t], [ optt_s[o] | o in optts[t] ], [ optt_dur[o] | o in optts[t] ]) ); predicate alternative(var int: s, var int: d, array[int] of var opt int: os, array[int] of int: od) = let { var min(index_set(os))..max(index_set(os)): m; } in ( [occurs(os[i]) | i in index_set(os)][m] /\ od[m] = d /\ [deopt(os[i]) | i in index_set(os)][m] = s /\ sum (i in index_set(os)) (bool2int(occurs(os[i]))) = 1 ); % Resource constraints % constraint forall(m in Mach)( let { set of int: MTasks = { o | o in OptTs where optt_mach[o] = m } } in ( disjunctive([optt_s[o] | o in MTasks], [optt_dur[o] | o in MTasks]) ) ); predicate disjunctive(array[int] of var opt int: s, array[int] of int: d) = forall(i, j in index_set(s) where i occurs(z); constraint occurs(z) -> deopt(z)=deopt(x)+deopt(y); } in z; function var opt int : maximum(array[int] of var opt int : x) = let { var opt lb_array(x)..ub_array(x) : y; constraint (occurs(y) <- exists(i in index_set(x))(occurs(x[i]))) /\ occurs(y) -> (exists(i in index_set(x))(occurs(x[i]) /\ x[i] `opt_eq` y) /\ forall(i in index_set(x))(x[i] `opt_le` y)) } in y; function var bool: opt_le(var opt int : x, var opt int : y) = (occurs(x) /\ occurs(y)) -> deopt(x) <= deopt(y); function var bool: opt_eq(var opt int : x, var opt int : y) = occurs(x) -> (occurs(y) /\ deopt(x) = deopt(y)); % tasks' durations on different machines are NOT the same % all jobs have the same number of tasks % Average number of machines per task 2.20 no_mach = 6; no_jobs = 5; no_task = 15; no_optt = 33; tasks = [1..3, 4..6, 7..9, 10..12, 13..15]; optts = [1..3, 4..5, 6..7, 8..9, 10..11, 12..13, 14..15, 16..17, 18..20, 21..22, {23}, 24..25, 26..28, 29..31, 32..33]; optt_mach = [1, 2, 3, 2, 4, 4, 5, 1, 3, 2, 3, 5, 6, 1, 2, 3, 4, 4, 5, 6, 1, 2, 5, 4, 6, 1, 2, 3, 3, 4, 5, 5, 6]; optt_dur = [147, 123, 145, 130, 140, 150, 160, 214, 150, 66, 87, 178, 95, 87, 62, 180, 105, 190, 100, 153, 87, 65, 173, 145, 136, 128, 123, 145, 86, 65, 47, 110, 85]; libminizinc-2.0.11/share/examples/functions/0000755000175000017500000000000012646030173017472 5ustar kaolkaollibminizinc-2.0.11/share/examples/functions/warehouses.mzn0000644000175000017500000000653212646030173022413 0ustar kaolkaol%----------------------------------------------------------------------------- % Warehouse allocation % (Problem 034 in CSPLib) % % Guido Tack, guido.tack@monash.edu % % Ported from the Gecode example %----------------------------------------------------------------------------- % A company needs to construct warehouses to supply stores with goods. Each % warehouse possibly to be constructed has a certain capacity defining how many % stores it can supply. Constructing a warehouse incurs a fixed cost. Costs % for transportation from warehouses to stores depend on the locations of % warehouses and stores. % % Determine which warehouses should be constructed and which warehouse should % supply which store such that overall cost (transportation cost plus % construction cost) is smallest. %----------------------------------------------------------------------------- % This example shows the use of the count function % In MiniZinc 1.6, count needed to be used as a relation, which required % the introduction of an auxiliary variable. include "globals.mzn"; %----------------------------------------------------------------------------- % Instance n_suppliers = 5; n_stores = 10; building_cost = 30; capacity = [1,4,2,1,3]; cost_matrix = [|20, 24, 11, 25, 30 |28, 27, 82, 83, 74 |74, 97, 71, 96, 70 | 2, 55, 73, 69, 61 |46, 96, 59, 83, 4 |42, 22, 29, 67, 59 | 1, 5, 73, 59, 56 |10, 73, 13, 43, 96 |93, 35, 63, 85, 46 |47, 65, 55, 71, 95|]; %----------------------------------------------------------------------------- % Model int: n_suppliers; int: n_stores; int: building_cost; array[1..n_suppliers] of int: capacity; array[1..n_stores,1..n_suppliers] of int: cost_matrix; int: MaxCost = max(i in 1..n_stores, j in 1..n_suppliers)(cost_matrix[i,j]); int: MaxTotal = (n_suppliers * building_cost) + sum(i in 1..n_stores, j in 1..n_suppliers)(cost_matrix[i,j]); array[1..n_stores] of var 1..n_suppliers: supplier; array[1..n_suppliers] of var bool: open; array[1..n_stores] of var 1..MaxCost: cost; var 1..MaxTotal: total; constraint sum (i in 1..n_suppliers) (building_cost * bool2int(open[i])) + sum (i in 1..n_stores) (cost[i]) = total; constraint forall (i in 1..n_stores) ( cost_matrix[i,supplier[i]] = cost[i] ); constraint forall (i in 1..n_suppliers) ( count(supplier,i) <= capacity[i] ); constraint forall (i in 1..n_suppliers) ( (exists (j in 1..n_stores) (supplier[j] == i)) == open[i] ); solve :: int_search( supplier ++ cost ++ [bool2int(open[i]) | i in 1..n_suppliers], first_fail, indomain_split, complete ) minimize total; output [ "warehouses:" ] ++ [ "\ntotal = ", show(total) ] ++ [ "\nsupplier = [\n" ] ++ [ "\t" ++ show(supplier[i]) ++ if i = n_stores then "\n]" elseif i mod 5 = 0 then ",\n" else "," endif | i in 1..n_stores ] ++ [ "\ncost = [\n" ] ++ [ "\t" ++ show(cost[i]) ++ if i = n_stores then "\n]" elseif i mod 5 = 0 then ",\n" else "," endif | i in 1..n_stores ] ++ [ "\nopen = [\n" ] ++ [ "\t" ++ show(open[i]) ++ if i = n_suppliers then "\n]\n" elseif i mod 5 = 0 then ",\n" else "," endif | i in 1..n_suppliers ] %----------------------------------------------------------------------------- %----------------------------------------------------------------------------- libminizinc-2.0.11/share/examples/new_syntax/0000755000175000017500000000000012646030173017661 5ustar kaolkaollibminizinc-2.0.11/share/examples/new_syntax/var_if.mzn0000644000175000017500000000027712646030173021663 0ustar kaolkaol% The if-then-else construct has been extended to support var bool conditions. var bool: b; var 1..3: y; var 4..6: z; var int: x = if b then y else z endif; solve satisfy; output [show(x)]; libminizinc-2.0.11/share/examples/new_syntax/array_index_set.mzn0000644000175000017500000000047612646030173023576 0ustar kaolkaol% Array index sets can be arbitrary set valued expressions, as long as % they evaluate to a contiguous range set of int: S = 1..3; set of int: T = 3..7; array[3..6] of var int: x; % The following was illegal in MiniZinc 1.6: array[S union (T intersect index_set(x))] of var 0..3: y; solve satisfy; output [show(y)]; libminizinc-2.0.11/share/examples/new_syntax/extended_let.mzn0000644000175000017500000000034612646030173023056 0ustar kaolkaol% Let expressions can now contain constraint items. Items can be separated % with a semicolon instead of a comma. var int: x = let { var 0..3: x; var int: y; constraint y = 10-x; } in 3*y; solve satisfy; output [show(x)]; libminizinc-2.0.11/CMakeLists.txt0000644000175000017500000002424712646030173015313 0ustar kaolkaolcmake_minimum_required (VERSION 2.8.7) if (USE_STDLIBCPP) set(MZN_LIBCPP libstdc++) else() set(MZN_LIBCPP libc++) endif() if(APPLE) SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.7") set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x") set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "${MZN_LIBCPP}") endif(APPLE) project (libminizinc CXX) # The version number. set (libminizinc_VERSION_MAJOR 2) set (libminizinc_VERSION_MINOR 0) set (libminizinc_VERSION_PATCH 11) if (ADDITIONAL_DATE_STRING) set (libminizinc_VERSION_PATCH "${libminizinc_VERSION_PATCH}.${ADDITIONAL_DATE_STRING}") endif() include(CheckCXXCompilerFlag) SET(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") check_cxx_compiler_flag(-Werror HAS_WERROR) if (HAS_WERROR) SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror") endif() check_cxx_compiler_flag(-std=c++11 HAS_STDCPP11) if (HAS_STDCPP11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") else() check_cxx_compiler_flag(-std=c++0x HAS_STDCPP0X) if (HAS_STDCPP0X) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") endif() endif() check_cxx_compiler_flag(-stdlib=${MZN_LIBCPP} HAS_STDLIBLIBCPP) if (HAS_STDLIBLIBCPP) set(SAFE_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=${MZN_LIBCPP}") check_cxx_source_compiles("int main(void) {return 0;}" LINKS_STDLIBLIBCPP) if (NOT LINKS_STDLIBLIBCPP) set(CMAKE_CXX_FLAGS "${SAFE_CMAKE_CXX_FLAGS}") endif() endif() check_cxx_source_compiles("#include int main(void) { std::unordered_set x; return 0; }" HAS_CPP11) if (NOT HAS_CPP11) check_cxx_source_compiles("#include int main(void) { std::tr1::unordered_set x; return 0; }" HAS_CPP11_TR1) if (HAS_CPP11_TR1) set(MZN_NEED_TR1 1) else() message(FATAL_ERROR "A c++11 compatible C++ standard library is required to build libminizinc.") endif() endif() CHECK_CXX_SOURCE_COMPILES("int main(void) { static __thread int x; (void)x; return 0;}" HAS_ATTR_THREAD) if (NOT HAS_ATTR_THREAD) CHECK_CXX_SOURCE_COMPILES("int main(void) { __declspec(thread) static int x; (void)x; return 0;}" HAS_DECLSPEC_THREAD) endif() CHECK_CXX_SOURCE_COMPILES(" #include #include #include #include #include #include int main (int argc, char* argv[]) { pid_t pid = getpid(); char path[PROC_PIDPATHINFO_MAXSIZE]; (void) proc_pidpath (pid, path, sizeof(path)); return 0; } " HAS_PIDPATH) CHECK_CXX_SOURCE_COMPILES(" #include int main (int argc, char* argv[]) { char path[MAX_PATH]; (void) GetModuleFileName(NULL, path, MAX_PATH); return 0; }" HAS_GETMODULEFILENAME) CHECK_CXX_SOURCE_COMPILES(" #include int main (int argc, char* argv[]) { (void) GetFileAttributes(NULL); return 0; }" HAS_GETFILEATTRIBUTES) CHECK_CXX_SOURCE_COMPILES(" #include int main (int argc, char* argv[]) { (void) memcpy_s(NULL,0,NULL,0); return 0; }" HAS_MEMCPY_S) SET (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/minizinc) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/doc/html) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/doc/pdf) # configure a header file to pass some of the CMake settings # to the source code configure_file ( ${PROJECT_SOURCE_DIR}/include/minizinc/config.hh.in ${PROJECT_BINARY_DIR}/minizinc/config.hh ) configure_file ( ${PROJECT_SOURCE_DIR}/doc/spec/version.tex.in ${PROJECT_BINARY_DIR}/doc/pdf/version.tex ) include_directories(${PROJECT_BINARY_DIR}) include_directories(${PROJECT_SOURCE_DIR}/include) add_custom_target(MZNParser echo "Creating parser") # When updating the cached files, update MD5 sums defined in this file include(${PROJECT_SOURCE_DIR}/lib/cached/md5_cached.cmake) macro(MD5 filename md5sum) file(READ "${filename}" RAW_MD5_FILE) string(REGEX REPLACE "\r" "" STRIPPED_MD5_FILE "${RAW_MD5_FILE}") string(MD5 ${md5sum} "${STRIPPED_MD5_FILE}") endmacro(MD5) find_program(FLEX_EXEC flex) if(FLEX_EXEC) add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/lexer.yy.cpp DEPENDS ${PROJECT_SOURCE_DIR}/lib/lexer.lxx COMMAND ${FLEX_EXEC} -L -o${PROJECT_BINARY_DIR}/lexer.yy.cpp ${PROJECT_SOURCE_DIR}/lib/lexer.lxx ) set_source_files_properties(${PROJECT_BINARY_DIR}/lexer.yy.cpp GENERATED) set(lexer_cpp ${PROJECT_BINARY_DIR}/lexer.yy.cpp) else(FLEX_EXEC) MD5(${PROJECT_SOURCE_DIR}/lib/lexer.lxx lexer_lxx_md5) if(NOT "${lexer_lxx_md5}" STREQUAL "${lexer_lxx_md5_cached}") message(FATAL_ERROR "The file lexer.lxx has been modified but flex cannot be run.") endif() set(lexer_cpp ${PROJECT_SOURCE_DIR}/lib/cached/lexer.yy.cpp) endif(FLEX_EXEC) find_program(BISON_EXEC bison) if(BISON_EXEC) add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/parser.tab.cpp ${PROJECT_BINARY_DIR}/minizinc/parser.tab.hh DEPENDS ${lexer_cpp} ${PROJECT_SOURCE_DIR}/lib/parser.yxx COMMAND "${BISON_EXEC}" -l -o ${PROJECT_BINARY_DIR}/parser.tab.cpp --defines=${PROJECT_BINARY_DIR}/minizinc/parser.tab.hh ${PROJECT_SOURCE_DIR}/lib/parser.yxx ) set_source_files_properties(${PROJECT_BINARY_DIR}/parser.tab.cpp GENERATED) set(parser_cpp ${PROJECT_BINARY_DIR}/parser.tab.cpp) set(parser_hh ${PROJECT_BINARY_DIR}/minizinc/parser.tab.hh) else(BISON_EXEC) MD5(${PROJECT_SOURCE_DIR}/lib/parser.yxx parser_yxx_md5) if(NOT "${parser_yxx_md5}" STREQUAL "${parser_yxx_md5_cached}") message(FATAL_ERROR "The file parser.yxx has been modified but bison cannot be run.") endif() include_directories(${PROJECT_SOURCE_DIR}/lib/cached) set(parser_cpp ${PROJECT_SOURCE_DIR}/lib/cached/parser.tab.cpp) set(parser_hh ${PROJECT_SOURCE_DIR}/lib/cached/minizinc/parser.tab.hh) endif(BISON_EXEC) add_library(minizinc lib/ast.cpp lib/astexception.cpp lib/aststring.cpp lib/astvec.cpp lib/builtins.cpp lib/copy.cpp lib/eval_par.cpp lib/file_utils.cpp lib/gc.cpp lib/htmlprinter.cpp ${lexer_cpp} lib/model.cpp ${parser_cpp} lib/prettyprinter.cpp lib/typecheck.cpp lib/flatten.cpp lib/optimize.cpp lib/optimize_constraints.cpp lib/parser.yxx lib/lexer.lxx lib/values.cpp include/minizinc/ast.hh include/minizinc/ast.hpp include/minizinc/astexception.hh include/minizinc/astiterator.hh include/minizinc/aststring.hh include/minizinc/astvec.hh include/minizinc/builtins.hh include/minizinc/config.hh.in include/minizinc/copy.hh include/minizinc/eval_par.hh include/minizinc/exception.hh include/minizinc/file_utils.hh include/minizinc/flatten.hh include/minizinc/flatten_internal.hh include/minizinc/gc.hh include/minizinc/hash.hh include/minizinc/htmlprinter.hh include/minizinc/iter.hh include/minizinc/model.hh include/minizinc/optimize.hh include/minizinc/optimize_constraints.hh include/minizinc/parser.hh include/minizinc/prettyprinter.hh include/minizinc/timer.hh include/minizinc/type.hh include/minizinc/typecheck.hh include/minizinc/values.hh include/minizinc/stl_map_set.hh include/minizinc/thirdparty/SafeInt3.hpp ${parser_hh} ) # add the executable add_executable(mzn2fzn mzn2fzn.cpp) target_link_libraries(mzn2fzn minizinc) add_executable(solns2out solns2out.cpp) target_link_libraries(solns2out minizinc) add_executable(mzn2doc mzn2doc.cpp) target_link_libraries(mzn2doc minizinc) INSTALL(TARGETS mzn2fzn solns2out mzn2doc minizinc RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) option (BUILD_HTML_DOCUMENTATION "Build HTML documentation for the MiniZinc library" OFF) if (BUILD_HTML_DOCUMENTATION) add_custom_target(doc ALL DEPENDS "mzn2doc" WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND mzn2doc --toplevel-groups 2 --include-stdlib --html-header ${PROJECT_SOURCE_DIR}/doc/html/header.html --html-footer ${PROJECT_SOURCE_DIR}/doc/html/footer.html --output-base ${PROJECT_BINARY_DIR}/doc/html/doc share/minizinc/std/globals.mzn ) FILE(COPY ${PROJECT_SOURCE_DIR}/doc/html/style.css ${PROJECT_SOURCE_DIR}/doc/html/header.html ${PROJECT_SOURCE_DIR}/doc/html/footer.html ${PROJECT_SOURCE_DIR}/doc/html/MiniZn_logo.jpg DESTINATION ${PROJECT_BINARY_DIR}/doc/html/) INSTALL(DIRECTORY ${PROJECT_BINARY_DIR}/doc/html DESTINATION doc) endif() option (BUILD_PDF_DOCUMENTATION "Build PDF documentation for the MiniZinc language" OFF) if (BUILD_PDF_DOCUMENTATION) add_custom_target(doc_spec ALL DEPENDS doc/spec/common-spec.tex doc/spec/minizinc-spec.tex WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/doc/spec COMMAND latexmk -pdf -output-directory=${PROJECT_BINARY_DIR}/doc/pdf minizinc-spec ) endif() option (BUILD_STATIC_EXECUTABLE "Build statically linked executables" OFF) if (BUILD_STATIC_EXECUTABLE) set(CMAKE_EXE_LINKER_FLAGS -static) endif() INSTALL(DIRECTORY share/minizinc DESTINATION share) INSTALL(DIRECTORY include/minizinc DESTINATION include PATTERN config.hh.in EXCLUDE ) INSTALL(FILES ${PROJECT_BINARY_DIR}/minizinc/config.hh DESTINATION include/minizinc) INSTALL(FILES README.txt INSTALL.txt LICENSE.txt DESTINATION doc/..) INSTALL(DIRECTORY doc/pdf DESTINATION doc) INSTALL(DIRECTORY share/examples DESTINATION share) INSTALL(DIRECTORY lib/cached DESTINATION lib PATTERN md5_cached.cmake EXCLUDE) INSTALL(FILES ${parser_hh} DESTINATION include/minizinc) SET(CPACK_PACKAGE_VERSION_MAJOR ${libminizinc_VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MINOR ${libminizinc_VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${libminizinc_VERSION_PATCH}) SET(CPACK_PACKAGE_INSTALL_DIRECTORY "CMake ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") IF(WIN32 AND NOT UNIX) SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} My Famous Project") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.minizinc.org") SET(CPACK_NSIS_CONTACT "info@minizinc.org") SET(CPACK_NSIS_MODIFY_PATH ON) SET(CPACK_GENERATOR "ZIP") ELSE(WIN32 AND NOT UNIX) SET(CPACK_STRIP_FILES "bin/MyExecutable") SET(CPACK_SOURCE_STRIP_FILES "") SET(CPACK_GENERATOR "TGZ") ENDIF(WIN32 AND NOT UNIX) set(CPACK_SOURCE_GENERATOR "TGZ;ZIP") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") set(CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}/;/tests/;/.git/;/.gitignore;~$;${CPACK_SOURCE_IGNORE_FILES}") include(CPack) libminizinc-2.0.11/README.txt0000644000175000017500000000626712646030173014253 0ustar kaolkaolMiniZinc 2 ========== This package contains the MiniZinc 2 constraint modelling language and tool chain. Compared to the previous version 1.6, it is a complete re-write of the MiniZinc-to-FlatZinc compiler, based on the new libminizinc C++ library. For installation and compilation instructions please refer to the file INSTALL.txt. Changes from version 1.6 ------------------------ MiniZinc 2.0 contains many new features and is based on a complete rewrite of the MiniZinc-to-FlatZinc compiler. If you are currently using the previous version 1.6, the new tools can be used as drop-in replacements. The generated FlatZinc is compatible with version 1.6, so all FlatZinc solvers should work without changes. ** MiniZinc language changes ** - MiniZinc now supports user-defined functions. Details have been published in the paper "MiniZinc with Functions". Both functions and predicates can be recursive. - MiniZinc now supports option types. Details have been published in the paper "Modelling with Option Types in MiniZinc". - Let expressions have been generalised. They can now contain constraint items in addition to variable declarations. - Array index sets can be declared using arbitrary set expressions as long as they evaluate to contiguous ranges. - The if-then-else expression has been generalised to allow the condition to be a var bool expression (instead of only par bool). - Array and set comprehensions as well as generator calls can now iterate over variables and use var bool where conditions. - Any bool expression can now automatically coerce to an int expression, likewise for int and float. This means that you don't have to write bool2int or int2float in you models any more. - Equality constraints can now be posted between array expressions. - Arbitrary expressions can now be included ("interpolated") into strings, using the syntax "some text \(e) some more text", where e is any expression. It is the same as writing "some text "++show(e)++" some more text". ** New built-in functions ** Array functions: array1d, arrayXd, row, col, has_index, has_element, sort_by, sort, arg_sort, arg_min, arg_max ** New global constraints ** - arg_max, arg_min - arg_sort - k-dimensional diffn - disjunctive - geost - knapsack - network_flow - regular with NFAs - symmetric all different - optional scheduling constraints: alternative, span, disjunctive, cumulative - functional versions of many global constraints ** New tool chain ** - There are a few new builtins that solvers can reimplement, these are listed in the redefinitions-2.0 file. - Include items use a different method for finding included files. Paths are now interpreted as relative to the file that has the include item. That way, the mzn2fzn compiler can be called from a different working directory. - A new tool, mzn2doc, can produce html output from the documentation comments. The MiniZinc distribution contains the documentation for global constraints and builtins generated directly from the library source code. ** Bugs ** If you encounter any problems with MiniZinc, please use the MiniZinc bug tracker at http://www.minizinc.org/trac to report any issues or feature requests.