1 /* 2 * Copyright 2007-2008, Christof Lutteroth, lutteroth@cs.auckland.ac.nz 3 * Copyright 2007-2008, James Kim, jkim202@ec.auckland.ac.nz 4 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de> 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "LinearSpec.h" 10 11 #include <new> 12 13 14 /** 15 * Constructor. 16 * Creates a new specification for a linear programming problem. 17 */ 18 LinearSpec::LinearSpec() 19 : 20 fLpPresolved(NULL), 21 fOptimization(MINIMIZE), 22 fObjFunction(new(std::nothrow) SummandList()), 23 fResult(ERROR), 24 fObjectiveValue(NAN), 25 fSolvingTime(NAN) 26 { 27 fLP = make_lp(0, 0); 28 if (fLP == NULL) 29 printf("Couldn't construct a new model."); 30 31 // minimize the objective functions, this is the default of lp_solve so we 32 // don't have to do it here: 33 // set_minim(fLP); 34 35 set_verbose(fLP, 1); 36 } 37 38 39 /** 40 * Destructor. 41 * Removes the specification and deletes all constraints, 42 * objective function summands and variables. 43 */ 44 LinearSpec::~LinearSpec() 45 { 46 _RemovePresolved(); 47 for (int32 i = 0; i < fConstraints.CountItems(); i++) 48 delete (Constraint*)fConstraints.ItemAt(i); 49 for (int32 i = 0; i < fObjFunction->CountItems(); i++) 50 delete (Summand*)fObjFunction->ItemAt(i); 51 while (fVariables.CountItems() > 0) 52 RemoveVariable(fVariables.ItemAt(0)); 53 54 delete_lp(fLP); 55 56 delete fObjFunction; 57 } 58 59 60 /** 61 * Adds a new variable to the specification. 62 * 63 * @return the new variable 64 */ 65 Variable* 66 LinearSpec::AddVariable() 67 { 68 Variable* variable = new(std::nothrow) Variable(this); 69 if (!variable) 70 return NULL; 71 if (!AddVariable(variable)) { 72 delete variable; 73 return NULL; 74 } 75 76 return variable; 77 } 78 79 80 bool 81 LinearSpec::AddVariable(Variable* variable) 82 { 83 if (variable->IsValid()) 84 return false; 85 86 double d = 0; 87 int i = 0; 88 89 if (!fVariables.AddItem(variable)) 90 return false; 91 if (add_columnex(fLP, 0, &d, &i) == 0) { 92 fVariables.RemoveItem(variable); 93 return false; 94 } 95 96 if (!SetRange(variable, variable->Min(), variable->Max())) { 97 RemoveVariable(variable, false); 98 return false; 99 } 100 101 variable->fIsValid = true; 102 return true; 103 } 104 105 106 bool 107 LinearSpec::RemoveVariable(Variable* variable, bool deleteVariable) 108 { 109 int32 index = IndexOf(variable); 110 if (index < 0) 111 return false; 112 113 if (!del_column(fLP, index)) 114 return false; 115 fVariables.RemoveItemAt(index - 1); 116 variable->fIsValid = false; 117 118 // invalidate all constraints that use this variable 119 ConstraintList markedForInvalidation; 120 const ConstraintList& constraints = Constraints(); 121 for (int i = 0; i < constraints.CountItems(); i++) { 122 Constraint* constraint = constraints.ItemAt(i); 123 124 if (!constraint->IsValid()) 125 continue; 126 127 SummandList* summands = constraint->LeftSide(); 128 for (int j = 0; j < summands->CountItems(); j++) { 129 Summand* summand = summands->ItemAt(j); 130 if (summand->Var() == variable) { 131 markedForInvalidation.AddItem(constraint); 132 break; 133 } 134 } 135 } 136 for (int i = 0; i < markedForInvalidation.CountItems(); i++) 137 markedForInvalidation.ItemAt(i)->Invalidate(); 138 139 140 if (deleteVariable) 141 delete variable; 142 return true; 143 } 144 145 146 int32 147 LinearSpec::IndexOf(const Variable* variable) const 148 { 149 int32 i = fVariables.IndexOf(variable); 150 if (i == -1) { 151 printf("Variable 0x%p not part of fLS->Variables().\n", variable); 152 return -1; 153 } 154 return i + 1; 155 } 156 157 158 bool 159 LinearSpec::SetRange(Variable* variable, double min, double max) 160 { 161 return set_bounds(fLP, IndexOf(variable), min, max); 162 } 163 164 165 bool 166 LinearSpec::AddConstraint(Constraint* constraint) 167 { 168 SummandList* summands = constraint->LeftSide(); 169 OperatorType op = constraint->Op(); 170 double rightSide = constraint->RightSide(); 171 double penaltyNeg = constraint->PenaltyNeg(); 172 double penaltyPos = constraint->PenaltyPos(); 173 174 double coeffs[summands->CountItems() + 2]; 175 int varIndexes[summands->CountItems() + 2]; 176 int32 nCoefficient = 0; 177 for (; nCoefficient < summands->CountItems(); nCoefficient++) { 178 Summand* s = summands->ItemAt(nCoefficient); 179 coeffs[nCoefficient] = s->Coeff(); 180 varIndexes[nCoefficient] = s->Var()->Index(); 181 } 182 183 if (penaltyNeg != INFINITY && penaltyNeg != 0. && op != OperatorType(LE)) { 184 constraint->fDNegObjSummand 185 = new(std::nothrow) Summand(constraint->PenaltyNeg(), 186 AddVariable()); 187 fObjFunction->AddItem(constraint->fDNegObjSummand); 188 varIndexes[nCoefficient] = constraint->fDNegObjSummand->Var()->Index(); 189 coeffs[nCoefficient] = 1.0; 190 nCoefficient++; 191 } 192 193 if (penaltyPos != INFINITY && penaltyPos != 0. && op != OperatorType(GE)) { 194 constraint->fDPosObjSummand 195 = new(std::nothrow) Summand(constraint->PenaltyPos(), 196 AddVariable()); 197 fObjFunction->AddItem(constraint->fDPosObjSummand); 198 varIndexes[nCoefficient] = constraint->fDPosObjSummand->Var()->Index(); 199 coeffs[nCoefficient] = -1.0; 200 nCoefficient++; 201 } 202 203 if (!add_constraintex(fLP, nCoefficient, &coeffs[0], &varIndexes[0], 204 (op == OperatorType(EQ) ? EQ : (op == OperatorType(GE)) ? GE 205 : LE), rightSide)) 206 return false; 207 208 UpdateObjectiveFunction(); 209 fConstraints.AddItem(constraint); 210 211 return true; 212 } 213 214 215 bool 216 LinearSpec::RemoveConstraint(Constraint* constraint, bool deleteConstraint) 217 { 218 if (constraint->fDNegObjSummand) { 219 fObjFunction->RemoveItem(constraint->fDNegObjSummand); 220 delete constraint->fDNegObjSummand->Var(); 221 delete constraint->fDNegObjSummand; 222 constraint->fDNegObjSummand = NULL; 223 } 224 if (constraint->fDPosObjSummand) { 225 fObjFunction->RemoveItem(constraint->fDPosObjSummand); 226 delete constraint->fDPosObjSummand->Var(); 227 delete constraint->fDPosObjSummand; 228 constraint->fDPosObjSummand = NULL; 229 } 230 231 del_constraint(fLP, constraint->Index()); 232 fConstraints.RemoveItem(constraint); 233 constraint->fIsValid = false; 234 235 if (deleteConstraint) 236 delete constraint; 237 return true; 238 } 239 240 241 bool 242 LinearSpec::UpdateLeftSide(Constraint* constraint) 243 { 244 if (!constraint->IsValid()) 245 return false; 246 247 SummandList* leftSide = constraint->LeftSide(); 248 OperatorType op = constraint->Op(); 249 250 double coeffs[leftSide->CountItems() + 2]; 251 int varIndexes[leftSide->CountItems() + 2]; 252 int32 i; 253 for (i = 0; i < leftSide->CountItems(); i++) { 254 Summand* s = leftSide->ItemAt(i); 255 coeffs[i] = s->Coeff(); 256 varIndexes[i] = s->Var()->Index(); 257 } 258 259 if (constraint->fDNegObjSummand != NULL && op != OperatorType(LE)) { 260 varIndexes[i] = constraint->fDNegObjSummand->Var()->Index(); 261 coeffs[i] = 1.0; 262 i++; 263 } 264 265 if (constraint->fDPosObjSummand != NULL && op != OperatorType(GE)) { 266 varIndexes[i] = constraint->fDPosObjSummand->Var()->Index(); 267 coeffs[i] = -1.0; 268 i++; 269 } 270 271 if (!set_rowex(fLP, constraint->Index(), i, &coeffs[0], 272 &varIndexes[0])) 273 return false; 274 275 UpdateObjectiveFunction(); 276 _RemovePresolved(); 277 return true; 278 } 279 280 281 bool 282 LinearSpec::UpdateRightSide(Constraint* constraint) 283 { 284 if (!set_rh(fLP, constraint->Index(), constraint->RightSide())) 285 return false; 286 287 _RemovePresolved(); 288 return true; 289 } 290 291 292 bool 293 LinearSpec::UpdateOperator(Constraint* constraint) 294 { 295 OperatorType op = constraint->Op(); 296 if (!set_constr_type(fLP, constraint->Index(), 297 (op == OperatorType(EQ)) ? EQ : (op == OperatorType(GE)) ? GE 298 : LE)) 299 return false; 300 301 _RemovePresolved(); 302 return true; 303 } 304 305 306 /** 307 * Adds a new hard linear constraint to the specification. 308 * 309 * @param coeffs the constraint's coefficients 310 * @param vars the constraint's variables 311 * @param op the constraint's operand 312 * @param rightSide the constant value on the constraint's right side 313 * @return the new constraint 314 */ 315 Constraint* 316 LinearSpec::AddConstraint(SummandList* summands, OperatorType op, 317 double rightSide) 318 { 319 return AddConstraint(summands, op, rightSide, INFINITY, INFINITY); 320 } 321 322 323 /** 324 * Adds a new hard linear constraint to the specification with a single summand. 325 * 326 * @param coeff1 the constraint's first coefficient 327 * @param var1 the constraint's first variable 328 * @param op the constraint's operand 329 * @param rightSide the constant value on the constraint's right side 330 * @return the new constraint 331 */ 332 Constraint* 333 LinearSpec::AddConstraint(double coeff1, Variable* var1, 334 OperatorType op, double rightSide) 335 { 336 return AddConstraint(coeff1, var1, op, rightSide, INFINITY, INFINITY); 337 } 338 339 340 /** 341 * Adds a new hard linear constraint to the specification with two summands. 342 * 343 * @param coeff1 the constraint's first coefficient 344 * @param var1 the constraint's first variable 345 * @param coeff2 the constraint's second coefficient 346 * @param var2 the constraint's second variable 347 * @param op the constraint's operand 348 * @param rightSide the constant value on the constraint's right side 349 * @return the new constraint 350 */ 351 Constraint* 352 LinearSpec::AddConstraint(double coeff1, Variable* var1, 353 double coeff2, Variable* var2, OperatorType op, double rightSide) 354 { 355 return AddConstraint(coeff1, var1, coeff2, var2, op, rightSide, INFINITY, 356 INFINITY); 357 } 358 359 360 /** 361 * Adds a new hard linear constraint to the specification with three summands. 362 * 363 * @param coeff1 the constraint's first coefficient 364 * @param var1 the constraint's first variable 365 * @param coeff2 the constraint's second coefficient 366 * @param var2 the constraint's second variable 367 * @param coeff3 the constraint's third coefficient 368 * @param var3 the constraint's third variable 369 * @param op the constraint's operand 370 * @param rightSide the constant value on the constraint's right side 371 * @return the new constraint 372 */ 373 Constraint* 374 LinearSpec::AddConstraint(double coeff1, Variable* var1, 375 double coeff2, Variable* var2, double coeff3, Variable* var3, 376 OperatorType op, double rightSide) 377 { 378 return AddConstraint(coeff1, var1, coeff2, var2, coeff3, var3, op, 379 rightSide, INFINITY, INFINITY); 380 } 381 382 383 /** 384 * Adds a new hard linear constraint to the specification with four summands. 385 * 386 * @param coeff1 the constraint's first coefficient 387 * @param var1 the constraint's first variable 388 * @param coeff2 the constraint's second coefficient 389 * @param var2 the constraint's second variable 390 * @param coeff3 the constraint's third coefficient 391 * @param var3 the constraint's third variable 392 * @param coeff4 the constraint's fourth coefficient 393 * @param var4 the constraint's fourth variable 394 * @param op the constraint's operand 395 * @param rightSide the constant value on the constraint's right side 396 * @return the new constraint 397 */ 398 Constraint* 399 LinearSpec::AddConstraint(double coeff1, Variable* var1, 400 double coeff2, Variable* var2, double coeff3, Variable* var3, 401 double coeff4, Variable* var4, OperatorType op, double rightSide) 402 { 403 return AddConstraint(coeff1, var1, coeff2, var2, coeff3, var3, coeff4, var4, 404 op, rightSide, INFINITY, INFINITY); 405 } 406 407 408 /** 409 * Adds a new soft linear constraint to the specification. 410 * i.e. a constraint that does not always have to be satisfied. 411 * 412 * @param coeffs the constraint's coefficients 413 * @param vars the constraint's variables 414 * @param op the constraint's operand 415 * @param rightSide the constant value on the constraint's right side 416 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution 417 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution 418 */ 419 Constraint* 420 LinearSpec::AddConstraint(SummandList* summands, OperatorType op, 421 double rightSide, double penaltyNeg, double penaltyPos) 422 { 423 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos); 424 } 425 426 427 /** 428 * Adds a new soft linear constraint to the specification with a single summand. 429 * 430 * @param coeff1 the constraint's first coefficient 431 * @param var1 the constraint's first variable 432 * @param op the constraint's operand 433 * @param rightSide the constant value on the constraint's right side 434 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution 435 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution 436 */ 437 Constraint* 438 LinearSpec::AddConstraint(double coeff1, Variable* var1, 439 OperatorType op, double rightSide, double penaltyNeg, double penaltyPos) 440 { 441 SummandList* summands = new(std::nothrow) SummandList(1); 442 if (!summands) 443 return NULL; 444 summands->AddItem(new(std::nothrow) Summand(coeff1, var1)); 445 if (!_CheckSummandList(summands)) 446 return NULL; 447 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos); 448 } 449 450 451 /** 452 * Adds a new soft linear constraint to the specification with two summands. 453 * 454 * @param coeff1 the constraint's first coefficient 455 * @param var1 the constraint's first variable 456 * @param coeff2 the constraint's second coefficient 457 * @param var2 the constraint's second variable 458 * @param op the constraint's operand 459 * @param rightSide the constant value on the constraint's right side 460 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution 461 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution 462 */ 463 Constraint* 464 LinearSpec::AddConstraint(double coeff1, Variable* var1, 465 double coeff2, Variable* var2, OperatorType op, double rightSide, 466 double penaltyNeg, double penaltyPos) 467 { 468 SummandList* summands = new(std::nothrow) SummandList(2); 469 if (!summands) 470 return NULL; 471 summands->AddItem(new(std::nothrow) Summand(coeff1, var1)); 472 summands->AddItem(new(std::nothrow) Summand(coeff2, var2)); 473 if (!_CheckSummandList(summands)) 474 return NULL; 475 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos); 476 } 477 478 479 /** 480 * Adds a new soft linear constraint to the specification with three summands. 481 * 482 * @param coeff1 the constraint's first coefficient 483 * @param var1 the constraint's first variable 484 * @param coeff2 the constraint's second coefficient 485 * @param var2 the constraint's second variable 486 * @param coeff3 the constraint's third coefficient 487 * @param var3 the constraint's third variable 488 * @param op the constraint's operand 489 * @param rightSide the constant value on the constraint's right side 490 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution 491 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution 492 */ 493 Constraint* 494 LinearSpec::AddConstraint(double coeff1, Variable* var1, 495 double coeff2, Variable* var2, double coeff3, Variable* var3, 496 OperatorType op, double rightSide, double penaltyNeg, double penaltyPos) 497 { 498 SummandList* summands = new(std::nothrow) SummandList(2); 499 if (!summands) 500 return NULL; 501 summands->AddItem(new(std::nothrow) Summand(coeff1, var1)); 502 summands->AddItem(new(std::nothrow) Summand(coeff2, var2)); 503 summands->AddItem(new(std::nothrow) Summand(coeff3, var3)); 504 if (!_CheckSummandList(summands)) 505 return NULL; 506 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos); 507 } 508 509 510 /** 511 * Adds a new soft linear constraint to the specification with four summands. 512 * 513 * @param coeff1 the constraint's first coefficient 514 * @param var1 the constraint's first variable 515 * @param coeff2 the constraint's second coefficient 516 * @param var2 the constraint's second variable 517 * @param coeff3 the constraint's third coefficient 518 * @param var3 the constraint's third variable 519 * @param coeff4 the constraint's fourth coefficient 520 * @param var4 the constraint's fourth variable 521 * @param op the constraint's operand 522 * @param rightSide the constant value on the constraint's right side 523 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution 524 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution 525 */ 526 Constraint* 527 LinearSpec::AddConstraint(double coeff1, Variable* var1, 528 double coeff2, Variable* var2, double coeff3, Variable* var3, 529 double coeff4, Variable* var4, OperatorType op, double rightSide, 530 double penaltyNeg, double penaltyPos) 531 { 532 SummandList* summands = new(std::nothrow) SummandList(2); 533 if (!summands) 534 return NULL; 535 summands->AddItem(new(std::nothrow) Summand(coeff1, var1)); 536 summands->AddItem(new(std::nothrow) Summand(coeff2, var2)); 537 summands->AddItem(new(std::nothrow) Summand(coeff3, var3)); 538 summands->AddItem(new(std::nothrow) Summand(coeff4, var4)); 539 if (!_CheckSummandList(summands)) 540 return NULL; 541 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos); 542 } 543 544 545 /** 546 * Adds a new penalty function to the specification. 547 * 548 * @param var the penalty function's variable 549 * @param xs the penalty function's sampling points 550 * @param gs the penalty function's gradients 551 * @return the new penalty function 552 */ 553 PenaltyFunction* 554 LinearSpec::AddPenaltyFunction(Variable* var, BList* xs, BList* gs) 555 { 556 return new(std::nothrow) PenaltyFunction(this, var, xs, gs); 557 } 558 559 560 /** 561 * Gets the objective function. 562 * 563 * @return SummandList containing the objective function's summands 564 */ 565 SummandList* 566 LinearSpec::ObjectiveFunction() 567 { 568 return fObjFunction; 569 } 570 571 572 SummandList* 573 LinearSpec::SwapObjectiveFunction(SummandList* objFunction) 574 { 575 SummandList* list = fObjFunction; 576 fObjFunction = objFunction; 577 UpdateObjectiveFunction(); 578 return list; 579 } 580 581 582 /** 583 * Sets a new objective function. 584 * 585 * @param summands SummandList containing the objective function's summands 586 */ 587 void 588 LinearSpec::SetObjectiveFunction(SummandList* objFunction) 589 { 590 for (int32 i = 0; i < fObjFunction->CountItems(); i++) 591 delete (Summand*)fObjFunction->ItemAt(i); 592 delete fObjFunction; 593 594 fObjFunction = objFunction; 595 UpdateObjectiveFunction(); 596 } 597 598 599 /** 600 * Updates the internal representation of the objective function. 601 * Must be called whenever the summands of the objective function are changed. 602 */ 603 void 604 LinearSpec::UpdateObjectiveFunction() 605 { 606 int32 size = fObjFunction->CountItems(); 607 double coeffs[size]; 608 int varIndexes[size]; 609 Summand* current; 610 for (int32 i = 0; i < size; i++) { 611 current = (Summand*)fObjFunction->ItemAt(i); 612 coeffs[i] = current->Coeff(); 613 varIndexes[i] = current->Var()->Index(); 614 } 615 616 if (!set_obj_fnex(fLP, size, &coeffs[0], &varIndexes[0])) 617 printf("Error in set_obj_fnex.\n"); 618 619 _RemovePresolved(); 620 } 621 622 623 bool 624 LinearSpec::_CheckSummandList(SummandList* list) 625 { 626 bool ok = true; 627 for (int i = 0; i < list->CountItems(); i++) { 628 if (list->ItemAt(i) == NULL) { 629 ok = false; 630 break; 631 } 632 } 633 if (ok) 634 return true; 635 636 for (int i = 0; i < list->CountItems(); i++) 637 delete list->ItemAt(i); 638 delete list; 639 return false; 640 } 641 642 643 Constraint* 644 LinearSpec::_AddConstraint(SummandList* leftSide, OperatorType op, 645 double rightSide, double penaltyNeg, double penaltyPos) 646 { 647 Constraint* constraint = new(std::nothrow) Constraint(this, leftSide, 648 op, rightSide, penaltyNeg, penaltyPos); 649 if (constraint == NULL) 650 return NULL; 651 if (!AddConstraint(constraint)) { 652 delete constraint; 653 return NULL; 654 } 655 _RemovePresolved(); 656 return constraint; 657 } 658 659 660 /** 661 * Remove a cached presolved model, if existent. 662 * This is automatically done each time after the model has been changed, 663 * to avoid an old cached presolved model getting out of sync. 664 */ 665 void 666 LinearSpec::_RemovePresolved() 667 { 668 if (fLpPresolved == NULL) 669 return; 670 delete_lp(fLpPresolved); 671 fLpPresolved = NULL; 672 } 673 674 675 /** 676 * Creates and caches a simplified version of the linear programming problem, 677 * where redundant rows, columns and constraints are removed, 678 * if it has not been created before. 679 * Then, the simplified problem is solved. 680 * 681 * @return the result of the solving attempt 682 */ 683 ResultType 684 LinearSpec::_Presolve() 685 { 686 bigtime_t start, end; 687 start = system_time(); 688 689 if (fLpPresolved == NULL) { 690 fLpPresolved = copy_lp(fLP); 691 set_presolve(fLpPresolved, PRESOLVE_ROWS | PRESOLVE_COLS 692 | PRESOLVE_LINDEP, get_presolveloops(fLpPresolved)); 693 } 694 695 fResult = (ResultType)solve(fLpPresolved); 696 fObjectiveValue = get_objective(fLpPresolved); 697 698 if (fResult == OPTIMAL) { 699 int32 size = fVariables.CountItems(); 700 for (int32 i = 0; i < size; i++) { 701 Variable* current = (Variable*)fVariables.ItemAt(i); 702 current->SetValue(get_var_primalresult(fLpPresolved, 703 get_Norig_rows(fLpPresolved) + current->Index())); 704 } 705 } 706 707 end = system_time(); 708 fSolvingTime = (end - start) / 1000.0; 709 710 return fResult; 711 } 712 713 714 /** 715 * Tries to solve the linear programming problem. 716 * If a cached simplified version of the problem exists, it is used instead. 717 * 718 * @return the result of the solving attempt 719 */ 720 ResultType 721 LinearSpec::Solve() 722 { 723 if (fLpPresolved != NULL) 724 return _Presolve(); 725 726 bigtime_t start, end; 727 start = system_time(); 728 729 fResult = (ResultType)solve(fLP); 730 fObjectiveValue = get_objective(fLP); 731 732 if (fResult == OPTIMAL) { 733 int32 size = fVariables.CountItems(); 734 double x[size]; 735 if (!get_variables(fLP, &x[0])) 736 printf("Error in get_variables.\n"); 737 738 int32 i = 0; 739 while (i < size) { 740 ((Variable*)fVariables.ItemAt(i))->SetValue(x[i]); 741 i++; 742 } 743 } 744 745 end = system_time(); 746 fSolvingTime = (end - start) / 1000.0; 747 748 return fResult; 749 } 750 751 752 /** 753 * Writes the specification into a text file. 754 * The file will be overwritten if it exists. 755 * 756 * @param fname the file name 757 */ 758 void 759 LinearSpec::Save(const char* fileName) 760 { 761 // TODO: Constness should be fixed in liblpsolve API. 762 write_lp(fLP, const_cast<char*>(fileName)); 763 } 764 765 766 /** 767 * Gets the current optimization. 768 * The default is minimization. 769 * 770 * @return the current optimization 771 */ 772 OptimizationType 773 LinearSpec::Optimization() const 774 { 775 return fOptimization; 776 } 777 778 779 /** 780 * Sets whether the solver should minimize or maximize the objective function. 781 * The default is minimization. 782 * 783 * @param optimization the optimization type 784 */ 785 void 786 LinearSpec::SetOptimization(OptimizationType value) 787 { 788 fOptimization = value; 789 if (fOptimization == MINIMIZE) 790 set_minim(fLP); 791 else 792 set_maxim(fLP); 793 } 794 795 796 /** 797 * Gets the constraints. 798 * 799 * @return the constraints 800 */ 801 const ConstraintList& 802 LinearSpec::Constraints() const 803 { 804 return fConstraints; 805 } 806 807 808 /** 809 * Gets the result type. 810 * 811 * @return the result type 812 */ 813 ResultType 814 LinearSpec::Result() const 815 { 816 return fResult; 817 } 818 819 820 /** 821 * Gets the objective value. 822 * 823 * @return the objective value 824 */ 825 double 826 LinearSpec::ObjectiveValue() const 827 { 828 return fObjectiveValue; 829 } 830 831 832 /** 833 * Gets the solving time. 834 * 835 * @return the solving time 836 */ 837 double 838 LinearSpec::SolvingTime() const 839 { 840 return fSolvingTime; 841 } 842 843 844 LinearSpec::operator BString() const 845 { 846 BString string; 847 GetString(string); 848 return string; 849 } 850 851 852 void 853 LinearSpec::GetString(BString& string) const 854 { 855 string << "LinearSpec " << (int32)this << ":\n"; 856 for (int i = 0; i < fVariables.CountItems(); i++) { 857 Variable* variable = static_cast<Variable*>(fVariables.ItemAt(i)); 858 variable->GetString(string); 859 string << "=" << (float)variable->Value() << " "; 860 } 861 string << "\n"; 862 for (int i = 0; i < fConstraints.CountItems(); i++) { 863 Constraint* c = static_cast<Constraint*>(fConstraints.ItemAt(i)); 864 string << i << ": "; 865 c->GetString(string); 866 string << "\n"; 867 } 868 string << "Result="; 869 if (fResult==-1) 870 string << "ERROR"; 871 else if (fResult==0) 872 string << "OPTIMAL"; 873 else if (fResult==1) 874 string << "SUBOPTIMAL"; 875 else if (fResult==2) 876 string << "INFEASIBLE"; 877 else if (fResult==3) 878 string << "UNBOUNDED"; 879 else if (fResult==4) 880 string << "DEGENERATE"; 881 else if (fResult==5) 882 string << "NUMFAILURE"; 883 else 884 string << fResult; 885 string << " SolvingTime=" << (float)fSolvingTime << "ms"; 886 } 887 888