Refactor the linear programming class to use a minimal solver interface class and implement the interface for lp_solve. As a result lp_solve is not visible to the outside any more. This interface could be used to use other solvers as well. Rename operator constants to no clash with lp_solve constants.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39829 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler
2010-12-13 18:41:58 +00:00
parent 654520d700
commit 5440f6fee3
15 changed files with 401 additions and 177 deletions
+36 -10
View File
@@ -22,11 +22,41 @@
#include "Summand.h" #include "Summand.h"
#include "Variable.h" #include "Variable.h"
#include "lp_lib.h"
namespace LinearProgramming { 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. * Specification of a linear programming problem.
*/ */
@@ -40,8 +70,7 @@ public:
bool RemoveVariable(Variable* variable, bool RemoveVariable(Variable* variable,
bool deleteVariable = true); bool deleteVariable = true);
int32 IndexOf(const Variable* variable) const; int32 IndexOf(const Variable* variable) const;
bool SetRange(Variable* variable, double min, bool UpdateRange(Variable* variable);
double max);
bool AddConstraint(Constraint* constraint); bool AddConstraint(Constraint* constraint);
bool RemoveConstraint(Constraint* constraint, bool RemoveConstraint(Constraint* constraint,
@@ -97,7 +126,7 @@ public:
void UpdateObjectiveFunction(); void UpdateObjectiveFunction();
ResultType Solve(); ResultType Solve();
void Save(const char* fileName); bool Save(const char* fileName);
int32 CountColumns() const; int32 CountColumns() const;
OptimizationType Optimization() const; OptimizationType Optimization() const;
@@ -125,12 +154,8 @@ private:
OperatorType op, double rightSide, OperatorType op, double rightSide,
double penaltyNeg, double penaltyPos); double penaltyNeg, double penaltyPos);
ResultType _Presolve();
void _RemovePresolved();
lprec* fLpPresolved;
OptimizationType fOptimization; OptimizationType fOptimization;
lprec* fLP;
SummandList* fObjFunction; SummandList* fObjFunction;
VariableList fVariables; VariableList fVariables;
ConstraintList fConstraints; ConstraintList fConstraints;
@@ -138,6 +163,7 @@ private:
double fObjectiveValue; double fObjectiveValue;
double fSolvingTime; double fSolvingTime;
SolverInterface* fSolver;
}; };
} // namespace LinearProgramming } // namespace LinearProgramming
+3 -1
View File
@@ -14,7 +14,9 @@ namespace LinearProgramming {
* Possible operators for linear constraints. * Possible operators for linear constraints.
*/ */
enum OperatorType { enum OperatorType {
EQ, LE, GE kEQ,
kLE,
kGE
}; };
} // namespace LinearProgramming } // namespace LinearProgramming
@@ -19,6 +19,7 @@
using namespace BPrivate; using namespace BPrivate;
using namespace LinearProgramming;
const uint32 kExtentPenalty = 10; const uint32 kExtentPenalty = 10;
@@ -163,27 +164,27 @@ GroupCookie::Init(SATGroup* group, WindowArea* area)
// create constraints // create constraints
BRect frame = fSATWindow->CompleteWindowFrame(); BRect frame = fSATWindow->CompleteWindowFrame();
fLeftConstraint = linearSpec->AddConstraint(1.0, fLeftBorder, fLeftConstraint = linearSpec->AddConstraint(1.0, fLeftBorder, kEQ,
OperatorType(EQ), frame.left, 1, 1); frame.left, 1, 1);
fTopConstraint = linearSpec->AddConstraint(1.0, fTopBorder, fTopConstraint = linearSpec->AddConstraint(1.0, fTopBorder, kEQ,
OperatorType(EQ), frame.top, 1, 1); frame.top, 1, 1);
int32 minWidth, maxWidth, minHeight, maxHeight; int32 minWidth, maxWidth, minHeight, maxHeight;
fSATWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, fSATWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight,
&maxHeight); &maxHeight);
fMinWidthConstraint = linearSpec->AddConstraint(1.0, fRightBorder, -1.0, fMinWidthConstraint = linearSpec->AddConstraint(1.0, fRightBorder, -1.0,
fLeftBorder, OperatorType(GE), minWidth); fLeftBorder, kGE, minWidth);
fMinHeightConstraint = linearSpec->AddConstraint(1.0, fBottomBorder, -1.0, 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 // The width and height constraints have higher penalties than the
// position constraints (left, top), so a window will keep its size // position constraints (left, top), so a window will keep its size
// unless explicitly resized. // unless explicitly resized.
fWidthConstraint = linearSpec->AddConstraint(-1.0, fLeftBorder, 1.0, fWidthConstraint = linearSpec->AddConstraint(-1.0, fLeftBorder, 1.0,
fRightBorder, OperatorType(EQ), frame.Width(), kExtentPenalty, fRightBorder, kEQ, frame.Width(), kExtentPenalty,
kExtentPenalty); kExtentPenalty);
fHeightConstraint = linearSpec->AddConstraint(-1.0, fTopBorder, 1.0, fHeightConstraint = linearSpec->AddConstraint(-1.0, fTopBorder, 1.0,
fBottomBorder, OperatorType(EQ), frame.Height(), kExtentPenalty, fBottomBorder, kEQ, frame.Height(), kExtentPenalty,
kExtentPenalty); kExtentPenalty);
if (!fLeftConstraint || !fTopConstraint || !fMinWidthConstraint if (!fLeftConstraint || !fTopConstraint || !fMinWidthConstraint
@@ -20,7 +20,7 @@
#include "WindowList.h" #include "WindowList.h"
//#define DEBUG_STACK_AND_TILE #define DEBUG_STACK_AND_TILE
#ifdef DEBUG_STACK_AND_TILE #ifdef DEBUG_STACK_AND_TILE
# define STRACE_SAT(x...) debug_printf("SAT: "x) # define STRACE_SAT(x...) debug_printf("SAT: "x)
+3
View File
@@ -17,6 +17,9 @@
#include "ResultType.h" #include "ResultType.h"
using namespace LinearProgramming;
const BSize kUnsetSize(B_SIZE_UNSET, B_SIZE_UNSET); const BSize kUnsetSize(B_SIZE_UNSET, B_SIZE_UNSET);
const BSize kMinSize(0, 0); const BSize kMinSize(0, 0);
const BSize kMaxSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); const BSize kMaxSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
+11 -12
View File
@@ -20,6 +20,7 @@
#include "ALMLayout.h" #include "ALMLayout.h"
using namespace LinearProgramming;
using namespace std; using namespace std;
@@ -361,7 +362,7 @@ Area::SetContentAspectRatio(double ratio)
fContentAspectRatioC = NULL; fContentAspectRatioC = NULL;
} else if (fContentAspectRatioC == NULL) { } else if (fContentAspectRatioC == NULL) {
fContentAspectRatioC = fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, 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); fConstraints.AddItem(fContentAspectRatioC);
} else { } else {
fContentAspectRatioC->SetLeftSide(-1.0, fLeft, 1.0, fRight, ratio, fContentAspectRatioC->SetLeftSide(-1.0, fLeft, 1.0, fRight, ratio,
@@ -513,7 +514,7 @@ Constraint*
Area::SetWidthAs(Area* area, float factor) Area::SetWidthAs(Area* area, float factor)
{ {
return fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, factor, area->Left(), 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) Area::SetHeightAs(Area* area, float factor)
{ {
return fLS->AddConstraint(-1.0, fTop, 1.0, fBottom, factor, area->Top(), 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 // 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 // left x-tab is really to the left of the right x-tab, and the top y-tab
// really above the bottom y-tab // really above the bottom y-tab
fMinContentWidth = ls->AddConstraint(-1.0, fLeft, 1.0, fRight, fMinContentWidth = ls->AddConstraint(-1.0, fLeft, 1.0, fRight, kGE, 0);
OperatorType(GE), 0); fMinContentHeight = ls->AddConstraint(-1.0, fTop, 1.0, fBottom, kGE, 0);
fMinContentHeight = ls->AddConstraint(-1.0, fTop, 1.0, fBottom,
OperatorType(GE), 0);
fConstraints.AddItem(fMinContentWidth); fConstraints.AddItem(fMinContentWidth);
fConstraints.AddItem(fMinContentHeight); fConstraints.AddItem(fMinContentHeight);
fPreferredContentWidth = fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, -1.0, fPreferredContentWidth = fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, -1.0,
fScaleWidth, OperatorType(EQ), 0, fShrinkPenalties.Width(), fScaleWidth, kEQ, 0, fShrinkPenalties.Width(),
fGrowPenalties.Width()); fGrowPenalties.Width());
fPreferredContentHeight = fLS->AddConstraint(-1.0, fTop, 1.0, fBottom, -1.0, fPreferredContentHeight = fLS->AddConstraint(-1.0, fTop, 1.0, fBottom, -1.0,
fScaleHeight, OperatorType(EQ), 0, fShrinkPenalties.Height(), fScaleHeight, kEQ, 0, fShrinkPenalties.Height(),
fGrowPenalties.Height()); fGrowPenalties.Height());
fConstraints.AddItem(fPreferredContentWidth); fConstraints.AddItem(fPreferredContentWidth);
@@ -694,7 +693,7 @@ Area::_UpdateMaxSizeConstraint(BSize max)
if (alignment.Vertical() == B_ALIGN_USE_FULL_HEIGHT) { if (alignment.Vertical() == B_ALIGN_USE_FULL_HEIGHT) {
if (fMaxContentHeight == NULL) { if (fMaxContentHeight == NULL) {
fMaxContentHeight = fLS->AddConstraint(-1.0, fTop, 1.0, fBottom, fMaxContentHeight = fLS->AddConstraint(-1.0, fTop, 1.0, fBottom,
OperatorType(LE), max.Height()); kLE, max.Height());
fConstraints.AddItem(fMaxContentHeight); fConstraints.AddItem(fMaxContentHeight);
} else } else
fMaxContentHeight->SetRightSide(max.Height()); fMaxContentHeight->SetRightSide(max.Height());
@@ -707,8 +706,8 @@ Area::_UpdateMaxSizeConstraint(BSize max)
if (alignment.Horizontal() == B_ALIGN_USE_FULL_WIDTH) { if (alignment.Horizontal() == B_ALIGN_USE_FULL_WIDTH) {
if (fMaxContentWidth == NULL) { if (fMaxContentWidth == NULL) {
fMaxContentWidth = fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, fMaxContentWidth = fLS->AddConstraint(-1.0, fLeft, 1.0, fRight, kLE,
OperatorType(LE), max.Width()); max.Width());
fConstraints.AddItem(fMaxContentWidth); fConstraints.AddItem(fMaxContentWidth);
} else } else
fMaxContentWidth->SetRightSide(max.Width()); fMaxContentWidth->SetRightSide(max.Width());
+4 -1
View File
@@ -13,6 +13,9 @@
#include "Tab.h" #include "Tab.h"
using namespace LinearProgramming;
/** /**
* The left boundary of the column. * The left boundary of the column.
*/ */
@@ -156,7 +159,7 @@ Column::HasSameWidthAs(Column* column)
{ {
Constraint* constraint = fLS->AddConstraint( Constraint* constraint = fLS->AddConstraint(
-1.0, Left(), 1.0, Right(), 1.0, column->Left(), -1.0, column->Right(), -1.0, Left(), 1.0, Right(), 1.0, column->Left(), -1.0, column->Right(),
OperatorType(EQ), 0.0); kEQ, 0.0);
fConstraints.AddItem(constraint); fConstraints.AddItem(constraint);
return constraint; return constraint;
} }
+6 -3
View File
@@ -14,7 +14,10 @@
#include <SupportDefs.h> #include <SupportDefs.h>
using namespace LinearProgramming;
/** /**
* The top boundary of the row. * The top boundary of the row.
*/ */
@@ -159,8 +162,8 @@ Constraint*
Row::HasSameHeightAs(Row* row) Row::HasSameHeightAs(Row* row)
{ {
Constraint* constraint = fLS->AddConstraint( Constraint* constraint = fLS->AddConstraint(
-1.0, Top(), 1.0, Bottom(), 1.0, row->Top(), -1.0, row->Bottom(), -1.0, Top(), 1.0, Bottom(), 1.0, row->Top(), -1.0, row->Bottom(), kEQ,
OperatorType(EQ), 0.0); 0.0);
fConstraints.AddItem(constraint); fConstraints.AddItem(constraint);
return constraint; return constraint;
} }
+7 -6
View File
@@ -9,6 +9,7 @@
#include "Constraint.h" #include "Constraint.h"
#include <new> #include <new>
#include <stdio.h>
#include "LinearSpec.h" #include "LinearSpec.h"
#include "Variable.h" #include "Variable.h"
@@ -321,11 +322,11 @@ Constraint::WriteXML(BFile* file)
file->Write(buffer, sprintf(buffer, "\t\t</leftside>\n")); file->Write(buffer, sprintf(buffer, "\t\t</leftside>\n"));
const char* op = "??"; const char* op = "??";
if (fOp == OperatorType(EQ)) if (fOp == kEQ)
op = "EQ"; op = "EQ";
else if (fOp == OperatorType(LE)) else if (fOp == kLE)
op = "LE"; op = "LE";
else if (fOp == OperatorType(GE)) else if (fOp == kGE)
op = "GE"; op = "GE";
file->Write(buffer, sprintf(buffer, "\t\t<op>%s</op>\n", op)); file->Write(buffer, sprintf(buffer, "\t\t<op>%s</op>\n", op));
@@ -406,9 +407,9 @@ Constraint::GetString(BString& string) const
s->Var()->GetString(string); s->Var()->GetString(string);
string << " "; string << " ";
} }
string << ((fOp == OperatorType(EQ)) ? "== " string << ((fOp == kEQ) ? "== "
: (fOp == OperatorType(GE)) ? ">= " : (fOp == kGE) ? ">= "
: (fOp == OperatorType(LE)) ? "<= " : (fOp == kLE) ? "<= "
: "?? "); : "?? ");
string << (float)fRightSide; string << (float)fRightSide;
string << " PenaltyPos=" << (float)PenaltyPos(); string << " PenaltyPos=" << (float)PenaltyPos();
+1
View File
@@ -8,6 +8,7 @@ UsePrivateHeaders shared ;
StaticLibrary liblinprog.a : StaticLibrary liblinprog.a :
Constraint.cpp Constraint.cpp
LinearSpec.cpp LinearSpec.cpp
LPSolveInterface.cpp
Summand.cpp Summand.cpp
PenaltyFunction.cpp PenaltyFunction.cpp
Variable.cpp Variable.cpp
+225
View File
@@ -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<char*>(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;
}
+49
View File
@@ -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
+28 -121
View File
@@ -9,6 +9,9 @@
#include "LinearSpec.h" #include "LinearSpec.h"
#include <new> #include <new>
#include <stdio.h>
#include "LPSolveInterface.h"
/** /**
@@ -17,22 +20,13 @@
*/ */
LinearSpec::LinearSpec() LinearSpec::LinearSpec()
: :
fLpPresolved(NULL),
fOptimization(MINIMIZE), fOptimization(MINIMIZE),
fObjFunction(new(std::nothrow) SummandList()), fObjFunction(new(std::nothrow) SummandList()),
fResult(ERROR), fResult(ERROR),
fObjectiveValue(NAN), fObjectiveValue(NAN),
fSolvingTime(NAN) fSolvingTime(NAN)
{ {
fLP = make_lp(0, 0); fSolver = new LPSolveInterface;
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);
} }
@@ -43,7 +37,6 @@ LinearSpec::LinearSpec()
*/ */
LinearSpec::~LinearSpec() LinearSpec::~LinearSpec()
{ {
_RemovePresolved();
for (int32 i = 0; i < fConstraints.CountItems(); i++) for (int32 i = 0; i < fConstraints.CountItems(); i++)
delete (Constraint*)fConstraints.ItemAt(i); delete (Constraint*)fConstraints.ItemAt(i);
for (int32 i = 0; i < fObjFunction->CountItems(); i++) for (int32 i = 0; i < fObjFunction->CountItems(); i++)
@@ -51,9 +44,8 @@ LinearSpec::~LinearSpec()
while (fVariables.CountItems() > 0) while (fVariables.CountItems() > 0)
RemoveVariable(fVariables.ItemAt(0)); RemoveVariable(fVariables.ItemAt(0));
delete_lp(fLP);
delete fObjFunction; delete fObjFunction;
delete fSolver;
} }
@@ -83,17 +75,14 @@ LinearSpec::AddVariable(Variable* variable)
if (variable->IsValid()) if (variable->IsValid())
return false; return false;
double d = 0;
int i = 0;
if (!fVariables.AddItem(variable)) if (!fVariables.AddItem(variable))
return false; return false;
if (add_columnex(fLP, 0, &d, &i) == 0) { if (!fSolver->AddVariable()) {
fVariables.RemoveItem(variable); fVariables.RemoveItem(variable);
return false; return false;
} }
if (!SetRange(variable, variable->Min(), variable->Max())) { if (!UpdateRange(variable)) {
RemoveVariable(variable, false); RemoveVariable(variable, false);
return false; return false;
} }
@@ -110,7 +99,7 @@ LinearSpec::RemoveVariable(Variable* variable, bool deleteVariable)
if (index < 0) if (index < 0)
return false; return false;
if (!del_column(fLP, index)) if (!fSolver->RemoveVariable(index))
return false; return false;
fVariables.RemoveItemAt(index - 1); fVariables.RemoveItemAt(index - 1);
variable->fIsValid = false; variable->fIsValid = false;
@@ -156,9 +145,12 @@ LinearSpec::IndexOf(const Variable* variable) const
bool 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(); varIndexes[nCoefficient] = s->Var()->Index();
} }
if (penaltyNeg != INFINITY && penaltyNeg != 0. && op != OperatorType(LE)) { if (penaltyNeg != INFINITY && penaltyNeg != 0. && op != LE) {
constraint->fDNegObjSummand constraint->fDNegObjSummand
= new(std::nothrow) Summand(constraint->PenaltyNeg(), = new(std::nothrow) Summand(constraint->PenaltyNeg(),
AddVariable()); AddVariable());
@@ -190,7 +182,7 @@ LinearSpec::AddConstraint(Constraint* constraint)
nCoefficient++; nCoefficient++;
} }
if (penaltyPos != INFINITY && penaltyPos != 0. && op != OperatorType(GE)) { if (penaltyPos != INFINITY && penaltyPos != 0. && op != GE) {
constraint->fDPosObjSummand constraint->fDPosObjSummand
= new(std::nothrow) Summand(constraint->PenaltyPos(), = new(std::nothrow) Summand(constraint->PenaltyPos(),
AddVariable()); AddVariable());
@@ -200,10 +192,10 @@ LinearSpec::AddConstraint(Constraint* constraint)
nCoefficient++; nCoefficient++;
} }
if (!add_constraintex(fLP, nCoefficient, &coeffs[0], &varIndexes[0], if (!fSolver->AddConstraint(nCoefficient, &coeffs[0], &varIndexes[0], op,
(op == OperatorType(EQ) ? EQ : (op == OperatorType(GE)) ? GE rightSide)) {
: LE), rightSide))
return false; return false;
}
UpdateObjectiveFunction(); UpdateObjectiveFunction();
fConstraints.AddItem(constraint); fConstraints.AddItem(constraint);
@@ -228,7 +220,7 @@ LinearSpec::RemoveConstraint(Constraint* constraint, bool deleteConstraint)
constraint->fDPosObjSummand = NULL; constraint->fDPosObjSummand = NULL;
} }
del_constraint(fLP, constraint->Index()); fSolver->RemoveConstraint(constraint->Index());
fConstraints.RemoveItem(constraint); fConstraints.RemoveItem(constraint);
constraint->fIsValid = false; constraint->fIsValid = false;
@@ -268,12 +260,11 @@ LinearSpec::UpdateLeftSide(Constraint* constraint)
i++; i++;
} }
if (!set_rowex(fLP, constraint->Index(), i, &coeffs[0], if (!fSolver->SetLeftSide(constraint->Index(), i, &coeffs[0],
&varIndexes[0])) &varIndexes[0]))
return false; return false;
UpdateObjectiveFunction(); UpdateObjectiveFunction();
_RemovePresolved();
return true; return true;
} }
@@ -281,10 +272,8 @@ LinearSpec::UpdateLeftSide(Constraint* constraint)
bool bool
LinearSpec::UpdateRightSide(Constraint* constraint) LinearSpec::UpdateRightSide(Constraint* constraint)
{ {
if (!set_rh(fLP, constraint->Index(), constraint->RightSide())) if (!fSolver->SetRightSide(constraint->Index(), constraint->RightSide()))
return false; return false;
_RemovePresolved();
return true; return true;
} }
@@ -292,13 +281,8 @@ LinearSpec::UpdateRightSide(Constraint* constraint)
bool bool
LinearSpec::UpdateOperator(Constraint* constraint) LinearSpec::UpdateOperator(Constraint* constraint)
{ {
OperatorType op = constraint->Op(); if (!fSolver->SetOperator(constraint->Index(), constraint->Op()))
if (!set_constr_type(fLP, constraint->Index(),
(op == OperatorType(EQ)) ? EQ : (op == OperatorType(GE)) ? GE
: LE))
return false; return false;
_RemovePresolved();
return true; return true;
} }
@@ -613,10 +597,8 @@ LinearSpec::UpdateObjectiveFunction()
varIndexes[i] = current->Var()->Index(); 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"); printf("Error in set_obj_fnex.\n");
_RemovePresolved();
} }
@@ -652,65 +634,10 @@ LinearSpec::_AddConstraint(SummandList* leftSide, OperatorType op,
delete constraint; delete constraint;
return NULL; return NULL;
} }
_RemovePresolved();
return constraint; 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. * Tries to solve the linear programming problem.
* If a cached simplified version of the problem exists, it is used instead. * If a cached simplified version of the problem exists, it is used instead.
@@ -720,27 +647,11 @@ LinearSpec::_Presolve()
ResultType ResultType
LinearSpec::Solve() LinearSpec::Solve()
{ {
if (fLpPresolved != NULL)
return _Presolve();
bigtime_t start, end; bigtime_t start, end;
start = system_time(); start = system_time();
fResult = (ResultType)solve(fLP); fResult = fSolver->Solve(fVariables);
fObjectiveValue = get_objective(fLP); fObjectiveValue = fSolver->GetObjectiveValue();
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++;
}
}
end = system_time(); end = system_time();
fSolvingTime = (end - start) / 1000.0; fSolvingTime = (end - start) / 1000.0;
@@ -755,11 +666,10 @@ LinearSpec::Solve()
* *
* @param fname the file name * @param fname the file name
*/ */
void bool
LinearSpec::Save(const char* fileName) LinearSpec::Save(const char* fileName)
{ {
// TODO: Constness should be fixed in liblpsolve API. return fSolver->SaveModel(fileName) == B_OK;
write_lp(fLP, const_cast<char*>(fileName));
} }
@@ -786,10 +696,7 @@ void
LinearSpec::SetOptimization(OptimizationType value) LinearSpec::SetOptimization(OptimizationType value)
{ {
fOptimization = value; fOptimization = value;
if (fOptimization == MINIMIZE) fSolver->SetOptimization(value);
set_minim(fLP);
else
set_maxim(fLP);
} }
+9 -5
View File
@@ -4,12 +4,16 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include "PenaltyFunction.h" #include "PenaltyFunction.h"
#include <stdio.h>
#include "Constraint.h" #include "Constraint.h"
#include "Summand.h"
#include "OperatorType.h"
#include "Variable.h"
#include "LinearSpec.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); fConstraints = new BList(sizeGs + 1);
fObjFunctionSummands = new BList(sizeGs); 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*)(xs->ItemAt(0)), -*(double*)(gs->ItemAt(0)),
*(double*)(gs->ItemAt(1)))); *(double*)(gs->ItemAt(1))));
for (int32 i = 1; i < sizeGs; i++) { for (int32 i = 1; i < sizeGs; i++) {
Variable* dPos = ls->AddVariable(); 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)))); *(double*)(xs->ItemAt(i))));
Summand* objSummand = new Summand(*(double*)(gs->ItemAt(i + 1)) - *(double*)(gs->ItemAt(i)), dPos); Summand* objSummand = new Summand(*(double*)(gs->ItemAt(i + 1)) - *(double*)(gs->ItemAt(i)), dPos);
+9 -9
View File
@@ -135,7 +135,7 @@ Variable::SetRange(double min, double max)
fMin = min; fMin = min;
fMax = max; fMax = max;
fLS->SetRange(this, fMin, fMax); fLS->UpdateRange(this);
} }
@@ -196,7 +196,7 @@ Variable::IsEqual(Variable* var)
if (!fIsValid) if (!fIsValid)
return NULL; 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) if (!fIsValid)
return NULL; 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) if (!fIsValid)
return NULL; 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) if (!fIsValid)
return NULL; 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); penaltyNeg, penaltyPos);
} }
@@ -249,8 +249,8 @@ Variable::IsSmallerOrEqual(Variable* var, double penaltyNeg, double penaltyPos)
if (!fIsValid) if (!fIsValid)
return NULL; 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, penaltyNeg,
penaltyNeg, penaltyPos); penaltyPos);
} }
@@ -260,8 +260,8 @@ Variable::IsGreaterOrEqual(Variable* var, double penaltyNeg, double penaltyPos)
if (!fIsValid) if (!fIsValid)
return NULL; 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, penaltyNeg,
penaltyNeg, penaltyPos); penaltyPos);
} }