Add support for soft inequality constraints for quadratic solvers. A slack variable is used in a normal hard inequality and the slack variable is minimized with a high penalty. In this way the constraint is only violated when necessary. Some smaller clean up.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42225 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler
2011-06-18 01:26:31 +00:00
parent 8ef1944247
commit 6c7a658d1c
7 changed files with 170 additions and 26 deletions
+14 -14
View File
@@ -1,5 +1,15 @@
/*
* Copyright 2010 - 2011, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <[email protected]>
*/
#include "ActiveSetSolver.h"
#include <algorithm>
#include <stdio.h>
#include "LayoutOptimizer.h"
@@ -16,17 +26,7 @@
using namespace LinearProgramming;
//using namespace BPrivate::Layout;
template<typename Type>
static inline void
swap(Type& a, Type& b)
{
Type c = a;
a = b;
b = c;
}
using namespace std;
EquationSystem::EquationSystem(int32 rows, int32 columns)
@@ -273,7 +273,7 @@ EquationSystem::Print()
ActiveSetSolver::ActiveSetSolver(LinearSpec* linearSpec)
:
SolverInterface(linearSpec),
QPSolverInterface(linearSpec),
fVariables(linearSpec->UsedVariables()),
fConstraints(linearSpec->Constraints())
@@ -462,14 +462,14 @@ ActiveSetSolver::VariableRangeChanged(Variable* variable)
bool
ActiveSetSolver::ConstraintAdded(Constraint* constraint)
{
return true;
return QPSolverInterface::ConstraintAdded(constraint);
}
bool
ActiveSetSolver::ConstraintRemoved(Constraint* constraint)
{
return true;
return QPSolverInterface::ConstraintRemoved(constraint);
}
+2 -2
View File
@@ -6,7 +6,7 @@
#define ACTICE_SET_SOLVER_H
#include "LinearSpec.h"
#include "QPSolverInterface.h"
class EquationSystem {
@@ -48,7 +48,7 @@ private:
};
class ActiveSetSolver : public LinearProgramming::SolverInterface {
class ActiveSetSolver : public QPSolverInterface {
public:
ActiveSetSolver(LinearSpec* linearSpec);
~ActiveSetSolver();
+4 -5
View File
@@ -310,10 +310,9 @@ Constraint::DPos() const
bool
Constraint::IsSoft() const
{
if (fPenaltyNeg > 0. && fOp != kLE)
return true;
if (fPenaltyPos > 0. && fOp != kGE)
if (fOp != kEQ)
return false;
if (fPenaltyNeg > 0. || fPenaltyPos > 0.)
return true;
return false;
}
@@ -406,7 +405,7 @@ Constraint::~Constraint()
Invalidate();
for (int32 i = 0; i < fLeftSide->CountItems(); i++)
delete (Summand*)fLeftSide->ItemAt(i);
delete fLeftSide->ItemAt(i);
delete fLeftSide;
fLeftSide = NULL;
}
+3 -2
View File
@@ -7,12 +7,13 @@ UsePrivateHeaders shared ;
StaticLibrary liblinprog.a :
ActiveSetSolver.cpp
Constraint.cpp
LayoutOptimizer.cpp
LinearSpec.cpp
LPSolveInterface.cpp
QPSolverInterface.cpp
Summand.cpp
Variable.cpp
LayoutOptimizer.cpp
ActiveSetSolver.cpp
;
+7 -3
View File
@@ -112,10 +112,14 @@ LinearSpec::AddVariable(Variable* variable)
bool
LinearSpec::RemoveVariable(Variable* variable, bool deleteVariable)
{
// must be called first otherwise the index is invalid
if (!fSolver->VariableRemoved(variable))
// do we know the variable?
if (fVariables.RemoveItem(variable) == false)
return false;
fVariables.RemoveItem(variable);
// must be called first otherwise the index is invalid
if (fSolver->VariableRemoved(variable) == false)
return false;
variable->fIsValid = false;
// invalidate all constraints that use this variable
+98
View File
@@ -0,0 +1,98 @@
/*
* Copyright 2011, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler <haiku@clemens-zeidler.de>
*/
#include "QPSolverInterface.h"
using namespace std;
using namespace LinearProgramming;
QPSolverInterface::QPSolverInterface(LinearSpec* linearSpec)
:
SolverInterface(linearSpec)
{
}
QPSolverInterface::~QPSolverInterface()
{
/*for (unsigned int i = 0; i < fInEqSlackConstraints.size(); i++) {
SoftInEqData& data = fInEqSlackConstraints[i];
_DestroyData(data);
}*/
}
bool
QPSolverInterface::ConstraintAdded(Constraint* constraint)
{
if (_IsSoftInequality(constraint) == false)
return true;
SoftInEqData data;
double coeff = -1;
if (constraint->Op() == kGE)
coeff = 1;
data.slack = new Summand(coeff, fLinearSpec->AddVariable());
data.slack->Var()->SetRange(0, 20000);
data.minSlackConstraint = fLinearSpec->AddConstraint(1.,
data.slack->Var(), kEQ, 0., constraint->PenaltyNeg(),
constraint->PenaltyPos());
fInEqSlackConstraints.push_back(data);
SummandList* leftSide = constraint->LeftSide();
leftSide->AddItem(data.slack);
constraint->SetLeftSide(leftSide);
return true;
}
bool
QPSolverInterface::ConstraintRemoved(Constraint* constraint)
{
if (_IsSoftInequality(constraint) == false)
return true;
for (unsigned int i = 0; i < fInEqSlackConstraints.size(); i++) {
SoftInEqData& data = fInEqSlackConstraints[i];
if (data.minSlackConstraint != constraint)
continue;
SummandList* leftSide = constraint->LeftSide();
leftSide->RemoveItem(data.slack);
constraint->SetLeftSide(leftSide);
_DestroyData(data);
fInEqSlackConstraints.erase(fInEqSlackConstraints.begin() + i);
break;
}
return true;
}
void
QPSolverInterface::_DestroyData(SoftInEqData& data)
{
fLinearSpec->RemoveConstraint(data.minSlackConstraint);
fLinearSpec->RemoveVariable(data.slack->Var());
delete data.slack;
}
bool
QPSolverInterface::_IsSoftInequality(Constraint* constraint)
{
if (constraint->PenaltyNeg() <= 0. && constraint->PenaltyPos() <= 0.)
return false;
if (constraint->Op() != kEQ)
return true;
return false;
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
* Distributed under the terms of the MIT License.
*/
#ifndef QP_SOLVER_INTERFACE_H
#define QP_SOLVER_INTERFACE_H
#include "LinearSpec.h"
#include <vector>
/*! The purpose of this class is to manage soft inequality constraints. This is
done by adding a slack variable which is minimized. For example:
$$width - s < maxSize$$
$$s = 0, soft constraint$$
*/
class QPSolverInterface : public LinearProgramming::SolverInterface {
public:
QPSolverInterface(LinearSpec* linearSpec);
virtual ~QPSolverInterface();
virtual bool ConstraintAdded(Constraint* constraint);
virtual bool ConstraintRemoved(Constraint* constraint);
private:
struct SoftInEqData {
Summand* slack;
Constraint* minSlackConstraint;
};
typedef std::vector<SoftInEqData> SoftInEqList;
inline void _DestroyData(SoftInEqData& data);
inline bool _IsSoftInequality(Constraint* constraint);
SoftInEqList fInEqSlackConstraints;
};
#endif // QP_SOLVER_INTERFACE_H