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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user