1 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 /*
3  *  Main authors:
4  *     Guido Tack <tack@gecode.org>
5  *
6  *  Contributing authors:
7  *     Gabriel Hjort Blindell <gabriel.hjort.blindell@gmail.com>
8  *
9  *  Copyright:
10  *     Guido Tack, 2007-2012
11  *     Gabriel Hjort Blindell, 2012
12  *
13  *  This file is part of Gecode, the generic constraint
14  *  development environment:
15  *     http://www.gecode.org
16  *
17  *  Permission is hereby granted, free of charge, to any person obtaining
18  *  a copy of this software and associated documentation files (the
19  *  "Software"), to deal in the Software without restriction, including
20  *  without limitation the rights to use, copy, modify, merge, publish,
21  *  distribute, sublicense, and/or sell copies of the Software, and to
22  *  permit persons to whom the Software is furnished to do so, subject to
23  *  the following conditions:
24  *
25  *  The above copyright notice and this permission notice shall be
26  *  included in all copies or substantial portions of the Software.
27  *
28  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35  *
36  */
37 
38 #ifndef GECODE_FLATZINC_HH
39 #define GECODE_FLATZINC_HH
40 
41 #include <iostream>
42 
43 #include <gecode/kernel.hh>
44 #include <gecode/int.hh>
45 #ifdef GECODE_HAS_SET_VARS
46 #include <gecode/set.hh>
47 #endif
48 #ifdef GECODE_HAS_FLOAT_VARS
49 #include <gecode/float.hh>
50 #endif
51 #include <map>
52 
53 /*
54  * Support for DLLs under Windows
55  *
56  */
57 
58 #if !defined(GECODE_STATIC_LIBS) && \
59     (defined(__CYGWIN__) || defined(__MINGW32__) || defined(_MSC_VER))
60 
61 #ifdef GECODE_BUILD_FLATZINC
62 #define GECODE_FLATZINC_EXPORT __declspec( dllexport )
63 #else
64 #define GECODE_FLATZINC_EXPORT __declspec( dllimport )
65 #endif
66 
67 #else
68 
69 #ifdef GECODE_GCC_HAS_CLASS_VISIBILITY
70 
71 #define GECODE_FLATZINC_EXPORT __attribute__ ((visibility("default")))
72 
73 #else
74 
75 #define GECODE_FLATZINC_EXPORT
76 
77 #endif
78 #endif
79 
80 // Configure auto-linking
81 #ifndef GECODE_BUILD_FLATZINC
82 #define GECODE_LIBRARY_NAME "FlatZinc"
83 #include <gecode/support/auto-link.hpp>
84 #endif
85 
86 #include <gecode/driver.hh>
87 
88 #include <gecode/flatzinc/conexpr.hh>
89 #include <gecode/flatzinc/ast.hh>
90 #include <gecode/flatzinc/varspec.hh>
91 
92 /**
93  * \namespace Gecode::FlatZinc
94  * \brief Interpreter for the %FlatZinc language
95  *
96  * The Gecode::FlatZinc namespace contains all functionality required
97  * to parse and solve constraint models written in the %FlatZinc language.
98  *
99  */
100 
101 namespace Gecode { namespace FlatZinc {
102 
103   /**
104    * \brief Output support class for %FlatZinc interpreter
105    *
106    */
107   class GECODE_FLATZINC_EXPORT Printer {
108   private:
109     /// Names of integer variables
110     std::vector<std::string> iv_names;
111     /// Names of Boolean variables
112     std::vector<std::string> bv_names;
113 #ifdef GECODE_HAS_FLOAT_VARS
114     /// Names of float variables
115     std::vector<std::string> fv_names;
116 #endif
117 #ifdef GECODE_HAS_SET_VARS
118     /// Names of set variables
119     std::vector<std::string> sv_names;
120 #endif
121     AST::Array* _output;
122     void printElem(std::ostream& out,
123                    AST::Node* ai,
124                    const Gecode::IntVarArray& iv,
125                    const Gecode::BoolVarArray& bv
126 #ifdef GECODE_HAS_SET_VARS
127                    ,
128                    const Gecode::SetVarArray& sv
129 #endif
130 #ifdef GECODE_HAS_FLOAT_VARS
131                   ,
132                   const Gecode::FloatVarArray& fv
133 #endif
134                    ) const;
135     void printElemDiff(std::ostream& out,
136                        AST::Node* ai,
137                        const Gecode::IntVarArray& iv1,
138                        const Gecode::IntVarArray& iv2,
139                        const Gecode::BoolVarArray& bv1,
140                        const Gecode::BoolVarArray& bv2
141 #ifdef GECODE_HAS_SET_VARS
142                        ,
143                        const Gecode::SetVarArray& sv1,
144                        const Gecode::SetVarArray& sv2
145 #endif
146 #ifdef GECODE_HAS_FLOAT_VARS
147                        ,
148                        const Gecode::FloatVarArray& fv1,
149                        const Gecode::FloatVarArray& fv2
150 #endif
151                        ) const;
152   public:
Printer(void)153     Printer(void) : _output(nullptr) {}
154     void init(AST::Array* output);
155 
156     void print(std::ostream& out,
157                const Gecode::IntVarArray& iv,
158                const Gecode::BoolVarArray& bv
159 #ifdef GECODE_HAS_SET_VARS
160                ,
161                const Gecode::SetVarArray& sv
162 #endif
163 #ifdef GECODE_HAS_FLOAT_VARS
164                ,
165                const Gecode::FloatVarArray& fv
166 #endif
167                ) const;
168 
169     void printDiff(std::ostream& out,
170                const Gecode::IntVarArray& iv1, const Gecode::IntVarArray& iv2,
171                const Gecode::BoolVarArray& bv1, const Gecode::BoolVarArray& bv2
172 #ifdef GECODE_HAS_SET_VARS
173                ,
174                const Gecode::SetVarArray& sv1, const Gecode::SetVarArray& sv2
175 #endif
176 #ifdef GECODE_HAS_FLOAT_VARS
177                ,
178                const Gecode::FloatVarArray& fv1,
179                const Gecode::FloatVarArray& fv2
180 #endif
181                ) const;
182 
183 
184     ~Printer(void);
185 
186     void addIntVarName(const std::string& n);
intVarName(int i) const187     const std::string& intVarName(int i) const { return iv_names[i]; }
188     void addBoolVarName(const std::string& n);
boolVarName(int i) const189     const std::string& boolVarName(int i) const { return bv_names[i]; }
190 #ifdef GECODE_HAS_FLOAT_VARS
191     void addFloatVarName(const std::string& n);
floatVarName(int i) const192     const std::string& floatVarName(int i) const { return fv_names[i]; }
193 #endif
194 #ifdef GECODE_HAS_SET_VARS
195     void addSetVarName(const std::string& n);
setVarName(int i) const196     const std::string& setVarName(int i) const { return sv_names[i]; }
197 #endif
198 
199     void shrinkElement(AST::Node* node,
200                        std::map<int,int>& iv, std::map<int,int>& bv,
201                        std::map<int,int>& sv, std::map<int,int>& fv);
202 
203     void shrinkArrays(Space& home,
204                       int& optVar, bool optVarIsInt,
205                       Gecode::IntVarArray& iv,
206                       Gecode::BoolVarArray& bv
207 #ifdef GECODE_HAS_SET_VARS
208                       ,
209                       Gecode::SetVarArray& sv
210 #endif
211 #ifdef GECODE_HAS_FLOAT_VARS
212                       ,
213                       Gecode::FloatVarArray& fv
214 #endif
215                      );
216 
217   private:
218     Printer(const Printer&);
219     Printer& operator=(const Printer&);
220   };
221 
222   /**
223    * \brief %Options for running %FlatZinc models
224    *
225    */
226   class FlatZincOptions : public Gecode::BaseOptions {
227   protected:
228       /// \name Search options
229       //@{
230       Gecode::Driver::IntOption         _solutions; ///< How many solutions
231       Gecode::Driver::BoolOption        _allSolutions; ///< Return all solutions
232       Gecode::Driver::DoubleOption      _threads;   ///< How many threads to use
233       Gecode::Driver::BoolOption        _free; ///< Use free search
234       Gecode::Driver::DoubleOption      _decay;       ///< Decay option
235       Gecode::Driver::UnsignedIntOption _c_d;       ///< Copy recomputation distance
236       Gecode::Driver::UnsignedIntOption _a_d;       ///< Adaptive recomputation distance
237       Gecode::Driver::UnsignedLongLongIntOption _node;      ///< Cutoff for number of nodes
238       Gecode::Driver::UnsignedLongLongIntOption _fail;      ///< Cutoff for number of failures
239       Gecode::Driver::DoubleOption _time;      ///< Cutoff for time
240       Gecode::Driver::DoubleOption _time_limit;  ///< Cutoff for time (for compatibility with flatzinc command line)
241       Gecode::Driver::IntOption         _seed;      ///< Random seed
242       Gecode::Driver::StringOption      _restart;   ///< Restart method option
243       Gecode::Driver::DoubleOption      _r_base;    ///< Restart base
244       Gecode::Driver::UnsignedIntOption _r_scale;   ///< Restart scale factor
245       Gecode::Driver::BoolOption        _nogoods;   ///< Whether to use no-goods
246       Gecode::Driver::UnsignedIntOption _nogoods_limit; ///< Depth limit for extracting no-goods
247       Gecode::Driver::BoolOption        _interrupt; ///< Whether to catch SIGINT
248       Gecode::Driver::DoubleOption      _step;        ///< Step option
249       //@}
250 
251       /// \name Execution options
252       //@{
253       Gecode::Driver::StringOption      _mode;       ///< Script mode to run
254       Gecode::Driver::BoolOption        _stat;       ///< Emit statistics
255       Gecode::Driver::StringValueOption _output;     ///< Output file
256 
257 #ifdef GECODE_HAS_CPPROFILER
258       Gecode::Driver::ProfilerOption    _profiler; ///< Use this execution id for the CP-profiler
259 #endif
260 
261       //@}
262   public:
263     /// Constructor
FlatZincOptions(const char * s)264     FlatZincOptions(const char* s)
265     : Gecode::BaseOptions(s),
266       _solutions("n","number of solutions (0 = all, -1 = one/best)",-1),
267       _allSolutions("a", "return all solutions (equal to -n 0)"),
268       _threads("p","number of threads (0 = #processing units)",
269                Gecode::Search::Config::threads),
270       _free("f", "free search, no need to follow search-specification"),
271       _decay("decay","decay factor",0.99),
272       _c_d("c-d","recomputation commit distance",Gecode::Search::Config::c_d),
273       _a_d("a-d","recomputation adaption distance",Gecode::Search::Config::a_d),
274       _node("node","node cutoff (0 = none, solution mode)"),
275       _fail("fail","failure cutoff (0 = none, solution mode)"),
276       _time("time","time (in ms) cutoff (0 = none, solution mode)"),
277       _time_limit("t","time (in ms) cutoff (0 = none, solution mode)"),
278       _seed("r","random seed",0),
279       _restart("restart","restart sequence type",RM_NONE),
280       _r_base("restart-base","base for geometric restart sequence",1.5),
281       _r_scale("restart-scale","scale factor for restart sequence",250),
282       _nogoods("nogoods","whether to use no-goods from restarts",false),
283       _nogoods_limit("nogoods-limit","depth limit for no-good extraction",
284                      Search::Config::nogoods_limit),
285       _interrupt("interrupt","whether to catch Ctrl-C (true) or not (false)",
286                  true),
287       _step("step","step distance for float optimization",0.0),
288       _mode("mode","how to execute script",Gecode::SM_SOLUTION),
289       _stat("s","emit statistics"),
290       _output("o","file to send output to")
291 
292 #ifdef GECODE_HAS_CPPROFILER
293       ,
294       _profiler("cp-profiler", "use this execution id and port (comma separated) with CP-profiler")
295 #endif
296     {
297       _mode.add(Gecode::SM_SOLUTION, "solution");
298       _mode.add(Gecode::SM_STAT, "stat");
299       _mode.add(Gecode::SM_GIST, "gist");
300       _restart.add(RM_NONE,"none");
301       _restart.add(RM_CONSTANT,"constant");
302       _restart.add(RM_LINEAR,"linear");
303       _restart.add(RM_LUBY,"luby");
304       _restart.add(RM_GEOMETRIC,"geometric");
305 
306       add(_solutions); add(_threads); add(_c_d); add(_a_d);
307       add(_allSolutions);
308       add(_free);
309       add(_decay);
310       add(_node); add(_fail); add(_time); add(_time_limit); add(_interrupt);
311       add(_seed);
312       add(_step);
313       add(_restart); add(_r_base); add(_r_scale);
314       add(_nogoods); add(_nogoods_limit);
315       add(_mode); add(_stat);
316       add(_output);
317 #ifdef GECODE_HAS_CPPROFILER
318       add(_profiler);
319 #endif
320     }
321 
parse(int & argc,char * argv[])322     void parse(int& argc, char* argv[]) {
323       Gecode::BaseOptions::parse(argc,argv);
324       if (_allSolutions.value() && _solutions.value()==-1) {
325         _solutions.value(0);
326       }
327       if (_time_limit.value()) {
328         _time.value(_time_limit.value());
329       }
330       if (_stat.value())
331         _mode.value(Gecode::SM_STAT);
332     }
333 
help(void)334     virtual void help(void) {
335       std::cerr << "Gecode FlatZinc interpreter" << std::endl
336                 << " - Supported FlatZinc version: " << GECODE_FLATZINC_VERSION
337                 << std::endl << std::endl;
338       Gecode::BaseOptions::help();
339     }
340 
solutions(void) const341     int solutions(void) const { return _solutions.value(); }
allSolutions(void) const342     bool allSolutions(void) const { return _allSolutions.value(); }
threads(void) const343     double threads(void) const { return _threads.value(); }
free(void) const344     bool free(void) const { return _free.value(); }
c_d(void) const345     unsigned int c_d(void) const { return _c_d.value(); }
a_d(void) const346     unsigned int a_d(void) const { return _a_d.value(); }
node(void) const347     unsigned long long int node(void) const { return _node.value(); }
fail(void) const348     unsigned long long int fail(void) const { return _fail.value(); }
time(void) const349     double time(void) const { return _time.value(); }
seed(void) const350     int seed(void) const { return _seed.value(); }
step(void) const351     double step(void) const { return _step.value(); }
output(void) const352     const char* output(void) const { return _output.value(); }
353 
mode(void) const354     Gecode::ScriptMode mode(void) const {
355       return static_cast<Gecode::ScriptMode>(_mode.value());
356     }
357 
decay(void) const358     double decay(void) const { return _decay.value(); }
restart(void) const359     RestartMode restart(void) const {
360       return static_cast<RestartMode>(_restart.value());
361     }
restart(RestartMode rm)362     void restart(RestartMode rm) {
363       _restart.value(rm);
364     }
restart_base(void) const365     double restart_base(void) const { return _r_base.value(); }
restart_base(double d)366     void restart_base(double d) { _r_base.value(d); }
restart_scale(void) const367     unsigned int restart_scale(void) const { return _r_scale.value(); }
restart_scale(int i)368     void restart_scale(int i) { _r_scale.value(i); }
nogoods(void) const369     bool nogoods(void) const { return _nogoods.value(); }
nogoods_limit(void) const370     unsigned int nogoods_limit(void) const { return _nogoods_limit.value(); }
interrupt(void) const371     bool interrupt(void) const { return _interrupt.value(); }
372 
373 #ifdef GECODE_HAS_CPPROFILER
374 
profiler_id(void) const375     int profiler_id(void) const { return _profiler.execution_id(); }
profiler_port(void) const376     unsigned int profiler_port(void) const { return _profiler.port(); }
profiler_info(void) const377     bool profiler_info(void) const { return true; }
378 
379 #endif
380 
allSolutions(bool b)381     void allSolutions(bool b) { _allSolutions.value(b); }
382   };
383 
384   class BranchInformation : public SharedHandle {
385   public:
386     /// Constructor
387     BranchInformation(void);
388     /// Copy constructor
389     BranchInformation(const BranchInformation& bi);
390     /// Initialise for use
391     void init(void);
392     /// Add new brancher information
393     void add(BrancherGroup bg,
394              const std::string& rel0,
395              const std::string& rel1,
396              const std::vector<std::string>& n);
397     /// Output branch information
398     void print(const Brancher& b,
399                unsigned int a, int i, int n, std::ostream& o) const;
400 #ifdef GECODE_HAS_FLOAT_VARS
401     /// Output branch information
402     void print(const Brancher& b,
403                unsigned int a, int i, const FloatNumBranch& nl,
404                std::ostream& o) const;
405 #endif
406   };
407 
408   /// Uninitialized default random number generator
409   GECODE_FLATZINC_EXPORT
410   extern Rnd defrnd;
411 
412   class FlatZincSpaceInitData;
413 
414   /**
415    * \brief A space that can be initialized with a %FlatZinc model
416    *
417    */
418   class GECODE_FLATZINC_EXPORT FlatZincSpace : public Space {
419   public:
420     enum Meth {
421       SAT, //< Solve as satisfaction problem
422       MIN, //< Solve as minimization problem
423       MAX  //< Solve as maximization problem
424     };
425   protected:
426     /// Initialisation data (only used for posting constraints)
427     FlatZincSpaceInitData* _initData;
428     /// Number of integer variables
429     int intVarCount;
430     /// Number of Boolean variables
431     int boolVarCount;
432     /// Number of float variables
433     int floatVarCount;
434     /// Number of set variables
435     int setVarCount;
436 
437     /// Index of the variable to optimize
438     int _optVar;
439     /// Whether variable to optimize is integer (or float)
440     bool _optVarIsInt;
441 
442     /// Whether to solve as satisfaction or optimization problem
443     Meth _method;
444 
445     /// Percentage of variables to keep in LNS (or 0 for no LNS)
446     unsigned int _lns;
447 
448     /// Initial solution to start the LNS (or nullptr for no LNS)
449     IntSharedArray _lnsInitialSolution;
450 
451     /// Random number generator
452     Rnd _random;
453 
454     /// Annotations on the solve item
455     AST::Array* _solveAnnotations;
456 
457     /// Copy constructor
458     FlatZincSpace(FlatZincSpace&);
459   private:
460     /// Run the search engine
461     template<template<class> class Engine>
462     void
463     runEngine(std::ostream& out, const Printer& p,
464               const FlatZincOptions& opt, Gecode::Support::Timer& t_total);
465     /// Run the meta search engine
466     template<template<class> class Engine,
467              template<class, template<class> class> class Meta>
468     void
469     runMeta(std::ostream& out, const Printer& p,
470             const FlatZincOptions& opt, Gecode::Support::Timer& t_total);
471     void
472     branchWithPlugin(AST::Node* ann);
473   public:
474     /// The integer variables
475     Gecode::IntVarArray iv;
476     /// The introduced integer variables
477     Gecode::IntVarArray iv_aux;
478 
479     /// The integer variables used in LNS
480     Gecode::IntVarArray iv_lns;
481 
482     /// Indicates whether an integer variable is introduced by mzn2fzn
483     std::vector<bool> iv_introduced;
484     /// Indicates whether an integer variable aliases a Boolean variable
485     int* iv_boolalias;
486     /// The Boolean variables
487     Gecode::BoolVarArray bv;
488     /// The introduced Boolean variables
489     Gecode::BoolVarArray bv_aux;
490     /// Indicates whether a Boolean variable is introduced by mzn2fzn
491     std::vector<bool> bv_introduced;
492 #ifdef GECODE_HAS_SET_VARS
493     /// The set variables
494     Gecode::SetVarArray sv;
495     /// The introduced set variables
496     Gecode::SetVarArray sv_aux;
497     /// Indicates whether a set variable is introduced by mzn2fzn
498     std::vector<bool> sv_introduced;
499 #endif
500 #ifdef GECODE_HAS_FLOAT_VARS
501     /// The float variables
502     Gecode::FloatVarArray fv;
503     /// The introduced float variables
504     Gecode::FloatVarArray fv_aux;
505     /// Indicates whether a float variable is introduced by mzn2fzn
506     std::vector<bool> fv_introduced;
507     /// Step by which a next solution has to have lower cost
508     Gecode::FloatNum step;
509 #endif
510     /// Whether the introduced variables still need to be copied
511     bool needAuxVars;
512     /// Construct empty space
513     FlatZincSpace(Rnd& random = defrnd);
514 
515     /// Destructor
516     ~FlatZincSpace(void);
517 
518     /// Initialize space with given number of variables
519     void init(int intVars, int boolVars, int setVars, int floatVars);
520 
521     /// Create new integer variable from specification
522     void newIntVar(IntVarSpec* vs);
523     /// Link integer variable \a iv to Boolean variable \a bv
524     void aliasBool2Int(int iv, int bv);
525     /// Return linked Boolean variable for integer variable \a iv
526     int aliasBool2Int(int iv);
527     /// Create new Boolean variable from specification
528     void newBoolVar(BoolVarSpec* vs);
529     /// Create new set variable from specification
530     void newSetVar(SetVarSpec* vs);
531     /// Create new float variable from specification
532     void newFloatVar(FloatVarSpec* vs);
533 
534     /// Post a constraint specified by \a ce
535     void postConstraints(std::vector<ConExpr*>& ces);
536 
537     /// Post the solve item
538     void solve(AST::Array* annotation);
539     /// Post that integer variable \a var should be minimized
540     void minimize(int var, bool isInt, AST::Array* annotation);
541     /// Post that integer variable \a var should be maximized
542     void maximize(int var, bool isInt, AST::Array* annotation);
543 
544     /// Run the search
545     void run(std::ostream& out, const Printer& p,
546              const FlatZincOptions& opt, Gecode::Support::Timer& t_total);
547 
548     /// Produce output on \a out using \a p
549     void print(std::ostream& out, const Printer& p) const;
550 #ifdef GECODE_HAS_CPPROFILER
551     /// Get string representing the domains of variables (for cpprofiler)
552     std::string getDomains(const Printer& p) const;
553 #endif
554     /// Compare this space with space \a s and print the differences on
555     /// \a out
556     void compare(const Space& s, std::ostream& out) const;
557     /// Compare this space with space \a s and print the differences on
558     /// \a out using \a p
559     void compare(const FlatZincSpace& s, std::ostream& out,
560                  const Printer& p) const;
561 
562     /**
563      * \brief Remove all variables not needed for output
564      *
565      * After calling this function, no new constraints can be posted through
566      * FlatZinc variable references, and the createBranchers method must
567      * not be called again.
568      *
569      */
570     void shrinkArrays(Printer& p);
571 
572     /// Return whether to solve a satisfaction or optimization problem
573     Meth method(void) const;
574 
575     /// Return index of variable used for optimization
576     int optVar(void) const;
577     /// Return whether variable used for optimization is integer (or float)
578     bool optVarIsInt(void) const;
579 
580     /**
581      * \brief Create branchers corresponding to the solve item annotations
582      *
583      * If \a ignoreUnknown is true, unknown solve item annotations will be
584      * ignored, otherwise a warning is written to \a err.
585      *
586      * The seed for random branchers is given by the \a seed parameter.
587      *
588      */
589     void createBranchers(Printer& p, AST::Node* ann,
590                          FlatZincOptions& opt, bool ignoreUnknown,
591                          std::ostream& err = std::cerr);
592 
593     /// Return the solve item annotations
594     AST::Array* solveAnnotations(void) const;
595 
596     /// Information for printing branches
597     BranchInformation branchInfo;
598 
599     /// Implement optimization
600     virtual void constrain(const Space& s);
601     /// Copy function
602     virtual Gecode::Space* copy(void);
603     /// Slave function for restarts
604     virtual bool slave(const MetaInfo& mi);
605 
606     /// \name AST to variable and value conversion
607     //@{
608     /// Convert \a arg (array of integers) to IntArgs
609     IntArgs arg2intargs(AST::Node* arg, int offset = 0);
610     /// Convert \a arg (array of integers) to IntSharedArray
611     IntSharedArray arg2intsharedarray(AST::Node* arg, int offset = 0);
612     /// Convert \a arg (array of Booleans) to IntArgs
613     IntArgs arg2boolargs(AST::Node* arg, int offset = 0);
614     /// Convert \a arg (array of integers) to IntSharedArray
615     IntSharedArray arg2boolsharedarray(AST::Node* arg, int offset = 0);
616     /// Convert \a n to IntSet
617     IntSet arg2intset(AST::Node* n);
618     /// Convert \a arg to IntSetArgs
619     IntSetArgs arg2intsetargs(AST::Node* arg, int offset = 0);
620     /// Convert \a arg to IntVarArgs
621     IntVarArgs arg2intvarargs(AST::Node* arg, int offset = 0);
622     /// Convert \a arg to BoolVarArgs
623     BoolVarArgs arg2boolvarargs(AST::Node* arg, int offset = 0, int siv=-1);
624     /// Convert \a n to BoolVar
625     BoolVar arg2BoolVar(AST::Node* n);
626     /// Convert \a n to IntVar
627     IntVar arg2IntVar(AST::Node* n);
628     /// Convert \a a to TupleSet
629     TupleSet arg2tupleset(const IntArgs& a, int noOfVars);
630     /// Check if \a b is array of Booleans (or has a single integer)
631     bool isBoolArray(AST::Node* b, int& singleInt);
632 #ifdef GECODE_HAS_SET_VARS
633     /// Convert \a n to SetVar
634     SetVar arg2SetVar(AST::Node* n);
635     /// Convert \a n to SetVarArgs
636     SetVarArgs arg2setvarargs(AST::Node* arg, int offset = 0, int doffset = 0,
637                               const IntSet& od=IntSet::empty);
638 #endif
639 #ifdef GECODE_HAS_FLOAT_VARS
640     /// Convert \a n to FloatValArgs
641     FloatValArgs arg2floatargs(AST::Node* arg, int offset = 0);
642     /// Convert \a n to FloatVar
643     FloatVar arg2FloatVar(AST::Node* n);
644     /// Convert \a n to FloatVarArgs
645     FloatVarArgs arg2floatvarargs(AST::Node* arg, int offset = 0);
646 #endif
647     /// Convert \a ann to integer propagation level
648     IntPropLevel ann2ipl(AST::Node* ann);
649     /// Share DFA \a a if possible
650     DFA getSharedDFA(DFA& a);
651     //@}
652   };
653 
654   /// %Exception class for %FlatZinc errors
655   class GECODE_VTABLE_EXPORT Error {
656   private:
657     const std::string msg;
658   public:
Error(const std::string & where,const std::string & what)659     Error(const std::string& where, const std::string& what)
660     : msg(where+": "+what) {}
Error(const std::string & where,const std::string & what,AST::Array * const ann)661     Error(const std::string& where, const std::string& what, AST::Array *const ann)
662     : msg(make_message(where, what, ann)) {}
toString(void) const663     const std::string& toString(void) const { return msg; }
664   private:
make_message(const std::string & where,const std::string & what,AST::Array * const ann)665     static std::string make_message(const std::string &where, const std::string &what, AST::Array *const ann) {
666       std::ostringstream result;
667       result << where << ": " << what;
668 
669       std::vector<std::string> names = get_constraint_names(ann);
670       if (names.size() > 1) {
671         result << " in constraints ";
672         for (unsigned int i = 0; i < names.size(); ++i) {
673           result << '\"' << names[i] << '\"';
674           if (i < names.size() - 1) {
675             result << ",";
676           }
677           result << " ";
678         }
679       } else if (names.size() == 1) {
680         result << " in constraint " << '\"' << names[0] << '\"';
681       }
682 
683       return result.str();
684     }
get_constraint_names(AST::Array * const ann)685     static std::vector<std::string> get_constraint_names(AST::Array *const ann) {
686       std::vector<std::string> result;
687       if (ann) {
688         for (const auto & i : ann->a) {
689           if (i->isArray()) {
690             auto nested_result = get_constraint_names(i->getArray());
691             result.insert(result.end(), nested_result.begin(), nested_result.end());
692           } else if (i->isCall("mzn_constraint_name")) {
693             result.emplace_back(i->getCall()->args->getString());
694           }
695         }
696       }
697       return result;
698     }
699   };
700 
701   /**
702    * \brief Parse FlatZinc file \a fileName into \a fzs and return it.
703    *
704    * Creates a new empty FlatZincSpace if \a fzs is nullptr.
705    */
706   GECODE_FLATZINC_EXPORT
707   FlatZincSpace* parse(const std::string& fileName,
708                        Printer& p, std::ostream& err = std::cerr,
709                        FlatZincSpace* fzs=nullptr, Rnd& rnd=defrnd);
710 
711   /**
712    * \brief Parse FlatZinc from \a is into \a fzs and return it.
713    *
714    * Creates a new empty FlatZincSpace if \a fzs is nullptr.
715    */
716   GECODE_FLATZINC_EXPORT
717   FlatZincSpace* parse(std::istream& is,
718                        Printer& p, std::ostream& err = std::cerr,
719                        FlatZincSpace* fzs=nullptr, Rnd& rnd=defrnd);
720 
721 }}
722 
723 #endif
724 
725 // STATISTICS: flatzinc-any
726