this repo has no description
at develop 14 kB view raw
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* 4 * Main authors: 5 * Guido Tack <guido.tack@monash.edu> 6 */ 7 8/* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12#include <minizinc/eval_par.hh> 13#include <minizinc/flatten_internal.hh> 14#include <minizinc/optimize_constraints.hh> 15 16namespace MiniZinc { 17 18void OptimizeRegistry::reg(const MiniZinc::ASTString& call, optimizer opt) { 19 _m.insert(std::make_pair(call, opt)); 20} 21 22OptimizeRegistry::ConstraintStatus OptimizeRegistry::process(EnvI& env, MiniZinc::Item* i, 23 MiniZinc::Call* c, 24 Expression*& rewrite) { 25 ASTStringMap<optimizer>::t::iterator it = _m.find(c->id()); 26 if (it != _m.end()) { 27 return it->second(env, i, c, rewrite); 28 } 29 return CS_NONE; 30} 31 32OptimizeRegistry& OptimizeRegistry::registry(void) { 33 static OptimizeRegistry reg; 34 return reg; 35} 36 37namespace Optimizers { 38 39OptimizeRegistry::ConstraintStatus o_linear(EnvI& env, Item* ii, Call* c, Expression*& rewrite) { 40 ArrayLit* al_c = eval_array_lit(env, c->arg(0)); 41 std::vector<IntVal> coeffs(al_c->size()); 42 for (unsigned int i = 0; i < al_c->size(); i++) { 43 coeffs[i] = eval_int(env, (*al_c)[i]); 44 } 45 ArrayLit* al_x = eval_array_lit(env, c->arg(1)); 46 std::vector<KeepAlive> x(al_x->size()); 47 for (unsigned int i = 0; i < al_x->size(); i++) { 48 x[i] = (*al_x)[i]; 49 } 50 IntVal d = 0; 51 simplify_lin<IntLit>(coeffs, x, d); 52 if (coeffs.size() == 0) { 53 bool failed; 54 if (c->id() == constants().ids.int_.lin_le) { 55 failed = (d > eval_int(env, c->arg(2))); 56 } else if (c->id() == constants().ids.int_.lin_eq) { 57 failed = (d != eval_int(env, c->arg(2))); 58 } else { 59 failed = (d == eval_int(env, c->arg(2))); 60 } 61 if (failed) { 62 return OptimizeRegistry::CS_FAILED; 63 } else { 64 return OptimizeRegistry::CS_ENTAILED; 65 } 66 } else if (coeffs.size() == 1 && 67 (ii->isa<ConstraintI>() || 68 ii->cast<VarDeclI>()->e()->ti()->domain() == constants().lit_true)) { 69 VarDecl* vd = x[0]()->cast<Id>()->decl(); 70 IntSetVal* domain = vd->ti()->domain() ? eval_intset(env, vd->ti()->domain()) : NULL; 71 if (c->id() == constants().ids.int_.lin_eq) { 72 IntVal rd = eval_int(env, c->arg(2)) - d; 73 if (rd % coeffs[0] == 0) { 74 IntVal nd = rd / coeffs[0]; 75 if (domain && !domain->contains(nd)) return OptimizeRegistry::CS_FAILED; 76 std::vector<Expression*> args(2); 77 args[0] = x[0](); 78 args[1] = IntLit::a(nd); 79 Call* c = new Call(Location(), constants().ids.int_.eq, args); 80 c->type(Type::varbool()); 81 rewrite = c; 82 return OptimizeRegistry::CS_REWRITE; 83 } else { 84 return OptimizeRegistry::CS_FAILED; 85 } 86 } else if (c->id() == constants().ids.int_.lin_le) { 87 IntVal ac = std::abs(coeffs[0]); 88 IntVal rd = eval_int(env, c->arg(2)) - d; 89 IntVal ad = std::abs(rd); 90 IntVal nd; 91 if (ad % ac == 0) { 92 nd = rd / coeffs[0]; 93 } else { 94 double nd_d = static_cast<double>(ad.toInt()) / static_cast<double>(ac.toInt()); 95 if (coeffs[0] >= 0 && rd >= 0) { 96 nd = static_cast<long long int>(std::floor(nd_d)); 97 } else if (rd >= 0) { 98 nd = -static_cast<long long int>(std::floor(nd_d)); 99 } else if (coeffs[0] >= 0) { 100 nd = -static_cast<long long int>(std::ceil(nd_d)); 101 } else { 102 nd = static_cast<long long int>(std::ceil(nd_d)); 103 } 104 } 105 bool swapSign = coeffs[0] < 0; 106 if (domain) { 107 if (swapSign) { 108 if (domain->max() < nd) { 109 return OptimizeRegistry::CS_FAILED; 110 } else if (domain->min() >= nd) 111 return OptimizeRegistry::CS_ENTAILED; 112 } else { 113 if (domain->min() > nd) { 114 return OptimizeRegistry::CS_FAILED; 115 } else if (domain->max() <= nd) 116 return OptimizeRegistry::CS_ENTAILED; 117 } 118 std::vector<Expression*> args(2); 119 args[0] = x[0](); 120 args[1] = IntLit::a(nd); 121 if (swapSign) std::swap(args[0], args[1]); 122 Call* nc = new Call(Location(), constants().ids.int_.le, args); 123 nc->type(Type::varbool()); 124 rewrite = nc; 125 return OptimizeRegistry::CS_REWRITE; 126 } 127 } 128 } else if (c->id() == constants().ids.int_.lin_eq && coeffs.size() == 2 && 129 ((coeffs[0] == 1 && coeffs[1] == -1) || (coeffs[1] == 1 && coeffs[0] == -1)) && 130 eval_int(env, c->arg(2)) - d == 0) { 131 std::vector<Expression*> args(2); 132 args[0] = x[0](); 133 args[1] = x[1](); 134 Call* c = new Call(Location(), constants().ids.int_.eq, args); 135 rewrite = c; 136 return OptimizeRegistry::CS_REWRITE; 137 } 138 if (coeffs.size() < al_c->size()) { 139 std::vector<Expression*> coeffs_e(coeffs.size()); 140 std::vector<Expression*> x_e(coeffs.size()); 141 for (unsigned int i = 0; i < coeffs.size(); i++) { 142 coeffs_e[i] = IntLit::a(coeffs[i]); 143 x_e[i] = x[i](); 144 } 145 ArrayLit* al_c_new = new ArrayLit(al_c->loc(), coeffs_e); 146 al_c_new->type(Type::parint(1)); 147 ArrayLit* al_x_new = new ArrayLit(al_x->loc(), x_e); 148 al_x_new->type(al_x->type()); 149 150 std::vector<Expression*> args(3); 151 args[0] = al_c_new; 152 args[1] = al_x_new; 153 args[2] = IntLit::a(eval_int(env, c->arg(2)) - d); 154 Call* nc = new Call(Location(), c->id(), args); 155 nc->type(Type::varbool()); 156 for (ExpressionSetIter it = c->ann().begin(); it != c->ann().end(); ++it) { 157 nc->addAnnotation(*it); 158 } 159 160 rewrite = nc; 161 return OptimizeRegistry::CS_REWRITE; 162 } 163 return OptimizeRegistry::CS_OK; 164} 165 166OptimizeRegistry::ConstraintStatus o_lin_exp(EnvI& env, Item* i, Call* c, Expression*& rewrite) { 167 if (c->type().isint()) { 168 ArrayLit* al_c = eval_array_lit(env, c->arg(0)); 169 std::vector<IntVal> coeffs(al_c->size()); 170 for (unsigned int i = 0; i < al_c->size(); i++) { 171 coeffs[i] = eval_int(env, (*al_c)[i]); 172 } 173 ArrayLit* al_x = eval_array_lit(env, c->arg(1)); 174 std::vector<KeepAlive> x(al_x->size()); 175 for (unsigned int i = 0; i < al_x->size(); i++) { 176 x[i] = (*al_x)[i]; 177 } 178 IntVal d = eval_int(env, c->arg(2)); 179 simplify_lin<IntLit>(coeffs, x, d); 180 if (coeffs.size() == 0) { 181 rewrite = IntLit::a(d); 182 return OptimizeRegistry::CS_REWRITE; 183 } else if (coeffs.size() < al_c->size()) { 184 if (coeffs.size() == 1 && coeffs[0] == 1 && d == 0) { 185 rewrite = x[0](); 186 return OptimizeRegistry::CS_REWRITE; 187 } 188 189 std::vector<Expression*> coeffs_e(coeffs.size()); 190 std::vector<Expression*> x_e(coeffs.size()); 191 for (unsigned int i = 0; i < coeffs.size(); i++) { 192 coeffs_e[i] = IntLit::a(coeffs[i]); 193 x_e[i] = x[i](); 194 } 195 ArrayLit* al_c_new = new ArrayLit(al_c->loc(), coeffs_e); 196 al_c_new->type(Type::parint(1)); 197 ArrayLit* al_x_new = new ArrayLit(al_x->loc(), x_e); 198 al_x_new->type(al_x->type()); 199 200 std::vector<Expression*> args(3); 201 args[0] = al_c_new; 202 args[1] = al_x_new; 203 args[2] = IntLit::a(d); 204 Call* nc = new Call(Location(), c->id(), args); 205 nc->type(c->type()); 206 for (ExpressionSetIter it = c->ann().begin(); it != c->ann().end(); ++it) { 207 nc->addAnnotation(*it); 208 } 209 rewrite = nc; 210 return OptimizeRegistry::CS_REWRITE; 211 } 212 } 213 return OptimizeRegistry::CS_OK; 214} 215 216OptimizeRegistry::ConstraintStatus o_element(EnvI& env, Item* i, Call* c, Expression*& rewrite) { 217 if (c->arg(0)->isa<IntLit>()) { 218 IntVal idx = eval_int(env, c->arg(0)); 219 ArrayLit* al = eval_array_lit(env, c->arg(1)); 220 if (idx < 1 || idx > al->size()) { 221 return OptimizeRegistry::CS_FAILED; 222 } 223 Expression* result = (*al)[static_cast<int>(idx.toInt()) - 1]; 224 std::vector<Expression*> args(2); 225 args[0] = result; 226 args[1] = c->arg(2); 227 Call* eq = new Call(Location(), constants().ids.int_.eq, args); 228 rewrite = eq; 229 return OptimizeRegistry::CS_REWRITE; 230 } 231 return OptimizeRegistry::CS_OK; 232} 233 234OptimizeRegistry::ConstraintStatus o_clause(EnvI& env, Item* i, Call* c, Expression*& rewrite) { 235 std::vector<VarDecl*> pos; 236 std::vector<VarDecl*> neg; 237 ArrayLit* al_pos = eval_array_lit(env, c->arg(0)); 238 for (unsigned int i = 0; i < al_pos->size(); i++) { 239 if (Id* ident = (*al_pos)[i]->dyn_cast<Id>()) { 240 if (ident->decl()->ti()->domain() == NULL) pos.push_back(ident->decl()); 241 } 242 } 243 ArrayLit* al_neg = eval_array_lit(env, c->arg(1)); 244 for (unsigned int i = 0; i < al_neg->size(); i++) { 245 if (Id* ident = (*al_neg)[i]->dyn_cast<Id>()) { 246 if (ident->decl()->ti()->domain() == NULL) neg.push_back(ident->decl()); 247 } 248 } 249 bool subsumed = false; 250 if (pos.size() > 0 && neg.size() > 0) { 251 std::sort(pos.begin(), pos.end()); 252 std::sort(neg.begin(), neg.end()); 253 unsigned int ix = 0; 254 unsigned int iy = 0; 255 for (;;) { 256 if (pos[ix] == neg[iy]) { 257 subsumed = true; 258 break; 259 } 260 if (pos[ix] < neg[iy]) { 261 ix++; 262 } else { 263 iy++; 264 } 265 if (ix == pos.size() || iy == neg.size()) break; 266 } 267 } 268 if (subsumed) { 269 return OptimizeRegistry::CS_ENTAILED; 270 } else { 271 return OptimizeRegistry::CS_OK; 272 } 273} 274 275OptimizeRegistry::ConstraintStatus o_div(EnvI& env, Item* i, Call* c, Expression*& rewrite) { 276 if (c->arg(1)->type().ispar()) { 277 IntVal c1v = eval_int(env, c->arg(1)); 278 if (c->arg(0)->type().ispar() && c->n_args() == 3 && c->arg(2)->type().ispar()) { 279 IntVal c0v = eval_int(env, c->arg(0)); 280 IntVal c2v = eval_int(env, c->arg(2)); 281 return (c0v / c1v == c2v) ? OptimizeRegistry::CS_ENTAILED : OptimizeRegistry::CS_FAILED; 282 } 283 } 284 return OptimizeRegistry::CS_OK; 285} 286 287OptimizeRegistry::ConstraintStatus o_set_in(EnvI& env, Item* i, Call* c, Expression*& rewrite) { 288 if (c->arg(1)->type().ispar()) { 289 if (c->arg(0)->type().ispar()) { 290 IntSetVal* isv = eval_intset(env, c->arg(1)); 291 return isv->contains(eval_int(env, c->arg(0))) ? OptimizeRegistry::CS_ENTAILED 292 : OptimizeRegistry::CS_FAILED; 293 } else if (Id* ident = c->arg(0)->dyn_cast<Id>()) { 294 VarDecl* vd = ident->decl(); 295 IntSetVal* isv = eval_intset(env, c->arg(1)); 296 if (vd->ti()->domain()) { 297 IntSetVal* dom = eval_intset(env, vd->ti()->domain()); 298 { 299 IntSetRanges isv_r(isv); 300 IntSetRanges dom_r(dom); 301 if (Ranges::subset(dom_r, isv_r)) return OptimizeRegistry::CS_ENTAILED; 302 } 303 { 304 IntSetRanges isv_r(isv); 305 IntSetRanges dom_r(dom); 306 if (Ranges::disjoint(dom_r, isv_r)) return OptimizeRegistry::CS_FAILED; 307 } 308 } else if (isv->min() == isv->max()) { 309 std::vector<Expression*> args(2); 310 args[0] = vd->id(); 311 args[1] = IntLit::a(isv->min()); 312 Call* eq = new Call(Location(), constants().ids.int_.eq, args); 313 rewrite = eq; 314 return OptimizeRegistry::CS_REWRITE; 315 } 316 } 317 } 318 return OptimizeRegistry::CS_OK; 319} 320 321OptimizeRegistry::ConstraintStatus o_int_ne(EnvI& env, Item* i, Call* c, Expression*& rewrite) { 322 Expression* e0 = c->arg(0); 323 Expression* e1 = c->arg(1); 324 if (e0->type().ispar() && e1->type().ispar()) { 325 return eval_int(env, e0) != eval_int(env, e1) ? OptimizeRegistry::CS_ENTAILED 326 : OptimizeRegistry::CS_FAILED; 327 } 328 if (e1->isa<Id>()) { 329 std::swap(e0, e1); 330 } 331 if (Id* ident = e0->dyn_cast<Id>()) { 332 if (e1->type().ispar()) { 333 if (ident->decl()->ti()->domain()) { 334 IntVal e1v = eval_int(env, e1); 335 IntSetVal* isv = eval_intset(env, ident->decl()->ti()->domain()); 336 if (!isv->contains(e1v)) return OptimizeRegistry::CS_ENTAILED; 337 if (e1v == isv->min() && e1v == isv->max()) return OptimizeRegistry::CS_FAILED; 338 } 339 } 340 } 341 342 return OptimizeRegistry::CS_OK; 343} 344 345class Register { 346private: 347 Model* _keepAliveModel; 348 349public: 350 Register(void) { 351 GCLock lock; 352 _keepAliveModel = new Model; 353 ASTString id_element("array_int_element"); 354 ASTString id_var_element("array_var_int_element"); 355 std::vector<Expression*> e; 356 e.push_back(new StringLit(Location(), id_element)); 357 e.push_back(new StringLit(Location(), id_var_element)); 358 _keepAliveModel->addItem(new ConstraintI(Location(), new ArrayLit(Location(), e))); 359 OptimizeRegistry::registry().reg(constants().ids.int_.lin_eq, o_linear); 360 OptimizeRegistry::registry().reg(constants().ids.int_.lin_le, o_linear); 361 OptimizeRegistry::registry().reg(constants().ids.int_.lin_ne, o_linear); 362 OptimizeRegistry::registry().reg(constants().ids.int_.div, o_div); 363 OptimizeRegistry::registry().reg(id_element, o_element); 364 OptimizeRegistry::registry().reg(constants().ids.lin_exp, o_lin_exp); 365 OptimizeRegistry::registry().reg(id_var_element, o_element); 366 OptimizeRegistry::registry().reg(constants().ids.clause, o_clause); 367 OptimizeRegistry::registry().reg(constants().ids.bool_clause, o_clause); 368 OptimizeRegistry::registry().reg(constants().ids.set_in, o_set_in); 369 OptimizeRegistry::registry().reg(constants().ids.int_.ne, o_int_ne); 370 } 371 ~Register(void) { delete _keepAliveModel; } 372} _r; 373 374} // namespace Optimizers 375 376} // namespace MiniZinc