diff --git a/headers/libs/linprog/LinearSpec.h b/headers/libs/linprog/LinearSpec.h index 78661ed123..d1af92b567 100644 --- a/headers/libs/linprog/LinearSpec.h +++ b/headers/libs/linprog/LinearSpec.h @@ -22,11 +22,41 @@ #include "Summand.h" #include "Variable.h" -#include "lp_lib.h" - namespace LinearProgramming { +class SolverInterface { +public: + virtual ~SolverInterface() {} + + virtual ResultType Solve(VariableList& variables) = 0; + virtual double GetObjectiveValue() = 0; + + virtual bool AddVariable() = 0; + virtual bool RemoveVariable(int variable) = 0; + virtual bool SetVariableRange(int variable, double min, + double max) = 0; + + virtual bool AddConstraint(int nElements, + double* coefficients, int* variableIndices, + OperatorType op, double rightSide) = 0; + virtual bool RemoveConstraint(int constraint) = 0; + virtual bool SetLeftSide(int constraint, int nElements, + double* coefficients, + int* variableIndices) = 0; + virtual bool SetRightSide(int constraint, double value) = 0; + virtual bool SetOperator(int constraint, + OperatorType op) = 0; + + virtual bool SetObjectiveFunction(int nElements, + double* coefficients, + int* variableIndices) = 0; + virtual bool SetOptimization(OptimizationType value) = 0; + + virtual bool SaveModel(const char* fileName) = 0; +}; + + /*! * Specification of a linear programming problem. */ @@ -40,8 +70,7 @@ public: bool RemoveVariable(Variable* variable, bool deleteVariable = true); int32 IndexOf(const Variable* variable) const; - bool SetRange(Variable* variable, double min, - double max); + bool UpdateRange(Variable* variable); bool AddConstraint(Constraint* constraint); bool RemoveConstraint(Constraint* constraint, @@ -97,7 +126,7 @@ public: void UpdateObjectiveFunction(); ResultType Solve(); - void Save(const char* fileName); + bool Save(const char* fileName); int32 CountColumns() const; OptimizationType Optimization() const; @@ -125,12 +154,8 @@ private: OperatorType op, double rightSide, double penaltyNeg, double penaltyPos); - ResultType _Presolve(); - void _RemovePresolved(); - - lprec* fLpPresolved; OptimizationType fOptimization; - lprec* fLP; + SummandList* fObjFunction; VariableList fVariables; ConstraintList fConstraints; @@ -138,6 +163,7 @@ private: double fObjectiveValue; double fSolvingTime; + SolverInterface* fSolver; }; } // namespace LinearProgramming diff --git a/headers/libs/linprog/OperatorType.h b/headers/libs/linprog/OperatorType.h index 23eb1a7755..48972b6154 100644 --- a/headers/libs/linprog/OperatorType.h +++ b/headers/libs/linprog/OperatorType.h @@ -14,7 +14,9 @@ namespace LinearProgramming { * Possible operators for linear constraints. */ enum OperatorType { - EQ, LE, GE + kEQ, + kLE, + kGE }; } // namespace LinearProgramming diff --git a/src/add-ons/decorators/SATDecorator/SATWindow.cpp b/src/add-ons/decorators/SATDecorator/SATWindow.cpp index c3ef650e54..a492d5fd73 100644 --- a/src/add-ons/decorators/SATDecorator/SATWindow.cpp +++ b/src/add-ons/decorators/SATDecorator/SATWindow.cpp @@ -19,6 +19,7 @@ using namespace BPrivate; +using namespace LinearProgramming; const uint32 kExtentPenalty = 10; @@ -163,27 +164,27 @@ GroupCookie::Init(SATGroup* group, WindowArea* area) // create constraints BRect frame = fSATWindow->CompleteWindowFrame(); - fLeftConstraint = linearSpec->AddConstraint(1.0, fLeftBorder, - OperatorType(EQ), frame.left, 1, 1); - fTopConstraint = linearSpec->AddConstraint(1.0, fTopBorder, - OperatorType(EQ), frame.top, 1, 1); + fLeftConstraint = linearSpec->AddConstraint(1.0, fLeftBorder, kEQ, + frame.left, 1, 1); + fTopConstraint = linearSpec->AddConstraint(1.0, fTopBorder, kEQ, + frame.top, 1, 1); int32 minWidth, maxWidth, minHeight, maxHeight; fSATWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); fMinWidthConstraint = linearSpec->AddConstraint(1.0, fRightBorder, -1.0, - fLeftBorder, OperatorType(GE), minWidth); + fLeftBorder, kGE, minWidth); fMinHeightConstraint = linearSpec->AddConstraint(1.0, fBottomBorder, -1.0, - fTopBorder, OperatorType(GE), minHeight); + fTopBorder, kGE, minHeight); // The width and height constraints have higher penalties than the // position constraints (left, top), so a window will keep its size // unless explicitly resized. fWidthConstraint = linearSpec->AddConstraint(-1.0, fLeftBorder, 1.0, - fRightBorder, OperatorType(EQ), frame.Width(), kExtentPenalty, + fRightBorder, kEQ, frame.Width(), kExtentPenalty, kExtentPenalty); fHeightConstraint = linearSpec->AddConstraint(-1.0, fTopBorder, 1.0, - fBottomBorder, OperatorType(EQ), frame.Height(), kExtentPenalty, + fBottomBorder, kEQ, frame.Height(), kExtentPenalty, kExtentPenalty); if (!fLeftConstraint || !fTopConstraint || !fMinWidthConstraint diff --git a/src/add-ons/decorators/SATDecorator/StackAndTile.h b/src/add-ons/decorators/SATDecorator/StackAndTile.h index 18b125c219..9d5abbcf53 100644 --- a/src/add-ons/decorators/SATDecorator/StackAndTile.h +++ b/src/add-ons/decorators/SATDecorator/StackAndTile.h @@ -20,7 +20,7 @@ #include "WindowList.h" -//#define DEBUG_STACK_AND_TILE +#define DEBUG_STACK_AND_TILE #ifdef DEBUG_STACK_AND_TILE # define STRACE_SAT(x...) debug_printf("SAT: "x) diff --git a/src/libs/alm/ALMLayout.cpp b/src/libs/alm/ALMLayout.cpp index b334479e87..c07f57b050 100644 --- a/src/libs/alm/ALMLayout.cpp +++ b/src/libs/alm/ALMLayout.cpp @@ -17,6 +17,9 @@ #include "ResultType.h" +using namespace LinearProgramming; + + const BSize kUnsetSize(B_SIZE_UNSET, B_SIZE_UNSET); const BSize kMinSize(0, 0); const BSize kMaxSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); diff --git a/src/libs/alm/Area.cpp b/src/libs/alm/Area.cpp index 1a6eda833d..051302f3d8 100644 --- a/src/libs/alm/Area.cpp +++ b/src/libs/alm/Area.cpp @@ -20,6 +20,7 @@ #include "ALMLayout.h" +using namespace LinearProgramming; using namespace std; @@ -361,7 +362,7 @@ Area::SetContentAspectRatio(double ratio) fContentAspectRatioC = NULL; } else if (fContentAspectRatioC == NULL) { fContentAspectRatioC = fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, - ratio, fTop, -ratio, fBottom, OperatorType(EQ), 0.0); + ratio, fTop, -ratio, fBottom, kEQ, 0.0); fConstraints.AddItem(fContentAspectRatioC); } else { fContentAspectRatioC->SetLeftSide(-1.0, fLeft, 1.0, fRight, ratio, @@ -513,7 +514,7 @@ Constraint* Area::SetWidthAs(Area* area, float factor) { return fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, factor, area->Left(), - -factor, area->Right(), OperatorType(EQ), 0.0); + -factor, area->Right(), kEQ, 0.0); } @@ -528,7 +529,7 @@ Constraint* Area::SetHeightAs(Area* area, float factor) { return fLS->AddConstraint(-1.0, fTop, 1.0, fBottom, factor, area->Top(), - -factor, area->Bottom(), OperatorType(EQ), 0.0); + -factor, area->Bottom(), kEQ, 0.0); } @@ -614,20 +615,18 @@ Area::_Init(LinearSpec* ls, XTab* left, YTab* top, XTab* right, YTab* bottom, // adds the two essential constraints of the area that make sure that the // left x-tab is really to the left of the right x-tab, and the top y-tab // really above the bottom y-tab - fMinContentWidth = ls->AddConstraint(-1.0, fLeft, 1.0, fRight, - OperatorType(GE), 0); - fMinContentHeight = ls->AddConstraint(-1.0, fTop, 1.0, fBottom, - OperatorType(GE), 0); + fMinContentWidth = ls->AddConstraint(-1.0, fLeft, 1.0, fRight, kGE, 0); + fMinContentHeight = ls->AddConstraint(-1.0, fTop, 1.0, fBottom, kGE, 0); fConstraints.AddItem(fMinContentWidth); fConstraints.AddItem(fMinContentHeight); fPreferredContentWidth = fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, -1.0, - fScaleWidth, OperatorType(EQ), 0, fShrinkPenalties.Width(), + fScaleWidth, kEQ, 0, fShrinkPenalties.Width(), fGrowPenalties.Width()); fPreferredContentHeight = fLS->AddConstraint(-1.0, fTop, 1.0, fBottom, -1.0, - fScaleHeight, OperatorType(EQ), 0, fShrinkPenalties.Height(), + fScaleHeight, kEQ, 0, fShrinkPenalties.Height(), fGrowPenalties.Height()); fConstraints.AddItem(fPreferredContentWidth); @@ -694,7 +693,7 @@ Area::_UpdateMaxSizeConstraint(BSize max) if (alignment.Vertical() == B_ALIGN_USE_FULL_HEIGHT) { if (fMaxContentHeight == NULL) { fMaxContentHeight = fLS->AddConstraint(-1.0, fTop, 1.0, fBottom, - OperatorType(LE), max.Height()); + kLE, max.Height()); fConstraints.AddItem(fMaxContentHeight); } else fMaxContentHeight->SetRightSide(max.Height()); @@ -707,8 +706,8 @@ Area::_UpdateMaxSizeConstraint(BSize max) if (alignment.Horizontal() == B_ALIGN_USE_FULL_WIDTH) { if (fMaxContentWidth == NULL) { - fMaxContentWidth = fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, - OperatorType(LE), max.Width()); + fMaxContentWidth = fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, kLE, + max.Width()); fConstraints.AddItem(fMaxContentWidth); } else fMaxContentWidth->SetRightSide(max.Width()); diff --git a/src/libs/alm/Column.cpp b/src/libs/alm/Column.cpp index 98f203c188..9f0f2936a6 100644 --- a/src/libs/alm/Column.cpp +++ b/src/libs/alm/Column.cpp @@ -13,6 +13,9 @@ #include "Tab.h" +using namespace LinearProgramming; + + /** * The left boundary of the column. */ @@ -156,7 +159,7 @@ Column::HasSameWidthAs(Column* column) { Constraint* constraint = fLS->AddConstraint( -1.0, Left(), 1.0, Right(), 1.0, column->Left(), -1.0, column->Right(), - OperatorType(EQ), 0.0); + kEQ, 0.0); fConstraints.AddItem(constraint); return constraint; } diff --git a/src/libs/alm/Row.cpp b/src/libs/alm/Row.cpp index 9d90e75322..fb635cb165 100644 --- a/src/libs/alm/Row.cpp +++ b/src/libs/alm/Row.cpp @@ -14,7 +14,10 @@ #include - + +using namespace LinearProgramming; + + /** * The top boundary of the row. */ @@ -159,8 +162,8 @@ Constraint* Row::HasSameHeightAs(Row* row) { Constraint* constraint = fLS->AddConstraint( - -1.0, Top(), 1.0, Bottom(), 1.0, row->Top(), -1.0, row->Bottom(), - OperatorType(EQ), 0.0); + -1.0, Top(), 1.0, Bottom(), 1.0, row->Top(), -1.0, row->Bottom(), kEQ, + 0.0); fConstraints.AddItem(constraint); return constraint; } diff --git a/src/libs/linprog/Constraint.cpp b/src/libs/linprog/Constraint.cpp index 090fc09941..a87ed524b4 100644 --- a/src/libs/linprog/Constraint.cpp +++ b/src/libs/linprog/Constraint.cpp @@ -9,6 +9,7 @@ #include "Constraint.h" #include +#include #include "LinearSpec.h" #include "Variable.h" @@ -321,11 +322,11 @@ Constraint::WriteXML(BFile* file) file->Write(buffer, sprintf(buffer, "\t\t\n")); const char* op = "??"; - if (fOp == OperatorType(EQ)) + if (fOp == kEQ) op = "EQ"; - else if (fOp == OperatorType(LE)) + else if (fOp == kLE) op = "LE"; - else if (fOp == OperatorType(GE)) + else if (fOp == kGE) op = "GE"; file->Write(buffer, sprintf(buffer, "\t\t%s\n", op)); @@ -406,9 +407,9 @@ Constraint::GetString(BString& string) const s->Var()->GetString(string); string << " "; } - string << ((fOp == OperatorType(EQ)) ? "== " - : (fOp == OperatorType(GE)) ? ">= " - : (fOp == OperatorType(LE)) ? "<= " + string << ((fOp == kEQ) ? "== " + : (fOp == kGE) ? ">= " + : (fOp == kLE) ? "<= " : "?? "); string << (float)fRightSide; string << " PenaltyPos=" << (float)PenaltyPos(); diff --git a/src/libs/linprog/Jamfile b/src/libs/linprog/Jamfile index 5431f51e45..8ac0101090 100644 --- a/src/libs/linprog/Jamfile +++ b/src/libs/linprog/Jamfile @@ -8,6 +8,7 @@ UsePrivateHeaders shared ; StaticLibrary liblinprog.a : Constraint.cpp LinearSpec.cpp + LPSolveInterface.cpp Summand.cpp PenaltyFunction.cpp Variable.cpp diff --git a/src/libs/linprog/LPSolveInterface.cpp b/src/libs/linprog/LPSolveInterface.cpp new file mode 100644 index 0000000000..a9d8b6830b --- /dev/null +++ b/src/libs/linprog/LPSolveInterface.cpp @@ -0,0 +1,225 @@ +#include "LPSolveInterface.h" + + +using namespace LinearProgramming; + + +LPSolveInterface::LPSolveInterface() + : + fLpPresolved(NULL), + fLP(NULL) +{ + fLP = make_lp(0, 0); + if (fLP == NULL) + printf("Couldn't construct a new model."); + + // minimize the objective functions, this is the default of lp_solve so we + // don't have to do it here: + // set_minim(fLP); + + set_verbose(fLP, 1); +} + + +LPSolveInterface::~LPSolveInterface() +{ + _RemovePresolved(); + delete_lp(fLP); +} + + +ResultType +LPSolveInterface::Solve(VariableList& variables) +{ + if (fLpPresolved != NULL) + return _Presolve(variables); + + ResultType result = (ResultType)solve(fLP); + + if (result == OPTIMAL) { + int32 size = variables.CountItems(); + double x[size]; + if (!get_variables(fLP, &x[0])) + printf("Error in get_variables.\n"); + + for (int32 i = 0; i < size; i++) + variables.ItemAt(i)->SetValue(x[i]); + } + return result; +} + + +double +LPSolveInterface::GetObjectiveValue() +{ + if (fLpPresolved) + return get_objective(fLpPresolved); + return get_objective(fLP); +} + + +bool +LPSolveInterface::AddVariable() +{ + double d = 0; + int i = 0; + if (!add_columnex(fLP, 0, &d, &i)) + return false; + _RemovePresolved(); + return true; +} + + +bool +LPSolveInterface::RemoveVariable(int variable) +{ + if (!del_column(fLP, variable)) + return false; + _RemovePresolved(); + return true; +} + + +bool +LPSolveInterface::SetVariableRange(int variable, double min, double max) +{ + if (!set_bounds(fLP, variable, min, max)) + return false; + _RemovePresolved(); + return true; +} + + +bool +LPSolveInterface::AddConstraint(int nElements, double* coefficients, + int* variableIndices, OperatorType op, double rightSide) +{ + if (!add_constraintex(fLP, nElements, coefficients, variableIndices, + (op == kEQ ? EQ : (op == kGE) ? GE : LE), rightSide)) { + return false; + } + _RemovePresolved(); + return true; +} + + +bool +LPSolveInterface::RemoveConstraint(int constraint) +{ + if (!del_constraint(fLP, constraint)) + return false; + _RemovePresolved(); + return true; +} + + +bool +LPSolveInterface::SetLeftSide(int constraint, int nElements, + double* coefficients, int* variableIndices) +{ + if (!set_rowex(fLP, constraint, nElements, coefficients, variableIndices)) + return false; + _RemovePresolved(); + return true; +} + + +bool +LPSolveInterface::SetRightSide(int constraint, double value) +{ + if (!set_rh(fLP, constraint, value)) + return false; + _RemovePresolved(); + return true; +} + + +bool +LPSolveInterface::SetOperator(int constraint, OperatorType op) +{ + if (!set_constr_type(fLP, constraint, op == kEQ) ? EQ : (op == kGE) ? GE + : LE) { + return false; + } + _RemovePresolved(); + return true; +} + + +bool +LPSolveInterface::SetObjectiveFunction(int nElements, double* coefficients, + int* variableIndices) +{ + if (!set_obj_fnex(fLP, nElements, coefficients, variableIndices)) + return false; + _RemovePresolved(); + return true; +} + + +bool +LPSolveInterface::SetOptimization(OptimizationType value) +{ + if (value == LinearProgramming::MINIMIZE) + set_minim(fLP); + else + set_maxim(fLP); + return true; +} + + +bool +LPSolveInterface::SaveModel(const char* fileName) +{ + // TODO: Constness should be fixed in liblpsolve API. + if (!write_lp(fLP, const_cast(fileName))) + return false; + return true; +} + + +/** + * Remove a cached presolved model, if existent. + * This is automatically done each time after the model has been changed, + * to avoid an old cached presolved model getting out of sync. + */ +void +LPSolveInterface::_RemovePresolved() +{ + if (fLpPresolved == NULL) + return; + delete_lp(fLpPresolved); + fLpPresolved = NULL; +} + + +/** + * Creates and caches a simplified version of the linear programming problem, + * where redundant rows, columns and constraints are removed, + * if it has not been created before. + * Then, the simplified problem is solved. + * + * @return the result of the solving attempt + */ +ResultType +LPSolveInterface::_Presolve(VariableList& variables) +{ + if (fLpPresolved == NULL) { + fLpPresolved = copy_lp(fLP); + set_presolve(fLpPresolved, PRESOLVE_ROWS | PRESOLVE_COLS + | PRESOLVE_LINDEP, get_presolveloops(fLpPresolved)); + } + + ResultType result = (ResultType)solve(fLpPresolved); + + if (result == OPTIMAL) { + int32 size = variables.CountItems(); + for (int32 i = 0; i < size; i++) { + Variable* current = variables.ItemAt(i); + current->SetValue(get_var_primalresult(fLpPresolved, + get_Norig_rows(fLpPresolved) + current->Index())); + } + } + + return result; +} diff --git a/src/libs/linprog/LPSolveInterface.h b/src/libs/linprog/LPSolveInterface.h new file mode 100644 index 0000000000..7eda73ab52 --- /dev/null +++ b/src/libs/linprog/LPSolveInterface.h @@ -0,0 +1,49 @@ +#ifndef LP_SOLVE_INTERFACE_H +#define LP_SOLVE_INTERFACE_H + + +#include "LinearSpec.h" + +#include "lp_lib.h" + + +class LPSolveInterface : public LinearProgramming::SolverInterface { +public: + LPSolveInterface(); + ~LPSolveInterface(); + + ResultType Solve(VariableList& variables); + double GetObjectiveValue(); + + bool AddVariable(); + bool RemoveVariable(int variable); + bool SetVariableRange(int variable, double min, + double max); + + bool AddConstraint(int nElements, + double* coefficients, int* variableIndices, + OperatorType op, double rightSide); + bool RemoveConstraint(int constraint); + bool SetLeftSide(int constraint, int nElements, + double* coefficients, int* variableIndices); + bool SetRightSide(int constraint, double value); + bool SetOperator(int constraint, + OperatorType op); + + bool SetObjectiveFunction(int nElements, + double* coefficients, + int* variableIndices); + bool SetOptimization(OptimizationType value); + + bool SaveModel(const char* fileName); + +private: + ResultType _Presolve(VariableList& variables); + void _RemovePresolved(); + + lprec* fLpPresolved; + lprec* fLP; +}; + + +#endif // LP_SOLVE_INTERFACE_H diff --git a/src/libs/linprog/LinearSpec.cpp b/src/libs/linprog/LinearSpec.cpp index 66981a2477..79e8e09045 100644 --- a/src/libs/linprog/LinearSpec.cpp +++ b/src/libs/linprog/LinearSpec.cpp @@ -9,6 +9,9 @@ #include "LinearSpec.h" #include +#include + +#include "LPSolveInterface.h" /** @@ -17,22 +20,13 @@ */ LinearSpec::LinearSpec() : - fLpPresolved(NULL), fOptimization(MINIMIZE), fObjFunction(new(std::nothrow) SummandList()), fResult(ERROR), fObjectiveValue(NAN), fSolvingTime(NAN) { - fLP = make_lp(0, 0); - if (fLP == NULL) - printf("Couldn't construct a new model."); - - // minimize the objective functions, this is the default of lp_solve so we - // don't have to do it here: - // set_minim(fLP); - - set_verbose(fLP, 1); + fSolver = new LPSolveInterface; } @@ -43,7 +37,6 @@ LinearSpec::LinearSpec() */ LinearSpec::~LinearSpec() { - _RemovePresolved(); for (int32 i = 0; i < fConstraints.CountItems(); i++) delete (Constraint*)fConstraints.ItemAt(i); for (int32 i = 0; i < fObjFunction->CountItems(); i++) @@ -51,9 +44,8 @@ LinearSpec::~LinearSpec() while (fVariables.CountItems() > 0) RemoveVariable(fVariables.ItemAt(0)); - delete_lp(fLP); - delete fObjFunction; + delete fSolver; } @@ -83,17 +75,14 @@ LinearSpec::AddVariable(Variable* variable) if (variable->IsValid()) return false; - double d = 0; - int i = 0; - if (!fVariables.AddItem(variable)) return false; - if (add_columnex(fLP, 0, &d, &i) == 0) { + if (!fSolver->AddVariable()) { fVariables.RemoveItem(variable); return false; } - if (!SetRange(variable, variable->Min(), variable->Max())) { + if (!UpdateRange(variable)) { RemoveVariable(variable, false); return false; } @@ -110,7 +99,7 @@ LinearSpec::RemoveVariable(Variable* variable, bool deleteVariable) if (index < 0) return false; - if (!del_column(fLP, index)) + if (!fSolver->RemoveVariable(index)) return false; fVariables.RemoveItemAt(index - 1); variable->fIsValid = false; @@ -156,9 +145,12 @@ LinearSpec::IndexOf(const Variable* variable) const bool -LinearSpec::SetRange(Variable* variable, double min, double max) +LinearSpec::UpdateRange(Variable* variable) { - return set_bounds(fLP, IndexOf(variable), min, max); + if (!fSolver->SetVariableRange(IndexOf(variable), variable->Min(), + variable->Max())) + return false; + return true; } @@ -180,7 +172,7 @@ LinearSpec::AddConstraint(Constraint* constraint) varIndexes[nCoefficient] = s->Var()->Index(); } - if (penaltyNeg != INFINITY && penaltyNeg != 0. && op != OperatorType(LE)) { + if (penaltyNeg != INFINITY && penaltyNeg != 0. && op != LE) { constraint->fDNegObjSummand = new(std::nothrow) Summand(constraint->PenaltyNeg(), AddVariable()); @@ -190,7 +182,7 @@ LinearSpec::AddConstraint(Constraint* constraint) nCoefficient++; } - if (penaltyPos != INFINITY && penaltyPos != 0. && op != OperatorType(GE)) { + if (penaltyPos != INFINITY && penaltyPos != 0. && op != GE) { constraint->fDPosObjSummand = new(std::nothrow) Summand(constraint->PenaltyPos(), AddVariable()); @@ -200,10 +192,10 @@ LinearSpec::AddConstraint(Constraint* constraint) nCoefficient++; } - if (!add_constraintex(fLP, nCoefficient, &coeffs[0], &varIndexes[0], - (op == OperatorType(EQ) ? EQ : (op == OperatorType(GE)) ? GE - : LE), rightSide)) + if (!fSolver->AddConstraint(nCoefficient, &coeffs[0], &varIndexes[0], op, + rightSide)) { return false; + } UpdateObjectiveFunction(); fConstraints.AddItem(constraint); @@ -228,7 +220,7 @@ LinearSpec::RemoveConstraint(Constraint* constraint, bool deleteConstraint) constraint->fDPosObjSummand = NULL; } - del_constraint(fLP, constraint->Index()); + fSolver->RemoveConstraint(constraint->Index()); fConstraints.RemoveItem(constraint); constraint->fIsValid = false; @@ -268,12 +260,11 @@ LinearSpec::UpdateLeftSide(Constraint* constraint) i++; } - if (!set_rowex(fLP, constraint->Index(), i, &coeffs[0], + if (!fSolver->SetLeftSide(constraint->Index(), i, &coeffs[0], &varIndexes[0])) return false; UpdateObjectiveFunction(); - _RemovePresolved(); return true; } @@ -281,10 +272,8 @@ LinearSpec::UpdateLeftSide(Constraint* constraint) bool LinearSpec::UpdateRightSide(Constraint* constraint) { - if (!set_rh(fLP, constraint->Index(), constraint->RightSide())) + if (!fSolver->SetRightSide(constraint->Index(), constraint->RightSide())) return false; - - _RemovePresolved(); return true; } @@ -292,13 +281,8 @@ LinearSpec::UpdateRightSide(Constraint* constraint) bool LinearSpec::UpdateOperator(Constraint* constraint) { - OperatorType op = constraint->Op(); - if (!set_constr_type(fLP, constraint->Index(), - (op == OperatorType(EQ)) ? EQ : (op == OperatorType(GE)) ? GE - : LE)) + if (!fSolver->SetOperator(constraint->Index(), constraint->Op())) return false; - - _RemovePresolved(); return true; } @@ -613,10 +597,8 @@ LinearSpec::UpdateObjectiveFunction() varIndexes[i] = current->Var()->Index(); } - if (!set_obj_fnex(fLP, size, &coeffs[0], &varIndexes[0])) + if (!fSolver->SetObjectiveFunction(size, &coeffs[0], &varIndexes[0])) printf("Error in set_obj_fnex.\n"); - - _RemovePresolved(); } @@ -652,65 +634,10 @@ LinearSpec::_AddConstraint(SummandList* leftSide, OperatorType op, delete constraint; return NULL; } - _RemovePresolved(); return constraint; } -/** - * Remove a cached presolved model, if existent. - * This is automatically done each time after the model has been changed, - * to avoid an old cached presolved model getting out of sync. - */ -void -LinearSpec::_RemovePresolved() -{ - if (fLpPresolved == NULL) - return; - delete_lp(fLpPresolved); - fLpPresolved = NULL; -} - - -/** - * Creates and caches a simplified version of the linear programming problem, - * where redundant rows, columns and constraints are removed, - * if it has not been created before. - * Then, the simplified problem is solved. - * - * @return the result of the solving attempt - */ -ResultType -LinearSpec::_Presolve() -{ - bigtime_t start, end; - start = system_time(); - - if (fLpPresolved == NULL) { - fLpPresolved = copy_lp(fLP); - set_presolve(fLpPresolved, PRESOLVE_ROWS | PRESOLVE_COLS - | PRESOLVE_LINDEP, get_presolveloops(fLpPresolved)); - } - - fResult = (ResultType)solve(fLpPresolved); - fObjectiveValue = get_objective(fLpPresolved); - - if (fResult == OPTIMAL) { - int32 size = fVariables.CountItems(); - for (int32 i = 0; i < size; i++) { - Variable* current = (Variable*)fVariables.ItemAt(i); - current->SetValue(get_var_primalresult(fLpPresolved, - get_Norig_rows(fLpPresolved) + current->Index())); - } - } - - end = system_time(); - fSolvingTime = (end - start) / 1000.0; - - return fResult; -} - - /** * Tries to solve the linear programming problem. * If a cached simplified version of the problem exists, it is used instead. @@ -720,27 +647,11 @@ LinearSpec::_Presolve() ResultType LinearSpec::Solve() { - if (fLpPresolved != NULL) - return _Presolve(); - bigtime_t start, end; start = system_time(); - fResult = (ResultType)solve(fLP); - fObjectiveValue = get_objective(fLP); - - if (fResult == OPTIMAL) { - int32 size = fVariables.CountItems(); - double x[size]; - if (!get_variables(fLP, &x[0])) - printf("Error in get_variables.\n"); - - int32 i = 0; - while (i < size) { - ((Variable*)fVariables.ItemAt(i))->SetValue(x[i]); - i++; - } - } + fResult = fSolver->Solve(fVariables); + fObjectiveValue = fSolver->GetObjectiveValue(); end = system_time(); fSolvingTime = (end - start) / 1000.0; @@ -755,11 +666,10 @@ LinearSpec::Solve() * * @param fname the file name */ -void +bool LinearSpec::Save(const char* fileName) { - // TODO: Constness should be fixed in liblpsolve API. - write_lp(fLP, const_cast(fileName)); + return fSolver->SaveModel(fileName) == B_OK; } @@ -786,10 +696,7 @@ void LinearSpec::SetOptimization(OptimizationType value) { fOptimization = value; - if (fOptimization == MINIMIZE) - set_minim(fLP); - else - set_maxim(fLP); + fSolver->SetOptimization(value); } diff --git a/src/libs/linprog/PenaltyFunction.cpp b/src/libs/linprog/PenaltyFunction.cpp index 8047ccc5fa..481029f6ad 100644 --- a/src/libs/linprog/PenaltyFunction.cpp +++ b/src/libs/linprog/PenaltyFunction.cpp @@ -4,12 +4,16 @@ * Distributed under the terms of the MIT License. */ + #include "PenaltyFunction.h" + +#include + #include "Constraint.h" -#include "Summand.h" -#include "OperatorType.h" -#include "Variable.h" #include "LinearSpec.h" +#include "OperatorType.h" +#include "Summand.h" +#include "Variable.h" /** @@ -34,14 +38,14 @@ PenaltyFunction::PenaltyFunction(LinearSpec* ls, Variable* var, BList* xs, BList fConstraints = new BList(sizeGs + 1); fObjFunctionSummands = new BList(sizeGs); - fConstraints->AddItem(ls->AddConstraint(1.0, var, OperatorType(EQ), + fConstraints->AddItem(ls->AddConstraint(1.0, var, kEQ, *(double*)(xs->ItemAt(0)), -*(double*)(gs->ItemAt(0)), *(double*)(gs->ItemAt(1)))); for (int32 i = 1; i < sizeGs; i++) { Variable* dPos = ls->AddVariable(); - fConstraints->AddItem(ls->AddConstraint(1.0, var, -1.0, dPos, OperatorType(LE), + fConstraints->AddItem(ls->AddConstraint(1.0, var, -1.0, dPos, kLE, *(double*)(xs->ItemAt(i)))); Summand* objSummand = new Summand(*(double*)(gs->ItemAt(i + 1)) - *(double*)(gs->ItemAt(i)), dPos); diff --git a/src/libs/linprog/Variable.cpp b/src/libs/linprog/Variable.cpp index dc84a81942..3419b273f1 100644 --- a/src/libs/linprog/Variable.cpp +++ b/src/libs/linprog/Variable.cpp @@ -135,7 +135,7 @@ Variable::SetRange(double min, double max) fMin = min; fMax = max; - fLS->SetRange(this, fMin, fMax); + fLS->UpdateRange(this); } @@ -196,7 +196,7 @@ Variable::IsEqual(Variable* var) if (!fIsValid) return NULL; - return fLS->AddConstraint(1.0, this, -1.0, var, OperatorType(EQ), 0.0); + return fLS->AddConstraint(1.0, this, -1.0, var, kEQ, 0.0); } @@ -212,7 +212,7 @@ Variable::IsSmallerOrEqual(Variable* var) if (!fIsValid) return NULL; - return fLS->AddConstraint(1.0, this, -1.0, var, OperatorType(LE), 0.0); + return fLS->AddConstraint(1.0, this, -1.0, var, kLE, 0.0); } @@ -228,7 +228,7 @@ Variable::IsGreaterOrEqual(Variable* var) if (!fIsValid) return NULL; - return fLS->AddConstraint(-1.0, var, 1.0, this, OperatorType(GE), 0.0); + return fLS->AddConstraint(-1.0, var, 1.0, this, kGE, 0.0); } @@ -238,7 +238,7 @@ Variable::IsEqual(Variable* var, double penaltyNeg, double penaltyPos) if (!fIsValid) return NULL; - return fLS->AddConstraint(1.0, this, -1.0, var, OperatorType(EQ), 0.0, + return fLS->AddConstraint(1.0, this, -1.0, var, kEQ, 0.0, penaltyNeg, penaltyPos); } @@ -249,8 +249,8 @@ Variable::IsSmallerOrEqual(Variable* var, double penaltyNeg, double penaltyPos) if (!fIsValid) return NULL; - return fLS->AddConstraint(1.0, this, -1.0, var, OperatorType(LE), 0.0, - penaltyNeg, penaltyPos); + return fLS->AddConstraint(1.0, this, -1.0, var, kLE, 0.0, penaltyNeg, + penaltyPos); } @@ -260,8 +260,8 @@ Variable::IsGreaterOrEqual(Variable* var, double penaltyNeg, double penaltyPos) if (!fIsValid) return NULL; - return fLS->AddConstraint(-1.0, var, 1.0, this, OperatorType(GE), 0.0, - penaltyNeg, penaltyPos); + return fLS->AddConstraint(-1.0, var, 1.0, this, kGE, 0.0, penaltyNeg, + penaltyPos); }