haiku/src/libs/linprog/Constraint.cpp
Clemens Zeidler 7583db5a1e Add an alternative solver to lp_solve. The solver based on Ingo's active set solver but is able to handle arbitrary hard and soft constraints. The advantage to lp_solve is that the active set solver can optimize variable in respect to a quadratic objective function. This makes it possible to minimise the quadratic derivation to a desired value e.g. \Sum_i(x_i - x_{i,pref})^2 -> min.
The solver part has been refactored in this way that both solver can be used with the same layout specifications. The active set solver is default now; the performance is not as good as lp_solve, though.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40285 a95241bf-73f2-0310-859d-f6bbb57e9c96
2011-01-25 04:59:40 +00:00

406 lines
7.2 KiB
C++

/*
* Copyright 2007-2008, Christof Lutteroth, lutteroth@cs.auckland.ac.nz
* Copyright 2007-2008, James Kim, jkim202@ec.auckland.ac.nz
* Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
* Distributed under the terms of the MIT License.
*/
#include "Constraint.h"
#include <new>
#include <stdio.h>
#include "LinearSpec.h"
#include "Variable.h"
// Toggle debug output
//#define DEBUG_CONSTRAINT
#ifdef DEBUG_CONSTRAINT
# define STRACE(x) debug_printf x
#else
# define STRACE(x) ;
#endif
/**
* Gets the index of the constraint.
*
* @return the index of the constraint
*/
int32
Constraint::Index() const
{
int32 i = fLS->Constraints().IndexOf(this);
if (i == -1)
STRACE(("Constraint not part of fLS->Constraints()."));
return i;
}
/**
* Gets the left side of the constraint.
*
* @return pointer to a BList containing the summands on the left side of the constraint
*/
SummandList*
Constraint::LeftSide()
{
return fLeftSide;
}
/**
* Sets the summands on the left side of the constraint.
* The old summands are NOT deleted.
*
* @param summands a BList containing the Summand objects that make up the new left side
*/
void
Constraint::SetLeftSide(SummandList* summands)
{
if (!fIsValid)
return;
fLeftSide = summands;
fLS->UpdateLeftSide(this);
}
void
Constraint::SetLeftSide(double coeff1, Variable* var1)
{
if (!fIsValid)
return;
for (int i=0; i<fLeftSide->CountItems(); i++)
delete fLeftSide->ItemAt(i);
fLeftSide->MakeEmpty();
fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1));
fLS->UpdateLeftSide(this);
}
void
Constraint::SetLeftSide(double coeff1, Variable* var1,
double coeff2, Variable* var2)
{
if (!fIsValid)
return;
for (int i=0; i<fLeftSide->CountItems(); i++)
delete fLeftSide->ItemAt(i);
fLeftSide->MakeEmpty();
fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1));
fLeftSide->AddItem(new(std::nothrow) Summand(coeff2, var2));
fLS->UpdateLeftSide(this);
}
void
Constraint::SetLeftSide(double coeff1, Variable* var1,
double coeff2, Variable* var2,
double coeff3, Variable* var3)
{
if (!fIsValid)
return;
for (int i=0; i<fLeftSide->CountItems(); i++)
delete fLeftSide->ItemAt(i);
fLeftSide->MakeEmpty();
fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1));
fLeftSide->AddItem(new(std::nothrow) Summand(coeff2, var2));
fLeftSide->AddItem(new(std::nothrow) Summand(coeff3, var3));
fLS->UpdateLeftSide(this);
}
void
Constraint::SetLeftSide(double coeff1, Variable* var1,
double coeff2, Variable* var2,
double coeff3, Variable* var3,
double coeff4, Variable* var4)
{
if (!fIsValid)
return;
for (int i=0; i<fLeftSide->CountItems(); i++)
delete fLeftSide->ItemAt(i);
fLeftSide->MakeEmpty();
fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1));
fLeftSide->AddItem(new(std::nothrow) Summand(coeff2, var2));
fLeftSide->AddItem(new(std::nothrow) Summand(coeff3, var3));
fLeftSide->AddItem(new(std::nothrow) Summand(coeff4, var4));
fLS->UpdateLeftSide(this);
}
/**
* Gets the operator used for this constraint.
*
* @return the operator used for this constraint
*/
OperatorType
Constraint::Op()
{
return fOp;
}
/**
* Sets the operator used for this constraint.
*
* @param value operator
*/
void
Constraint::SetOp(OperatorType value)
{
if (!fIsValid)
return;
fOp = value;
fLS->UpdateOperator(this);
}
/**
* Gets the constant value that is on the right side of the operator.
*
* @return the constant value that is on the right side of the operator
*/
double
Constraint::RightSide() const
{
return fRightSide;
}
/**
* Sets the constant value that is on the right side of the operator.
*
* @param value constant value that is on the right side of the operator
*/
void
Constraint::SetRightSide(double value)
{
if (!fIsValid)
return;
if (fRightSide == value)
return;
fRightSide = value;
fLS->UpdateRightSide(this);
}
/**
* Gets the penalty coefficient for negative deviations.
*
* @return the penalty coefficient
*/
double
Constraint::PenaltyNeg() const
{
return fPenaltyNeg;
}
/**
* The penalty coefficient for negative deviations from the soft constraint's exact solution,&nbsp;
* i.e. if the left side is too large.
*
* @param value coefficient of negative penalty <code>double</code>
*/
void
Constraint::SetPenaltyNeg(double value)
{
fPenaltyNeg = value;
fLS->UpdateLeftSide(this);
}
/**
* Gets the penalty coefficient for positive deviations.
*
* @return the penalty coefficient
*/
double
Constraint::PenaltyPos() const
{
return fPenaltyPos;
}
/**
* The penalty coefficient for negative deviations from the soft constraint's
* exact solution, i.e. if the left side is too small.
* @param value coefficient of positive penalty <code>double</code>
*/
void
Constraint::SetPenaltyPos(double value)
{
fPenaltyPos = value;
fLS->UpdateLeftSide(this);
}
const char*
Constraint::Label()
{
return fLabel.String();
}
void
Constraint::SetLabel(const char* label)
{
fLabel = label;
}
/**
* Gets the slack variable for the negative variations.
*
* @return the slack variable for the negative variations
*/
Variable*
Constraint::DNeg() const
{
if (fDNegObjSummand == NULL)
return NULL;
return fDNegObjSummand->Var();
}
/**
* Gets the slack variable for the positive variations.
*
* @return the slack variable for the positive variations
*/
Variable*
Constraint::DPos() const
{
if (fDPosObjSummand == NULL)
return NULL;
return fDPosObjSummand->Var();
}
bool
Constraint::IsSoft() const
{
if (fPenaltyNeg > 0. && fOp != kLE)
return true;
if (fPenaltyPos > 0. && fOp != kGE)
return true;
return false;
}
bool
Constraint::IsValid()
{
return fIsValid;
}
void
Constraint::Invalidate()
{
STRACE(("Constraint::Invalidate() on %d\n", this));
if (!fIsValid)
return;
fIsValid = false;
fLS->RemoveConstraint(this, false);
}
Constraint::operator BString() const
{
BString string;
GetString(string);
return string;
}
void
Constraint::GetString(BString& string) const
{
string << "Constraint ";
string << fLabel;
string << "(" << (int32)this << "): ";
if (fIsValid) {
for (int i = 0; i < fLeftSide->CountItems(); i++) {
Summand* s = static_cast<Summand*>(fLeftSide->ItemAt(i));
string << (float)s->Coeff() << "*";
string << "x";
string << s->Var()->Index() - 1;
string << " ";
}
string << ((fOp == kEQ) ? "== "
: (fOp == kGE) ? ">= "
: (fOp == kLE) ? "<= "
: "?? ");
string << (float)fRightSide;
string << " PenaltyPos=" << (float)PenaltyPos();
string << " PenaltyNeg=" << (float)PenaltyNeg();
} else
string << "invalid";
}
void
Constraint::PrintToStream()
{
BString string;
GetString(string);
printf("%s\n", string.String());
}
/**
* Constructor.
*/
Constraint::Constraint(LinearSpec* ls, SummandList* summands, OperatorType op,
double rightSide, double penaltyNeg, double penaltyPos)
:
fLS(ls),
fLeftSide(summands),
fOp(op),
fRightSide(rightSide),
fPenaltyNeg(penaltyNeg),
fPenaltyPos(penaltyPos),
fDNegObjSummand(NULL),
fDPosObjSummand(NULL),
fIsValid(true)
{
}
/**
* Destructor.
* Removes the constraint from its specification and deletes all the summands.
*/
Constraint::~Constraint()
{
Invalidate();
for (int32 i = 0; i < fLeftSide->CountItems(); i++)
delete (Summand*)fLeftSide->ItemAt(i);
delete fLeftSide;
fLeftSide = NULL;
}