/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Christian Schulte * * Copyright: * Christian Schulte, 2006 * * 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. * */ #include namespace Gecode { namespace MiniModel { /// Non-linear arithmetic expressions over integer variables class GECODE_MINIMODEL_EXPORT ArithNonLinIntExpr : public NonLinIntExpr { public: /// The expression type enum ArithNonLinIntExprType { ANLE_ABS, ///< Absolute value expression ANLE_MIN, ///< Minimum expression ANLE_MAX, ///< Maximum expression ANLE_MULT, ///< Multiplication expression ANLE_DIV, ///< Division expression ANLE_MOD, ///< Modulo expression ANLE_SQR, ///< Square expression ANLE_SQRT, ///< Square root expression ANLE_POW, ///< Pow expression ANLE_NROOT, ///< Nroot expression ANLE_ELMNT, ///< Element expression ANLE_ITE ///< If-then-else expression } t; /// Expressions LinIntExpr* a; /// Size of variable array int n; /// Integer argument (used in nroot for example) int aInt; /// Boolean expression argument (used in ite for example) BoolExpr b; /// Constructor ArithNonLinIntExpr(ArithNonLinIntExprType t0, int n0) : t(t0), a(heap.alloc(n0)), n(n0) {} /// Constructor ArithNonLinIntExpr(ArithNonLinIntExprType t0, int n0, int a0) : t(t0), a(heap.alloc(n0)), n(n0), aInt(a0) {} /// Constructor ArithNonLinIntExpr(ArithNonLinIntExprType t0, int n0, const BoolExpr& b0) : t(t0), a(heap.alloc(n0)), n(n0), b(b0) {} /// Destructor ~ArithNonLinIntExpr(void) { heap.free(a,n); } /// Post expression virtual IntVar post(Home home, IntVar* ret, const IntPropLevels& ipls) const { IntVar y; switch (t) { case ANLE_ABS: { IntVar x = a[0].post(home, ipls); if (x.min() >= 0) y = result(home,ret,x); else { y = result(home,ret); abs(home, x, y, ipls.abs()); } } break; case ANLE_MIN: if (n==1) { y = result(home,ret, a[0].post(home, ipls)); } else if (n==2) { IntVar x0 = a[0].post(home, ipls); IntVar x1 = a[1].post(home, ipls); if (x0.max() <= x1.min()) y = result(home,ret,x0); else if (x1.max() <= x0.min()) y = result(home,ret,x1); else { y = result(home,ret); min(home, x0, x1, y, ipls.min2()); } } else { IntVarArgs x(n); for (int i=n; i--;) x[i] = a[i].post(home, ipls); y = result(home,ret); min(home, x, y, ipls.min()); } break; case ANLE_MAX: if (n==1) { y = result(home,ret,a[0].post(home, ipls)); } else if (n==2) { IntVar x0 = a[0].post(home, ipls); IntVar x1 = a[1].post(home, ipls); if (x0.max() <= x1.min()) y = result(home,ret,x1); else if (x1.max() <= x0.min()) y = result(home,ret,x0); else { y = result(home,ret); max(home, x0, x1, y, ipls.max2()); } } else { IntVarArgs x(n); for (int i=n; i--;) x[i] = a[i].post(home, ipls); y = result(home,ret); max(home, x, y, ipls.max()); } break; case ANLE_MULT: { assert(n == 2); IntVar x0 = a[0].post(home, ipls); IntVar x1 = a[1].post(home, ipls); if (x0.assigned() && (x0.val() == 0)) y = result(home,ret,x0); else if (x0.assigned() && (x0.val() == 1)) y = result(home,ret,x1); else if (x1.assigned() && (x1.val() == 0)) y = result(home,ret,x1); else if (x1.assigned() && (x1.val() == 1)) y = result(home,ret,x0); else { y = result(home,ret); mult(home, x0, x1, y, ipls.mult()); } } break; case ANLE_DIV: { assert(n == 2); IntVar x0 = a[0].post(home, ipls); IntVar x1 = a[1].post(home, ipls); rel(home, x1, IRT_NQ, 0); if (x1.assigned() && (x1.val() == 1)) y = result(home,ret,x0); else if (x0.assigned() && (x0.val() == 0)) y = result(home,ret,x0); else { y = result(home,ret); div(home, x0, x1, y, ipls.div()); } } break; case ANLE_MOD: { assert(n == 2); IntVar x0 = a[0].post(home, ipls); IntVar x1 = a[1].post(home, ipls); y = result(home,ret); mod(home, x0, x1, y, ipls.mod()); } break; case ANLE_SQR: { assert(n == 1); IntVar x = a[0].post(home, ipls); if (x.assigned() && ((x.val() == 0) || (x.val() == 1))) y = result(home,ret,x); else { y = result(home,ret); sqr(home, x, y, ipls.sqr()); } } break; case ANLE_SQRT: { assert(n == 1); IntVar x = a[0].post(home, ipls); if (x.assigned() && ((x.val() == 0) || (x.val() == 1))) y = result(home,ret,x); else { y = result(home,ret); sqrt(home, x, y, ipls.sqrt()); } } break; case ANLE_POW: { assert(n == 1); IntVar x = a[0].post(home, ipls); if (x.assigned() && (aInt > 0) && ((x.val() == 0) || (x.val() == 1))) y = result(home,ret,x); else { y = result(home,ret); pow(home, x, aInt, y, ipls.pow()); } } break; case ANLE_NROOT: { assert(n == 1); IntVar x = a[0].post(home, ipls); if (x.assigned() && (aInt > 0) && ((x.val() == 0) || (x.val() == 1))) y = result(home,ret,x); else { y = result(home,ret); nroot(home, x, aInt, y, ipls.nroot()); } } break; case ANLE_ELMNT: { IntVar z = a[n-1].post(home, ipls); if (z.assigned() && z.val() >= 0 && z.val() < n-1) { y = result(home,ret,a[z.val()].post(home, ipls)); } else { IntVarArgs x(n-1); bool assigned = true; for (int i=n-1; i--;) { x[i] = a[i].post(home, ipls); if (!x[i].assigned()) assigned = false; } y = result(home,ret); if (assigned) { IntArgs xa(n-1); for (int i=n-1; i--;) xa[i] = x[i].val(); element(home, xa, z, y, ipls.element()); } else { element(home, x, z, y, ipls.element()); } } } break; case ANLE_ITE: { assert(n == 2); BoolVar c = b.expr(home, ipls); IntVar x0 = a[0].post(home, ipls); IntVar x1 = a[1].post(home, ipls); y = result(home,ret); ite(home, c, x0, x1, y, ipls.ite()); } break; default: GECODE_NEVER; } return y; } virtual void post(Home home, IntRelType irt, int c, const IntPropLevels& ipls) const { if ((t == ANLE_MIN && (irt == IRT_GQ || irt == IRT_GR)) || (t == ANLE_MAX && (irt == IRT_LQ || irt == IRT_LE)) ) { IntVarArgs x(n); for (int i=n; i--;) x[i] = a[i].post(home, ipls); rel(home, x, irt, c); } else { rel(home, post(home,nullptr,ipls), irt, c); } } virtual void post(Home home, IntRelType irt, int c, BoolVar b, const IntPropLevels& ipls) const { rel(home, post(home,nullptr,ipls), irt, c, b); } }; /// Check if \a e is of type \a t bool hasType(const LinIntExpr& e, ArithNonLinIntExpr::ArithNonLinIntExprType t) { return e.nle() && dynamic_cast(e.nle()) != nullptr && dynamic_cast(e.nle())->t == t; } }} namespace Gecode { LinIntExpr abs(const LinIntExpr& e) { using namespace MiniModel; if (hasType(e, ArithNonLinIntExpr::ANLE_ABS)) return e; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_ABS,1); ae->a[0] = e; return LinIntExpr(ae); } LinIntExpr min(const LinIntExpr& e0, const LinIntExpr& e1) { using namespace MiniModel; int n = 0; if (hasType(e0, ArithNonLinIntExpr::ANLE_MIN)) n += static_cast(e0.nle())->n; else n += 1; if (hasType(e1, ArithNonLinIntExpr::ANLE_MIN)) n += static_cast(e1.nle())->n; else n += 1; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_MIN,n); int i=0; if (hasType(e0, ArithNonLinIntExpr::ANLE_MIN)) { ArithNonLinIntExpr* e0e = static_cast(e0.nle()); for (; in; i++) ae->a[i] = e0e->a[i]; } else { ae->a[i++] = e0; } if (hasType(e1, ArithNonLinIntExpr::ANLE_MIN)) { ArithNonLinIntExpr* e1e = static_cast(e1.nle()); int curN = i; for (; in; i++) ae->a[i] = e1e->a[i-curN]; } else { ae->a[i++] = e1; } return LinIntExpr(ae); } LinIntExpr max(const LinIntExpr& e0, const LinIntExpr& e1) { using namespace MiniModel; int n = 0; if (hasType(e0, ArithNonLinIntExpr::ANLE_MAX)) n += static_cast(e0.nle())->n; else n += 1; if (hasType(e1, ArithNonLinIntExpr::ANLE_MAX)) n += static_cast(e1.nle())->n; else n += 1; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_MAX,n); int i=0; if (hasType(e0, ArithNonLinIntExpr::ANLE_MAX)) { ArithNonLinIntExpr* e0e = static_cast(e0.nle()); for (; in; i++) ae->a[i] = e0e->a[i]; } else { ae->a[i++] = e0; } if (hasType(e1, ArithNonLinIntExpr::ANLE_MAX)) { ArithNonLinIntExpr* e1e = static_cast(e1.nle()); int curN = i; for (; in; i++) ae->a[i] = e1e->a[i-curN]; } else { ae->a[i++] = e1; } return LinIntExpr(ae); } LinIntExpr min(const IntVarArgs& x) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_MIN,x.size()); for (int i=x.size(); i--;) ae->a[i] = x[i]; return LinIntExpr(ae); } LinIntExpr max(const IntVarArgs& x) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_MAX,x.size()); for (int i=x.size(); i--;) ae->a[i] = x[i]; return LinIntExpr(ae); } LinIntExpr operator *(const LinIntExpr& e0, const LinIntExpr& e1) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_MULT,2); ae->a[0] = e0; ae->a[1] = e1; return LinIntExpr(ae); } LinIntExpr sqr(const LinIntExpr& e) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_SQR,1); ae->a[0] = e; return LinIntExpr(ae); } LinIntExpr sqrt(const LinIntExpr& e) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_SQRT,1); ae->a[0] = e; return LinIntExpr(ae); } LinIntExpr pow(const LinIntExpr& e, int n) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_POW,1,n); ae->a[0] = e; return LinIntExpr(ae); } LinIntExpr nroot(const LinIntExpr& e, int n) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_NROOT,1,n); ae->a[0] = e; return LinIntExpr(ae); } LinIntExpr operator /(const LinIntExpr& e0, const LinIntExpr& e1) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_DIV,2); ae->a[0] = e0; ae->a[1] = e1; return LinIntExpr(ae); } LinIntExpr operator %(const LinIntExpr& e0, const LinIntExpr& e1) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_MOD,2); ae->a[0] = e0; ae->a[1] = e1; return LinIntExpr(ae); } LinIntExpr element(const IntVarArgs& x, const LinIntExpr& e) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_ELMNT,x.size()+1); for (int i=x.size(); i--;) ae->a[i] = x[i]; ae->a[x.size()] = e; return LinIntExpr(ae); } LinIntExpr element(const IntArgs& x, const LinIntExpr& e) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_ELMNT,x.size()+1); for (int i=x.size(); i--;) ae->a[i] = x[i]; ae->a[x.size()] = e; return LinIntExpr(ae); } LinIntExpr ite(const BoolExpr& b, const LinIntExpr& e0, const LinIntExpr& e1) { using namespace MiniModel; ArithNonLinIntExpr* ae = new ArithNonLinIntExpr(ArithNonLinIntExpr::ANLE_ITE,2,b); ae->a[0] = e0; ae->a[1] = e1; return LinIntExpr(ae); } } // STATISTICS: minimodel-any