/* -*- 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 #include #include namespace MiniZinc { class VarDeclIterator; class ConstraintIterator; class FunctionIterator; class CopyMap; class EnvI; /// A MiniZinc model class Model { friend class GC; friend class FZNSolverInstance; 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; struct FnEntry { std::vector t; FunctionI* fi; bool isPolymorphic; FnEntry(FunctionI* fi0); bool operator<(const FnEntry&) const; static bool compare(const FnEntry& e1, const FnEntry& e2); }; /// Add all instances of polymorphic entry \a fe to \a entries void addPolymorphicInstances(Model::FnEntry& fe, std::vector& entries); /// Type of map from identifiers to function declarations typedef ASTStringMap >::t FnMap; /// Map from identifiers to function declarations FnMap fnmap; /// Type of map from Type (represented as int) to reverse mapper functions typedef std::unordered_map RevMapperMap; /// Map from Type (represented as int) to reverse mapper functions RevMapperMap revmapmap; /// 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; /// Store some declarations struct FnDecls { using TCheckedDecl = std::pair; // bool means that it was checked TCheckedDecl bounds_disj = {false, nullptr}; // SCIP's bound disjunction } fnDecls; public: /// Construct empty model Model(void); /// Destructor ~Model(void); /// Add \a i to the model void addItem(Item* i); /// 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); /// Check that registered functions do not clash wrt overloading void checkFnOverloading(EnvI& env); /// Fix function table after type checking void fixFnMap(void); /// Return function declaration for \a id matching \a args FunctionI* matchFn(EnvI& env, const ASTString& id, const std::vector& args, bool strictEnums) const; /// Return function declaration for \a id matching types \a t FunctionI* matchFn(EnvI& env, const ASTString& id, const std::vector& t, bool strictEnums); /// Return function declaration matching call \a c FunctionI* matchFn(EnvI& env, Call* c, bool strictEnums) const; /// Return function declaration for reverse mapper for type \a t FunctionI* matchRevMap(EnvI& env, const Type& t) const; /// Merge all builtin functions into \a m void mergeStdLib(EnvI& env, Model* m) 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); FunctionIterator begin_functions(void); FunctionIterator end_functions(void); SolveI* solveItem(void); OutputI* outputItem(void); void setOutputItem(OutputI* oi); /// 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); /// Get the stored function declarations FnDecls& getFnDecls() { return fnDecls; } }; 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 FunctionIterator { Model* _model; Model::iterator _it; public: typedef Model::iterator::difference_type difference_type; typedef Model::iterator::value_type value_type; typedef FunctionI& reference; typedef FunctionI* pointer; typedef std::forward_iterator_tag iterator_category; FunctionIterator() {} FunctionIterator(const FunctionIterator& vi) : _it(vi._it) {} FunctionIterator(Model* model, const Model::iterator& it) : _model(model), _it(it) { while (_it != _model->end() && !(*_it)->isa()) { ++_it; } } ~FunctionIterator() {} FunctionIterator& operator=(const FunctionIterator& vi) { if (this != &vi) { _it = vi._it; } return *this; } bool operator==(const FunctionIterator& vi) const { return _it == vi._it; } bool operator!=(const FunctionIterator& vi) const { return _it != vi._it; } FunctionIterator& 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 = NULL, std::ostream& outstream = std::cout, std::ostream& errstream = std::cerr); ~Env(void); Model* model(void); void model(Model* m); Model* flat(void); void swap(); 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; std::ostream& evalOutput(std::ostream& os); }; 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) { std::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; std::vector includedModels; for (unsigned int i = 0; i < cm->size(); 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()) { includedModels.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; } } for (unsigned int i = static_cast(includedModels.size()); i--;) { models.push_back(includedModels[i]); } } } }; /// Run iterator \a i over all items of model \a m template void iterItems(I& i, Model* m) { ItemIter(i).run(m); } } // namespace MiniZinc #endif