From 676ef01ba74e966b1ce7f4117372bbc5f1290cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 16 Oct 2009 12:13:07 +0000 Subject: [PATCH] * Applied patch by Hong Yul Yang to update linprog. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33609 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/libs/linprog/Constraint.h | 30 +++- headers/libs/linprog/LinearSpec.h | 6 +- headers/libs/linprog/Summand.h | 1 + headers/libs/linprog/Variable.h | 36 ++++- src/libs/linprog/Constraint.cpp | 251 +++++++++++++++++++++++++----- src/libs/linprog/LinearSpec.cpp | 80 ++++++++-- src/libs/linprog/Summand.cpp | 4 + src/libs/linprog/Variable.cpp | 193 +++++++++++++++++++---- 8 files changed, 511 insertions(+), 90 deletions(-) diff --git a/headers/libs/linprog/Constraint.h b/headers/libs/linprog/Constraint.h index 6db27f1ff4..f804350c81 100644 --- a/headers/libs/linprog/Constraint.h +++ b/headers/libs/linprog/Constraint.h @@ -11,6 +11,7 @@ #include "Variable.h" #include "Summand.h" +#include #include #include #include @@ -29,7 +30,7 @@ class Constraint { public: int32 Index(); - + BList* LeftSide(); void SetLeftSide(BList* summands); void UpdateLeftSide(); @@ -46,17 +47,30 @@ public: OperatorType Op(); void SetOp(OperatorType value); - double RightSide(); + double RightSide() const; void SetRightSide(double value); - double PenaltyNeg(); + double PenaltyNeg() const; void SetPenaltyNeg(double value); - double PenaltyPos(); + double PenaltyPos() const; void SetPenaltyPos(double value); + const char* Label(); + void SetLabel(const char* label); + + void WriteXML(BFile* file); + Variable* DNeg() const; Variable* DPos() const; - - BString ToString(); + + void SetOwner(void* owner); + void* Owner() const; + + bool IsValid(); + void Invalidate(); + + BString* ToBString(); + const char* ToString(); + ~Constraint(); protected: @@ -71,6 +85,10 @@ private: double fRightSide; Summand* fDNegObjSummand; Summand* fDPosObjSummand; + void* fOwner; + char* fLabel; + + bool fIsValid; public: friend class LinearSpec; diff --git a/headers/libs/linprog/LinearSpec.h b/headers/libs/linprog/LinearSpec.h index 4a7d4eaf60..d21a8d1f2e 100644 --- a/headers/libs/linprog/LinearSpec.h +++ b/headers/libs/linprog/LinearSpec.h @@ -18,6 +18,7 @@ #include "lp_lib.h" #include +#include #include #include #include @@ -37,7 +38,7 @@ class LinearSpec { public: LinearSpec(); - ~LinearSpec(); + virtual ~LinearSpec(); Variable* AddVariable(); @@ -100,6 +101,9 @@ public: double ObjectiveValue() const; double SolvingTime() const; + BString* ToBString(); + const char* ToString(); + protected: int32 fCountColumns; diff --git a/headers/libs/linprog/Summand.h b/headers/libs/linprog/Summand.h index 2f25a36a22..ead65faf54 100644 --- a/headers/libs/linprog/Summand.h +++ b/headers/libs/linprog/Summand.h @@ -29,6 +29,7 @@ public: private: double fCoeff; Variable* fVar; + bool fUsedInPenaltyFunction; //not set yet }; diff --git a/headers/libs/linprog/Variable.h b/headers/libs/linprog/Variable.h index c85c5e3eba..45cf7a28ea 100644 --- a/headers/libs/linprog/Variable.h +++ b/headers/libs/linprog/Variable.h @@ -7,13 +7,16 @@ #ifndef VARIABLE_H #define VARIABLE_H +#include #include +#include namespace LinearProgramming { class Constraint; class LinearSpec; +class Summand; /** * Contains minimum and maximum values. @@ -23,7 +26,6 @@ class Variable { public: int32 Index(); LinearSpec* LS() const; - void SetLS(LinearSpec* value); double Value() const; void SetValue(double value); double Min() const; @@ -31,24 +33,46 @@ public: double Max() const; void SetMax(double max); void SetRange(double min, double max); - //~ string ToString(); + + const char* Label(); + void SetLabel(const char* label); + + BString* ToBString(); + const char* ToString(); + Constraint* IsEqual(Variable* var); Constraint* IsSmallerOrEqual(Variable* var); - Constraint* IsGreaterorEqual(Variable* var); + Constraint* IsGreaterOrEqual(Variable* var); + + Constraint* IsEqual(Variable* var, + double penaltyNeg, double penaltyPos); + Constraint* IsSmallerOrEqual(Variable* var, + double penaltyNeg, double penaltyPos); + Constraint* IsGreaterOrEqual(Variable* var, + double penaltyNeg, double penaltyPos); + + bool IsValid(); + void Invalidate(); + + virtual ~Variable(); protected: Variable(LinearSpec* ls); - ~Variable(); private: LinearSpec* fLS; + BList* fUsingSummands; // All Summands that link to this Variable double fValue; double fMin; double fMax; + char* fLabel; + + bool fIsValid; public: - friend class LinearSpec; - friend class Constraint; + friend class LinearSpec; + friend class Constraint; + friend class Summand; }; diff --git a/src/libs/linprog/Constraint.cpp b/src/libs/linprog/Constraint.cpp index c4190216e4..03e80df639 100644 --- a/src/libs/linprog/Constraint.cpp +++ b/src/libs/linprog/Constraint.cpp @@ -11,6 +11,16 @@ #include "lp_lib.h" +// Toggle debug output +//#define DEBUG_CONSTRAINT + +#ifdef DEBUG_CONSTRAINT +# define STRACE(x) debug_printf x +#else +# define STRACE(x) ; +#endif + + /** * Gets the index of the constraint. * @@ -20,8 +30,10 @@ int32 Constraint::Index() { int32 i = fLS->Constraints()->IndexOf(this); - if (i == -1) - printf("Constraint not part of fLS->Constraints()."); + if (i == -1) { + STRACE(("Constraint not part of fLS->Constraints().")); + return -1; + } return i + 1; } @@ -47,6 +59,9 @@ Constraint::LeftSide() void Constraint::SetLeftSide(BList* summands) { + if (!fIsValid) + return; + fLeftSide = summands; UpdateLeftSide(); } @@ -55,6 +70,9 @@ Constraint::SetLeftSide(BList* summands) void Constraint::UpdateLeftSide() { + if (!fIsValid) + return; + double coeffs[fLeftSide->CountItems() + 2]; int varIndexes[fLeftSide->CountItems() + 2]; int32 i; @@ -77,7 +95,7 @@ Constraint::UpdateLeftSide() } if (!set_rowex(fLS->fLP, this->Index(), i, &coeffs[0], &varIndexes[0])) - printf("Error in set_rowex."); + STRACE(("Error in set_rowex.")); fLS->UpdateObjFunction(); fLS->RemovePresolved(); @@ -87,6 +105,9 @@ Constraint::UpdateLeftSide() void Constraint::SetLeftSide(double coeff1, Variable* var1) { + if (!fIsValid) + return; + for (int i=0; iCountItems(); i++) delete (Summand*)fLeftSide->ItemAt(i); fLeftSide->MakeEmpty(); @@ -99,6 +120,9 @@ void Constraint::SetLeftSide(double coeff1, Variable* var1, double coeff2, Variable* var2) { + if (!fIsValid) + return; + for (int i=0; iCountItems(); i++) delete (Summand*)fLeftSide->ItemAt(i); fLeftSide->MakeEmpty(); @@ -113,6 +137,9 @@ Constraint::SetLeftSide(double coeff1, Variable* var1, double coeff2, Variable* var2, double coeff3, Variable* var3) { + if (!fIsValid) + return; + for (int i=0; iCountItems(); i++) delete (Summand*)fLeftSide->ItemAt(i); fLeftSide->MakeEmpty(); @@ -129,6 +156,9 @@ Constraint::SetLeftSide(double coeff1, Variable* var1, double coeff3, Variable* var3, double coeff4, Variable* var4) { + if (!fIsValid) + return; + for (int i=0; iCountItems(); i++) delete (Summand*)fLeftSide->ItemAt(i); fLeftSide->MakeEmpty(); @@ -160,12 +190,15 @@ Constraint::Op() void Constraint::SetOp(OperatorType value) { + if (!fIsValid) + return; + fOp = value; if (!set_constr_type(fLS->fLP, this->Index(), ((fOp == OperatorType(EQ)) ? EQ : (fOp == OperatorType(GE)) ? GE : LE))) - printf("Error in set_constr_type."); + STRACE(("Error in set_constr_type.")); fLS->RemovePresolved(); } @@ -177,7 +210,7 @@ Constraint::SetOp(OperatorType value) * @return the constant value that is on the right side of the operator */ double -Constraint::RightSide() +Constraint::RightSide() const { return fRightSide; } @@ -191,9 +224,12 @@ Constraint::RightSide() void Constraint::SetRightSide(double value) { + if (!fIsValid) + return; + fRightSide = value; if (!set_rh(fLS->fLP, Index(), fRightSide)) - printf("Error in set_rh."); + STRACE(("Error in set_rh.")); fLS->RemovePresolved(); } @@ -205,7 +241,7 @@ Constraint::SetRightSide(double value) * @return the penalty coefficient */ double -Constraint::PenaltyNeg() +Constraint::PenaltyNeg() const { if (fDNegObjSummand == NULL) return INFINITY; @@ -222,6 +258,9 @@ Constraint::PenaltyNeg() void Constraint::SetPenaltyNeg(double value) { + if (!fIsValid) + return; + if (fDNegObjSummand == NULL) { fDNegObjSummand = new Summand(value, new Variable(fLS)); fLS->ObjFunction()->AddItem(fDNegObjSummand); @@ -244,7 +283,7 @@ Constraint::SetPenaltyNeg(double value) * @return the penalty coefficient */ double -Constraint::PenaltyPos() +Constraint::PenaltyPos() const { if (fDPosObjSummand == NULL) return INFINITY; @@ -261,6 +300,9 @@ Constraint::PenaltyPos() void Constraint::SetPenaltyPos(double value) { + if (!fIsValid) + return; + if (fDPosObjSummand == NULL) { fDPosObjSummand = new Summand(value, new Variable(fLS)); fLS->ObjFunction()->AddItem(fDPosObjSummand); @@ -277,6 +319,62 @@ Constraint::SetPenaltyPos(double value) } +const char* +Constraint::Label() +{ + return fLabel; +} + + +void +Constraint::SetLabel(const char* label) +{ + fLabel = (char*) malloc(strlen(label) + 1); + strcpy(fLabel, label); +} + + +void +Constraint::WriteXML(BFile* file) +{ + if (file->IsWritable() && fOwner == NULL) { + char buffer[200]; + + file->Write(buffer, sprintf(buffer, "\t\n")); + file->Write(buffer, sprintf(buffer, "\t\t\n")); + + Summand* summand; + for (int32 i = 0; i < fLeftSide->CountItems(); i++) { + summand = (Summand*)fLeftSide->ItemAt(i); + file->Write(buffer, sprintf(buffer, "\t\t\t\n")); + file->Write(buffer, sprintf(buffer, "\t\t\t\t%f\n", + summand->Coeff())); + BString* varStr = summand->Var()->ToBString(); + file->Write(buffer, sprintf(buffer, "\t\t\t\t%s\n", + varStr->String())); + delete varStr; + file->Write(buffer, sprintf(buffer, "\t\t\t\n")); + } + + file->Write(buffer, sprintf(buffer, "\t\t\n")); + + char* op; + if (fOp == OperatorType(EQ)) + op = "EQ"; + else if (fOp == OperatorType(LE)) + op = "LE"; + else if (fOp == OperatorType(GE)) + op = "GE"; + + file->Write(buffer, sprintf(buffer, "\t\t%s\n", op)); + file->Write(buffer, sprintf(buffer, "\t\t%f\n", fRightSide)); + //~ file->Write(buffer, sprintf(buffer, "\t\t%s\n", PenaltyNeg())); + //~ file->Write(buffer, sprintf(buffer, "\t\t%s\n", PenaltyPos())); + file->Write(buffer, sprintf(buffer, "\t\n")); + } +} + + /** * Gets the slack variable for the negative variations. * @@ -305,17 +403,114 @@ Constraint::DPos() const } +void +Constraint::SetOwner(void* owner) +{ + fOwner = owner; +} + + +void* +Constraint::Owner() const +{ + return fOwner; +} + + +bool +Constraint::IsValid() +{ + return fIsValid; +} + + +void +Constraint::Invalidate() +{ + STRACE(("Constraint::Invalidate() on %d\n", this)); + + if (!fIsValid) + return; + + fIsValid = false; + + for (int32 i = 0; i < fLeftSide->CountItems(); i++) + delete (Summand*)fLeftSide->ItemAt(i); + delete fLeftSide; + fLeftSide = NULL; + + if (fDNegObjSummand) { + fLS->ObjFunction()->RemoveItem(fDNegObjSummand); + delete fDNegObjSummand->Var(); + delete fDNegObjSummand; + fDNegObjSummand = NULL; + } + if (fDPosObjSummand) { + fLS->ObjFunction()->RemoveItem(fDPosObjSummand); + delete fDPosObjSummand->Var(); + delete fDPosObjSummand; + fDPosObjSummand = NULL; + } + + del_constraint(fLS->fLP, this->Index()); + fLS->Constraints()->RemoveItem(this); +} + + +BString* +Constraint::ToBString() +{ + BString* str = new BString(); + *str << "Constraint "; + if (fLabel) + *str << fLabel; + *str << "(" << (int32)this << "): "; + + if (fIsValid) { + for (int i = 0; i < fLeftSide->CountItems(); i++) { + Summand* s = static_cast(fLeftSide->ItemAt(i)); + *str << (float)s->Coeff() << "*"; + BString* varString = s->Var()->ToBString(); + *str << *varString << " "; + delete varString; + } + *str << ((fOp == OperatorType(EQ)) ? "== " + : (fOp == OperatorType(GE)) ? ">= " + : (fOp == OperatorType(LE)) ? "<= " + : "?? "); + *str << (float)fRightSide; + *str << " PenaltyPos=" << (float)PenaltyPos(); + *str << " PenaltyNeg=" << (float)PenaltyNeg(); + } else + *str << "invalid"; + return str; +} + + +const char* +Constraint::ToString() +{ + BString* str = ToBString(); + char* result = (char*) malloc(str->Length() + 1); + str->CopyInto(result, 0, str->Length()); + delete str; + return result; +} + + /** * Constructor. */ Constraint::Constraint(LinearSpec* ls, BList* summands, OperatorType op, double rightSide, double penaltyNeg, double penaltyPos) + : fLS(ls), + fLeftSide(summands), + fOp(op), + fRightSide(rightSide), + fOwner(NULL), + fLabel(NULL), + fIsValid(true) { - fLS = ls; - fLeftSide = summands; - fOp = op; - fRightSide = rightSide; - double coeffs[summands->CountItems() + 2]; int varIndexes[summands->CountItems() + 2]; int32 i; @@ -327,8 +522,8 @@ Constraint::Constraint(LinearSpec* ls, BList* summands, OperatorType op, if (penaltyNeg != INFINITY && fOp != OperatorType(LE)) { - fDNegObjSummand = new Summand(penaltyNeg, new Variable(ls)); - ls->fObjFunction->AddItem(fDNegObjSummand); + fDNegObjSummand = new Summand(penaltyNeg, new Variable(fLS)); + fLS->fObjFunction->AddItem(fDNegObjSummand); varIndexes[i] = fDNegObjSummand->Var()->Index(); coeffs[i] = 1.0; i++; @@ -338,8 +533,8 @@ Constraint::Constraint(LinearSpec* ls, BList* summands, OperatorType op, if (penaltyPos != INFINITY && fOp != OperatorType(GE)) { - fDPosObjSummand = new Summand(penaltyPos, new Variable(ls)); - ls->fObjFunction->AddItem(fDPosObjSummand); + fDPosObjSummand = new Summand(penaltyPos, new Variable(fLS)); + fLS->fObjFunction->AddItem(fDPosObjSummand); varIndexes[i] = fDPosObjSummand->Var()->Index(); coeffs[i] = -1.0; i++; @@ -347,14 +542,14 @@ Constraint::Constraint(LinearSpec* ls, BList* summands, OperatorType op, else fDPosObjSummand = NULL; - if (!add_constraintex(ls->fLP, i, &coeffs[0], &varIndexes[0], + if (!add_constraintex(fLS->fLP, i, &coeffs[0], &varIndexes[0], ((fOp == OperatorType(EQ)) ? EQ : (fOp == OperatorType(GE)) ? GE : LE), rightSide)) - printf("Error in add_constraintex."); + STRACE(("Error in add_constraintex.")); fLS->UpdateObjFunction(); - ls->Constraints()->AddItem(this); + fLS->Constraints()->AddItem(this); } @@ -364,20 +559,6 @@ Constraint::Constraint(LinearSpec* ls, BList* summands, OperatorType op, */ Constraint::~Constraint() { - for (int i=0; iCountItems(); i++) - delete (Summand*)fLeftSide->ItemAt(i); - delete fLeftSide; - - if (fDNegObjSummand != NULL) { - delete fDNegObjSummand->Var(); - delete fDNegObjSummand; - } - if (fDPosObjSummand != NULL) { - delete fDPosObjSummand->Var(); - delete fDPosObjSummand; - } - - del_constraint(fLS->fLP, Index()); - fLS->Constraints()->RemoveItem(this); + Invalidate(); } diff --git a/src/libs/linprog/LinearSpec.cpp b/src/libs/linprog/LinearSpec.cpp index 8da74f09b3..0f74b8b426 100644 --- a/src/libs/linprog/LinearSpec.cpp +++ b/src/libs/linprog/LinearSpec.cpp @@ -12,21 +12,20 @@ * Creates a new specification for a linear programming problem. */ LinearSpec::LinearSpec() + : fCountColumns(0), + fLpPresolved(NULL), + fOptimization(MINIMIZE), + fObjFunction(new BList()), + fVariables(new BList()), + fConstraints(new BList()), + fResult(ERROR), + fObjectiveValue(NAN), + fSolvingTime(NAN) { fLP = make_lp(0, 0); if (fLP == NULL) printf("Couldn't construct a new model."); set_verbose(fLP, 1); - - fObjFunction = new BList(); - fVariables = new BList(); - fConstraints = new BList(); - fCountColumns = 0; - fLpPresolved = NULL; - fOptimization = MINIMIZE; - fResult = ERROR; - fObjectiveValue = NAN; - fSolvingTime = NAN; } @@ -38,12 +37,11 @@ LinearSpec::LinearSpec() LinearSpec::~LinearSpec() { RemovePresolved(); - int i; - for (i=0; iCountItems(); i++) + for (int32 i=0; iCountItems(); i++) delete (Constraint*)fConstraints->ItemAt(i); - for (i=0; iCountItems(); i++) + for (int32 i=0; iCountItems(); i++) delete (Summand*)fObjFunction->ItemAt(i); - for (i=0; iCountItems(); i++) + for (int32 i=0; iCountItems(); i++) delete (Variable*)fVariables->ItemAt(i); delete_lp(fLP); } @@ -496,7 +494,7 @@ LinearSpec::Save(char* fname) /** * Gets the number of columns. - * + * * @return the number of columns */ int32 @@ -595,3 +593,55 @@ LinearSpec::SolvingTime() const return fSolvingTime; } + +BString* +LinearSpec::ToBString() +{ + BString* str = new BString(); + *str << "LinearSpec " << (int32)this << ":\n"; + for (int i = 0; i < fVariables->CountItems(); i++) { + Variable* variable = static_cast(fVariables->ItemAt(i)); + BString* vStr = variable->ToBString(); + *str << *vStr << "=" << (float)variable->Value() << " "; + delete vStr; + } + *str << "\n"; + for (int i = 0; i < fConstraints->CountItems(); i++) { + Constraint* c = static_cast(fConstraints->ItemAt(i)); + BString* cStr = c->ToBString(); + *str << i << ": " << *cStr; + delete cStr; + *str << "\n"; + } + *str << "Result="; + if (fResult==-1) + *str << "ERROR"; + else if (fResult==0) + *str << "OPTIMAL"; + else if (fResult==1) + *str << "SUBOPTIMAL"; + else if (fResult==2) + *str << "INFEASIBLE"; + else if (fResult==3) + *str << "UNBOUNDED"; + else if (fResult==4) + *str << "DEGENERATE"; + else if (fResult==5) + *str << "NUMFAILURE"; + else + *str << fResult; + *str << " SolvingTime=" << (float)fSolvingTime << "ms"; + return str; +} + + +const char* +LinearSpec::ToString() +{ + BString* str = ToBString(); + char* result = (char*) malloc(str->Length() + 1); + str->CopyInto(result, 0, str->Length()); + delete str; + return result; +} + diff --git a/src/libs/linprog/Summand.cpp b/src/libs/linprog/Summand.cpp index 376851285e..8caeb892cb 100644 --- a/src/libs/linprog/Summand.cpp +++ b/src/libs/linprog/Summand.cpp @@ -62,6 +62,7 @@ Summand::SetVar(Variable* var) */ Summand::~Summand() { + fVar->fUsingSummands->RemoveItem(this); } @@ -72,5 +73,8 @@ Summand::Summand(double coeff, Variable* var) { fCoeff = coeff; fVar = var; + fUsedInPenaltyFunction = false; + fVar->fUsingSummands->AddItem(this); + } diff --git a/src/libs/linprog/Variable.cpp b/src/libs/linprog/Variable.cpp index 6dee50f9fe..16457b75d4 100644 --- a/src/libs/linprog/Variable.cpp +++ b/src/libs/linprog/Variable.cpp @@ -14,6 +14,16 @@ #include // for DBL_MAX +// Toggle debug output +//#define DEBUG_VARIABLE + +#ifdef DEBUG_VARIABLE +# define STRACE(x) debug_printf x +#else +# define STRACE(x) ; +#endif + + /** * Gets index of the variable. * @@ -23,8 +33,10 @@ int32 Variable::Index() { int32 i = fLS->Variables()->IndexOf(this); - if (i == -1) + if (i == -1) { printf("Variable not part of fLS->Variables()."); + return -1; + } return i + 1; } @@ -41,18 +53,6 @@ Variable::LS() const } -/** - * Sets the current linear specification. - * - * @param value the current linear specification - */ -void -Variable::SetLS(LinearSpec* value) -{ - fLS = value; -} - - /** * Gets the value. * @@ -97,6 +97,9 @@ Variable::Min() const void Variable::SetMin(double min) { + if (!fIsValid) + return; + fMin = min; set_bounds(fLS->fLP, this->Index(), fMin, fMax); } @@ -122,6 +125,9 @@ Variable::Max() const void Variable::SetMax(double max) { + if (!fIsValid) + return; + fMax = max; set_bounds(fLS->fLP, this->Index(), fMin, fMax); } @@ -136,21 +142,64 @@ Variable::SetMax(double max) void Variable::SetRange(double min, double max) { + if (!fIsValid) + return; + fMin = min; fMax = max; set_bounds(fLS->fLP, this->Index(), fMin, fMax); } +const char* +Variable::Label() +{ + return fLabel; +} + + +void +Variable::SetLabel(const char* label) +{ + fLabel = (char*) malloc(strlen(label) + 1); + strcpy(fLabel, label); +} + + /** * Returns index of the variable as String. * E.g. "Var2" * * @return the String index of the variable */ -//~ string Variable::ToString() { - //~ return "Var" + Index(); -//~ } +BString* +Variable::ToBString() +{ + BString* str = new BString(); + if (fLabel) { + *str << fLabel; + if (!fIsValid) + *str << "(invalid)"; + } else { + *str << "Var"; + if (!fIsValid) + *str << "(invalid," << (int32)this << ")"; + else + *str << Index(); + } + return str; +} + + +const char* +Variable::ToString() +{ + BString* str = ToBString(); + char* result = (char*) malloc(str->Length() + 1); + str->CopyInto(result, 0, str->Length()); + delete str; + return result; +} /** @@ -162,6 +211,9 @@ Variable::SetRange(double min, double max) Constraint* Variable::IsEqual(Variable* var) { + if (!fIsValid) + return NULL; + return fLS->AddConstraint(1.0, this, -1.0, var, OperatorType(EQ), 0.0); } @@ -175,6 +227,9 @@ Variable::IsEqual(Variable* var) Constraint* Variable::IsSmallerOrEqual(Variable* var) { + if (!fIsValid) + return NULL; + return fLS->AddConstraint(1.0, this, -1.0, var, OperatorType(LE), 0.0); } @@ -186,28 +241,111 @@ Variable::IsSmallerOrEqual(Variable* var) * @return the new constraint */ Constraint* -Variable::IsGreaterorEqual(Variable* var) +Variable::IsGreaterOrEqual(Variable* var) { + if (!fIsValid) + return NULL; + return fLS->AddConstraint(-1.0, var, 1.0, this, OperatorType(GE), 0.0); } +Constraint* +Variable::IsEqual(Variable* var, double penaltyNeg, double penaltyPos) +{ + if (!fIsValid) + return NULL; + + return fLS->AddConstraint(1.0, this, -1.0, var, OperatorType(EQ), 0.0, + penaltyNeg, penaltyPos); +} + + +Constraint* +Variable::IsSmallerOrEqual(Variable* var, double penaltyNeg, double penaltyPos) +{ + if (!fIsValid) + return NULL; + + return fLS->AddConstraint(1.0, this, -1.0, var, OperatorType(LE), 0.0, + penaltyNeg, penaltyPos); +} + + +Constraint* +Variable::IsGreaterOrEqual(Variable* var, double penaltyNeg, double penaltyPos) +{ + if (!fIsValid) + return NULL; + + return fLS->AddConstraint(-1.0, var, 1.0, this, OperatorType(GE), 0.0, + penaltyNeg, penaltyPos); +} + + +bool +Variable::IsValid() +{ + return fIsValid; +} + + +void +Variable::Invalidate() +{ + STRACE(("Variable::Invalidate() on %s\n", ToString())); + + if (!fIsValid) + return; + + fIsValid = false; + del_column(fLS->fLP, Index()); + fLS->Variables()->RemoveItem(this); + + // invalidate all constraints that use this variable + BList* markedForInvalidation = new BList(); + BList* constraints = fLS->Constraints(); + for (int i = 0; i < constraints->CountItems(); i++) { + Constraint* constraint = static_cast( + constraints->ItemAt(i)); + + if (!constraint->IsValid()) + continue; + + BList* summands = constraint->LeftSide(); + for (int j = 0; j < summands->CountItems(); j++) { + Summand* summand = static_cast(summands->ItemAt(j)); + if (summand->Var() == this) { + markedForInvalidation->AddItem(constraint); + break; + } + } + } + for (int i = 0; i < markedForInvalidation->CountItems(); i++) + static_cast(markedForInvalidation->ItemAt(i)) + ->Invalidate(); + delete markedForInvalidation; +} + + /** * Constructor. */ Variable::Variable(LinearSpec* ls) + : fLS(ls), + fUsingSummands(new BList()), + fValue(NAN), + fMin(0), + fMax(DBL_MAX), + fLabel(NULL), + fIsValid(true) { - fMin = 0; - fMax = DBL_MAX; - fValue = NULL; - fLS = ls; + fLS->Variables()->AddItem(this); - ls->Variables()->AddItem(this); - - if (ls->Variables()->CountItems() > ls->CountColumns()) { + if (fLS->Variables()->CountItems() > fLS->CountColumns()) { double d = 0; int i = 0; - if (!add_columnex(ls->fLP, 0, &d, &i)) + if (!add_columnex(fLS->fLP, 0, &d, &i)) printf("Error in add_columnex."); } } @@ -219,7 +357,8 @@ Variable::Variable(LinearSpec* ls) */ Variable::~Variable() { - del_column(fLS->fLP, this->Index()); - fLS->Variables()->RemoveItem(this); + Invalidate(); + free(fLabel); + delete fUsingSummands; }