/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
 *  Main authors:
 *     Christian Schulte <schulte@gecode.org>
 *     Guido Tack <tack@gecode.org>
 *     Mikael Lagerkvist <lagerkvist@gecode.org>
 *     Vincent Barichard <Vincent.Barichard@univ-angers.fr>
 *
 *  Copyright:
 *     Christian Schulte, 2004
 *     Guido Tack, 2004
 *     Mikael Lagerkvist, 2005
 *     Vincent Barichard, 2012
 *
 *  Last modified:
 *     $Date: 2016-09-27 11:32:06 +0200 (Tue, 27 Sep 2016) $ by $Author: schulte $
 *     $Revision: 15172 $
 *
 *  This file is part of Gecode, the generic constraint
 *  development environment:
 *     http://www.gecode.org
 *
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#ifndef __GECODE_MINIMODEL_HH__
#define __GECODE_MINIMODEL_HH__

#include <gecode/kernel.hh>
#include <gecode/int.hh>
#ifdef GECODE_HAS_SET_VARS
#include <gecode/set.hh>
#endif
#ifdef GECODE_HAS_FLOAT_VARS
#include <gecode/float.hh>
#endif

#include <iostream>

/*
 * Support for DLLs under Windows
 *
 */

#if !defined(GECODE_STATIC_LIBS) && \
    (defined(__CYGWIN__) || defined(__MINGW32__) || defined(_MSC_VER))

#ifdef GECODE_BUILD_MINIMODEL
#define GECODE_MINIMODEL_EXPORT __declspec( dllexport )
#else
#define GECODE_MINIMODEL_EXPORT __declspec( dllimport )
#endif

#else

#ifdef GECODE_GCC_HAS_CLASS_VISIBILITY

#define GECODE_MINIMODEL_EXPORT __attribute__ ((visibility("default")))

#else

#define GECODE_MINIMODEL_EXPORT

#endif
#endif

// Configure auto-linking
#ifndef GECODE_BUILD_MINIMODEL
#define GECODE_LIBRARY_NAME "MiniModel"
#include <gecode/support/auto-link.hpp>
#endif

namespace Gecode {

  /// Minimalistic modeling support
  namespace MiniModel {}

}

#include <gecode/minimodel/exception.hpp>

namespace Gecode {

  class LinIntRel;
#ifdef GECODE_HAS_SET_VARS
  class SetExpr;
#endif
#ifdef GECODE_HAS_FLOAT_VARS
  class LinFloatExpr;
#endif

  /// Base class for non-linear expressions over integer variables
  class NonLinIntExpr {
  public:
    /// Return variable constrained to be equal to the expression
    virtual IntVar post(Home home, IntVar* ret, IntPropLevel ipl) const = 0;
    /// Post expression to be in relation \a irt with \a c
    virtual void post(Home home, IntRelType irt, int c,
                      IntPropLevel ipl) const = 0;
    /// Post reified expression to be in relation \a irt with \a c
    virtual void post(Home home, IntRelType irt, int c,
                      BoolVar b, IntPropLevel ipl) const = 0;
    /// Destructor
    virtual ~NonLinIntExpr(void) {}
    /// Return fresh variable if \a x is NULL, \a x otherwise
    static IntVar result(Home home, IntVar* x) {
      if (x==NULL)
        return IntVar(home,Int::Limits::min,Int::Limits::max);
      return *x;
    }
    /// Constrain \a x to be equal to \a y if \a x is not NULL
    static IntVar result(Home home, IntVar* x, IntVar y) {
      if (x!=NULL)
        rel(home,*x,IRT_EQ,y);
      return y;
    }
    /// Memory management
    void* operator new(size_t size) { return heap.ralloc(size); }
    /// Memory management
    void operator delete(void* p, size_t) { heap.rfree(p); }
  };

  /// Linear expressions over integer variables
  class LinIntExpr {
    friend class LinIntRel;
#ifdef GECODE_HAS_SET_VARS
    friend class SetExpr;
#endif
#ifdef GECODE_HAS_FLOAT_VARS
    friend class LinFloatExpr;
#endif
  public:
    /// Type of linear expression
    enum NodeType {
      NT_CONST,    ///< Integer constant
      NT_VAR_INT,  ///< Linear term with integer variable
      NT_VAR_BOOL, ///< Linear term with Boolean variable
      NT_NONLIN,   ///< Non-linear expression
      NT_SUM_INT,  ///< Sum of integer variables
      NT_SUM_BOOL, ///< Sum of Boolean variables
      NT_ADD,      ///< Addition of linear terms
      NT_SUB,      ///< Subtraction of linear terms
      NT_MUL       ///< Multiplication by coefficient
    };
  private:
    /// Nodes for linear expressions
    class Node;
    /// The actual node
    Node* n;
  public:
    /// Default constructor
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(void);
    /// Create expression for constant \a c
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(int c);
    /// Create expression
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(const IntVar& x, int a=1);
    /// Create expression
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(const BoolVar& x, int a=1);
    /// Create sum expression
    GECODE_MINIMODEL_EXPORT
    explicit LinIntExpr(const IntVarArgs& x);
    /// Create sum expression
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(const IntArgs& a, const IntVarArgs& x);
    /// Create sum expression
    GECODE_MINIMODEL_EXPORT
    explicit LinIntExpr(const BoolVarArgs& x);
    /// Create sum expression
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(const IntArgs& a, const BoolVarArgs& x);
    /// Copy constructor
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(const LinIntExpr& e);
    /// Create expression for type and subexpressions
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(const LinIntExpr& e0, NodeType t, const LinIntExpr& e1);
    /// Create expression for type and subexpression
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(const LinIntExpr& e0, NodeType t, int c);
    /// Create expression for multiplication
    GECODE_MINIMODEL_EXPORT
    LinIntExpr(int a, const LinIntExpr& e);
    /// Create non-linear expression
    GECODE_MINIMODEL_EXPORT
    explicit LinIntExpr(NonLinIntExpr* e);
    /// Assignment operator
    GECODE_MINIMODEL_EXPORT
    const LinIntExpr& operator =(const LinIntExpr& e);
    /// Post propagator
    GECODE_MINIMODEL_EXPORT
    void post(Home home, IntRelType irt, IntPropLevel ipl) const;
    /// Post reified propagator
    GECODE_MINIMODEL_EXPORT
    void post(Home home, IntRelType irt, const BoolVar& b,
              IntPropLevel ipl) const;
    /// Post propagator and return variable for value
    GECODE_MINIMODEL_EXPORT
    IntVar post(Home home, IntPropLevel ipl) const;
    /// Return non-linear expression inside, or NULL if not non-linear
    GECODE_MINIMODEL_EXPORT
    NonLinIntExpr* nle(void) const;
    /// Destructor
    GECODE_MINIMODEL_EXPORT
    ~LinIntExpr(void);
  };

  class BoolExpr;

  /// Linear relations over integer variables
  class LinIntRel {
    friend class BoolExpr;
  private:
    /// Linear expression describing the entire relation
    LinIntExpr e;
    /// Which relation
    IntRelType irt;
    /// Negate relation type
    static IntRelType neg(IntRelType irt);
    /// Default constructor
    LinIntRel(void);
  public:
    /// Create linear relation for expressions \a l and \a r
    LinIntRel(const LinIntExpr& l, IntRelType irt, const LinIntExpr& r);
    /// Create linear relation for expression \a l and integer \a r
    LinIntRel(const LinIntExpr& l, IntRelType irt, int r);
    /// Create linear relation for integer \a l and expression \a r
    LinIntRel(int l, IntRelType irt, const LinIntExpr& r);
    /// Post propagator for relation (if \a t is false for negated relation)
    void post(Home home, bool t,  IntPropLevel ipl) const;
    /// Post reified propagator for relation (if \a t is false for negated relation)
    void post(Home home, const BoolVar& b, bool t, IntPropLevel ipl) const;
  };

  /**
   * \defgroup TaskModelMiniModelLin Linear expressions and relations
   *
   * Linear expressions can be freely composed of sums and differences of
   * integer variables (Gecode::IntVar) or Boolean variables
   * (Gecode::BoolVar) possibly with integer coefficients and integer
   * constants.
   *
   * Note that both integer and Boolean variables are automatically
   * available as linear expressions.
   *
   * Linear relations are obtained from linear expressions with the normal
   * relation operators.
   *
   * \ingroup TaskModelMiniModel
   */

  //@{
  /// Construct linear expression as sum of integer variable and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(int, const IntVar&);
  /// Construct linear expression as sum of Boolean variable and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(int, const BoolVar&);
  /// Construct linear expression as sum of linear expression and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(int, const LinIntExpr&);
  /// Construct linear expression as sum of integer variable and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const IntVar&, int);
  /// Construct linear expression as sum of Boolean variable and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const BoolVar&, int);
  /// Construct linear expression as sum of linear expression and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const LinIntExpr&, int);
  /// Construct linear expression as sum of integer variables
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const IntVar&, const IntVar&);
  /// Construct linear expression as sum of integer and Boolean variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const IntVar&, const BoolVar&);
  /// Construct linear expression as sum of Boolean and integer variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const BoolVar&, const IntVar&);
  /// Construct linear expression as sum of Boolean variables
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const BoolVar&, const BoolVar&);
  /// Construct linear expression as sum of integer variable and linear expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const IntVar&, const LinIntExpr&);
  /// Construct linear expression as sum of Boolean variable and linear expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const BoolVar&, const LinIntExpr&);
  /// Construct linear expression as sum of linear expression and integer variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const LinIntExpr&, const IntVar&);
  /// Construct linear expression as sum of linear expression and Boolean variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const LinIntExpr&, const BoolVar&);
  /// Construct linear expression as sum of linear expressions
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator +(const LinIntExpr&, const LinIntExpr&);

  /// Construct linear expression as sum of integer variable and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(int, const IntVar&);
  /// Construct linear expression as sum of Boolean variable and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(int, const BoolVar&);
  /// Construct linear expression as sum of integer and linear expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(int, const LinIntExpr&);
  /// Construct linear expression as sum of integer variable and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const IntVar&, int);
  /// Construct linear expression as sum of Boolean variable and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const BoolVar&, int);
  /// Construct linear expression as sum of linear expression and integer
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const LinIntExpr&, int);
  /// Construct linear expression as sum of integer variables
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const IntVar&, const IntVar&);
  /// Construct linear expression as sum of integer and Boolean variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const IntVar&, const BoolVar&);
  /// Construct linear expression as sum of Boolean and integer variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const BoolVar&, const IntVar&);
  /// Construct linear expression as sum of Boolean variables
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const BoolVar&, const BoolVar&);
  /// Construct linear expression as sum of integer variable and linear expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const IntVar&, const LinIntExpr&);
  /// Construct linear expression as sum of Boolean variable and linear expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const BoolVar&, const LinIntExpr&);
  /// Construct linear expression as sum of linear expression and integer variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const LinIntExpr&, const IntVar&);
  /// Construct linear expression as sum of linear expression and Boolean variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const LinIntExpr&, const BoolVar&);
  /// Construct linear expression as sum of linear expressions
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const LinIntExpr&, const LinIntExpr&);

  /// Construct linear expression as negative of integer variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const IntVar&);
  /// Construct linear expression as negative of Boolean variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const BoolVar&);
  /// Construct linear expression as negative of linear expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator -(const LinIntExpr&);

  /// Construct linear expression as product of integer coefficient and integer variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator *(int, const IntVar&);
  /// Construct linear expression as product of integer coefficient and Boolean variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator *(int, const BoolVar&);
  /// Construct linear expression as product of integer coefficient and integer variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator *(const IntVar&, int);
  /// Construct linear expression as product of integer coefficient and Boolean variable
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator *(const BoolVar&, int);
  /// Construct linear expression as product of integer coefficient and linear expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator *(const LinIntExpr&, int);
  /// Construct linear expression as product of integer coefficient and linear expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator *(int, const LinIntExpr&);

  /// Construct linear expression as sum of integer variables
  GECODE_MINIMODEL_EXPORT LinIntExpr
  sum(const IntVarArgs& x);
  /// Construct linear expression as sum of integer variables with coefficients
  GECODE_MINIMODEL_EXPORT LinIntExpr
  sum(const IntArgs& a, const IntVarArgs& x);
  /// Construct linear expression as sum of Boolean variables
  GECODE_MINIMODEL_EXPORT LinIntExpr
  sum(const BoolVarArgs& x);
  /// Construct linear expression as sum of Boolean variables with coefficients
  GECODE_MINIMODEL_EXPORT LinIntExpr
  sum(const IntArgs& a, const BoolVarArgs& x);
  /// Construct linear expression as sum of \ref IntArgs
  GECODE_MINIMODEL_EXPORT LinIntExpr
  sum(const IntArgs& args);

  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(int l, const IntVar& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(int l, const BoolVar& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(int l, const LinIntExpr& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const IntVar& l, int r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const BoolVar& l, int r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const LinIntExpr& l, int r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const IntVar& l, const IntVar& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const IntVar& l, const BoolVar& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const BoolVar& l, const IntVar& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const BoolVar& l, const BoolVar& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const IntVar& l, const LinIntExpr& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const BoolVar& l, const LinIntExpr& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const LinIntExpr& l, const IntVar& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const LinIntExpr& l, const BoolVar& r);
  /// Construct linear equality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator ==(const LinIntExpr& l, const LinIntExpr& r);

  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(int l, const IntVar& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(int l, const BoolVar& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(int l, const LinIntExpr& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const IntVar& l, int r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const BoolVar& l, int r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const LinIntExpr& l, int r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const IntVar& l, const IntVar& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const IntVar& l, const BoolVar& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const BoolVar& l, const IntVar& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const BoolVar& l, const BoolVar& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const IntVar& l, const LinIntExpr& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const BoolVar& l, const LinIntExpr& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const LinIntExpr& l, const IntVar& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const LinIntExpr& l, const BoolVar& r);
  /// Construct linear disequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator !=(const LinIntExpr& l, const LinIntExpr& r);

  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(int l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(int l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(int l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const IntVar& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const BoolVar& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const LinIntExpr& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const IntVar& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const IntVar& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const BoolVar& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const BoolVar& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const IntVar& l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const BoolVar& l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const LinIntExpr& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const LinIntExpr& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <(const LinIntExpr& l, const LinIntExpr& r);

  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(int l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(int l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(int l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const IntVar& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const BoolVar& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const LinIntExpr& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const IntVar& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const IntVar& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const BoolVar& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const BoolVar& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const IntVar& l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const BoolVar& l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const LinIntExpr& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const LinIntExpr& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator <=(const LinIntExpr& l, const LinIntExpr& r);

  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(int l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(int l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(int l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const IntVar& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const BoolVar& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const LinIntExpr& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const IntVar& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const IntVar& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const BoolVar& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const BoolVar& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const IntVar& l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const BoolVar& l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const LinIntExpr& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const LinIntExpr& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >(const LinIntExpr& l, const LinIntExpr& r);

  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(int l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(int l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(int l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const IntVar& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const BoolVar& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const LinIntExpr& l, int r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const IntVar& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const IntVar& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const BoolVar& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const BoolVar& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const IntVar& l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const BoolVar& l, const LinIntExpr& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const LinIntExpr& l, const IntVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const LinIntExpr& l, const BoolVar& r);
  /// Construct linear inequality relation
  GECODE_MINIMODEL_EXPORT LinIntRel
  operator >=(const LinIntExpr& l, const LinIntExpr& r);
  //@}

#ifdef GECODE_HAS_FLOAT_VARS
  /// Base class for non-linear float expressions
  class NonLinFloatExpr {
  public:
    /// Return variable constrained to be equal to the expression
    virtual FloatVar post(Home home, FloatVar* ret) const = 0;
    /// Post expression to be in relation \a frt with \a c
    virtual void post(Home home, FloatRelType frt, FloatVal c) const = 0;
    /// Post reified expression to be in relation \a frt with \a c
    virtual void post(Home home, FloatRelType frt, FloatVal c,
                      BoolVar b) const = 0;
    /// Destructor
    virtual ~NonLinFloatExpr(void) {}
    /// Return fresh variable if \a x is NULL, \a x otherwise
    static FloatVar result(Home home, FloatVar* x) {
      if (x == NULL)
        return FloatVar(home,Float::Limits::min,Float::Limits::max);
      return *x;
    }
    /// Constrain \a x to be equal to \a y if \a x is not NULL
    static FloatVar result(Home home, FloatVar* x, FloatVar y) {
      if (x!=NULL)
        rel(home,*x,FRT_EQ,y);
      return y;
    }
    /// Memory management
    void* operator new(size_t size) { return heap.ralloc(size); }
    /// Memory management
    void operator delete(void* p, size_t) { heap.rfree(p); }
  };

  /// %Float expressions
  class LinFloatExpr {
    friend class LinFloatRel;
  public:
    /// Type of linear expression
    enum NodeType {
      NT_CONST,    ///< Float value constant
      NT_VAR,      ///< Linear term with variable
      NT_NONLIN,   ///< Non-linear expression
      NT_SUM,      ///< Sum of float variables
      NT_ADD,      ///< Addition of linear terms
      NT_SUB,      ///< Subtraction of linear terms
      NT_MUL       ///< Multiplication by coefficient
    };
  private:
    /// Nodes for linear expressions
    class Node;
    Node* n;
  public:
    /// Default constructor
    GECODE_MINIMODEL_EXPORT
    LinFloatExpr(void);
    /// Create expression for constant \a c
    GECODE_MINIMODEL_EXPORT
    LinFloatExpr(const FloatVal& c);
    /// Create expression
    GECODE_MINIMODEL_EXPORT
    LinFloatExpr(const FloatVar& x);
    /// Create expression
    GECODE_MINIMODEL_EXPORT
    LinFloatExpr(const FloatVar& x, FloatVal a);
    /// Create sum expression
    GECODE_MINIMODEL_EXPORT
    explicit LinFloatExpr(const FloatVarArgs& x);
    /// Create sum expression
    GECODE_MINIMODEL_EXPORT
    LinFloatExpr(const FloatValArgs& a, const FloatVarArgs& x);
    /// Copy constructor
    GECODE_MINIMODEL_EXPORT
    LinFloatExpr(const LinFloatExpr& e);
    /// Create expression for type and subexpressions
    GECODE_MINIMODEL_EXPORT
    LinFloatExpr(const LinFloatExpr& e0, NodeType t, const LinFloatExpr& e1);
    /// Create expression for type and subexpression
    GECODE_MINIMODEL_EXPORT
    LinFloatExpr(const LinFloatExpr& e0, NodeType t, const FloatVal& c);
    /// Create expression for multiplication
    GECODE_MINIMODEL_EXPORT
    LinFloatExpr(FloatVal a, const LinFloatExpr& e);
    /// Create non-linear expression
    GECODE_MINIMODEL_EXPORT
    explicit LinFloatExpr(NonLinFloatExpr* e);
    /// Assignment operator
    GECODE_MINIMODEL_EXPORT
    const LinFloatExpr& operator =(const LinFloatExpr& e);
    /// Post propagator
    GECODE_MINIMODEL_EXPORT
    void post(Home home, FloatRelType frt) const;
    /// Post reified propagator
    GECODE_MINIMODEL_EXPORT
    void post(Home home, FloatRelType frt, const BoolVar& b) const;
    /// Post propagator and return variable for value
    GECODE_MINIMODEL_EXPORT
    FloatVar post(Home home) const;
    /// Return non-linear expression inside, or NULL if not non-linear
    GECODE_MINIMODEL_EXPORT
    NonLinFloatExpr* nlfe(void) const;
    /// Destructor
    GECODE_MINIMODEL_EXPORT
    ~LinFloatExpr(void);
  };

  class BoolExpr;

  /// Linear relations
  class LinFloatRel {
    friend class BoolExpr;
  private:
    /// Linear float expression describing the entire relation
    LinFloatExpr e;
    /// Which relation
    FloatRelType frt;
    /// Negate relation type
    static FloatRelType neg(FloatRelType frt);
    /// Default constructor
    LinFloatRel(void);
  public:
    /// Create linear float relation for expressions \a l and \a r
    LinFloatRel(const LinFloatExpr& l, FloatRelType frt, const LinFloatExpr& r);
    /// Create linear float relation for expression \a l and FloatVal \a r
    LinFloatRel(const LinFloatExpr& l, FloatRelType frt, FloatVal r);
    /// Create linear float relation for FloatVal \a l and expression \a r
    LinFloatRel(FloatVal l, FloatRelType frt, const LinFloatExpr& r);
    /// Post propagator for relation (if \a t is false for negated relation)
    void post(Home home, bool t) const;
    /// Post reified propagator for relation (if \a t is false for negated relation)
    void post(Home home, const BoolVar& b, bool t) const;
  };

  /**
   * \defgroup TaskModelMiniModelFloat Linear float expressions and relations
   *
   * Linear float expressions can be freely composed of sums and differences of
   * float variables (Gecode::FloatVar) with float coefficients and float
   * constants.
   *
   * Linear float relations are obtained from linear float expressions with the normal
   * relation operators.
   *
   * \ingroup TaskModelMiniModel
   */
  //@{
  /// Construct linear float expression as sum of float variable and float
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator +(const FloatVal&, const FloatVar&);
  /// Construct linear float expression as sum of linear float expression and float
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator +(const FloatVal&, const LinFloatExpr&);
  /// Construct linear float expression as sum of float variable and float
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator +(const FloatVar&, const FloatVal&);
  /// Construct linear float expression as sum of linear float expression and float
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator +(const LinFloatExpr&, const FloatVal&);
  /// Construct linear float expression as sum of float variables
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator +(const FloatVar&, const FloatVar&);
  /// Construct linear float expression as sum of float variable and linear float expression
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator +(const FloatVar&, const LinFloatExpr&);
  /// Construct linear float expression as sum of linear float expression and float variable
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator +(const LinFloatExpr&, const FloatVar&);
  /// Construct linear float expression as sum of linear float expressions
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator +(const LinFloatExpr&, const LinFloatExpr&);

  /// Construct linear float expression as sum of float variable and float
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const FloatVal&, const FloatVar&);
  /// Construct linear float expression as sum of float and linear float expression
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const FloatVal&, const LinFloatExpr&);
  /// Construct linear float expression as sum of float variable and float
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const FloatVar&, const FloatVal&);
  /// Construct linear float expression as sum of linear float expression and float
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const LinFloatExpr&, const FloatVal&);
  /// Construct linear float expression as sum of float variables
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const FloatVar&, const FloatVar&);
  /// Construct linear float expression as sum of float variable and linear float expression
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const FloatVar&, const LinFloatExpr&);
  /// Construct linear float expression as sum of linear float expression and float variable
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const LinFloatExpr&, const FloatVar&);
  /// Construct linear float expression as sum of linear float expressions
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const LinFloatExpr&, const LinFloatExpr&);

  /// Construct linear float expression as negative of float variable
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const FloatVar&);
  /// Construct linear float expression as negative of linear float expression
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator -(const LinFloatExpr&);

  /// Construct linear float expression as product of float coefficient and float variable
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator *(const FloatVal&, const FloatVar&);
  /// Construct linear float expression as product of float coefficient and float variable
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator *(const FloatVar&, const FloatVal&);
  /// Construct linear float expression as product of float coefficient and linear float expression
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator *(const LinFloatExpr&, const FloatVal&);
  /// Construct linear float expression as product of float coefficient and linear float expression
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator *(const FloatVal&, const LinFloatExpr&);

  /// Construct linear float expression as sum of float variables
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  sum(const FloatVarArgs& x);
  /// Construct linear float expression as sum of float variables with coefficients
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  sum(const FloatValArgs& a, const FloatVarArgs& x);

  /// Construct linear float equality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator ==(const FloatVal& l, const FloatVar& r);
  /// Construct linear float equality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator ==(const FloatVal& l, const LinFloatExpr& r);
  /// Construct linear float equality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator ==(const FloatVar& l, const FloatVal& r);
  /// Construct linear float equality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator ==(const LinFloatExpr& l, const FloatVal& r);
  /// Construct linear float equality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator ==(const FloatVar& l, const FloatVar& r);
  /// Construct linear float equality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator ==(const FloatVar& l, const LinFloatExpr& r);
  /// Construct linear float equality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator ==(const LinFloatExpr& l, const FloatVar& r);
  /// Construct linear float equality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator ==(const LinFloatExpr& l, const LinFloatExpr& r);

  /// Construct linear float disequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator !=(const FloatVal& l, const FloatVar& r);
  /// Construct linear float disequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator !=(const FloatVal& l, const LinFloatExpr& r);
  /// Construct linear float disequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator !=(const FloatVar& l, const FloatVal& r);
  /// Construct linear float disequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator !=(const LinFloatExpr& l, const FloatVal& r);
  /// Construct linear float disequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator !=(const FloatVar& l, const FloatVar& r);
  /// Construct linear float disequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator !=(const FloatVar& l, const LinFloatExpr& r);
  /// Construct linear float disequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator !=(const LinFloatExpr& l, const FloatVar& r);
  /// Construct linear float disequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator !=(const LinFloatExpr& l, const LinFloatExpr& r);

  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <(const FloatVal& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <(const FloatVal& l, const LinFloatExpr& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <(const FloatVar& l, const FloatVal& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <(const LinFloatExpr& l, const FloatVal& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <(const FloatVar& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <(const FloatVar& l, const LinFloatExpr& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <(const LinFloatExpr& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <(const LinFloatExpr& l, const LinFloatExpr& r);

  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <=(const FloatVal& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <=(const FloatVal& l, const LinFloatExpr& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <=(const FloatVar& l, const FloatVal& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <=(const LinFloatExpr& l, const FloatVal& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <=(const FloatVar& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <=(const FloatVar& l, const LinFloatExpr& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <=(const LinFloatExpr& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator <=(const LinFloatExpr& l, const LinFloatExpr& r);

  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >(const FloatVal& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >(const FloatVal& l, const LinFloatExpr& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >(const FloatVar& l, const FloatVal& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >(const LinFloatExpr& l, const FloatVal& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >(const FloatVar& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >(const FloatVar& l, const LinFloatExpr& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >(const LinFloatExpr& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >(const LinFloatExpr& l, const LinFloatExpr& r);

  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >=(const FloatVal& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >=(const FloatVal& l, const LinFloatExpr& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >=(const FloatVar& l, const FloatVal& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >=(const LinFloatExpr& l, const FloatVal& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >=(const FloatVar& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >=(const FloatVar& l, const LinFloatExpr& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >=(const LinFloatExpr& l, const FloatVar& r);
  /// Construct linear float inequality relation
  GECODE_MINIMODEL_EXPORT LinFloatRel
  operator >=(const LinFloatExpr& l, const LinFloatExpr& r);
  //@}
#endif

#ifdef GECODE_HAS_SET_VARS
  /// %Set expressions
  class SetExpr {
  public:
    /// Type of set expression
    enum NodeType {
      NT_VAR,    ///< Variable
      NT_CONST,  ///< Constant
      NT_LEXP,   ///< Linear expression
      NT_CMPL,   ///< Complement
      NT_INTER,  ///< Intersection
      NT_UNION,  ///< Union
      NT_DUNION  ///< Disjoint union
    };
    /// %Node for set expression
    class Node;
  private:
    /// Pointer to node for expression
    Node* n;
  public:
    /// Default constructor
    SetExpr(void);
    /// Copy constructor
    GECODE_MINIMODEL_EXPORT
    SetExpr(const SetExpr& e);
    /// Construct expression for type and subexpresssions
    GECODE_MINIMODEL_EXPORT
    SetExpr(const SetExpr& l, NodeType t, const SetExpr& r);
    /// Construct expression for variable
    GECODE_MINIMODEL_EXPORT
    SetExpr(const SetVar& x);
    /// Construct expression for integer variable
    GECODE_MINIMODEL_EXPORT
    explicit SetExpr(const LinIntExpr& x);
    /// Construct expression for constant
    GECODE_MINIMODEL_EXPORT
    SetExpr(const IntSet& s);
    /// Construct expression for negation
    GECODE_MINIMODEL_EXPORT
    SetExpr(const SetExpr& e, NodeType t);
    /// Post propagators for expression
    GECODE_MINIMODEL_EXPORT
    SetVar post(Home home) const;
    /// Post propagators for relation
    GECODE_MINIMODEL_EXPORT
    void post(Home home, SetRelType srt, const SetExpr& e) const;
    /// Post propagators for reified relation
    GECODE_MINIMODEL_EXPORT
    void post(Home home, BoolVar b, bool t,
              SetRelType srt, const SetExpr& e) const;
    /// Assignment operator
    GECODE_MINIMODEL_EXPORT
    const SetExpr& operator =(const SetExpr& e);
    /// Destructor
    GECODE_MINIMODEL_EXPORT
    ~SetExpr(void);
  };

  /// Comparison relation (for two-sided comparisons)
  class SetCmpRel {
  public:
    /// Left side of relation
    SetExpr l;
    /// Right side of relation
    SetExpr r;
    /// Which relation
    SetRelType srt;
    /// Constructor
    SetCmpRel(const SetExpr& l, SetRelType srt, const SetExpr& r);
  };

  /// %Set relations
  class SetRel {
  private:
    /// Expression
    SetExpr _e0;
    /// Relation
    SetRelType _srt;
    /// Expression
    SetExpr _e1;
  public:
    /// Default constructor
    SetRel(void);
    /// Constructor
    SetRel(const SetExpr& e0, SetRelType srt, const SetExpr& e1);
    /// Constructor
    SetRel(const SetCmpRel& r);
    /// Post propagators for relation (or negated relation if \a t is false)
    void post(Home home, bool t) const;
    /// Post propagators for reified relation (or negated relation if \a t is false)
    void post(Home home, BoolVar b, bool t) const;
  };

  /**
   * \defgroup TaskModelMiniModelSet Set expressions and relations
   *
   * Set expressions and relations can be freely composed of variables
   * with the usual connectives.
   *
   * \ingroup TaskModelMiniModel
   */

  //@{
  /// Singleton expression
  GECODE_MINIMODEL_EXPORT SetExpr
  singleton(const LinIntExpr&);
  /// Complement expression
  GECODE_MINIMODEL_EXPORT SetExpr
  operator -(const SetExpr&);
  /// Intersection of set expressions
  GECODE_MINIMODEL_EXPORT SetExpr
  operator &(const SetExpr&, const SetExpr&);
  /// Union of set expressions
  GECODE_MINIMODEL_EXPORT SetExpr
  operator |(const SetExpr&, const SetExpr&);
  /// Disjoint union of set expressions
  GECODE_MINIMODEL_EXPORT SetExpr
  operator +(const SetExpr&, const SetExpr&);
  /// Difference of set expressions
  GECODE_MINIMODEL_EXPORT SetExpr
  operator -(const SetExpr&, const SetExpr&);

  /// Intersection of set variables
  GECODE_MINIMODEL_EXPORT SetExpr
  inter(const SetVarArgs&);
  /// Union of set variables
  GECODE_MINIMODEL_EXPORT SetExpr
  setunion(const SetVarArgs&);
  /// Disjoint union of set variables
  GECODE_MINIMODEL_EXPORT SetExpr
  setdunion(const SetVarArgs&);

  /// Cardinality of set expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  cardinality(const SetExpr&);
  /// Minimum element of set expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  min(const SetExpr&);
  /// Minimum element of set expression
  GECODE_MINIMODEL_EXPORT LinIntExpr
  max(const SetExpr&);

  /// Equality of set expressions
  GECODE_MINIMODEL_EXPORT SetRel
  operator ==(const SetExpr&, const SetExpr&);
  /// Disequality of set expressions
  GECODE_MINIMODEL_EXPORT SetRel
  operator !=(const SetExpr&, const SetExpr&);
  /// Subset of set expressions
  GECODE_MINIMODEL_EXPORT SetCmpRel
  operator <=(const SetExpr&, const SetExpr&);
  /// Subset of set expressions
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator <=(const SetCmpRel&, const SetExpr&);
  /// Superset of set expressions
  GECODE_MINIMODEL_EXPORT SetCmpRel
  operator >=(const SetExpr&, const SetExpr&);
  /// Superset of set expressions
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator >=(const SetCmpRel&, const SetExpr&);
  /// Disjointness of set expressions
  GECODE_MINIMODEL_EXPORT SetRel
  operator ||(const SetExpr&, const SetExpr&);
  //@}
#endif

  /// Boolean expressions
  class BoolExpr {
  public:
    /// Type of Boolean expression
    enum NodeType {
      NT_VAR,       ///< Variable
      NT_NOT,       ///< Negation
      NT_AND,       ///< Conjunction
      NT_OR,        ///< Disjunction
      NT_EQV,       ///< Equivalence
      NT_RLIN,      ///< Reified linear relation
      NT_RLINFLOAT, ///< Reified linear relation
      NT_RSET,      ///< Reified set relation
      NT_MISC       ///< Other Boolean expression
    };
    /// Miscealloneous Boolean expressions
    class GECODE_VTABLE_EXPORT Misc : public HeapAllocated {
    public:
      /// Default constructor
      Misc(void);
      /** Constrain \a b to be equivalent to the expression
       *  (negated if \a neg) with propagation level
       *  \a ipl.
       */
      virtual void post(Home home, BoolVar b, bool neg,
                        IntPropLevel ipl) = 0;
      /// Destructor
      virtual GECODE_MINIMODEL_EXPORT ~Misc(void);
    };
    /// %Node for Boolean expression
    class Node;
  private:
    /// Pointer to node for expression
    Node* n;
  public:
    /// Default constructor
    GECODE_MINIMODEL_EXPORT
    BoolExpr(void);
    /// Copy constructor
    GECODE_MINIMODEL_EXPORT
    BoolExpr(const BoolExpr& e);
    /// Construct expression for type and subexpresssions
    GECODE_MINIMODEL_EXPORT
    BoolExpr(const BoolExpr& l, NodeType t, const BoolExpr& r);
    /// Construct expression for variable
    GECODE_MINIMODEL_EXPORT
    BoolExpr(const BoolVar& x);
    /// Construct expression for negation
    GECODE_MINIMODEL_EXPORT
    BoolExpr(const BoolExpr& e, NodeType t);
    /// Construct expression for reified linear relation
    GECODE_MINIMODEL_EXPORT
    BoolExpr(const LinIntRel& rl);
#ifdef GECODE_HAS_FLOAT_VARS
    /// Construct expression for reified float relation
    GECODE_MINIMODEL_EXPORT
    BoolExpr(const LinFloatRel& rfl);
#endif
#ifdef GECODE_HAS_SET_VARS
    /// Construct expression for reified set relation
    GECODE_MINIMODEL_EXPORT
    BoolExpr(const SetRel& rs);
    /// Construct expression for reified set relation
    GECODE_MINIMODEL_EXPORT
    BoolExpr(const SetCmpRel& rs);
#endif
    /// Construct expression for miscellaneous Boolean expression
    GECODE_MINIMODEL_EXPORT
    explicit BoolExpr(Misc* m);
    /// Post propagators for expression
    GECODE_MINIMODEL_EXPORT
    BoolVar expr(Home home, IntPropLevel ipl) const;
    /// Post propagators for relation
    GECODE_MINIMODEL_EXPORT
    void rel(Home home, IntPropLevel ipl) const;
    /// Assignment operator
    GECODE_MINIMODEL_EXPORT
    const BoolExpr& operator =(const BoolExpr& e);
    /// Destructor
    GECODE_MINIMODEL_EXPORT
    ~BoolExpr(void);
  };

  /**
   * \defgroup TaskModelMiniModelBool Boolean expressions
   *
   * Boolean expressions can be freely composed of variables with
   * the usual connectives and reified linear expressions.
   *
   * \ingroup TaskModelMiniModel
   */

  //@{
  /// Negated Boolean expression
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator !(const BoolExpr&);
  /// Conjunction of Boolean expressions
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator &&(const BoolExpr&, const BoolExpr&);
  /// Disjunction of Boolean expressions
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator ||(const BoolExpr&, const BoolExpr&);
  /// Exclusive-or of Boolean expressions
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator ^(const BoolExpr&, const BoolExpr&);

  /// Non-equivalence of Boolean expressions
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator !=(const BoolExpr&, const BoolExpr&);
  /// Equivalence of Boolean expressions
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator ==(const BoolExpr&, const BoolExpr&);
  /// Implication of Boolean expressions
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator >>(const BoolExpr&, const BoolExpr&);
  /// Reverse implication of Boolean expressions
  GECODE_MINIMODEL_EXPORT BoolExpr
  operator <<(const BoolExpr&, const BoolExpr&);

  //@}

  /**
   * \defgroup TaskModelMiniModelPost Posting of expressions and relations
   *
   * \ingroup TaskModelMiniModel
   */
  //@{
  /// Post linear expression and return its value
  GECODE_MINIMODEL_EXPORT IntVar
  expr(Home home, const LinIntExpr& e, IntPropLevel ipl=IPL_DEF);
#ifdef GECODE_HAS_FLOAT_VARS
  /// Post float expression and return its value
  GECODE_MINIMODEL_EXPORT FloatVar
  expr(Home home, const LinFloatExpr& e);
#endif
#ifdef GECODE_HAS_SET_VARS
  /// Post set expression and return its value
  GECODE_MINIMODEL_EXPORT SetVar
  expr(Home home, const SetExpr& e);
#endif
  /// Post Boolean expression and return its value
  GECODE_MINIMODEL_EXPORT BoolVar
  expr(Home home, const BoolExpr& e, IntPropLevel ipl=IPL_DEF);
  /// Post Boolean relation
  GECODE_MINIMODEL_EXPORT void
  rel(Home home, const BoolExpr& e, IntPropLevel ipl=IPL_DEF);
  //@}

}

#include <gecode/minimodel/int-rel.hpp>
#include <gecode/minimodel/float-rel.hpp>
#include <gecode/minimodel/bool-expr.hpp>
#include <gecode/minimodel/set-expr.hpp>
#include <gecode/minimodel/set-rel.hpp>

namespace Gecode {

  namespace MiniModel {
    class ExpInfo;
  }

  /**
   * \brief Regular expressions over integer values
   *
   * \ingroup TaskModelMiniModel
   */
  class GECODE_MINIMODEL_EXPORT REG {
    friend class MiniModel::ExpInfo;
  private:
    /// Implementation of the actual expression tree
    class Exp;
    /// The expression tree
    Exp* e;
    /// Initialize with given expression tree \a
    REG(Exp* e);
    /// Return string representatinon of expression tree
    std::string toString(void) const;
  public:
    /// Initialize as empty sequence (epsilon)
    REG(void);
    /// Initialize as single integer \a s
    REG(int s);
    /**
     * \brief Initialize as alternative of integers
     *
     * Throws an exception of type MiniModel::TooFewArguments if \a x
     * is empty.
     */
    REG(const IntArgs& x);

    /// Initialize from regular expression \a r
    REG(const REG& r);
    /// Assign to regular expression \a r
    const REG& operator =(const REG& r);

    /// Return expression for: this expression followed by \a r
    REG operator +(const REG& r);
    /// This expression is followed by \a r
    REG& operator +=(const REG& r);
    /// Return expression for: this expression or \a r
    REG operator |(const REG& r);
    /// This expression or \a r
    REG& operator |=(const REG& r);
    /// Return expression for: this expression arbitrarily often (Kleene star)
    REG operator *(void);
    /// Return expression for: this expression at least once
    REG operator +(void);
    /// Return expression for: this expression at least \a n and at most \a m times
    REG operator ()(unsigned int n, unsigned int m);
    /// Return expression for: this expression at least \a n times
    REG operator ()(unsigned int n);
    /// Print expression
    template<class Char, class Traits>
    std::basic_ostream<Char,Traits>&
    print(std::basic_ostream<Char,Traits>& os) const;
    /// Return DFA for regular expression
    operator DFA(void);
    /// Destructor
    ~REG(void);
  };

  /** \relates Gecode::REG
   * Print regular expression \a r
   */
  template<class Char, class Traits>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const REG& r);

}

#include <gecode/minimodel/reg.hpp>

namespace Gecode {

  /**
   * \defgroup TaskModelMiniModelArith Arithmetic functions
   *
   * \ingroup TaskModelMiniModel
   */
  //@{
  /// \brief Return expression for \f$|e|\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  abs(const LinIntExpr& e);
  /// \brief Return expression for \f$\min(x,y)\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  min(const LinIntExpr& x, const LinIntExpr& y);
  /// \brief Return expression for \f$\min(x)\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  min(const IntVarArgs& x);
  /// \brief Return expression for \f$\max(x,y)\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  max(const LinIntExpr& x, const LinIntExpr& y);
  /// \brief Return expression for \f$\max(x)\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  max(const IntVarArgs& x);
#ifdef GECODE_HAS_FLOAT_VARS
  /// \brief Return expression as product of float variables
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator *(const FloatVar&, const FloatVar&);
  /// \brief Return expression as product of float variable and linear float expression
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator *(const FloatVar&, const LinFloatExpr&);
  /// \brief Return expression as product of linear float expression and float variable
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator *(const LinFloatExpr&, const FloatVar&);
#endif
  /// \brief Return expression for \f$x\cdot y\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator *(const LinIntExpr& x, const LinIntExpr& y);
  /// \brief Return expression for \f$x\ \mathrm{div}\ y\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator /(const LinIntExpr& x, const LinIntExpr& y);
  /// \brief Return expression for \f$x\ \mathrm{mod}\ y\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  operator %(const LinIntExpr& x, const LinIntExpr& y);
  /// \brief Return expression for \f$x^2\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  sqr(const LinIntExpr& x);
  /// \brief Return expression for \f$\lfloor\sqrt{x}\rfloor\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  sqrt(const LinIntExpr& x);
  /// \brief Return expression for \f$x^n\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  pow(const LinIntExpr& x, int n);
  /// \brief Return expression for \f$\lfloor\sqrt[n]{x}\rfloor\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  nroot(const LinIntExpr& x, int n);
  /// \brief Return expression for \f$x[y]\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  element(const IntVarArgs& x, const LinIntExpr& y);
  /// \brief Return expression for \f$x[y]\f$
  GECODE_MINIMODEL_EXPORT BoolExpr
  element(const BoolVarArgs& x, const LinIntExpr& y);
  /// \brief Return expression for \f$x[y]\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  element(const IntArgs& x, const LinIntExpr& y);
  /// \brief Return expression for if-then-else \f$b?x:y\f$
  GECODE_MINIMODEL_EXPORT LinIntExpr
  ite(const BoolExpr& b, const LinIntExpr& x, const LinIntExpr& y);
  //@}

#ifdef GECODE_HAS_FLOAT_VARS
  /// \brief Return expression for \f$|e|\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  abs(const LinFloatExpr& e);
  /// \brief Return expression for \f$\min(x,y)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  min(const LinFloatExpr& x, const LinFloatExpr& y);
  /// \brief Return expression for \f$\min(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  min(const FloatVarArgs& x);
  /// \brief Return expression for \f$\max(x,y)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  max(const LinFloatExpr& x, const LinFloatExpr& y);
  /// \brief Return expression for \f$\max(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  max(const FloatVarArgs& x);
  /// \brief Return expression for \f$x\cdot y\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator *(const LinFloatExpr& x, const LinFloatExpr& y);
  /// \brief Return expression for \f$x/y\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  operator /(const LinFloatExpr& x, const LinFloatExpr& y);
  /// \brief Return expression for \f$x^2\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  sqr(const LinFloatExpr& x);
  /// \brief Return expression for \f$\sqrt{x}\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  sqrt(const LinFloatExpr& x);
  /// \brief Return expression for \f$x^n\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  pow(const LinFloatExpr& x, int n);
  /// \brief Return expression for \f$x^{1/n}\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  nroot(const LinFloatExpr& x, int n);
  //@}

#ifdef GECODE_HAS_MPFR
  /**
   * \defgroup TaskModelMiniModelTrans Transcendental functions
   *
   * \ingroup TaskModelMiniModel
   */
  //@{
  /// \brief Return expression for \f$ \mathrm{exp}(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  exp(const LinFloatExpr& x);
  /// \brief Return expression for \f$ \mathrm{log}(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  log(const LinFloatExpr& x);
  //@}

  /**
   * \defgroup TaskModelMiniModelTrigo Trigonometric functions
   *
   * \ingroup TaskModelMiniModel
   */
  //@{
  /// \brief Return expression for \f$ \mathrm{asin}(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  asin(const LinFloatExpr& x);
  /// \brief Return expression for \f$ \mathrm{sin}(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  sin(const LinFloatExpr& x);
  /// \brief Return expression for \f$ \mathrm{acos}(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  acos(const LinFloatExpr& x);
  /// \brief Return expression for \f$ \mathrm{cos}(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  cos(const LinFloatExpr& x);
  /// \brief Return expression for \f$ \mathrm{atan}(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  atan(const LinFloatExpr& x);
  /// \brief Return expression for \f$ \mathrm{tan}(x)\f$
  GECODE_MINIMODEL_EXPORT LinFloatExpr
  tan(const LinFloatExpr& x);
  //@}
#endif
#endif

  /**
   * \defgroup TaskModelMiniModelChannel Channel functions
   *
   * \ingroup TaskModelMiniModel
   */
  //@{
  /// Return Boolean variable equal to \f$x\f$
  inline BoolVar
  channel(Home home, IntVar x,
          IntPropLevel ipl=IPL_DEF) {
    (void) ipl;
    BoolVar b(home,0,1); channel(home,b,x);
    return b;
  }
  /// Return integer variable equal to \f$b\f$
  inline IntVar
  channel(Home home, BoolVar b,
          IntPropLevel ipl=IPL_DEF) {
    (void) ipl;
    IntVar x(home,0,1); channel(home,b,x);
    return x;
  }
#ifdef GECODE_HAS_FLOAT_VARS
  /// Return integer variable equal to \f$f\f$
  inline IntVar
  channel(Home home, FloatVar f) {
    int min = static_cast<int>(std::max(static_cast<double>(Int::Limits::min),
                                        std::ceil(f.min())));
    int max = static_cast<int>(std::min(static_cast<double>(Int::Limits::max),
                                        std::floor(f.max())));
    IntVar x(home,min,max);
    channel(home,f,x);
    return x;
  }
#endif
#ifdef GECODE_HAS_SET_VARS
  /// Return set variable equal to \f$\{x_0,\dots,x_{n-1}\}\f$
  inline SetVar
  channel(Home home, const IntVarArgs& x, IntPropLevel ipl=IPL_DEF) {
    (void) ipl;
    SetVar s(home,IntSet::empty,Set::Limits::min,Set::Limits::max);
    rel(home,SOT_UNION,x,s);
    nvalues(home,x,IRT_EQ,expr(home,cardinality(s)));
    return s;
  }
#endif
  //@}

}

namespace Gecode {

  /**
   * \defgroup TaskModelMiniModelIntAlias Aliases for integer constraints
   *
   * Contains definitions of common constraints which have different
   * names in Gecode.
   *
   * \ingroup TaskModelMiniModel
   */

  //@{
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=n\}\leq m\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  atmost(Home home, const IntVarArgs& x, int n, int m,
         IntPropLevel ipl=IPL_DEF) {
    count(home,x,n,IRT_LQ,m,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y\}\leq m\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  atmost(Home home, const IntVarArgs& x, IntVar y, int m,
         IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_LQ,m,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y_i\}\leq m\f$
   *
   * Supports domain consistent propagation only.
   *
   * Throws an exception of type Int::ArgumentSizeMismatch, if
   *  \a x and \a y are of different size.
   */
  inline void
  atmost(Home home, const IntVarArgs& x, const IntArgs& y, int m,
         IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_LQ,m,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=n\}\leq z\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  atmost(Home home, const IntVarArgs& x, int n, IntVar z,
         IntPropLevel ipl=IPL_DEF) {
    count(home,x,n,IRT_LQ,z,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y\}\leq z\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  atmost(Home home, const IntVarArgs& x, IntVar y, IntVar z,
         IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_LQ,z,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y_i\}\leq z\f$
   *
   * Supports domain consistent propagation only.
   *
   * Throws an exception of type Int::ArgumentSizeMismatch, if
   *  \a x and \a y are of different size.
   */
  inline void
  atmost(Home home, const IntVarArgs& x, const IntArgs& y, IntVar z,
         IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_LQ,z,ipl);
  }

  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=n\}\geq m\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  atleast(Home home, const IntVarArgs& x, int n, int m,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,n,IRT_GQ,m,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y\}\geq m\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  atleast(Home home, const IntVarArgs& x, IntVar y, int m,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_GQ,m,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y_i\}\geq m\f$
   *
   * Supports domain consistent propagation only.
   *
   * Throws an exception of type Int::ArgumentSizeMismatch, if
   *  \a x and \a y are of different size.
   */
  inline void
  atleast(Home home, const IntVarArgs& x, const IntArgs& y, int m,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_GQ,m,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=n\}\geq z\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  atleast(Home home, const IntVarArgs& x, int n, IntVar z,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,n,IRT_GQ,z,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y\}\geq z\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  atleast(Home home, const IntVarArgs& x, IntVar y, IntVar z,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_GQ,z,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y_i\}\geq z\f$
   *
   * Supports domain consistent propagation only.
   *
   * Throws an exception of type Int::ArgumentSizeMismatch, if
   *  \a x and \a y are of different size.
   */
  inline void
  atleast(Home home, const IntVarArgs& x, const IntArgs& y, IntVar z,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_GQ,z,ipl);
  }

  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=n\}=m\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  exactly(Home home, const IntVarArgs& x, int n, int m,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,n,IRT_EQ,m,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y\}=m\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  exactly(Home home, const IntVarArgs& x, IntVar y, int m,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_EQ,m,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y_i\}=m\f$
   *
   * Supports domain consistent propagation only.
   *
   * Throws an exception of type Int::ArgumentSizeMismatch, if
   *  \a x and \a y are of different size.
   */
  inline void
  exactly(Home home, const IntVarArgs& x, const IntArgs& y, int m,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_EQ,m,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=n\}=z\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  exactly(Home home, const IntVarArgs& x, int n, IntVar z,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,n,IRT_EQ,z,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y\}=z\f$
   *
   * Supports domain consistent propagation only.
   */
  inline void
  exactly(Home home, const IntVarArgs& x, IntVar y, IntVar z,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_EQ,z,ipl);
  }
  /** \brief Post constraint \f$\#\{i\in\{0,\ldots,|x|-1\}\;|\;x_i=y_i\}=z\f$
   *
   * Supports domain consistent propagation only.
   *
   * Throws an exception of type Int::ArgumentSizeMismatch, if
   *  \a x and \a y are of different size.
   */
  inline void
  exactly(Home home, const IntVarArgs& x, const IntArgs& y, IntVar z,
          IntPropLevel ipl=IPL_DEF) {
    count(home,x,y,IRT_EQ,z,ipl);
  }
  /** \brief Post lexical order between \a x and \a y.
   */
  inline void
  lex(Home home, const IntVarArgs& x, IntRelType r, const IntVarArgs& y,
      IntPropLevel ipl=IPL_DEF) {
    rel(home,x,r,y,ipl);
  }
  /** \brief Post lexical order between \a x and \a y.
   */
  inline void
  lex(Home home, const BoolVarArgs& x, IntRelType r, const BoolVarArgs& y,
      IntPropLevel ipl=IPL_DEF) {
    rel(home,x,r,y,ipl);
  }
  /** \brief Post constraint \f$\{x_0,\dots,x_{n-1}\}=y\f$
   */
  inline void
  values(Home home, const IntVarArgs& x, IntSet y,
         IntPropLevel ipl=IPL_DEF) {
    dom(home,x,y,ipl);
    nvalues(home,x,IRT_EQ,static_cast<int>(y.size()),ipl);
  }

  //@}

#ifdef GECODE_HAS_SET_VARS
  /**
   * \defgroup TaskModelMiniModelSetAlias Aliases for set constraints
   *
   * Contains definitions of common constraints which have different
   * names in Gecode.
   *
   * \ingroup TaskModelMiniModel
   */

  //@{
  /** \brief Post constraint \f$\{x_0,\dots,x_{n-1}\}=y\f$
   *
   * In addition to constraining \a y to the union of the \a x, this
   * also posts an nvalue constraint for additional cardinality propagation.
   */
  inline void
  channel(Home home, const IntVarArgs& x, SetVar y) {
    rel(home,SOT_UNION,x,y);
    nvalues(home,x,IRT_EQ,expr(home,cardinality(y)));
  }

  /** \brief Post constraint \f$\bigcup_{i\in y}\{x_i\}=z\f$
   */
  inline void
  range(Home home, const IntVarArgs& x, SetVar y, SetVar z) {
    element(home,SOT_UNION,x,y,z);
  }

  /** \brief Post constraint \f$\bigcup_{i\in z}\{j\ |\ x_j=i\}=z\f$
   *
   * Note that this creates one temporary set variable for each element
   * in the upper bound of \a z, so make sure that the bound is tight.
   */
  inline void
  roots(Home home, const IntVarArgs& x, SetVar y, SetVar z) {
    SetVarArgs xiv(home,z.lubMax()+1,IntSet::empty,0,x.size()-1);
    channel(home,x,xiv);
    element(home,SOT_UNION,xiv,z,y);
  }

  //@}
#endif
}

namespace Gecode {

  template<class> class Matrix;

  /** \brief A slice of a matrix.
   *
   * This class represents a slice of the matrix. It is used to get
   * context-dependent behaviour. The slice will be automatically
   * converted to an ArgsType Args-array or to a Matrix<ArgsType>
   * depending on the context where it is used.
   */
  template<class A>
  class Slice {
  public:
    /// The type of the Args-array type for ValueType values
    typedef typename ArrayTraits<A>::ArgsType ArgsType;
  private:
    ArgsType _r;     ///< The elements of the slice
    int _fc, ///< From column
      _tc,   ///< To column
      _fr,   ///< From row
      _tr;   ///< To row
  public:
    /// Construct slice
    Slice(const Matrix<A>& a, int fc, int tc, int fr, int tr);
    /** \brief Reverses the contents of the slice, and returns a
     *  reference to it.
     */
    Slice& reverse(void);
    /// Cast to array type
    operator ArgsType(void);
    /// Cast to matrix type
    operator Matrix<ArgsType>(void);

    /// Cast to array type
    operator const ArgsType(void) const;
    /// Cast to matrix type
    operator const Matrix<ArgsType>(void) const;
  };

  /// Concatenate \a x and \a y
  template<class A>
  typename Slice<A>::ArgsType
  operator+(const Slice<A>& x, const Slice<A>& y);

  /// Concatenate \a x and \a y
  template<class A>
  typename Slice<A>::ArgsType
  operator+(const Slice<A>& x, const typename ArrayTraits<A>::ArgsType& y);

  /// Concatenate \a x and \a y
  template<class A>
  typename Slice<A>::ArgsType
  operator+(const typename ArrayTraits<A>::ArgsType& x, const Slice<A>& y);

  /// Concatenate \a x and \a y
  template<class A>
  typename Slice<A>::ArgsType
  operator+(const Slice<A>& x, const typename ArrayTraits<A>::ValueType& y);

  /// Concatenate \a x and \a y
  template<class A>
  typename Slice<A>::ArgsType
  operator+(const typename ArrayTraits<A>::ValueType& x, const Slice<A>& y);

  /** \brief Matrix-interface for arrays
   *
   * This class allows for wrapping some array and accessing it as a
   * matrix.
   *
   * \note This is a light-weight wrapper, and is not intended for
   * storing variables directly instead of in an array.
   *
   * \ingroup TaskModelMiniModel
   */
  template<class A>
  class Matrix {
  public:
    /// The type of elements of this array
    typedef typename ArrayTraits<A>::ValueType ValueType;
    /// The type of the Args-array type for ValueType values
    typedef typename ArrayTraits<A>::ArgsType ArgsType;

  private:
    /// The type of storage for this array
    typedef typename ArrayTraits<A>::StorageType StorageType;
    StorageType _a; ///< The array wrapped
    int _w; ///< The width of the matrix
    int _h; ///< The height of the matrix

  public:
    /** \brief Basic constructor
     *
     * Constructs a Matrix from the array \a a, using \a w and \a h as
     * the width and height of the matrix.
     *
     * The elements in the wrapped array \a a are accessed in
     * row-major order.
     *
     * \exception MiniModel::ArgumentSizeMismatch Raised if the
     *            parameters \a w and \a h doesn't match the size
     *            of the array \a a.
     */
    Matrix(A a, int w, int h);

    /** \brief Basic constructor
     *
     * Constructs a square Matrix from the array \a a, using \a n as
     * the length of the sides.
     *
     * The elements in the wrapped array \a a are accessed in
     * row-major order.
     *
     * \exception MiniModel::ArgumentSizeMismatch Raised if the
     *            parameter \a n doesn't match the size
     *            of the array \a a.
     */
    Matrix(A a, int n);

    /// Return the width of the matrix
    int width(void) const;
    /// Return the height of the matrix
    int height(void) const;
    /// Return an Args-array of the contents of the matrix
    ArgsType const get_array(void) const;

    /** \brief Access element (\a c, \a r) of the matrix
     *
     * \exception MiniModel::ArgumentOutOfRange Raised if \a c or \a r
     *            are out of range.
     */
    ValueType& operator ()(int c, int r);

    /** \brief Access element (\a c, \a r) of the matrix
     *
     * \exception MiniModel::ArgumentOutOfRange Raised if \a c or \a r
     *            are out of range.
     */
    const ValueType& operator ()(int c, int r) const;

    /** \brief Access slice of the matrix
     *
     * This function allows accessing a slice of the matrix, located at
     * columns \f$[fc,tc)\f$ and rows \f$[fr,tr)\f$. The result of this
     * function is an object that can be converted into either a
     * Matrix<ArgsType> or into ArgsType.
     *
     * For further information, see Slice.
     */
    Slice<A> slice(int fc, int tc, int fr, int tr) const;

    /// Access row \a r.
    Slice<A> row(int r) const;

    /// Access column \a c.
    Slice<A> col(int c) const;
  };

  /** \relates Gecode::Matrix
   * Print matrix \a m
   */
  template<class Char, class Traits, class A>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const Matrix<A>& m);

  /** \relates Gecode::Matrix
   * Print slice \a s
   */
  template<class Char, class Traits, class A>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const Slice<A>& s);

  /** \brief Element constraint for matrix
   *
   * Here, \a x and \a y are the coordinates and \a z is the value
   * at position \a m(x,y).
   * \relates Gecode::Matrix
   */
  void element(Home home, const Matrix<IntArgs>& m, IntVar x, IntVar y,
               IntVar z, IntPropLevel ipl=IPL_DEF);
  /** \brief Element constraint for matrix
   *
   * Here, \a x and \a y are the coordinates and \a z is the value
   * at position \a m(x,y).
   * \relates Gecode::Matrix
   */
  void element(Home home, const Matrix<IntArgs>& m, IntVar x, IntVar y,
               BoolVar z, IntPropLevel ipl=IPL_DEF);
  /** \brief Element constraint for matrix
   *
   * Here, \a x and \a y are the coordinates and \a z is the value
   * at position \a m(x,y).
   * \relates Gecode::Matrix
   */
  void element(Home home, const Matrix<IntVarArgs>& m, IntVar x, IntVar y,
               IntVar z, IntPropLevel ipl=IPL_DEF);
  /** \brief Element constraint for matrix
   *
   * Here, \a x and \a y are the coordinates and \a z is the value
   * at position \a m(x,y).
   * \relates Gecode::Matrix
   */
  void element(Home home, const Matrix<BoolVarArgs>& m, IntVar x, IntVar y,
               BoolVar z, IntPropLevel ipl=IPL_DEF);
#ifdef GECODE_HAS_SET_VARS
  /** \brief Element constraint for matrix
   *
   * Here, \a x and \a y are the coordinates and \a z is the value
   * at position \a m(x,y).
   * \relates Gecode::Matrix
   */
  void element(Home home, const Matrix<IntSetArgs>& m, IntVar x, IntVar y,
               SetVar z);
  /** \brief Element constraint for matrix
   *
   * Here, \a x and \a y are the coordinates and \a z is the value
   * at position \a m(x,y).
   * \relates Gecode::Matrix
   */
  void element(Home home, const Matrix<SetVarArgs>& m, IntVar x, IntVar y,
               SetVar z);
#endif

  /** \brief Interchangeable rows symmetry specification.
   * \relates Gecode::Matrix
   */
  template<class A>
  SymmetryHandle rows_interchange(const Matrix<A>& m);
  /** \brief Interchangeable columns symmetry specification.
   * \relates Gecode::Matrix
   */
  template<class A>
  SymmetryHandle columns_interchange(const Matrix<A>& m);
  /** \brief Reflect rows symmetry specification.
   * \relates Gecode::Matrix
   */
  template<class A>
  SymmetryHandle rows_reflect(const Matrix<A>& m);
  /** \brief Reflect columns symmetry specification.
   * \relates Gecode::Matrix
   */
  template<class A>
  SymmetryHandle columns_reflect(const Matrix<A>& m);
  /** \brief Reflect around main diagonal symmetry specification.
   *
   * The matrix \m must be square.
   * \relates Gecode::Matrix
   */
  template<class A>
  SymmetryHandle diagonal_reflect(const Matrix<A>& m);
}

#include <gecode/minimodel/matrix.hpp>
#include <gecode/minimodel/ldsb.hpp>

/**
 * \addtogroup TaskModelMiniModelLin
 * @{
 */
namespace Gecode {

  /// Construct linear expression as sum of \ref IntArgs \ref Slice elements
  GECODE_MINIMODEL_EXPORT LinIntExpr
  sum(const Slice<IntArgs>& slice);
  /// Construct linear expression as sum of \ref IntArgs \ref Matrix elements
  GECODE_MINIMODEL_EXPORT LinIntExpr
  sum(const Matrix<IntArgs>& matrix);

}
/** @}*/

namespace Gecode {

  /**
   * \defgroup TaskModelMiniModelOptimize Support for cost-based optimization
   *
   * Provides for minimizing or maximizing the cost value as defined by
   * a cost-member function of a space.
   *
   * \ingroup TaskModelMiniModel
   */

  /**
   * \brief Class for minimizing integer cost
   * \ingroup TaskModelMiniModelOptimize
   */
  class GECODE_VTABLE_EXPORT IntMinimizeSpace : public Space {
  public:
    /// Default constructor
    IntMinimizeSpace(void);
    /// Constructor for cloning
    IntMinimizeSpace(bool share, IntMinimizeSpace& s);
    /// Member function constraining according to decreasing cost
    GECODE_MINIMODEL_EXPORT
    virtual void constrain(const Space& best);
    /// Return variable with current cost
    virtual IntVar cost(void) const = 0;
  };

  /**
   * \brief Class for maximizing integer cost
   * \ingroup TaskModelMiniModelOptimize
   */
  class GECODE_VTABLE_EXPORT IntMaximizeSpace : public Space {
  public:
    /// Default constructor
    IntMaximizeSpace(void);
    /// Constructor for cloning
    IntMaximizeSpace(bool share, IntMaximizeSpace& s);
    /// Member function constraining according to increasing cost
    GECODE_MINIMODEL_EXPORT
    virtual void constrain(const Space& best);
    /// Return variable with current cost
    virtual IntVar cost(void) const = 0;
  };

  /**
   * \brief Class for minimizing integer cost
   * \deprecated Use IntMinimizeSpace instead.
   */
  typedef IntMinimizeSpace MinimizeSpace;
  /**
   * \brief Class for maximizing integer cost
   * \deprecated Use IntMaximizeSpace instead.
   */
  typedef IntMaximizeSpace MaximizeSpace;


#ifdef GECODE_HAS_FLOAT_VARS

  /**
   * \brief Class for minimizing float cost
   *
   * The class supports using a step value \a step that will make sure
   * that better solutions must be better by at least the value of
   * \a step.
   *
   * \ingroup TaskModelMiniModelOptimize
   */
  class GECODE_VTABLE_EXPORT FloatMinimizeSpace : public Space {
  protected:
    /// Step by which a next solution has to have lower cost
    FloatNum step;
  public:
    /// Constructor with step \a s
    FloatMinimizeSpace(FloatNum s=0.0);
    /// Constructor for cloning
    FloatMinimizeSpace(bool share, FloatMinimizeSpace& s);
    /// Member function constraining according to cost
    GECODE_MINIMODEL_EXPORT
    virtual void constrain(const Space& best);
    /// Return variable with current cost
    virtual FloatVar cost(void) const = 0;
  };

  /**
   * \brief Class for maximizing float cost
   *
   * The class supports using a step value \a step that will make sure
   * that better solutions must be better by at least the value of
   * \a step.
   *
   * \ingroup TaskModelMiniModelOptimize
   */
  class GECODE_VTABLE_EXPORT FloatMaximizeSpace : public Space {
  protected:
    /// Step by which a next solution has to have lower cost
    FloatNum step;
  public:
    /// Constructor with step \a s
    FloatMaximizeSpace(FloatNum s=0.0);
    /// Constructor for cloning
    FloatMaximizeSpace(bool share, FloatMaximizeSpace& s);
    /// Member function constraining according to cost
    GECODE_MINIMODEL_EXPORT
    virtual void constrain(const Space& best);
    /// Return variable with current cost
    virtual FloatVar cost(void) const = 0;
  };

#endif

}

#include <gecode/minimodel/optimize.hpp>

#endif

// IFDEF: GECODE_HAS_INT_VARS
// STATISTICS: minimodel-any

