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:
@@ -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
|
||||
|
||||
@@ -14,7 +14,9 @@ namespace LinearProgramming {
|
||||
* Possible operators for linear constraints.
|
||||
*/
|
||||
enum OperatorType {
|
||||
EQ, LE, GE
|
||||
kEQ,
|
||||
kLE,
|
||||
kGE
|
||||
};
|
||||
|
||||
} // namespace LinearProgramming
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
+11
-12
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Constraint.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "LinearSpec.h"
|
||||
#include "Variable.h"
|
||||
@@ -321,11 +322,11 @@ Constraint::WriteXML(BFile* file)
|
||||
file->Write(buffer, sprintf(buffer, "\t\t</leftside>\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<op>%s</op>\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();
|
||||
|
||||
@@ -8,6 +8,7 @@ UsePrivateHeaders shared ;
|
||||
StaticLibrary liblinprog.a :
|
||||
Constraint.cpp
|
||||
LinearSpec.cpp
|
||||
LPSolveInterface.cpp
|
||||
Summand.cpp
|
||||
PenaltyFunction.cpp
|
||||
Variable.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<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;
|
||||
}
|
||||
@@ -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
@@ -9,6 +9,9 @@
|
||||
#include "LinearSpec.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#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<char*>(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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,12 +4,16 @@
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "PenaltyFunction.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user