diff --git a/src/libs/linprog/ActiveSetSolver.cpp b/src/libs/linprog/ActiveSetSolver.cpp index 4b847a0b32..895dcaf033 100644 --- a/src/libs/linprog/ActiveSetSolver.cpp +++ b/src/libs/linprog/ActiveSetSolver.cpp @@ -1,5 +1,15 @@ +/* + * Copyright 2010 - 2011, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Clemens Zeidler + */ + + #include "ActiveSetSolver.h" +#include #include #include "LayoutOptimizer.h" @@ -16,17 +26,7 @@ using namespace LinearProgramming; -//using namespace BPrivate::Layout; - - -template -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); } diff --git a/src/libs/linprog/ActiveSetSolver.h b/src/libs/linprog/ActiveSetSolver.h index 3c0cc17bb3..2a137c2e50 100644 --- a/src/libs/linprog/ActiveSetSolver.h +++ b/src/libs/linprog/ActiveSetSolver.h @@ -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(); diff --git a/src/libs/linprog/Constraint.cpp b/src/libs/linprog/Constraint.cpp index a6ce397610..e723c3a43f 100644 --- a/src/libs/linprog/Constraint.cpp +++ b/src/libs/linprog/Constraint.cpp @@ -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; } diff --git a/src/libs/linprog/Jamfile b/src/libs/linprog/Jamfile index b11568af18..d6e60024f8 100644 --- a/src/libs/linprog/Jamfile +++ b/src/libs/linprog/Jamfile @@ -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 ; diff --git a/src/libs/linprog/LinearSpec.cpp b/src/libs/linprog/LinearSpec.cpp index fd1c88e2d9..4117704565 100644 --- a/src/libs/linprog/LinearSpec.cpp +++ b/src/libs/linprog/LinearSpec.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 diff --git a/src/libs/linprog/QPSolverInterface.cpp b/src/libs/linprog/QPSolverInterface.cpp new file mode 100644 index 0000000000..a9f7bf7db5 --- /dev/null +++ b/src/libs/linprog/QPSolverInterface.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2011, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Clemens Zeidler + */ + + +#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; +} diff --git a/src/libs/linprog/QPSolverInterface.h b/src/libs/linprog/QPSolverInterface.h new file mode 100644 index 0000000000..e7233bfe2a --- /dev/null +++ b/src/libs/linprog/QPSolverInterface.h @@ -0,0 +1,42 @@ +/* + * Copyright 2011, Clemens Zeidler + * Distributed under the terms of the MIT License. + */ +#ifndef QP_SOLVER_INTERFACE_H +#define QP_SOLVER_INTERFACE_H + + +#include "LinearSpec.h" + +#include + + +/*! 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 SoftInEqList; + + inline void _DestroyData(SoftInEqData& data); + inline bool _IsSoftInequality(Constraint* constraint); + + SoftInEqList fInEqSlackConstraints; +}; + + +#endif // QP_SOLVER_INTERFACE_H