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 "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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Clemens Zeidler <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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 <[email protected]>
|
||||||
|
* 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