this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2/* 3 * Main authors: 4 * Vincent Barichard <Vincent.Barichard@univ-angers.fr> 5 * 6 * Copyright: 7 * Vincent Barichard, 2012 8 * 9 * This file is part of Gecode, the generic constraint 10 * development environment: 11 * http://www.gecode.org 12 * 13 * Permission is hereby granted, free of charge, to any person obtaining 14 * a copy of this software and associated documentation files (the 15 * "Software"), to deal in the Software without restriction, including 16 * without limitation the rights to use, copy, modify, merge, publish, 17 * distribute, sublicense, and/or sell copies of the Software, and to 18 * permit persons to whom the Software is furnished to do so, subject to 19 * the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be 22 * included in all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 * 32 */ 33 34#include <gecode/minimodel.hh> 35 36#ifdef GECODE_HAS_FLOAT_VARS 37 38#include <gecode/float/linear.hh> 39 40namespace Gecode { 41 42 /// Nodes for linear expressions 43 class LinFloatExpr::Node { 44 public: 45 /// Nodes are reference counted 46 unsigned int use; 47 /// Float variables in tree 48 int n_float; 49 /// Type of expression 50 NodeType t; 51 /// Subexpressions 52 Node *l, *r; 53 /// Sum of integer or Boolean variables, or non-linear expression 54 union { 55 /// Integer views and coefficients 56 Float::Linear::Term* tf; 57 /// Non-linear expression 58 NonLinFloatExpr* ne; 59 } sum; 60 /// Coefficient and offset 61 FloatVal a, c; 62 /// Float variable (potentially) 63 FloatVar x_float; 64 /// Default constructor 65 Node(void); 66 /// Generate linear terms from expression 67 GECODE_MINIMODEL_EXPORT 68 void fill(Home home, Float::Linear::Term*& tf, 69 FloatVal m, FloatVal& d) const; 70 /// Generate linear terms for expressions 71 FloatVal fill(Home home, Float::Linear::Term* tf) const; 72 /// Decrement reference count and possibly free memory 73 bool decrement(void); 74 /// Destructor 75 ~Node(void); 76 /// Memory management 77 static void* operator new(size_t size); 78 /// Memory management 79 static void operator delete(void* p,size_t size); 80 81 }; 82 83 /* 84 * Operations for nodes 85 * 86 */ 87 forceinline 88 LinFloatExpr::Node::Node(void) : use(1) { 89 } 90 91 forceinline 92 LinFloatExpr::Node::~Node(void) { 93 switch (t) { 94 case NT_SUM: 95 if (n_float > 0) 96 heap.free<Float::Linear::Term>(sum.tf,n_float); 97 break; 98 case NT_NONLIN: 99 delete sum.ne; 100 break; 101 default: ; 102 } 103 } 104 105 forceinline void* 106 LinFloatExpr::Node::operator new(size_t size) { 107 return heap.ralloc(size); 108 } 109 110 forceinline void 111 LinFloatExpr::Node::operator delete(void* p, size_t) { 112 heap.rfree(p); 113 } 114 115 bool 116 LinFloatExpr::Node::decrement(void) { 117 if (--use == 0) { 118 if ((l != nullptr) && l->decrement()) 119 delete l; 120 if ((r != nullptr) && r->decrement()) 121 delete r; 122 return true; 123 } 124 return false; 125 } 126 127 /* 128 * Operations for float expressions 129 * 130 */ 131 132 LinFloatExpr::LinFloatExpr(const LinFloatExpr& e) 133 : n(e.n) { 134 n->use++; 135 } 136 137 NonLinFloatExpr* 138 LinFloatExpr::nlfe(void) const { 139 return n->t == NT_NONLIN ? n->sum.ne : nullptr; 140 } 141 142 FloatVal 143 LinFloatExpr::Node::fill(Home home, 144 Float::Linear::Term* tf) const { 145 FloatVal d=0; 146 fill(home,tf,1.0,d); 147 Float::Limits::check(d,"MiniModel::LinFloatExpr"); 148 return d; 149 } 150 151 void 152 LinFloatExpr::post(Home home, FloatRelType frt) const { 153 if (home.failed()) return; 154 Region r; 155 if (n->t==NT_ADD && n->l == nullptr && n->r->t==NT_NONLIN) { 156 n->r->sum.ne->post(home,frt,-n->c); 157 } else if (n->t==NT_SUB && n->r->t==NT_NONLIN && n->l==nullptr) { 158 switch (frt) { 159 case FRT_LQ: frt=FRT_GQ; break; 160 case FRT_LE: frt=FRT_GR; break; 161 case FRT_GQ: frt=FRT_LQ; break; 162 case FRT_GR: frt=FRT_LE; break; 163 default: break; 164 } 165 n->r->sum.ne->post(home,frt,n->c); 166 } else if (frt==FRT_EQ && 167 n->t==NT_SUB && n->r->t==NT_NONLIN && 168 n->l != nullptr && n->l->t==NT_VAR 169 && n->l->a==1) { 170 (void) n->r->sum.ne->post(home,&n->l->x_float); 171 } else if (frt==FRT_EQ && 172 n->t==NT_SUB && n->r->t==NT_VAR && 173 n->l != nullptr && n->l->t==NT_NONLIN 174 && n->r->a==1) { 175 (void) n->l->sum.ne->post(home,&n->r->x_float); 176 } else { 177 Float::Linear::Term* fts = 178 r.alloc<Float::Linear::Term>(n->n_float); 179 FloatVal c = n->fill(home,fts); 180 Float::Linear::post(home, fts, n->n_float, frt, -c); 181 } 182 } 183 184 void 185 LinFloatExpr::post(Home home, FloatRelType frt, const BoolVar& b) const { 186 if (home.failed()) return; 187 Region r; 188 if (n->t==NT_ADD && n->l==nullptr && n->r->t==NT_NONLIN) { 189 n->r->sum.ne->post(home,frt,-n->c,b); 190 } else if (n->t==NT_SUB && n->l==nullptr && n->r->t==NT_NONLIN) { 191 switch (frt) { 192 case FRT_LQ: frt=FRT_GQ; break; 193 case FRT_LE: frt=FRT_GR; break; 194 case FRT_GQ: frt=FRT_LQ; break; 195 case FRT_GR: frt=FRT_LE; break; 196 default: break; 197 } 198 n->r->sum.ne->post(home,frt,n->c,b); 199 } else { 200 Float::Linear::Term* fts = 201 r.alloc<Float::Linear::Term>(n->n_float); 202 FloatVal c = n->fill(home,fts); 203 Float::Linear::post(home, fts, n->n_float, frt, -c, b); 204 } 205 206 } 207 208 FloatVar 209 LinFloatExpr::post(Home home) const { 210 if (home.failed()) return FloatVar(home,0,0); 211 Region r; 212 Float::Linear::Term* fts = 213 r.alloc<Float::Linear::Term>(n->n_float+1); 214 FloatVal c = n->fill(home,fts); 215 if ((n->n_float == 1) && (c == 0) && (fts[0].a == 1)) 216 return fts[0].x; 217 FloatNum min, max; 218 Float::Linear::estimate(&fts[0],n->n_float,c,min,max); 219 FloatVar x(home, min, max); 220 fts[n->n_float].x = x; fts[n->n_float].a = -1; 221 Float::Linear::post(home, fts, n->n_float+1, FRT_EQ, -c); 222 return x; 223 224 } 225 226 LinFloatExpr::LinFloatExpr(void) : 227 n(new Node) { 228 n->n_float = 0; 229 n->t = NT_VAR; 230 n->l = n->r = nullptr; 231 n->a = 0; 232 } 233 234 LinFloatExpr::LinFloatExpr(const FloatVal& c) : 235 n(new Node) { 236 n->n_float = 0; 237 n->t = NT_CONST; 238 n->l = n->r = nullptr; 239 n->a = 0; 240 Float::Limits::check(c,"MiniModel::LinFloatExpr"); 241 n->c = c; 242 } 243 244 LinFloatExpr::LinFloatExpr(const FloatVar& x) : 245 n(new Node) { 246 n->n_float = 1; 247 n->t = NT_VAR; 248 n->l = n->r = nullptr; 249 n->a = 1.0; 250 n->x_float = x; 251 } 252 253 LinFloatExpr::LinFloatExpr(const FloatVar& x, FloatVal a) : 254 n(new Node) { 255 n->n_float = 1; 256 n->t = NT_VAR; 257 n->l = n->r = nullptr; 258 n->a = a; 259 n->x_float = x; 260 } 261 262 LinFloatExpr::LinFloatExpr(const FloatVarArgs& x) : 263 n(new Node) { 264 n->n_float = x.size(); 265 n->t = NT_SUM; 266 n->l = n->r = nullptr; 267 if (x.size() > 0) { 268 n->sum.tf = heap.alloc<Float::Linear::Term>(x.size()); 269 for (int i=x.size(); i--; ) { 270 n->sum.tf[i].x = x[i]; 271 n->sum.tf[i].a = 1.0; 272 } 273 } 274 } 275 276 LinFloatExpr::LinFloatExpr(const FloatValArgs& a, const FloatVarArgs& x) : 277 n(new Node) { 278 if (a.size() != x.size()) 279 throw Float::ArgumentSizeMismatch("MiniModel::LinFloatExpr"); 280 n->n_float = x.size(); 281 n->t = NT_SUM; 282 n->l = n->r = nullptr; 283 if (x.size() > 0) { 284 n->sum.tf = heap.alloc<Float::Linear::Term>(x.size()); 285 for (int i=x.size(); i--; ) { 286 n->sum.tf[i].x = x[i]; 287 n->sum.tf[i].a = a[i]; 288 } 289 } 290 } 291 292 LinFloatExpr::LinFloatExpr(const LinFloatExpr& e0, NodeType t, const LinFloatExpr& e1) : 293 n(new Node) { 294 n->n_float = e0.n->n_float + e1.n->n_float; 295 n->t = t; 296 n->l = e0.n; n->l->use++; 297 n->r = e1.n; n->r->use++; 298 } 299 300 LinFloatExpr::LinFloatExpr(const LinFloatExpr& e, NodeType t, const FloatVal& c) : 301 n(new Node) { 302 n->n_float = e.n->n_float; 303 n->t = t; 304 n->l = nullptr; 305 n->r = e.n; n->r->use++; 306 n->c = c; 307 } 308 309 LinFloatExpr::LinFloatExpr(FloatVal a, const LinFloatExpr& e) : 310 n(new Node) { 311 n->n_float = e.n->n_float; 312 n->t = NT_MUL; 313 n->l = e.n; n->l->use++; 314 n->r = nullptr; 315 n->a = a; 316 } 317 318 LinFloatExpr::LinFloatExpr(NonLinFloatExpr* e) : 319 n(new Node) { 320 n->n_float = 1; 321 n->t = NT_NONLIN; 322 n->l = n->r = nullptr; 323 n->a = 0; 324 n->sum.ne = e; 325 } 326 327 const LinFloatExpr& 328 LinFloatExpr::operator =(const LinFloatExpr& e) { 329 if (this != &e) { 330 if (n->decrement()) 331 delete n; 332 n = e.n; n->use++; 333 } 334 return *this; 335 } 336 337 LinFloatExpr::~LinFloatExpr(void) { 338 if (n->decrement()) 339 delete n; 340 } 341 342 343 void 344 LinFloatExpr::Node::fill(Home home, 345 Float::Linear::Term*& tf, 346 FloatVal m, FloatVal& d) const { 347 switch (this->t) { 348 case NT_CONST: 349 Float::Limits::check(m*c,"MiniModel::LinFloatExpr"); 350 d += m*c; 351 break; 352 case NT_VAR: 353 Float::Limits::check(m*a,"MiniModel::LinFloatExpr"); 354 tf->a=m*a; tf->x=x_float; tf++; 355 break; 356 case NT_NONLIN: 357 tf->a=m; tf->x=sum.ne->post(home, nullptr); tf++; 358 break; 359 case NT_SUM: 360 for (int i=n_float; i--; ) { 361 Float::Limits::check(m*sum.tf[i].a,"MiniModel::LinFloatExpr"); 362 tf[i].x = sum.tf[i].x; tf[i].a = m*sum.tf[i].a; 363 } 364 tf += n_float; 365 break; 366 case NT_ADD: 367 if (l == nullptr) { 368 Float::Limits::check(m*c,"MiniModel::LinFloatExpr"); 369 d += m*c; 370 } else { 371 l->fill(home,tf,m,d); 372 } 373 r->fill(home,tf,m,d); 374 break; 375 case NT_SUB: 376 if (l == nullptr) { 377 Float::Limits::check(m*c,"MiniModel::LinFloatExpr"); 378 d += m*c; 379 } else { 380 l->fill(home,tf,m,d); 381 } 382 r->fill(home,tf,-m,d); 383 break; 384 case NT_MUL: 385 Float::Limits::check(m*a,"MiniModel::LinFloatExpr"); 386 l->fill(home,tf,m*a,d); 387 break; 388 default: 389 GECODE_NEVER; 390 } 391 } 392 393 394 /* 395 * Operators 396 * 397 */ 398 LinFloatExpr 399 operator +(const FloatVal& c, const FloatVar& x) { 400 if (x.assigned() && Float::Limits::valid(c+x.val())) 401 return LinFloatExpr(c+x.val()); 402 else 403 return LinFloatExpr(x,LinFloatExpr::NT_ADD,c); 404 } 405 LinFloatExpr 406 operator +(const FloatVal& c, const LinFloatExpr& e) { 407 return LinFloatExpr(e,LinFloatExpr::NT_ADD,c); 408 } 409 LinFloatExpr 410 operator +(const FloatVar& x, const FloatVal& c) { 411 if (x.assigned() && Float::Limits::valid(c+x.val())) 412 return LinFloatExpr(c+x.val()); 413 else 414 return LinFloatExpr(x,LinFloatExpr::NT_ADD,c); 415 } 416 LinFloatExpr 417 operator +(const LinFloatExpr& e, const FloatVal& c) { 418 return LinFloatExpr(e,LinFloatExpr::NT_ADD,c); 419 } 420 LinFloatExpr 421 operator +(const FloatVar& x, const FloatVar& y) { 422 if (x.assigned()) 423 return x.val() + y; 424 else if (y.assigned()) 425 return x + y.val(); 426 else 427 return LinFloatExpr(x,LinFloatExpr::NT_ADD,(const LinFloatExpr&)y); 428 } 429 LinFloatExpr 430 operator +(const FloatVar& x, const LinFloatExpr& e) { 431 if (x.assigned()) 432 return x.val() + e; 433 else 434 return LinFloatExpr(x,LinFloatExpr::NT_ADD,e); 435 } 436 LinFloatExpr 437 operator +(const LinFloatExpr& e, const FloatVar& x) { 438 if (x.assigned()) 439 return e + x.val(); 440 else 441 return LinFloatExpr(e,LinFloatExpr::NT_ADD,(const LinFloatExpr&)x); 442 } 443 LinFloatExpr 444 operator +(const LinFloatExpr& e1, const LinFloatExpr& e2) { 445 return LinFloatExpr(e1,LinFloatExpr::NT_ADD,e2); 446 } 447 448 LinFloatExpr 449 operator -(const FloatVal& c, const FloatVar& x) { 450 if (x.assigned() && Float::Limits::valid(c-x.val())) 451 return LinFloatExpr(c-x.val()); 452 else 453 return LinFloatExpr(x,LinFloatExpr::NT_SUB,c); 454 } 455 LinFloatExpr 456 operator -(const FloatVal& c, const LinFloatExpr& e) { 457 return LinFloatExpr(e,LinFloatExpr::NT_SUB,c); 458 } 459 LinFloatExpr 460 operator -(const FloatVar& x, const FloatVal& c) { 461 if (x.assigned() && Float::Limits::valid(x.val()-c)) 462 return LinFloatExpr(x.val()-c); 463 else 464 return LinFloatExpr(x,LinFloatExpr::NT_ADD,-c); 465 } 466 LinFloatExpr 467 operator -(const LinFloatExpr& e, const FloatVal& c) { 468 return LinFloatExpr(e,LinFloatExpr::NT_ADD,-c); 469 } 470 LinFloatExpr 471 operator -(const FloatVar& x, const FloatVar& y) { 472 if (x.assigned()) 473 return x.val() - y; 474 else if (y.assigned()) 475 return x - y.val(); 476 else 477 return LinFloatExpr(x,LinFloatExpr::NT_SUB,(const LinFloatExpr&)y); 478 } 479 LinFloatExpr 480 operator -(const FloatVar& x, const LinFloatExpr& e) { 481 if (x.assigned()) 482 return x.val() - e; 483 else 484 return LinFloatExpr(x,LinFloatExpr::NT_SUB,e); 485 } 486 LinFloatExpr 487 operator -(const LinFloatExpr& e, const FloatVar& x) { 488 if (x.assigned()) 489 return e - x.val(); 490 else 491 return LinFloatExpr(e,LinFloatExpr::NT_SUB,(const LinFloatExpr&)x); 492 } 493 LinFloatExpr 494 operator -(const LinFloatExpr& e1, const LinFloatExpr& e2) { 495 return LinFloatExpr(e1,LinFloatExpr::NT_SUB,e2); 496 } 497 498 LinFloatExpr 499 operator -(const FloatVar& x) { 500 if (x.assigned()) 501 return LinFloatExpr(-x.val()); 502 else 503 return LinFloatExpr(x,LinFloatExpr::NT_SUB,0); 504 } 505 LinFloatExpr 506 operator -(const LinFloatExpr& e) { 507 return LinFloatExpr(e,LinFloatExpr::NT_SUB,0); 508 } 509 510 LinFloatExpr 511 operator *(const FloatVal& a, const FloatVar& x) { 512 if (a == 0) 513 return LinFloatExpr(0.0); 514 else if (x.assigned() && 515 Float::Limits::valid(a*x.val())) 516 return LinFloatExpr(a*x.val()); 517 else 518 return LinFloatExpr(x,a); 519 } 520 LinFloatExpr 521 operator *(const FloatVar& x, const FloatVal& a) { 522 if (a == 0) 523 return LinFloatExpr(0.0); 524 else if (x.assigned() && 525 Float::Limits::valid(a*x.val())) 526 return LinFloatExpr(a*x.val()); 527 else 528 return LinFloatExpr(x,a); 529 } 530 LinFloatExpr 531 operator *(const LinFloatExpr& e, const FloatVal& a) { 532 if (a == 0) 533 return LinFloatExpr(0.0); 534 else 535 return LinFloatExpr(a,e); 536 } 537 LinFloatExpr 538 operator *(const FloatVal& a, const LinFloatExpr& e) { 539 if (a == 0) 540 return LinFloatExpr(0.0); 541 else 542 return LinFloatExpr(a,e); 543 } 544 545 LinFloatExpr 546 sum(const FloatVarArgs& x) { 547 return LinFloatExpr(x); 548 } 549 550 LinFloatExpr 551 sum(const FloatValArgs& a, const FloatVarArgs& x) { 552 return LinFloatExpr(a,x); 553 } 554 555 FloatVar 556 expr(Home home, const LinFloatExpr& e) { 557 PostInfo pi(home); 558 if (!home.failed()) 559 return e.post(home); 560 FloatVar x(home,Float::Limits::min,Float::Limits::max); 561 return x; 562 } 563 564} 565 566#endif 567 568// STATISTICS: minimodel-any