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 "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
+3 -1
View File
@@ -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)
+3
View File
@@ -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
View File
@@ -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());
+4 -1
View File
@@ -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;
}
+6 -3
View File
@@ -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;
}
+7 -6
View File
@@ -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();
+1
View File
@@ -8,6 +8,7 @@ UsePrivateHeaders shared ;
StaticLibrary liblinprog.a :
Constraint.cpp
LinearSpec.cpp
LPSolveInterface.cpp
Summand.cpp
PenaltyFunction.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 <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);
}
+9 -5
View File
@@ -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);
+9 -9
View File
@@ -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);
}