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 "ActiveSetSolver.h"
#include <algorithm>
#include <stdio.h> #include <stdio.h>
#include "LayoutOptimizer.h" #include "LayoutOptimizer.h"
@@ -16,17 +26,7 @@
using namespace LinearProgramming; using namespace LinearProgramming;
//using namespace BPrivate::Layout; using namespace std;
template<typename Type>
static inline void
swap(Type& a, Type& b)
{
Type c = a;
a = b;
b = c;
}
EquationSystem::EquationSystem(int32 rows, int32 columns) EquationSystem::EquationSystem(int32 rows, int32 columns)
@@ -273,7 +273,7 @@ EquationSystem::Print()
ActiveSetSolver::ActiveSetSolver(LinearSpec* linearSpec) ActiveSetSolver::ActiveSetSolver(LinearSpec* linearSpec)
: :
SolverInterface(linearSpec), QPSolverInterface(linearSpec),
fVariables(linearSpec->UsedVariables()), fVariables(linearSpec->UsedVariables()),
fConstraints(linearSpec->Constraints()) fConstraints(linearSpec->Constraints())
@@ -462,14 +462,14 @@ ActiveSetSolver::VariableRangeChanged(Variable* variable)
bool bool
ActiveSetSolver::ConstraintAdded(Constraint* constraint) ActiveSetSolver::ConstraintAdded(Constraint* constraint)
{ {
return true; return QPSolverInterface::ConstraintAdded(constraint);
} }
bool bool
ActiveSetSolver::ConstraintRemoved(Constraint* constraint) ActiveSetSolver::ConstraintRemoved(Constraint* constraint)
{ {
return true; return QPSolverInterface::ConstraintRemoved(constraint);
} }
+2 -2
View File
@@ -6,7 +6,7 @@
#define ACTICE_SET_SOLVER_H #define ACTICE_SET_SOLVER_H
#include "LinearSpec.h" #include "QPSolverInterface.h"
class EquationSystem { class EquationSystem {
@@ -48,7 +48,7 @@ private:
}; };
class ActiveSetSolver : public LinearProgramming::SolverInterface { class ActiveSetSolver : public QPSolverInterface {
public: public:
ActiveSetSolver(LinearSpec* linearSpec); ActiveSetSolver(LinearSpec* linearSpec);
~ActiveSetSolver(); ~ActiveSetSolver();
+4 -5
View File
@@ -310,10 +310,9 @@ Constraint::DPos() const
bool bool
Constraint::IsSoft() const Constraint::IsSoft() const
{ {
if (fPenaltyNeg > 0. && fOp != kLE) if (fOp != kEQ)
return true; return false;
if (fPenaltyNeg > 0. || fPenaltyPos > 0.)
if (fPenaltyPos > 0. && fOp != kGE)
return true; return true;
return false; return false;
} }
@@ -406,7 +405,7 @@ Constraint::~Constraint()
Invalidate(); Invalidate();
for (int32 i = 0; i < fLeftSide->CountItems(); i++) for (int32 i = 0; i < fLeftSide->CountItems(); i++)
delete (Summand*)fLeftSide->ItemAt(i); delete fLeftSide->ItemAt(i);
delete fLeftSide; delete fLeftSide;
fLeftSide = NULL; fLeftSide = NULL;
} }
+3 -2
View File
@@ -7,12 +7,13 @@ UsePrivateHeaders shared ;
StaticLibrary liblinprog.a : StaticLibrary liblinprog.a :
ActiveSetSolver.cpp
Constraint.cpp Constraint.cpp
LayoutOptimizer.cpp
LinearSpec.cpp LinearSpec.cpp
LPSolveInterface.cpp LPSolveInterface.cpp
QPSolverInterface.cpp
Summand.cpp Summand.cpp
Variable.cpp Variable.cpp
LayoutOptimizer.cpp
ActiveSetSolver.cpp
; ;
+7 -3
View File
@@ -112,10 +112,14 @@ LinearSpec::AddVariable(Variable* variable)
bool bool
LinearSpec::RemoveVariable(Variable* variable, bool deleteVariable) LinearSpec::RemoveVariable(Variable* variable, bool deleteVariable)
{ {
// must be called first otherwise the index is invalid // do we know the variable?
if (!fSolver->VariableRemoved(variable)) if (fVariables.RemoveItem(variable) == false)
return 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; variable->fIsValid = false;
// invalidate all constraints that use this variable // 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