BTRFS: Reimplement TreeIterator, add some error checks and remove redundancies.
[haiku.git] / src / libs / linprog / LinearSpec.cpp
blobbdb5d398842c4bb967901f394fd2c098015ccafe
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 */
9 #include "LinearSpec.h"
11 #include <new>
13 #include "ActiveSetSolver.h"
16 using namespace LinearProgramming;
19 // #define DEBUG_LINEAR_SPECIFICATIONS
21 #ifdef DEBUG_LINEAR_SPECIFICATIONS
22 #include <stdio.h>
23 #define TRACE(x...) printf(x)
24 #else
25 #define TRACE(x...) /* nothing */
26 #endif
29 SolverInterface::SolverInterface(LinearSpec* linSpec)
31 fLinearSpec(linSpec)
37 SolverInterface::~SolverInterface()
42 bool
43 SolverInterface::AddConstraint(Constraint* constraint, bool notifyListener)
45 return fLinearSpec->AddConstraint(constraint, notifyListener);
49 bool
50 SolverInterface::RemoveConstraint(Constraint* constraint, bool deleteConstraint,
51 bool notifyListener)
53 return fLinearSpec->RemoveConstraint(constraint, deleteConstraint,
54 notifyListener);
58 SpecificationListener::~SpecificationListener()
63 void
64 SpecificationListener::VariableAdded(Variable* variable)
69 void
70 SpecificationListener::VariableRemoved(Variable* variable)
75 void
76 SpecificationListener::ConstraintAdded(Constraint* constraint)
81 void
82 SpecificationListener::ConstraintRemoved(Constraint* constraint)
87 /**
88 * Constructor.
89 * Creates a new specification for a linear programming problem.
91 LinearSpec::LinearSpec()
93 fResult(kError),
94 fSolvingTime(0)
96 fSolver = new ActiveSetSolver(this);
101 * Destructor.
102 * Removes the specification and deletes all constraints,
103 * objective function summands and variables.
105 LinearSpec::~LinearSpec()
107 for (int32 i = 0; i < fConstraints.CountItems(); i++)
108 delete (Constraint*)fConstraints.ItemAt(i);
109 while (fVariables.CountItems() > 0)
110 RemoveVariable(fVariables.ItemAt(0));
112 delete fSolver;
116 bool
117 LinearSpec::AddListener(SpecificationListener* listener)
119 return fListeners.AddItem(listener);
123 bool
124 LinearSpec::RemoveListener(SpecificationListener* listener)
126 return fListeners.RemoveItem(listener);
131 * Adds a new variable to the specification.
133 * @return the new variable
135 Variable*
136 LinearSpec::AddVariable()
138 Variable* variable = new(std::nothrow) Variable(this);
139 if (!variable)
140 return NULL;
141 if (!AddVariable(variable)) {
142 delete variable;
143 return NULL;
146 return variable;
150 bool
151 LinearSpec::AddVariable(Variable* variable)
153 if (variable->IsValid())
154 return false;
156 if (!fVariables.AddItem(variable))
157 return false;
159 if (variable->fLS == NULL)
160 variable->fLS = this;
162 if (!fSolver->VariableAdded(variable)) {
163 fVariables.RemoveItem(variable);
164 return false;
166 variable->fIsValid = true;
168 if (!UpdateRange(variable)) {
169 RemoveVariable(variable, false);
170 return false;
173 for (int32 i = 0; i < fListeners.CountItems(); i++)
174 fListeners.ItemAt(i)->VariableAdded(variable);
176 return true;
180 bool
181 LinearSpec::RemoveVariable(Variable* variable, bool deleteVariable)
183 // must be called first otherwise the index is invalid
184 if (fSolver->VariableRemoved(variable) == false)
185 return false;
187 // do we know the variable?
188 if (fVariables.RemoveItem(variable) == false)
189 return false;
190 fUsedVariables.RemoveItem(variable);
191 variable->fIsValid = false;
193 // invalidate all constraints that use this variable
194 ConstraintList markedForInvalidation;
195 const ConstraintList& constraints = Constraints();
196 for (int i = 0; i < constraints.CountItems(); i++) {
197 Constraint* constraint = constraints.ItemAt(i);
199 SummandList* summands = constraint->LeftSide();
200 for (int j = 0; j < summands->CountItems(); j++) {
201 Summand* summand = summands->ItemAt(j);
202 if (summand->Var() == variable) {
203 markedForInvalidation.AddItem(constraint);
204 break;
208 for (int i = 0; i < markedForInvalidation.CountItems(); i++)
209 RemoveConstraint(markedForInvalidation.ItemAt(i));
211 if (deleteVariable)
212 delete variable;
214 for (int32 i = 0; i < fListeners.CountItems(); i++)
215 fListeners.ItemAt(i)->VariableRemoved(variable);
217 return true;
221 int32
222 LinearSpec::IndexOf(const Variable* variable) const
224 return fUsedVariables.IndexOf(variable);
228 int32
229 LinearSpec::GlobalIndexOf(const Variable* variable) const
231 return fVariables.IndexOf(variable);
235 bool
236 LinearSpec::UpdateRange(Variable* variable)
238 if (!fSolver->VariableRangeChanged(variable))
239 return false;
240 return true;
244 bool
245 LinearSpec::AddConstraint(Constraint* constraint)
247 return AddConstraint(constraint, true);
251 bool
252 LinearSpec::RemoveConstraint(Constraint* constraint, bool deleteConstraint)
254 return RemoveConstraint(constraint, deleteConstraint, true);
258 bool
259 LinearSpec::AddConstraint(Constraint* constraint, bool notifyListener)
261 if (!fConstraints.AddItem(constraint))
262 return false;
264 // ref count the used variables
265 SummandList* leftSide = constraint->LeftSide();
266 for (int i = 0; i < leftSide->CountItems(); i++) {
267 Variable* var = leftSide->ItemAt(i)->Var();
268 _AddConstraintRef(var);
271 if (!fSolver->ConstraintAdded(constraint)) {
272 RemoveConstraint(constraint, false);
273 return false;
276 constraint->fLS = this;
278 if (notifyListener) {
279 for (int32 i = 0; i < fListeners.CountItems(); i++)
280 fListeners.ItemAt(i)->ConstraintAdded(constraint);
283 return true;
287 bool
288 LinearSpec::RemoveConstraint(Constraint* constraint, bool deleteConstraint,
289 bool notifyListener)
291 if (constraint == NULL)
292 return false;
293 fSolver->ConstraintRemoved(constraint);
294 if (!fConstraints.RemoveItem(constraint))
295 return false;
297 SummandList* leftSide = constraint->LeftSide();
298 for (int32 i = 0; i < leftSide->CountItems(); i++) {
299 Variable* var = leftSide->ItemAt(i)->Var();
300 _RemoveConstraintRef(var);
303 if (notifyListener) {
304 for (int32 i = 0; i < fListeners.CountItems(); i++)
305 fListeners.ItemAt(i)->ConstraintRemoved(constraint);
308 constraint->fLS = NULL;
309 if (deleteConstraint)
310 delete constraint;
312 return true;
316 void
317 LinearSpec::_AddConstraintRef(Variable* var)
319 if (var->AddReference() == 1)
320 fUsedVariables.AddItem(var);
324 void
325 LinearSpec::_RemoveConstraintRef(Variable* var)
327 if (var->RemoveReference() == 0)
328 fUsedVariables.RemoveItem(var);
332 bool
333 LinearSpec::UpdateLeftSide(Constraint* constraint,
334 const SummandList* oldSummands)
336 SummandList* leftSide = constraint->LeftSide();
337 if (leftSide != NULL) {
338 for (int32 i = 0; i < leftSide->CountItems(); i++) {
339 Variable* var = leftSide->ItemAt(i)->Var();
340 _AddConstraintRef(var);
343 if (oldSummands != NULL) {
344 // the summands have changed, update the var ref count
345 for (int32 i = 0; i < oldSummands->CountItems(); i++) {
346 Variable* var = oldSummands->ItemAt(i)->Var();
347 _RemoveConstraintRef(var);
351 if (!fSolver->LeftSideChanged(constraint))
352 return false;
353 return true;
357 bool
358 LinearSpec::UpdateRightSide(Constraint* constraint)
360 if (!fSolver->RightSideChanged(constraint))
361 return false;
362 return true;
366 bool
367 LinearSpec::UpdateOperator(Constraint* constraint)
369 if (!fSolver->OperatorChanged(constraint))
370 return false;
371 return true;
375 bool
376 LinearSpec::UpdatePenalties(Constraint* constraint)
378 if (!fSolver->PenaltiesChanged(constraint))
379 return false;
380 return true;
385 * Adds a new soft linear constraint to the specification.
386 * i.e. a constraint that does not always have to be satisfied.
388 * @param coeffs the constraint's coefficients
389 * @param vars the constraint's variables
390 * @param op the constraint's operand
391 * @param rightSide the constant value on the constraint's right side
392 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution
393 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution
395 Constraint*
396 LinearSpec::AddConstraint(SummandList* summands, OperatorType op,
397 double rightSide, double penaltyNeg, double penaltyPos)
399 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
404 * Adds a new soft linear constraint to the specification with a single summand.
406 * @param coeff1 the constraint's first coefficient
407 * @param var1 the constraint's first variable
408 * @param op the constraint's operand
409 * @param rightSide the constant value on the constraint's right side
410 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution
411 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution
413 Constraint*
414 LinearSpec::AddConstraint(double coeff1, Variable* var1,
415 OperatorType op, double rightSide, double penaltyNeg, double penaltyPos)
417 SummandList* summands = new(std::nothrow) SummandList(1);
418 if (!summands)
419 return NULL;
420 summands->AddItem(new(std::nothrow) Summand(coeff1, var1));
421 if (!_CheckSummandList(summands))
422 return NULL;
423 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
428 * Adds a new soft linear constraint to the specification with two summands.
430 * @param coeff1 the constraint's first coefficient
431 * @param var1 the constraint's first variable
432 * @param coeff2 the constraint's second coefficient
433 * @param var2 the constraint's second variable
434 * @param op the constraint's operand
435 * @param rightSide the constant value on the constraint's right side
436 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution
437 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution
439 Constraint*
440 LinearSpec::AddConstraint(double coeff1, Variable* var1,
441 double coeff2, Variable* var2, OperatorType op, double rightSide,
442 double penaltyNeg, double penaltyPos)
444 SummandList* summands = new(std::nothrow) SummandList(2);
445 if (!summands)
446 return NULL;
447 summands->AddItem(new(std::nothrow) Summand(coeff1, var1));
448 summands->AddItem(new(std::nothrow) Summand(coeff2, var2));
449 if (!_CheckSummandList(summands))
450 return NULL;
451 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
456 * Adds a new soft linear constraint to the specification with three summands.
458 * @param coeff1 the constraint's first coefficient
459 * @param var1 the constraint's first variable
460 * @param coeff2 the constraint's second coefficient
461 * @param var2 the constraint's second variable
462 * @param coeff3 the constraint's third coefficient
463 * @param var3 the constraint's third variable
464 * @param op the constraint's operand
465 * @param rightSide the constant value on the constraint's right side
466 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution
467 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution
469 Constraint*
470 LinearSpec::AddConstraint(double coeff1, Variable* var1,
471 double coeff2, Variable* var2, double coeff3, Variable* var3,
472 OperatorType op, double rightSide, double penaltyNeg, double penaltyPos)
474 SummandList* summands = new(std::nothrow) SummandList(2);
475 if (!summands)
476 return NULL;
477 summands->AddItem(new(std::nothrow) Summand(coeff1, var1));
478 summands->AddItem(new(std::nothrow) Summand(coeff2, var2));
479 summands->AddItem(new(std::nothrow) Summand(coeff3, var3));
480 if (!_CheckSummandList(summands))
481 return NULL;
482 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
487 * Adds a new soft linear constraint to the specification with four summands.
489 * @param coeff1 the constraint's first coefficient
490 * @param var1 the constraint's first variable
491 * @param coeff2 the constraint's second coefficient
492 * @param var2 the constraint's second variable
493 * @param coeff3 the constraint's third coefficient
494 * @param var3 the constraint's third variable
495 * @param coeff4 the constraint's fourth coefficient
496 * @param var4 the constraint's fourth variable
497 * @param op the constraint's operand
498 * @param rightSide the constant value on the constraint's right side
499 * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution
500 * @param penaltyPos the coefficient penalizing positive deviations from the exact solution
502 Constraint*
503 LinearSpec::AddConstraint(double coeff1, Variable* var1,
504 double coeff2, Variable* var2, double coeff3, Variable* var3,
505 double coeff4, Variable* var4, OperatorType op, double rightSide,
506 double penaltyNeg, double penaltyPos)
508 SummandList* summands = new(std::nothrow) SummandList(2);
509 if (!summands)
510 return NULL;
511 summands->AddItem(new(std::nothrow) Summand(coeff1, var1));
512 summands->AddItem(new(std::nothrow) Summand(coeff2, var2));
513 summands->AddItem(new(std::nothrow) Summand(coeff3, var3));
514 summands->AddItem(new(std::nothrow) Summand(coeff4, var4));
515 if (!_CheckSummandList(summands))
516 return NULL;
517 return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
521 ResultType
522 LinearSpec::FindMins(const VariableList* variables)
524 fResult = fSolver->FindMins(variables);
525 return fResult;
529 ResultType
530 LinearSpec::FindMaxs(const VariableList* variables)
532 fResult = fSolver->FindMaxs(variables);
533 return fResult;
537 bool
538 LinearSpec::_CheckSummandList(SummandList* list)
540 bool ok = true;
541 for (int i = 0; i < list->CountItems(); i++) {
542 if (list->ItemAt(i) == NULL) {
543 ok = false;
544 break;
547 if (ok)
548 return true;
550 for (int i = 0; i < list->CountItems(); i++)
551 delete list->ItemAt(i);
552 delete list;
553 return false;
557 Constraint*
558 LinearSpec::_AddConstraint(SummandList* leftSide, OperatorType op,
559 double rightSide, double penaltyNeg, double penaltyPos)
561 Constraint* constraint = new(std::nothrow) Constraint(this, leftSide,
562 op, rightSide, penaltyNeg, penaltyPos);
563 if (constraint == NULL)
564 return NULL;
565 if (!AddConstraint(constraint)) {
566 delete constraint;
567 return NULL;
569 return constraint;
573 #ifdef DEBUG_LINEAR_SPECIFICATIONS
574 static bigtime_t sAverageSolvingTime = 0;
575 static int32 sSolvedCount = 0;
576 #endif
579 ResultType
580 LinearSpec::Solve()
582 bigtime_t startTime = system_time();
584 fResult = fSolver->Solve();
586 fSolvingTime = system_time() - startTime;
588 #ifdef DEBUG_LINEAR_SPECIFICATIONS
589 sAverageSolvingTime += fSolvingTime;
590 sSolvedCount++;
591 TRACE("Solving time %i average %i [micro s]\n", (int)fSolvingTime,
592 int(sAverageSolvingTime / sSolvedCount));
593 #endif
595 return fResult;
600 * Writes the specification into a text file.
601 * The file will be overwritten if it exists.
603 * @param fname the file name
605 bool
606 LinearSpec::Save(const char* fileName)
608 return fSolver->SaveModel(fileName) == B_OK;
613 * Gets the constraints generated by calls to Variable::SetRange()
616 void
617 LinearSpec::GetRangeConstraints(const Variable* var, const Constraint** _min,
618 const Constraint** _max) const
620 fSolver->GetRangeConstraints(var, _min, _max);
625 * Gets the constraints.
627 * @return the constraints
629 const ConstraintList&
630 LinearSpec::Constraints() const
632 return fConstraints;
636 const VariableList&
637 LinearSpec::UsedVariables() const
639 return fUsedVariables;
643 const VariableList&
644 LinearSpec::AllVariables() const
646 return fVariables;
651 * Gets the result type.
653 * @return the result type
655 ResultType
656 LinearSpec::Result() const
658 return fResult;
663 * Gets the solving time.
665 * @return the solving time
667 bigtime_t
668 LinearSpec::SolvingTime() const
670 return fSolvingTime;
674 BString
675 LinearSpec::ToString() const
677 BString string;
678 string << "LinearSpec " << (addr_t)this << ":\n";
679 for (int i = 0; i < fVariables.CountItems(); i++) {
680 Variable* variable = fVariables.ItemAt(i);
681 string += variable->ToString();
682 string << "=" << (float)variable->Value() << " ";
684 string << "\n";
685 for (int i = 0; i < fConstraints.CountItems(); i++) {
686 Constraint* c = fConstraints.ItemAt(i);
687 string << i << ": ";
688 string += c->ToString();
689 string << "\n";
691 string << "Result=";
692 if (fResult == kError)
693 string << "kError";
694 else if (fResult == kOptimal)
695 string << "kOptimal";
696 else if (fResult == kSuboptimal)
697 string << "kSuboptimal";
698 else if (fResult == kInfeasible)
699 string << "kInfeasible";
700 else if (fResult == kUnbounded)
701 string << "kUnbounded";
702 else if (fResult == kDegenerate)
703 string << "kDegenerate";
704 else if (fResult == kNumFailure)
705 string << "kNumFailure";
706 else
707 string << fResult;
708 string << " SolvingTime=" << fSolvingTime << "micro s";
709 return string;