From a101e99aada54cf545bbf25e0cbb6329ad45535e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 6 Feb 2008 10:51:44 +0000 Subject: [PATCH] Added libalm.so and its dependency liblinprog.so. libalm.so provides a BLayout implementation (BALMLayout) using the Auckland Layout Model (ALM). The original ALM was implemented by Christof Lutteroth, the Haiku/C++ version by James Kim. The code needs some review, but the test programs seem to work fine. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23889 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/HaikuImage | 2 +- headers/libs/alm/Area.h | 149 +++ headers/libs/alm/BALMLayout.h | 106 ++ headers/libs/alm/Column.h | 58 + headers/libs/alm/LayoutStyleType.h | 20 + headers/libs/alm/Row.h | 58 + headers/libs/alm/XTab.h | 38 + headers/libs/alm/YTab.h | 37 + headers/libs/linprog/Constraint.h | 56 + headers/libs/linprog/LinearSpec.h | 124 ++ headers/libs/linprog/ObjFunctionSummand.h | 39 + headers/libs/linprog/OperatorType.h | 18 + headers/libs/linprog/OptimizationType.h | 18 + headers/libs/linprog/PenaltyFunction.h | 43 + headers/libs/linprog/ResultType.h | 20 + headers/libs/linprog/SoftConstraint.h | 54 + headers/libs/linprog/Variable.h | 53 + src/libs/Jamfile | 3 + src/libs/alm/Area.cpp | 1267 +++++++++++++++++++++ src/libs/alm/BALMLayout.cpp | 699 ++++++++++++ src/libs/alm/Column.cpp | 218 ++++ src/libs/alm/Jamfile | 17 + src/libs/alm/Row.cpp | 220 ++++ src/libs/alm/XTab.cpp | 13 + src/libs/alm/YTab.cpp | 13 + src/libs/linprog/Constraint.cpp | 206 ++++ src/libs/linprog/Jamfile | 17 + src/libs/linprog/LinearSpec.cpp | 736 ++++++++++++ src/libs/linprog/ObjFunctionSummand.cpp | 76 ++ src/libs/linprog/PenaltyFunction.cpp | 116 ++ src/libs/linprog/SoftConstraint.cpp | 235 ++++ src/libs/linprog/Variable.cpp | 244 ++++ src/tests/Jamfile | 1 + src/tests/libs/Jamfile | 6 + src/tests/libs/alm/Jamfile | 24 + src/tests/libs/alm/TableTest.cpp | 70 ++ src/tests/libs/alm/Test1.cpp | 83 ++ src/tests/libs/alm/Test2.cpp | 162 +++ src/tests/libs/linprog/Jamfile | 11 + src/tests/libs/linprog/Program.cpp | 67 ++ src/tests/libs/lp_solve/Jamfile | 12 + src/tests/libs/lp_solve/demo.c | 146 +++ 42 files changed, 5554 insertions(+), 1 deletion(-) create mode 100644 headers/libs/alm/Area.h create mode 100644 headers/libs/alm/BALMLayout.h create mode 100644 headers/libs/alm/Column.h create mode 100644 headers/libs/alm/LayoutStyleType.h create mode 100644 headers/libs/alm/Row.h create mode 100644 headers/libs/alm/XTab.h create mode 100644 headers/libs/alm/YTab.h create mode 100644 headers/libs/linprog/Constraint.h create mode 100644 headers/libs/linprog/LinearSpec.h create mode 100644 headers/libs/linprog/ObjFunctionSummand.h create mode 100644 headers/libs/linprog/OperatorType.h create mode 100644 headers/libs/linprog/OptimizationType.h create mode 100644 headers/libs/linprog/PenaltyFunction.h create mode 100644 headers/libs/linprog/ResultType.h create mode 100644 headers/libs/linprog/SoftConstraint.h create mode 100644 headers/libs/linprog/Variable.h create mode 100644 src/libs/alm/Area.cpp create mode 100644 src/libs/alm/BALMLayout.cpp create mode 100644 src/libs/alm/Column.cpp create mode 100644 src/libs/alm/Jamfile create mode 100644 src/libs/alm/Row.cpp create mode 100644 src/libs/alm/XTab.cpp create mode 100644 src/libs/alm/YTab.cpp create mode 100644 src/libs/linprog/Constraint.cpp create mode 100644 src/libs/linprog/Jamfile create mode 100644 src/libs/linprog/LinearSpec.cpp create mode 100644 src/libs/linprog/ObjFunctionSummand.cpp create mode 100644 src/libs/linprog/PenaltyFunction.cpp create mode 100644 src/libs/linprog/SoftConstraint.cpp create mode 100644 src/libs/linprog/Variable.cpp create mode 100644 src/tests/libs/Jamfile create mode 100644 src/tests/libs/alm/Jamfile create mode 100644 src/tests/libs/alm/TableTest.cpp create mode 100644 src/tests/libs/alm/Test1.cpp create mode 100644 src/tests/libs/alm/Test2.cpp create mode 100644 src/tests/libs/linprog/Jamfile create mode 100644 src/tests/libs/linprog/Program.cpp create mode 100644 src/tests/libs/lp_solve/Jamfile create mode 100644 src/tests/libs/lp_solve/demo.c diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index adbf6ae17f..9d5146efbf 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -65,7 +65,7 @@ BEOS_SYSTEM_LIB = libbe.so $(HAIKU_LIBSTDC++) libmedia.so libtracker.so libtranslation.so libnetwork.so libdebug.so libbsd.so libmail.so libtextencoding.so libz.so libfreetype.so libpng.so libmidi.so libmidi2.so libdevice.so libgame.so libscreensaver.so libroot.so - $(X86_ONLY)libGL.so libfluidsynth.so + $(X86_ONLY)libGL.so libfluidsynth.so liblpsolve55.so liblinprog.so libalm.so ; BEOS_SYSTEM_SERVERS = registrar debug_server syslog_daemon media_server net_server media_addon_server input_server app_server fake_app_server diff --git a/headers/libs/alm/Area.h b/headers/libs/alm/Area.h new file mode 100644 index 0000000000..5ccb4403de --- /dev/null +++ b/headers/libs/alm/Area.h @@ -0,0 +1,149 @@ +#ifndef AREA_H +#define AREA_H + +#include "Constraint.h" +#include "SoftConstraint.h" + +#include +#include +#include +#include +#include + + +namespace BALM { + +class Column; +class BALMLayout; +class Row; +class XTab; +class YTab; + +/** + * Rectangular area in the GUI, defined by a tab on each side. + */ +class Area { + +public: + bool AutoPrefContentSize() const; + void SetAutoPrefContentSize(bool value); + XTab* Left() const; + void SetLeft(XTab* left); + XTab* Right() const; + void SetRight(XTab* right); + YTab* Top() const; + void SetTop(YTab* top); + YTab* Bottom() const; + void SetBottom(YTab* bottom); + Row* GetRow() const; + void SetRow(Row* row); + Column* GetColumn() const; + void SetColumn(Column* column); + BView* Content() const; + void SetContent(BView* content); + XTab* ContentLeft() const; + YTab* ContentTop() const; + XTab* ContentRight() const; + YTab* ContentBottom() const; + BSize MinContentSize() const; + void SetMinContentSize(BSize min); + BSize MaxContentSize() const; + void SetMaxContentSize(BSize max); + BSize PrefContentSize() const; + void SetPrefContentSize(BSize pref); + BSize ShrinkRigidity() const; + void SetShrinkRigidity(BSize shrink); + BSize ExpandRigidity() const; + void SetExpandRigidity(BSize expand); + double ContentAspectRatio() const; + void SetContentAspectRatio(double ratio); + BAlignment Alignment() const; + void SetAlignment(BAlignment alignment); + void SetHAlignment(alignment horizontal); + void SetVAlignment(vertical_alignment vertical); + int32 LeftInset() const; + void SetLeftInset(int32 left); + int32 TopInset() const; + void SetTopInset(int32 top); + int32 RightInset() const; + void SetRightInset(int32 right); + int32 BottomInset() const; + void SetBottomInset(int32 bottom); + void SetDefaultPrefContentSize(); + //~ string ToString(); + Constraint* HasSameWidthAs(Area* area); + Constraint* HasSameHeightAs(Area* area); + BList* HasSameSizetAs(Area* area); + ~Area(); + +protected: + Area(BALMLayout* ls, XTab* left, YTab* top, + XTab* right, YTab* bottom, + BView* content, + BSize minContentSize); + Area(BALMLayout* ls, Row* row, Column* column, + BView* content, + BSize minContentSize); + void DoLayout(); + +private: + void InitChildArea(); + void UpdateHorizontal(); + void UpdateVertical(); + void Init(BALMLayout* ls, XTab* left, YTab* top, + XTab* right, YTab* bottom, + BView* content, + BSize minContentSize); + +public: + static BSize kMaxSize; + static BSize kMinSize; + static BSize kUndefinedSize; + +protected: + BView* fContent; + BList* fConstraints; + +private: + BALMLayout* fLS; + XTab* fLeft; + XTab* fRight; + YTab* fTop; + YTab* fBottom; + Row* fRow; + Column* fColumn; + BSize fMinContentSize; + BSize fMaxContentSize; + Constraint* fMinContentWidth; + Constraint* fMaxContentWidth; + Constraint* fMinContentHeight; + Constraint* fMaxContentHeight; + BSize fPrefContentSize; + BSize fShrinkRigidity; + BSize fExpandRigidity; + double fContentAspectRatio; + Constraint* fContentAspectRatioC; + bool fAutoPrefContentSize; + SoftConstraint* fPrefContentWidth; + SoftConstraint* fPrefContentHeight; + Area* fChildArea; + BAlignment fAlignment; + int32 fLeftInset; + int32 fTopInset; + int32 fRightInset; + int32 fBottomInset; + Constraint* fLeftConstraint; + Constraint* fTopConstraint; + Constraint* fRightConstraint; + Constraint* fBottomConstraint; + +public: + friend class BALMLayout; + +}; + +} // namespace BALM + +using BALM::Area; + +#endif // AREA_H diff --git a/headers/libs/alm/BALMLayout.h b/headers/libs/alm/BALMLayout.h new file mode 100644 index 0000000000..4a86c9724c --- /dev/null +++ b/headers/libs/alm/BALMLayout.h @@ -0,0 +1,106 @@ +#ifndef BALM_LAYOUT_H +#define BALM_LAYOUT_H + +#include +#include +#include +#include +#include +#include + +#include "LayoutStyleType.h" +#include "LinearSpec.h" + + +namespace BALM { + +class Area; +class Column; +class Row; +class XTab; +class YTab; + +/** + * A GUI layout engine using the ALM. + */ +class BALMLayout : public BLayout, public LinearSpec { + +public: + BALMLayout(); + void SolveLayout(); + + XTab* AddXTab(); + YTab* AddYTab(); + Row* AddRow(); + Row* AddRow(YTab* top, YTab* bottom); + Column* AddColumn(); + Column* AddColumn(XTab* left, XTab* right); + Area* AddArea(XTab* left, YTab* top, XTab* right, YTab* bottom, + BView* content, BSize minContentSize); + Area* AddArea(Row* row, Column* column, BView* content, + BSize minContentSize); + Area* AddArea(XTab* left, YTab* top, XTab* right, YTab* bottom, + BView* content); + Area* AddArea(Row* row, Column* column, BView* content); + Area* AreaOf(BView* control); + BList* Areas() const; + void SetAreas(BList* areas); + XTab* Left() const; + void SetLeft(XTab* left); + XTab* Right() const; + void SetRight(XTab* right); + YTab* Top() const; + void SetTop(YTab* top); + YTab* Bottom() const; + void SetBottom(YTab* bottom); + + void RecoverLayout(BView* parent); + LayoutStyleType LayoutStyle() const; + void SetLayoutStyle(LayoutStyleType style); + + BLayoutItem* AddView(BView* child); + BLayoutItem* AddView(int32 index, BView* child); + bool AddItem(BLayoutItem* item); + bool AddItem(int32 index, BLayoutItem* item); + bool RemoveView(BView* child); + bool RemoveItem(BLayoutItem* item); + BLayoutItem* RemoveItem(int32 index); + + BSize MinSize(); + BSize MaxSize(); + BSize PreferredSize(); + BAlignment Alignment(); + bool HasHeightForWidth(); + void GetHeightForWidth(float width, float* min, + float* max, float* preferred); + void InvalidateLayout(); + void LayoutView(); + + char* PerformancePath() const; + void SetPerformancePath(char* path); + +private: + BSize CalculateMinSize(); + BSize CalculateMaxSize(); + BSize CalculatePreferredSize(); + +private: + LayoutStyleType fLayoutStyle; + bool fActivated; + + BList* fAreas; + XTab* fLeft; + XTab* fRight; + YTab* fTop; + YTab* fBottom; + BSize fMinSize; + BSize fMaxSize; + BSize fPreferredSize; + char* fPerformancePath; +}; + +} // namespace BALM + +using BALM::BALMLayout; + +#endif // BALM_LAYOUT_H diff --git a/headers/libs/alm/Column.h b/headers/libs/alm/Column.h new file mode 100644 index 0000000000..8dd74a4483 --- /dev/null +++ b/headers/libs/alm/Column.h @@ -0,0 +1,58 @@ +#ifndef COLUMN_H +#define COLUMN_H + +#include "Constraint.h" + +#include + + +namespace BALM { + +class BALMLayout; +class XTab; + +/** + * Represents a column defined by two x-tabs. + */ +class Column { + +public: + XTab* Left() const; + XTab* Right() const; + Column* Previous() const; + void SetPrevious(Column* value); + Column* Next() const; + void SetNext(Column* value); + //~ string ToString(); + void InsertBefore(Column* column); + void InsertAfter(Column* column); + Constraint* HasSameWidthAs(Column* column); + BList* Constraints() const; + void SetConstraints(BList* constraints); + ~Column(); + +protected: + Column(BALMLayout* ls); + +protected: + BALMLayout* fLS; + XTab* fLeft; + XTab* fRight; + +private: + Column* fPrevious; + Column* fNext; + Constraint* fPreviousGlue; + Constraint* fNextGlue; + BList* fConstraints; + +public: + friend class BALMLayout; + +}; + +} // namespace BALM + +using BALM::Column; + +#endif // COLUMN_H diff --git a/headers/libs/alm/LayoutStyleType.h b/headers/libs/alm/LayoutStyleType.h new file mode 100644 index 0000000000..a8c2c99c5f --- /dev/null +++ b/headers/libs/alm/LayoutStyleType.h @@ -0,0 +1,20 @@ +#ifndef LAYOUT_STYLE_TYPE_H +#define LAYOUT_STYLE_TYPE_H + + +namespace BALM { + +/** + * The possibilities for adjusting a GUI's layout. + * Either change the child controls so that they fit into their parent control, or adjust + * the size of the parent control so that the children have as much space as they want. + */ +enum LayoutStyleType { + FIT_TO_SIZE, ADJUST_SIZE +}; + +} // namespace BALM + +using BALM::LayoutStyleType; + +#endif diff --git a/headers/libs/alm/Row.h b/headers/libs/alm/Row.h new file mode 100644 index 0000000000..bfc0903100 --- /dev/null +++ b/headers/libs/alm/Row.h @@ -0,0 +1,58 @@ +#ifndef ROW_H +#define ROW_H + +#include "Constraint.h" + +#include + + +namespace BALM { + +class BALMLayout; +class YTab; + +/** + * Represents a row defined by two y-tabs. + */ +class Row { + +public: + YTab* Top() const; + YTab* Bottom() const; + Row* Previous() const; + void SetPrevious(Row* value); + Row* Next() const; + void SetNext(Row* value); + //~ string ToString(); + void InsertBefore(Row* row); + void InsertAfter(Row* row); + Constraint* HasSameHeightAs(Row* row); + BList* Constraints() const; + void SetConstraints(BList* constraints); + ~Row(); + +protected: + Row(BALMLayout* ls); + +protected: + BALMLayout* fLS; + YTab* fTop; + YTab* fBottom; + +private: + Row* fPrevious; + Row* fNext; + Constraint* fPreviousGlue; + Constraint* fNextGlue; + BList* fConstraints; + +public: + friend class BALMLayout; + +}; + +} // namespace BALM + +using BALM::Row; + +#endif // ROW_H diff --git a/headers/libs/alm/XTab.h b/headers/libs/alm/XTab.h new file mode 100644 index 0000000000..7c07cb494a --- /dev/null +++ b/headers/libs/alm/XTab.h @@ -0,0 +1,38 @@ +#ifndef X_TAB_H +#define X_TAB_H + +#include "Variable.h" + + +namespace BALM { + +class BALMLayout; + +/** + * Vertical grid line (x-tab). + */ +class XTab : public Variable { + +protected: + XTab(BALMLayout* ls); + +protected: + /** + * Property signifying if there is a constraint which relates + * this tab to a different tab that is further to the left. + * Only used for reverse engineering. + */ + bool fLeftLink; + +public: + friend class Area; + friend class Column; + friend class BALMLayout; + +}; + +} // namespace BALM + +using BALM::XTab; + +#endif // X_TAB_H diff --git a/headers/libs/alm/YTab.h b/headers/libs/alm/YTab.h new file mode 100644 index 0000000000..85583b6606 --- /dev/null +++ b/headers/libs/alm/YTab.h @@ -0,0 +1,37 @@ +#ifndef Y_TAB_H +#define Y_TAB_H + +#include "Variable.h" + +namespace BALM { + +class BALMLayout; + +/** + * Horizontal grid line (y-tab). + */ +class YTab : public Variable { + +protected: + YTab(BALMLayout* ls); + +protected: + /** + * Property signifying if there is a constraint which relates + * this tab to a different tab that is further to the top. + * Only used for reverse engineering. + */ + bool fTopLink; + +public: + friend class Area; + friend class Row; + friend class BALMLayout; + +}; + +} // namespace BALM + +using BALM::YTab; + +#endif // Y_TAB_H diff --git a/headers/libs/linprog/Constraint.h b/headers/libs/linprog/Constraint.h new file mode 100644 index 0000000000..4787af8f87 --- /dev/null +++ b/headers/libs/linprog/Constraint.h @@ -0,0 +1,56 @@ +#ifndef CONSTRAINT_H +#define CONSTRAINT_H + +#include "OperatorType.h" + +#include +#include +#include + + +namespace LinearProgramming { + +class LinearSpec; + +/** + * Hard linear constraint, i.e. one that must be satisfied. + * May render a specification infeasible. + */ +class Constraint { + +public: + int32 Index(); + BList* Coeffs(); + BList* Vars(); + virtual void ChangeLeftSide(BList* coeffs, BList* vars); + virtual OperatorType Op(); + virtual void SetOp(OperatorType value); + double RightSide(); + void SetRightSide(double value); + BString ToString(); + virtual ~Constraint(); + +protected: + Constraint(); + +private: + Constraint(LinearSpec* ls, BList* coeffs, BList* vars, + OperatorType op, double rightSide); + +protected: + LinearSpec* fLS; + BList* fCoeffs; + BList* fVars; + OperatorType fOp; + double fRightSide; + +public: + friend class LinearSpec; + +}; + +} // namespace LinearProgramming + +using LinearProgramming::Constraint; + +#endif // CONSTRAINT_H diff --git a/headers/libs/linprog/LinearSpec.h b/headers/libs/linprog/LinearSpec.h new file mode 100644 index 0000000000..2d3e5b983f --- /dev/null +++ b/headers/libs/linprog/LinearSpec.h @@ -0,0 +1,124 @@ +#ifndef LINEAR_SPEC_H +#define LINEAR_SPEC_H + +#include "OperatorType.h" +#include "ResultType.h" +#include "OptimizationType.h" + +#include "lp_lib.h" + +#include +#include +#include + + +namespace LinearProgramming { + +class Constraint; +class ObjFunctionSummand; +class PenaltyFunction; +class SoftConstraint; +class Variable; + +/** + * Specification of a linear programming problem. + */ +class LinearSpec { + +public: + LinearSpec(); + ~LinearSpec(); + void UpdateObjFunction(); + void SetObjFunction(BList* coeffs, BList* vars); + ObjFunctionSummand* AddObjFunctionSummand(double coeff, Variable* var); + Variable* AddVariable(); + + Constraint* AddConstraint(BList* coeffs, BList* vars, + OperatorType op, double rightSide); + Constraint* AddConstraint(double coeff1, Variable* var1, + OperatorType op, double rightSide); + Constraint* AddConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, + OperatorType op, double rightSide); + Constraint* AddConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, + double coeff3, Variable* var3, + OperatorType op, double rightSide); + Constraint* AddConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, + double coeff3, Variable* var3, + double coeff4, Variable* var4, + OperatorType op, double rightSide); + + SoftConstraint* AddSoftConstraint(BList* coeffs, BList* vars, + OperatorType op, double rightSide, + double penaltyNeg, double penaltyPos); + SoftConstraint* AddSoftConstraint(double coeff1, Variable* var1, + OperatorType op, double rightSide, + double penaltyNeg, double penaltyPos); + SoftConstraint* AddSoftConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, + OperatorType op, double rightSide, + double penaltyNeg, double penaltyPos); + SoftConstraint* AddSoftConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, + double coeff3, Variable* var3, + OperatorType op, double rightSide, + double penaltyNeg, double penaltyPos); + SoftConstraint* AddSoftConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, + double coeff3, Variable* var3, + double coeff4, Variable* var4, + OperatorType op, double rightSide, + double penaltyNeg, double penaltyPos); + + PenaltyFunction* AddPenaltyFunction(Variable* var, BList* xs, BList* gs); + void RemovePresolved(); + ResultType Presolve(); + ResultType Solve(); + void Save(char* fname); + + int32 Columns() const; + void SetColumns(int32 value); + OptimizationType Optimization() const; + void SetOptimization(OptimizationType value); + lprec* LP() const; + void SetLP(lprec* value); + BList* ObjFunctionSummands() const; + void SetObjFunctionSummands(BList* value); + BList* Variables() const; + void SetVariables(BList* value); + BList* Constraints() const; + void SetConstraints(BList* value); + ResultType Result() const; + void SetResult(ResultType value); + double ObjectiveValue() const; + void SetObjectiveValue(double value); + double SolvingTime() const; + void SetSolvingTime(double value); + +protected: + int32 fColumns; + +private: + lprec* fLpPresolved; + OptimizationType fOptimization; + lprec* fLP; + BList* fObjFunctionSummands; + BList* fVariables; + BList* fConstraints; + ResultType fResult; + double fObjectiveValue; + double fSolvingTime; // = Double.Nan + +public: + friend class ObjFunctionSummand; + friend class SoftConstraint; + +}; + +} // namespace LinearProgramming + +using LinearProgramming::LinearSpec; + +#endif // LINEAR_SPEC_H diff --git a/headers/libs/linprog/ObjFunctionSummand.h b/headers/libs/linprog/ObjFunctionSummand.h new file mode 100644 index 0000000000..4a2ef04a03 --- /dev/null +++ b/headers/libs/linprog/ObjFunctionSummand.h @@ -0,0 +1,39 @@ +#ifndef OBJ_FUNCTION_SUMMAND_H +#define OBJ_FUNCTION_SUMMAND_H + + +namespace LinearProgramming { + +class LinearSpec; +class Variable; + +/** + * A summand of the objective function. + */ +class ObjFunctionSummand { + +public: + double Coeff(); + void SetCoeff(double coeff); + Variable* Var(); + void SetVar(Variable* var); + ~ObjFunctionSummand(); + +protected: + ObjFunctionSummand(LinearSpec* ls, double coeff, Variable* var); + +private: + LinearSpec* fLS; + double fCoeff; + Variable* fVar; + +public: + friend class LinearSpec; + +}; + +} // namespace LinearProgramming + +using LinearProgramming::ObjFunctionSummand; + +#endif // OBJ_FUNCTION_SUMMAND_H diff --git a/headers/libs/linprog/OperatorType.h b/headers/libs/linprog/OperatorType.h new file mode 100644 index 0000000000..6160ccc423 --- /dev/null +++ b/headers/libs/linprog/OperatorType.h @@ -0,0 +1,18 @@ +#ifndef OPERATOR_TYPE_H +#define OPERATOR_TYPE_H + + +namespace LinearProgramming { + +/** + * Possible operators for linear constraints. + */ +enum OperatorType { + EQ, LE, GE +}; + +} // namespace LinearProgramming + +using LinearProgramming::OperatorType; + +#endif diff --git a/headers/libs/linprog/OptimizationType.h b/headers/libs/linprog/OptimizationType.h new file mode 100644 index 0000000000..2da9ee120a --- /dev/null +++ b/headers/libs/linprog/OptimizationType.h @@ -0,0 +1,18 @@ +#ifndef OPTIMIZATION_TYPE_H +#define OPTIMIZATION_TYPE_H + + +namespace LinearProgramming { + +/** + * The two possibilities for optimizing the objective function. + */ +enum OptimizationType { + MINIMIZE, MAXIMIZE +}; + +} // namespace LinearProgramming + +using LinearProgramming::OptimizationType; + +#endif diff --git a/headers/libs/linprog/PenaltyFunction.h b/headers/libs/linprog/PenaltyFunction.h new file mode 100644 index 0000000000..8c45a84f1d --- /dev/null +++ b/headers/libs/linprog/PenaltyFunction.h @@ -0,0 +1,43 @@ +#ifndef PENALTY_FUNCTION_H +#define PENALTY_FUNCTION_H + +#include + + +namespace LinearProgramming { + +class LinearSpec; +class Variable; + +/** + * Penalty function. + */ +class PenaltyFunction { + +protected: + PenaltyFunction(LinearSpec* ls, Variable* var, BList* xs, BList* gs); + +public: + ~PenaltyFunction(); + const Variable* Var() const; + const BList* Xs() const; + const BList* Gs() const; + +private: + LinearSpec* fLS; + Variable* fVar; + BList* fXs; // double + BList* fGs; // double + BList* fConstraints; + BList* fObjFunctionSummands; + +public: + friend class LinearSpec; + +}; + +} // namespace LinearProgramming + +using LinearProgramming::PenaltyFunction; + +#endif // PENALTY_FUNCTION_H diff --git a/headers/libs/linprog/ResultType.h b/headers/libs/linprog/ResultType.h new file mode 100644 index 0000000000..c7eafa0917 --- /dev/null +++ b/headers/libs/linprog/ResultType.h @@ -0,0 +1,20 @@ +#ifndef RESULT_TYPE_H +#define RESULT_TYPE_H + + +namespace LinearProgramming { + +/** + * The possible results of a solving attempt. + */ +enum ResultType { + NOMEMORY = -2, ERROR = -1, OPTIMAL = 0, SUBOPTIMAL = 1, INFEASIBLE = 2, UNBOUNDED = 3, + DEGENERATE = 4, NUMFAILURE = 5, USERABORT = 6, TIMEOUT = 7, PRESOLVED = 9, PROCFAIL = 10, + PROCBREAK = 11, FEASFOUND = 12, NOFEASFOUND = 13 +}; + +} // namespace LinearProgramming + +using LinearProgramming::ResultType; + +#endif diff --git a/headers/libs/linprog/SoftConstraint.h b/headers/libs/linprog/SoftConstraint.h new file mode 100644 index 0000000000..64b89fe9dd --- /dev/null +++ b/headers/libs/linprog/SoftConstraint.h @@ -0,0 +1,54 @@ +#ifndef SOFT_CONSTRAINT_H +#define SOFT_CONSTRAINT_H + +#include "Constraint.h" + +#include + + +namespace LinearProgramming { + +class LinearSpec; +class ObjFunctionSummand; +class Variable; + +/** + * Soft constraint, i.e. one that does not necessarily have to be satisfied. + * Use this instead of hard constraints to avoid over-constrained specifications. + */ +class SoftConstraint : public Constraint { + +public: + void ChangeLeftSide(BList* coeffs, BList* vars); + OperatorType Op(); + void SetOp(OperatorType value); + double PenaltyNeg(); + void SetPenaltyNeg(double value); + double PenaltyPos(); + void SetPenaltyPos(double value); + //~ string ToString(); + Variable* DNeg() const; + Variable* DPos() const; + ~SoftConstraint(); + +protected: + SoftConstraint(LinearSpec* ls, BList* coeffs, BList* vars, + OperatorType op, double rightSide, + double penaltyNeg, double penaltyPos); + +private: + Variable* fDNeg; + Variable* fDPos; + ObjFunctionSummand* fDNegSummand; + ObjFunctionSummand* fDPosSummand; + +public: + friend class LinearSpec; + +}; + +} // namespace LinearProgramming + +using LinearProgramming::SoftConstraint; + +#endif // SOFT_CONSTRAINT_H diff --git a/headers/libs/linprog/Variable.h b/headers/libs/linprog/Variable.h new file mode 100644 index 0000000000..cc10ccf5ce --- /dev/null +++ b/headers/libs/linprog/Variable.h @@ -0,0 +1,53 @@ +#ifndef VARIABLE_H +#define VARIABLE_H + +#include + + +namespace LinearProgramming { + +class Constraint; +class LinearSpec; + +/** + * Contains minimum and maximum values. + */ +class Variable { + +public: + int32 Index(); + LinearSpec* LS() const; + void SetLS(LinearSpec* value); + double Value() const; + void SetValue(double value); + double Min() const; + void SetMin(double min); + double Max() const; + void SetMax(double max); + void SetRange(double min, double max); + //~ string ToString(); + Constraint* IsEqual(Variable* var); + Constraint* IsSmallerOrEqual(Variable* var); + Constraint* IsGreaterorEqual(Variable* var); + +protected: + Variable(LinearSpec* ls); + ~Variable(); + +private: + LinearSpec* fLS; + double fValue; + double fMin; + double fMax; + +public: + friend class LinearSpec; + friend class SoftConstraint; + +}; + +} // namespace LinearProgramming + +using LinearProgramming::Variable; + +#endif // VARIABLE_H diff --git a/src/libs/Jamfile b/src/libs/Jamfile index 79db6a99cf..81f310da3e 100644 --- a/src/libs/Jamfile +++ b/src/libs/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src libs ; SubInclude HAIKU_TOP src libs agg ; +SubInclude HAIKU_TOP src libs alm ; SubInclude HAIKU_TOP src libs bsd ; SubInclude HAIKU_TOP src libs compat ; SubInclude HAIKU_TOP src libs crypt ; @@ -10,6 +11,8 @@ SubInclude HAIKU_TOP src libs fluidsynth ; SubInclude HAIKU_TOP src libs freetype2 ; SubInclude HAIKU_TOP src libs icon ; SubInclude HAIKU_TOP src libs libtelnet ; +SubInclude HAIKU_TOP src libs linprog ; +SubInclude HAIKU_TOP src libs lp_solve ; SubInclude HAIKU_TOP src libs ncurses ; SubInclude HAIKU_TOP src libs pdflib ; SubInclude HAIKU_TOP src libs png ; diff --git a/src/libs/alm/Area.cpp b/src/libs/alm/Area.cpp new file mode 100644 index 0000000000..78fa1f5edf --- /dev/null +++ b/src/libs/alm/Area.cpp @@ -0,0 +1,1267 @@ +#include "Area.h" +#include "Column.h" +#include "BALMLayout.h" +#include "OperatorType.h" +#include "Row.h" +#include "XTab.h" +#include "YTab.h" + +#include +#include +#include +#include +#include +#include + +#include // for max + + +BSize Area::kMaxSize(INT_MAX, INT_MAX); +BSize Area::kMinSize(0, 0); +BSize Area::kUndefinedSize(-1, -1); + + +/** + * Gets the auto preferred content size. + * + * @return the auto preferred content size + */ +bool +Area::AutoPrefContentSize() const +{ + return fAutoPrefContentSize; +} + + +/** + * Sets the auto preferred content size true or false. + * + * @param value the auto preferred content size + */ +void +Area::SetAutoPrefContentSize(bool value) +{ + fAutoPrefContentSize = value; +} + + +/** + * Gets the left tab of the area. + * + * @return the left tab of the area + */ +XTab* +Area::Left() const +{ + return fLeft; +} + + +/** + * Sets the left tab of the area. + * + * @param left the left tab of the area + */ +void +Area::SetLeft(XTab* left) +{ + fLeft = left; + + fColumn = NULL; + + if (fChildArea == NULL) { + BList* coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + BList* vars = new BList(2); + vars->AddItem(fLeft); + vars->AddItem(fRight); + fMinContentWidth->ChangeLeftSide(coeffs, vars); + + if (fMaxContentWidth != NULL) { + BList* coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + BList* vars2 = new BList(2); + vars2->AddItem(fLeft); + vars2->AddItem(fRight); + fMaxContentWidth->ChangeLeftSide(coeffs2, vars2); + } + } else + UpdateHorizontal(); + fLS->InvalidateLayout(); +} + + +/** + * Gets the right tab of the area. + * + * @return the right tab of the area + */ +XTab* +Area::Right() const +{ + return fRight; +} + + +/** + * Sets the right tab of the area. + * + * @param right the right tab of the area + */ +void +Area::SetRight(XTab* right) +{ + fRight = right; + + fColumn = NULL; + + if (fChildArea == NULL) { + BList* coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + BList* vars = new BList(2); + vars->AddItem(fLeft); + vars->AddItem(fRight); + fMinContentWidth->ChangeLeftSide(coeffs, vars); + + if (fMaxContentWidth != NULL) { + BList* coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + BList* vars2 = new BList(2); + vars2->AddItem(fLeft); + vars2->AddItem(fRight); + fMaxContentWidth->ChangeLeftSide(coeffs2, vars2); + } + } else + UpdateHorizontal(); + fLS->InvalidateLayout(); +} + + +/** + * Gets the top tab of the area. + */ +YTab* +Area::Top() const +{ + return fTop; +} + + +/** + * Sets the top tab of the area. + */ +void +Area::SetTop(YTab* top) +{ + fTop = top; + + fRow = NULL; + + if (fChildArea == NULL) { + BList* coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + BList* vars = new BList(2); + vars->AddItem(fTop); + vars->AddItem(fBottom); + fMinContentHeight->ChangeLeftSide(coeffs, vars); + + if (fMaxContentHeight != NULL) { + BList* coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + BList* vars2 = new BList(2); + vars2->AddItem(fTop); + vars2->AddItem(fBottom); + fMaxContentHeight->ChangeLeftSide(coeffs2, vars2); + } + } else + UpdateVertical(); + fLS->InvalidateLayout(); +} + + +/** + * Gets the bottom tab of the area. + */ +YTab* +Area::Bottom() const +{ + return fBottom; +} + + +/** + * Sets the bottom tab of the area. + */ +void +Area::SetBottom(YTab* bottom) +{ + fBottom = bottom; + + fRow = NULL; + + if (fChildArea == NULL) { + BList* coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + BList* vars = new BList(2); + vars->AddItem(fTop); + vars->AddItem(fBottom); + fMinContentHeight->ChangeLeftSide(coeffs, vars); + + if (fMaxContentHeight != NULL) { + BList* coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + BList* vars2 = new BList(2); + vars2->AddItem(fTop); + vars2->AddItem(fBottom); + fMaxContentHeight->ChangeLeftSide(coeffs2, vars2); + } + } else + UpdateVertical(); + fLS->InvalidateLayout(); +} + + +/** + * Gets the row that defines the top and bottom tabs. + */ +Row* +Area::GetRow() const +{ + return fRow; +} + + +/** + * Sets the row that defines the top and bottom tabs. + * May be null. + */ +void +Area::SetRow(Row* row) +{ + SetTop(row->Top()); + SetBottom(row->Bottom()); + fRow = row; + fLS->InvalidateLayout(); +} + + +/** + * Gets the column that defines the left and right tabs. + */ +Column* +Area::GetColumn() const +{ + return fColumn; +} + + +/** + * Sets the column that defines the left and right tabs. + * May be null. + */ +void +Area::SetColumn(Column* column) +{ + SetLeft(column->Left()); + SetRight(column->Right()); + fColumn = column; + fLS->InvalidateLayout(); +} + + +/** + * Gets the control that is the content of the area. + */ +BView* +Area::Content() const +{ + return (fChildArea == NULL) ? fContent : fChildArea->Content(); +} + + +/** + * Sets the control that is the content of the area. + */ +void +Area::SetContent(BView* content) +{ + if (fChildArea == NULL) fContent = content; + else fChildArea->fContent = content; + fLS->InvalidateLayout(); +} + + +/** + * Left tab of the area's content. May be different from the left tab of the area. + */ +XTab* +Area::ContentLeft() const +{ + return (fChildArea == NULL) ? fLeft : fChildArea->fLeft; +} + + +/** + * Top tab of the area's content. May be different from the top tab of the area. + */ +YTab* +Area::ContentTop() const +{ + return (fChildArea == NULL) ? fTop : fChildArea->fTop; +} + + +/** + * Right tab of the area's content. May be different from the right tab of the area. + */ +XTab* +Area::ContentRight() const +{ + return (fChildArea == NULL) ? fRight : fChildArea->fRight; +} + + +/** + * Bottom tab of the area's content. May be different from the bottom tab of the area. + */ +YTab* +Area::ContentBottom() const +{ + return (fChildArea == NULL) ? fBottom : fChildArea->fBottom; +} + + +/** + * Gets minimum size of the area's content. + */ +BSize +Area::MinContentSize() const +{ + return (fChildArea == NULL) ? fMinContentSize : fChildArea->fMinContentSize; +} + + +/** + * Sets minimum size of the area's content. + * May be different from the minimum size of the area. + */ +void +Area::SetMinContentSize(BSize min) +{ + if (fChildArea == NULL) { + fMinContentSize = min; + fMinContentWidth->SetRightSide(fMinContentSize.Width()); + fMinContentHeight->SetRightSide(fMinContentSize.Height()); + } else + fChildArea->SetMinContentSize(min); + fLS->InvalidateLayout(); +} + + +/** + * Gets maximum size of the area's content. + */ +BSize Area::MaxContentSize() const { + return (fChildArea == NULL) ? fMaxContentSize : fChildArea->fMaxContentSize; +} + + +/** + * Sets maximum size of the area's content. + * May be different from the maximum size of the area. + */ +void +Area::SetMaxContentSize(BSize max) +{ + if (fChildArea == NULL) { + fMaxContentSize = max; + if (fMaxContentWidth == NULL) { + BList* coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + BList* vars = new BList(2); + vars->AddItem(fLeft); + vars->AddItem(fRight); + fMaxContentWidth = fLS->AddConstraint(coeffs, vars, OperatorType(LE), + fMaxContentSize.Width()); + fConstraints->AddItem(fMaxContentWidth); + + BList* coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + BList* vars2 = new BList(2); + vars2->AddItem(fTop); + vars2->AddItem(fBottom); + fMaxContentHeight = fLS->AddConstraint(coeffs2, vars2, OperatorType(LE), + fMaxContentSize.Height()); + fConstraints->AddItem(fMaxContentHeight); + } else { + fMaxContentWidth->SetRightSide(fMaxContentSize.Width()); + fMaxContentHeight->SetRightSide(fMaxContentSize.Height()); + } + } else + fChildArea->SetMaxContentSize(max); + fLS->InvalidateLayout(); +} + + +/** + * Gets Preferred size of the area's content. + */ +BSize +Area::PrefContentSize() const +{ + return (fChildArea == NULL) ? fPrefContentSize : fChildArea->fPrefContentSize; +} + + +/** + * Sets Preferred size of the area's content. + * May be different from the preferred size of the area. + * Manual changes of PrefContentSize are ignored unless autoPrefContentSize is set to false. + */ +void +Area::SetPrefContentSize(BSize pref) +{ + if (fChildArea == NULL) { + fPrefContentSize = pref; + if (fPrefContentWidth == NULL) { + BList* coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + BList* vars = new BList(2); + vars->AddItem(fLeft); + vars->AddItem(fRight); + fPrefContentWidth = fLS->AddSoftConstraint(coeffs, vars, OperatorType(EQ), + fPrefContentSize.Width(), fShrinkRigidity.Width(), + fExpandRigidity.Width()); + fConstraints->AddItem(fPrefContentWidth); + + BList* coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + BList* vars2 = new BList(2); + vars2->AddItem(fTop); + vars2->AddItem(fBottom); + fPrefContentHeight = fLS->AddSoftConstraint(coeffs2, vars2, OperatorType(EQ), + fPrefContentSize.Height(), fShrinkRigidity.Height(), + fExpandRigidity.Height()); + fConstraints->AddItem(fPrefContentHeight); + } else { + fPrefContentWidth->SetRightSide(pref.Width()); + fPrefContentHeight->SetRightSide(pref.Height()); + } + } else + fChildArea->SetPrefContentSize(pref); + fLS->InvalidateLayout(); +} + + +/** + * The reluctance with which the area's content shrinks below its preferred size. + * The bigger the less likely is such shrinking. + */ +BSize +Area::ShrinkRigidity() const +{ + return (fChildArea == NULL) ? fShrinkRigidity : fChildArea->fShrinkRigidity; +} + + +void Area::SetShrinkRigidity(BSize shrink) { + if (fChildArea == NULL) { + fShrinkRigidity = shrink; + if (fPrefContentWidth != NULL) { + fPrefContentWidth->SetPenaltyNeg(shrink.Width()); + fPrefContentHeight->SetPenaltyNeg(shrink.Height()); + } + } else + fChildArea->SetShrinkRigidity(shrink); + fLS->InvalidateLayout(); +} + + +/** + * The reluctance with which the area's content expands over its preferred size. + * The bigger the less likely is such expansion. + */ +BSize +Area::ExpandRigidity() const +{ + return (fChildArea == NULL) ? fExpandRigidity : fChildArea->fExpandRigidity; +} + + +void +Area::SetExpandRigidity(BSize expand) +{ + if (fChildArea == NULL) { + fExpandRigidity = expand; + if (fPrefContentWidth != NULL) { + fPrefContentWidth->SetPenaltyPos(expand.Width()); + fPrefContentHeight->SetPenaltyPos(expand.Height()); + } + } else + fChildArea->SetExpandRigidity(expand); + fLS->InvalidateLayout(); +} + + +/** + * Gets aspect ratio of the area's content. + */ +double +Area::ContentAspectRatio() const +{ + return (fChildArea == NULL) ? fContentAspectRatio : fChildArea->fContentAspectRatio; +} + + +/** + * Sets aspect ratio of the area's content. + * May be different from the aspect ratio of the area. + */ +void +Area::SetContentAspectRatio(double ratio) +{ + if (fChildArea == NULL) { + fContentAspectRatio = ratio; + if (fContentAspectRatioC == NULL) { + BList* coeffs = new BList(4); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(ratio)); + coeffs->AddItem(new double(-ratio)); + BList* vars = new BList(4); + vars->AddItem(fLeft); + vars->AddItem(fRight); + vars->AddItem(fTop); + vars->AddItem(fBottom); + fContentAspectRatioC = fLS->AddConstraint(coeffs, vars, + OperatorType(EQ), 0.0); + fConstraints->AddItem(fContentAspectRatioC); + } else { + BList* coeffs2 = new BList(4); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + coeffs2->AddItem(new double(ratio)); + coeffs2->AddItem(new double(-ratio)); + BList* vars2 = new BList(4); + vars2->AddItem(fLeft); + vars2->AddItem(fRight); + vars2->AddItem(fTop); + vars2->AddItem(fBottom); + fContentAspectRatioC->ChangeLeftSide(coeffs2, vars2); + } + } else + fChildArea->SetContentAspectRatio(ratio); + fLS->InvalidateLayout(); +} + + +/** + * Gets alignment of the content in its area. + */ +BAlignment +Area::Alignment() const +{ + return fAlignment; +} + + +/** + * Sets alignment of the content in its area. + */ +void +Area::SetAlignment(BAlignment alignment) +{ + fAlignment = alignment; + UpdateHorizontal(); + fLS->InvalidateLayout(); + UpdateVertical(); + fLS->InvalidateLayout(); +} + + +/** + * Sets horizontal alignment of the content in its area. + */ +void Area::SetHAlignment(alignment horizontal) { + fAlignment.SetHorizontal(horizontal); + UpdateHorizontal(); + fLS->InvalidateLayout(); +} + + +/** + * Sets vertical alignment of the content in its area. + */ +void +Area::SetVAlignment(vertical_alignment vertical) +{ + fAlignment.SetVertical(vertical); + UpdateVertical(); + fLS->InvalidateLayout(); +} + + +/** + * Gets left inset between area and its content. + */ +int32 +Area::LeftInset() const +{ + return fLeftInset; +} + + +/** + * Sets left inset between area and its content. + */ +void +Area::SetLeftInset(int32 left) +{ + fLeftInset = left; + UpdateHorizontal(); + fLS->InvalidateLayout(); +} + + +/** + * Gets top inset between area and its content. + */ +int32 +Area::TopInset() const +{ + return fTopInset; +} + + +/** + * Sets top inset between area and its content. + */ +void +Area::SetTopInset(int32 top) +{ + fTopInset = top; + UpdateVertical(); + fLS->InvalidateLayout(); +} + + +/** + * Gets right inset between area and its content. + */ +int32 +Area::RightInset() const +{ + return fRightInset; +} + + +/** + * Sets right inset between area and its content. + */ +void +Area::SetRightInset(int32 right) +{ + fRightInset = right; + UpdateHorizontal(); +} + + +/** + * Gets bottom inset between area and its content. + */ +int32 +Area::BottomInset() const +{ + return fBottomInset; +} + + +/** + * Sets bottom inset between area and its content. + */ +void +Area::SetBottomInset(int32 bottom) +{ + fBottomInset = bottom; + UpdateVertical(); +} + + +/** + * Sets the preferred size according to the content's PreferredSize method, + * and the rigidities according to heuristics. + */ +void +Area::SetDefaultPrefContentSize() +{ + if (Content() == NULL) { + SetPrefContentSize(BSize(0, 0)); + SetShrinkRigidity(BSize(0, 0)); + SetExpandRigidity(BSize(0, 0)); + return; + } + + if (PrefContentSize() != Content()->PreferredSize()){ + SetPrefContentSize(Content()->PreferredSize()); + fLS->InvalidateLayout(); + } + + if (dynamic_cast(Content()) != NULL + || dynamic_cast(Content()) != NULL + || dynamic_cast(Content()) != NULL + || dynamic_cast(Content()) != NULL + || dynamic_cast(Content()) != NULL + || dynamic_cast(Content()) != NULL) { + //~ || Content is LinkLabel + //~ || Content is NumericUpDown) { + fShrinkRigidity = BSize(4, 4); + fExpandRigidity = BSize(3, 3); + } else { + fShrinkRigidity = BSize(2, 2); + fExpandRigidity = BSize(1, 1); + } +} + + +//~ string Area::ToString() { + //~ return "Area(" + fLeft->ToString() + "," + fTop->ToString() + "," + //~ + fRight->ToString() + "," + fBottom->ToString() + ")"; +//~ } + + +/** + * Sets the width of the area to be the same as the width of the given area. + * + * @param area the area that should have the same width + * @return the same-width constraint + */ +Constraint* +Area::HasSameWidthAs(Area* area) +{ + BList* coeffs = new BList(4); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(-1.0)); + BList* vars = new BList(4); + vars->AddItem(fLeft); + vars->AddItem(fRight); + vars->AddItem(area->fLeft); + vars->AddItem(area->fRight); + return fLS->AddConstraint(coeffs, vars, OperatorType(EQ), 0.0); +} + + +/** + * Sets the height of the area to be the same as the height of the given area. + * + * @param area the area that should have the same height + * @return the same-height constraint + */ +Constraint* +Area::HasSameHeightAs(Area* area) +{ + BList* coeffs = new BList(4); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(-1.0)); + BList* vars = new BList(4); + vars->AddItem(fTop); + vars->AddItem(fBottom); + vars->AddItem(area->fTop); + vars->AddItem(area->fBottom); + return fLS->AddConstraint(coeffs, vars, OperatorType(EQ), 0.0); +} + + +/** + * Sets the size of the area to be the same as the size of the given area. + * + * @param area the area that should have the same size + * @return a list containing a same-width and same-height constraint + */ +BList* +Area::HasSameSizetAs(Area* area) +{ + BList* constraints = new BList(2); + constraints->AddItem(this->HasSameWidthAs(area)); + constraints->AddItem(this->HasSameHeightAs(area)); + return constraints; +} + + +/** + * Destructor. + * Removes the area from its specification. + */ +Area::~Area() +{ + if (fChildArea != NULL) delete fChildArea; + for (int32 i = 0; i < fConstraints->CountItems(); i++) + delete (Constraint*)fConstraints->ItemAt(i); + fLS->Areas()->RemoveItem(this); +} + + +/** + * Constructor. + * Uses XTabs and YTabs. + */ +Area::Area(BALMLayout* ls, XTab* left, YTab* top, XTab* right, YTab* bottom, + BView* content, BSize minContentSize) +{ + Init(ls, left, top, right, bottom, content, minContentSize); +} + + +/** + * Constructor. + * Uses Rows and Columns. + */ +Area::Area(BALMLayout* ls, Row* row, Column* column, BView* content, + BSize minContentSize) +{ + + Init(ls, column->Left(), row->Top(), column->Right(), row->Bottom(), + content, minContentSize); + fRow = row; + fColumn = column; +} + + +/** + * Initialize variables. + */ +void +Area::Init(BALMLayout* ls, XTab* left, YTab* top, XTab* right, YTab* bottom, + BView* content, BSize minContentSize) +{ + + fConstraints = new BList(2); + fMaxContentSize = kMaxSize; + + fMaxContentWidth = NULL; + fMaxContentHeight = NULL; + + fPrefContentSize = kUndefinedSize; + fShrinkRigidity = BSize(2, 2); + fExpandRigidity = BSize(1, 1); + fContentAspectRatio = NULL; + fContentAspectRatioC = NULL; + + fAutoPrefContentSize = false; + + fPrefContentWidth = NULL; + fPrefContentHeight = NULL; + + fChildArea = NULL; + + fAlignment = BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); + fLeftInset = 0; + fTopInset = 0; + fRightInset = 0; + fBottomInset = 0; + + fLeftConstraint = NULL; + fTopConstraint = NULL; + fRightConstraint = NULL; + fBottomConstraint = NULL; + + fLS = ls; + fLeft = left; + fRight = right; + fTop = top; + fBottom = bottom; + SetContent(content); + fMinContentSize = minContentSize; + + // adds the two essential constraints of the area that make sure that the left x-tab is + // really to the left of the right x-tab, and the top y-tab really above the bottom y-tab + BList* coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + BList* vars = new BList(2); + vars->AddItem(left); + vars->AddItem(right); + fMinContentWidth = ls->AddConstraint(coeffs, vars, OperatorType(GE), + minContentSize.Width()); + fConstraints->AddItem(fMinContentWidth); + + BList* coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + BList* vars2 = new BList(2); + vars2->AddItem(top); + vars2->AddItem(bottom); + fMinContentHeight = ls->AddConstraint(coeffs2, vars2, OperatorType(GE), + minContentSize.Height()); + fConstraints->AddItem(fMinContentHeight); +} + + +/** + * Perform layout on the area. + */ +void Area::DoLayout() +{ + if (Content() == NULL) + return; // empty areas need no layout + + // if there is a childArea, then it is the childArea that actually contains the content + Area* area = (fChildArea != NULL) ? fChildArea : this; + + // set content location and size + area->Content()->MoveTo(floor(area->Left()->Value() + 0.5), + floor(area->Top()->Value() + 0.5)); + int32 width = (int32)floor(area->Right()->Value() - area->Left()->Value() + 0.5); + int32 height = (int32)floor(area->Bottom()->Value() - area->Top()->Value() + 0.5); + area->Content()->ResizeTo(width, height); +} + + +/** + * Adds a childArea to this area, together with constraints that specify the relative location + * of the childArea within this area. It is called when such a childArea becomes necessary, + * i.e. when the user requests insets or special alignment. + */ +void +Area::InitChildArea() +{ + // add a child area with new tabs, + // and add constraints that set its tabs to be equal to the + // coresponding tabs of this area (for a start) + fChildArea = new Area(fLS, new XTab(fLS), new YTab(fLS), new XTab(fLS), + new YTab(fLS), fContent, BSize(0, 0)); + fLeftConstraint = Left()->IsEqual(fChildArea->Left()); + fConstraints->AddItem(fLeftConstraint); + fTopConstraint = Top()->IsEqual(fChildArea->Top()); + fConstraints->AddItem(fTopConstraint); + fRightConstraint = Right()->IsEqual(fChildArea->Right()); + fConstraints->AddItem(fRightConstraint); + fBottomConstraint = Bottom()->IsEqual(fChildArea->Bottom()); + fConstraints->AddItem(fBottomConstraint); + + // remove the minimum content size constraints from this area + // and copy the minimum content size setting to the childArea + fConstraints->RemoveItem(fMinContentWidth); + delete fMinContentWidth; + fMinContentWidth = fChildArea->fMinContentWidth; + fConstraints->RemoveItem(fMinContentHeight); + delete fMinContentHeight; + fMinContentHeight = fChildArea->fMinContentHeight; + fChildArea->SetMinContentSize(fMinContentSize); + + // if there are maximum content size constraints on this area, + // change them so that they refer to the tabs of the childArea + // and copy the minimum content size settings to the childArea + if (fMaxContentWidth != NULL) { + fChildArea->fMaxContentSize = fMaxContentSize; + + fChildArea->fMaxContentWidth = fMaxContentWidth; + BList* coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + BList* vars = new BList(2); + vars->AddItem(fChildArea->Left()); + vars->AddItem(fChildArea->Right()); + fMaxContentWidth->ChangeLeftSide(coeffs, vars); + + fChildArea->fMaxContentHeight = fMaxContentHeight; + BList* coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + BList* vars2 = new BList(2); + vars2->AddItem(fChildArea->Top()); + vars2->AddItem(fChildArea->Bottom()); + fMaxContentHeight->ChangeLeftSide(coeffs2, vars2); + } + + // if there are preferred content size constraints on this area, + // change them so that they refer to the tabs of the childArea + // and copy the preferred content size settings to the childArea + if (fPrefContentHeight != NULL) { + fChildArea->fPrefContentSize = fPrefContentSize; + fChildArea->fShrinkRigidity = fShrinkRigidity; + fChildArea->fExpandRigidity = fExpandRigidity; + + fChildArea->fPrefContentWidth = fPrefContentWidth; + BList* coeffs3 = new BList(2); + coeffs3->AddItem(new double(-1.0)); + coeffs3->AddItem(new double(1.0)); + BList* vars3 = new BList(2); + vars3->AddItem(fChildArea->Left()); + vars3->AddItem(fChildArea->Right()); + fPrefContentWidth->ChangeLeftSide(coeffs3, vars3); + + fChildArea->fPrefContentHeight = fPrefContentHeight; + BList* coeffs4 = new BList(2); + coeffs4->AddItem(new double(-1.0)); + coeffs4->AddItem(new double(1.0)); + BList* vars4 = new BList(2); + vars4->AddItem(fChildArea->Top()); + vars4->AddItem(fChildArea->Bottom()); + fPrefContentHeight->ChangeLeftSide(coeffs4, vars4); + } +} + + +/** + * Update the constraints for horizontal insets and alignment. + */ +void +Area::UpdateHorizontal() +{ + // if the area does not have a childAdrea yet, this is the time to add it + if (fChildArea == NULL) + InitChildArea(); + + BList* coeffs; + BList* coeffs2; + BList* vars; + BList* vars2; + + // change the constraints leftConstraint and rightConstraint so that the horizontal + // alignment and insets of the childArea within this area are as specified by the user + if (fAlignment.Horizontal() == B_ALIGN_LEFT) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Left()); + vars->AddItem(fChildArea->Left()); + fLeftConstraint->ChangeLeftSide(coeffs, vars); + fLeftConstraint->SetOp(OperatorType(EQ)); + fLeftConstraint->SetRightSide(fLeftInset); + + coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + vars2 = new BList(2); + vars2->AddItem(fChildArea->Right()); + vars2->AddItem(Right()); + fRightConstraint->ChangeLeftSide(coeffs2, vars2); + fRightConstraint->SetOp(OperatorType(GE)); + fRightConstraint->SetRightSide(fRightInset); + } else if (fAlignment.Horizontal() == B_ALIGN_RIGHT) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Left()); + vars->AddItem(fChildArea->Left()); + fLeftConstraint->ChangeLeftSide(coeffs, vars); + fLeftConstraint->SetOp(OperatorType(GE)); + fLeftConstraint->SetRightSide(fLeftInset); + + coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + vars2 = new BList(2); + vars2->AddItem(fChildArea->Right()); + vars2->AddItem(Right()); + fRightConstraint->ChangeLeftSide(coeffs2, vars2); + fRightConstraint->SetOp(OperatorType(EQ)); + fRightConstraint->SetRightSide(fRightInset); + } else if (fAlignment.Horizontal() == B_ALIGN_HORIZONTAL_CENTER) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Left()); + vars->AddItem(fChildArea->Left()); + fLeftConstraint->ChangeLeftSide(coeffs, vars); + fLeftConstraint->SetOp(OperatorType(GE)); + fLeftConstraint->SetRightSide(max(fLeftInset, fRightInset)); + + coeffs2 = new BList(4); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + coeffs2->AddItem(new double(1.0)); + coeffs2->AddItem(new double(-1.0)); + vars2 = new BList(4); + vars2->AddItem(Left()); + vars2->AddItem(fChildArea->Left()); + vars2->AddItem(fChildArea->Right()); + vars2->AddItem(Right()); + fRightConstraint->ChangeLeftSide(coeffs2, vars2); + fRightConstraint->SetOp(OperatorType(EQ)); + fRightConstraint->SetRightSide(0); + } else if (fAlignment.Horizontal() == B_ALIGN_USE_FULL_WIDTH) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Left()); + vars->AddItem(fChildArea->Left()); + fLeftConstraint->ChangeLeftSide(coeffs, vars); + fLeftConstraint->SetOp(OperatorType(EQ)); + fLeftConstraint->SetRightSide(fLeftInset); + + coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + vars2 = new BList(2); + vars2->AddItem(fChildArea->Right()); + vars2->AddItem(Right()); + fRightConstraint->ChangeLeftSide(coeffs2, vars2); + fRightConstraint->SetOp(OperatorType(EQ)); + fRightConstraint->SetRightSide(fRightInset); + } else if (fAlignment.Horizontal() == B_ALIGN_HORIZONTAL_UNSET) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Left()); + vars->AddItem(fChildArea->Left()); + fLeftConstraint->ChangeLeftSide(coeffs, vars); + fLeftConstraint->SetOp(OperatorType(GE)); + fLeftConstraint->SetRightSide(fLeftInset); + + coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + vars2 = new BList(2); + vars2->AddItem(fChildArea->Right()); + vars2->AddItem(Right()); + fRightConstraint->ChangeLeftSide(coeffs2, vars2); + fRightConstraint->SetOp(OperatorType(GE)); + fRightConstraint->SetRightSide(fRightInset); + } +} + + +/** + * Update the constraints for vertical insets and alignment. + */ +void Area::UpdateVertical() { + // if the area does not have a childAdrea yet, this is the time to add it + if (fChildArea == NULL) + InitChildArea(); + + BList* coeffs; + BList* coeffs2; + BList* vars; + BList* vars2; + + // change the constraints topConstraint and bottomConstraint so that the vertical + // alignment and insets of the childArea within this area are as specified by the user + if (fAlignment.Vertical() == B_ALIGN_TOP) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Top()); + vars->AddItem(fChildArea->Top()); + fTopConstraint->ChangeLeftSide(coeffs, vars); + fTopConstraint->SetOp(OperatorType(EQ)); + fTopConstraint->SetRightSide(fTopInset); + + coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + vars2 = new BList(2); + vars2->AddItem(fChildArea->Bottom()); + vars2->AddItem(Bottom()); + fBottomConstraint->ChangeLeftSide(coeffs2, vars2); + fBottomConstraint->SetOp(OperatorType(GE)); + fBottomConstraint->SetRightSide(fBottomInset); + } else if (fAlignment.Vertical() == B_ALIGN_BOTTOM) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Top()); + vars->AddItem(fChildArea->Top()); + fTopConstraint->ChangeLeftSide(coeffs, vars); + fTopConstraint->SetOp(OperatorType(GE)); + fTopConstraint->SetRightSide(fTopInset); + + coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + vars2 = new BList(2); + vars2->AddItem(fChildArea->Bottom()); + vars2->AddItem(Bottom()); + fBottomConstraint->ChangeLeftSide(coeffs2, vars2); + fBottomConstraint->SetOp(OperatorType(EQ)); + fBottomConstraint->SetRightSide(fBottomInset); + } else if (fAlignment.Vertical() == B_ALIGN_VERTICAL_CENTER) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Top()); + vars->AddItem(fChildArea->Top()); + fTopConstraint->ChangeLeftSide(coeffs, vars); + fTopConstraint->SetOp(OperatorType(GE)); + fTopConstraint->SetRightSide(max(fTopInset, fBottomInset)); + + coeffs2 = new BList(4); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + coeffs2->AddItem(new double(1.0)); + coeffs2->AddItem(new double(-1.0)); + vars2 = new BList(4); + vars2->AddItem(Top()); + vars2->AddItem(fChildArea->Top()); + vars2->AddItem(fChildArea->Bottom()); + vars2->AddItem(Bottom()); + fBottomConstraint->ChangeLeftSide(coeffs2, vars2); + fBottomConstraint->SetOp(OperatorType(EQ)); + fBottomConstraint->SetRightSide(0); + } else if (fAlignment.Vertical() == B_ALIGN_USE_FULL_HEIGHT) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Top()); + vars->AddItem(fChildArea->Top()); + fTopConstraint->ChangeLeftSide(coeffs, vars); + fTopConstraint->SetOp(OperatorType(EQ)); + fTopConstraint->SetRightSide(fTopInset); + + coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + vars2 = new BList(2); + vars2->AddItem(fChildArea->Bottom()); + vars2->AddItem(Bottom()); + fBottomConstraint->ChangeLeftSide(coeffs2, vars2); + fBottomConstraint->SetOp(OperatorType(EQ)); + fBottomConstraint->SetRightSide(fBottomInset); + } else if (fAlignment.Vertical() == B_ALIGN_VERTICAL_UNSET) { + coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + vars = new BList(2); + vars->AddItem(Top()); + vars->AddItem(fChildArea->Top()); + fTopConstraint->ChangeLeftSide(coeffs, vars); + fTopConstraint->SetOp(OperatorType(GE)); + fTopConstraint->SetRightSide(fTopInset); + + coeffs2 = new BList(2); + coeffs2->AddItem(new double(-1.0)); + coeffs2->AddItem(new double(1.0)); + vars2 = new BList(2); + vars2->AddItem(fChildArea->Bottom()); + vars2->AddItem(Bottom()); + fBottomConstraint->ChangeLeftSide(coeffs2, vars2); + fBottomConstraint->SetOp(OperatorType(GE)); + fBottomConstraint->SetRightSide(fBottomInset); + } +} + diff --git a/src/libs/alm/BALMLayout.cpp b/src/libs/alm/BALMLayout.cpp new file mode 100644 index 0000000000..2d3e50a65e --- /dev/null +++ b/src/libs/alm/BALMLayout.cpp @@ -0,0 +1,699 @@ +#include "BALMLayout.h" +#include "Area.h" +#include "Column.h" +#include "ResultType.h" +#include "Row.h" +#include "XTab.h" +#include "YTab.h" + +#include // for floor + + +/** + * Constructor. + * Creates new layout engine. + */ +BALMLayout::BALMLayout() + : BLayout(), + LinearSpec() +{ + fLayoutStyle = FIT_TO_SIZE; + fActivated = true; + + fAreas = new BList(1); + fLeft = new XTab(this); + fRight = new XTab(this); + fTop = new YTab(this); + fBottom = new YTab(this); + + // the Left tab is always at x-position 0, and the Top tab is always at y-position 0 + fLeft->SetRange(0, 0); + fTop->SetRange(0, 0); + + // cached layout values + // need to be invalidated whenever the layout specification is changed + fMinSize = Area::kUndefinedSize; + fMaxSize = Area::kUndefinedSize; + fPreferredSize = Area::kUndefinedSize; + + fPerformancePath = NULL; +} + + +/** + * Solves the layout. + */ +void +BALMLayout::SolveLayout() +{ + // if autoPrefContentSize is set on an area, readjust its prefContentSize and + // rigidity settings + int32 sizeAreas = fAreas->CountItems(); + Area* currentArea; + for (int32 i = 0; i < sizeAreas; i++) { + currentArea = (Area*)fAreas->ItemAt(i); + if (currentArea->AutoPrefContentSize()) + currentArea->SetDefaultPrefContentSize(); + } + + // try to solve the layout until the result is OPTIMAL or INFEASIBLE, maximally + // 15 tries sometimes the solving algorithm encounters numerical problems + // (NUMFAILURE), and repeating the solving often helps to overcome them + BFile* file = new BFile(fPerformancePath, + B_READ_WRITE | B_CREATE_FILE | B_OPEN_AT_END); + + ResultType result; + for (int32 tries = 0; tries < 15; tries++) { + result = Solve(); + if (fPerformancePath != NULL) { + char buffer [100]; + file->Write(buffer, sprintf(buffer, "%d\t%fms\t#vars=%d\t#constraints=%d\n", + result, SolvingTime(), Variables()->CountItems(), + Constraints()->CountItems())); + } + if (result == OPTIMAL || result == INFEASIBLE) break; + } + delete file; +} + + +/** + * Adds a new x-tab to the specification. + * + * @return the new x-tab + */ +XTab* +BALMLayout::AddXTab() +{ + return new XTab(this); +} + + +/** + * Adds a new y-tab to the specification. + * + * @return the new y-tab + */ +YTab* +BALMLayout::AddYTab() +{ + return new YTab(this); +} + + +/** + * Adds a new row to the specification. + * + * @return the new row + */ +Row* +BALMLayout::AddRow() +{ + return new Row(this); +} + + +/** + * Adds a new row to the specification that is glued to the given y-tabs. + * + * @param top + * @param bottom + * @return the new row + */ +Row* +BALMLayout::AddRow(YTab* top, YTab* bottom) +{ + Row* row = new Row(this); + if (top != NULL) row->Constraints()->AddItem(row->Top()->IsEqual(top)); + if (bottom != NULL) row->Constraints()->AddItem(row->Bottom()->IsEqual(bottom)); + return row; +} + + +/** + * Adds a new column to the specification. + * + * @return the new column + */ +Column* +BALMLayout::AddColumn() +{ + return new Column(this); +} + + +/** + * Adds a new column to the specification that is glued to the given x-tabs. + * + * @param left + * @param right + * @return the new column + */ +Column* +BALMLayout::AddColumn(XTab* left, XTab* right) +{ + Column* column = new Column(this); + if (left != NULL) column->Constraints()->AddItem(column->Left()->IsEqual(left)); + if (right != NULL) column->Constraints()->AddItem(column->Right()->IsEqual(right)); + return column; +} + + +/** + * Adds a new area to the specification, setting only the necessary minimum size constraints. + * + * @param left left border + * @param top top border + * @param right right border + * @param bottom bottom border + * @param content the control which is the area content + * @param minContentSize minimum content size + * @return the new area + */ +Area* +BALMLayout::AddArea(XTab* left, YTab* top, XTab* right, YTab* bottom, + BView* content, BSize minContentSize) +{ + InvalidateLayout(); + if (content != NULL) + View()->AddChild(content); + Area* area = new Area(this, left, top, right, bottom, content, minContentSize); + fAreas->AddItem(area); + return area; +} + + +/** + * Adds a new area to the specification, setting only the necessary minimum size constraints. + * + * @param row the row that defines the top and bottom border + * @param column the column that defines the left and right border + * @param content the control which is the area content + * @param minContentSize minimum content size + * @return the new area + */ +Area* +BALMLayout::AddArea(Row* row, Column* column, BView* content, + BSize minContentSize) +{ + InvalidateLayout(); + if (content != NULL) + View()->AddChild(content); + Area* area = new Area(this, row, column, content, minContentSize); + fAreas->AddItem(area); + return area; +} + + +/** + * Adds a new area to the specification, automatically setting preferred size constraints. + * + * @param left left border + * @param top top border + * @param right right border + * @param bottom bottom border + * @param content the control which is the area content + * @return the new area + */ +Area* +BALMLayout::AddArea(XTab* left, YTab* top, XTab* right, YTab* bottom, + BView* content) +{ + InvalidateLayout(); + if (content != NULL) + View()->AddChild(content); + Area* area = new Area(this, left, top, right, bottom, content, BSize(0, 0)); + area->SetDefaultPrefContentSize(); + area->SetAutoPrefContentSize(true); + fAreas->AddItem(area); + return area; +} + + +/** + * Adds a new area to the specification, automatically setting preferred size constraints. + * + * @param row the row that defines the top and bottom border + * @param column the column that defines the left and right border + * @param content the control which is the area content + * @return the new area + */ +Area* +BALMLayout::AddArea(Row* row, Column* column, BView* content) +{ + InvalidateLayout(); + if (content != NULL) + View()->AddChild(content); + Area* area = new Area(this, row, column, content, BSize(0, 0)); + area->SetDefaultPrefContentSize(); + area->SetAutoPrefContentSize(true); + fAreas->AddItem(area); + return area; +} + + +/** + * Finds the area that contains the given control. + * + * @param control the control to look for + * @return the area that contains the control + */ +Area* +BALMLayout::AreaOf(BView* control) +{ + Area* area; + for (int32 i = 0; i < fAreas->CountItems(); i++) { + area = (Area*)fAreas->ItemAt(i); + if (area->Content() == control) + return area; + } + return NULL; +} + + +/** + * Gets the ares. + * + * @return the areas + */ +BList* +BALMLayout::Areas() const +{ + return fAreas; +} + + +/** + * Sets the ares. + * + * @param areas the areas + */ +void +BALMLayout::SetAreas(BList* areas) +{ + fAreas = areas; +} + + +/** + * Gets the left variable. + */ +XTab* +BALMLayout::Left() const +{ + return fLeft; +} + + +/** + * Sets the left variable. + */ +void +BALMLayout::SetLeft(XTab* left) +{ + fLeft = left; +} + + +/** + * Gets the right variable. + */ +XTab* +BALMLayout::Right() const +{ + return fRight; +} + + +/** + * Sets the right variable. + */ +void +BALMLayout::SetRight(XTab* right) +{ + fRight = right; +} + + +/** + * Gets the top variable. + */ +YTab* +BALMLayout::Top() const +{ + return fTop; +} + + +/** + * Sets the top variable. + */ +void +BALMLayout::SetTop(YTab* top) +{ + fTop = top; +} + + +/** + * Gets the bottom variable. + */ +YTab* +BALMLayout::Bottom() const +{ + return fBottom; +} + + +/** + * Sets the bottom variable. + */ +void +BALMLayout::SetBottom(YTab* bottom) +{ + fBottom = bottom; +} + + +/** + * Reverse engineers a GUI and recovers an ALM specification. + * @param parent the parent container of the GUI + */ +void +BALMLayout::RecoverLayout(BView* parent) {} // Still working on it. + + +/** + * Gets the current layout style. + */ +LayoutStyleType +BALMLayout::LayoutStyle() const +{ + return fLayoutStyle; +} + + +/** + * Sets the current layout style. + */ +void +BALMLayout::SetLayoutStyle(LayoutStyleType style) +{ + fLayoutStyle = style; +} + + +/** + * Adds view to layout. + */ +BLayoutItem* +BALMLayout::AddView(BView* child) +{ + return NULL; +} + + +/** + * Adds view to layout. + */ +BLayoutItem* +BALMLayout::AddView(int32 index, BView* child) +{ +return NULL; +} + + +/** + * Adds item to layout. + */ +bool +BALMLayout::AddItem(BLayoutItem* item) +{ + return false; +} + + +/** + * Adds item to layout. + */ +bool +BALMLayout::AddItem(int32 index, BLayoutItem* item) +{ + return false; +} + + +/** + * Removes view from layout. + */ +bool +BALMLayout::RemoveView(BView* child) +{ + return false; +} + + +/** + * Removes item from layout. + */ +bool +BALMLayout::RemoveItem(BLayoutItem* item) +{ + return false; +} + + +/** + * Removes item from layout. + */ +BLayoutItem* +BALMLayout::RemoveItem(int32 index) +{ + return NULL; +} + + +/** + * Sets and gets minimum size. + */ +BSize BALMLayout::MinSize() { + if (fMinSize == Area::kUndefinedSize) + fMinSize = CalculateMinSize(); + return fMinSize; +} + + +/** + * Sets and gets maximum size. + */ +BSize +BALMLayout::MaxSize() +{ + if (fMaxSize == Area::kUndefinedSize) + fMaxSize = CalculateMaxSize(); + return fMaxSize; +} + + +/** + * Sets and gets preferred size. + */ +BSize +BALMLayout::PreferredSize() +{ + if (fPreferredSize == Area::kUndefinedSize) + fPreferredSize = CalculatePreferredSize(); + return fPreferredSize; +} + + +/** + * Gets the alignment. + */ +BAlignment +BALMLayout::Alignment() +{ + BAlignment alignment; + alignment.SetHorizontal(B_ALIGN_HORIZONTAL_CENTER); + alignment.SetVertical(B_ALIGN_VERTICAL_CENTER); + return alignment; +} + + +/** + * Gets whether the height of the layout depends on its width. + */ +bool +BALMLayout::HasHeightForWidth() +{ + return false; +} + + +/** + * Sets whether the height of the layout depends on its width. + */ +void +BALMLayout::GetHeightForWidth(float width, float* min, float* max, float* preferred) {} + + +/** + * Invalidates the layout. + * Resets minimum/maximum/preferred size. + */ +void +BALMLayout::InvalidateLayout() +{ + fMinSize = Area::kUndefinedSize; + fMaxSize = Area::kUndefinedSize; + fPreferredSize = Area::kUndefinedSize; +} + + +/** + * Calculate and set the layout. + * If no layout specification is given, a specification is reverse engineered automatically. + */ +void +BALMLayout::LayoutView() +{ + // make sure that layout events occuring during layout are ignored + // i.e. activated is set to false during layout caluclation + if (!fActivated) + return; + fActivated = false; + + if (View() == NULL) + return; + + // reverse engineer a layout specification if none was given + //~ if (this == NULL) RecoverLayout(View()); + + // if the layout engine is set to fit the GUI to the given size, + // then the given size is enforced by setting absolute positions for Right and Bottom + if (fLayoutStyle == FIT_TO_SIZE) { + Right()->SetRange(View()->Bounds().Width(), View()->Bounds().Width()); + Bottom()->SetRange(View()->Bounds().Height(), View()->Bounds().Height()); + } + + SolveLayout(); + + // if new layout is infasible, use previous layout + if (Result() == INFEASIBLE) { + fActivated = true; // now layout calculation is allowed to run again + return; + } + + if (Result() != OPTIMAL) { + Save("failed-layout.txt"); + printf("Could not solve the layout specification (%d). ", Result()); + printf("Saved specification in file failed-layout.txt\n"); + } + + // change the size of the GUI according to the calculated size + // if the layout engine was configured to do so + if (fLayoutStyle == ADJUST_SIZE) { + View()->ResizeTo(floor(Right()->Value() - Left()->Value() + 0.5), + floor(Bottom()->Value() - Top()->Value() + 0.5)); + } + + // set the calculated positions and sizes for every area + for (int32 i = 0; i < Areas()->CountItems(); i++) + ((Area*)Areas()->ItemAt(i))->DoLayout(); + + fActivated = true; +} + + +/** + * Gets the path of the performance log file. + * + * @return the path of the performance log file + */ +char* +BALMLayout::PerformancePath() const +{ + return fPerformancePath; +} + + +/** + * Sets the path of the performance log file. + * + * @param path the path of the performance log file + */ +void +BALMLayout::SetPerformancePath(char* path) +{ + fPerformancePath = path; +} + + +/** + * Caculates the miminum size. + */ +BSize +BALMLayout::CalculateMinSize() +{ + printf("CalculateMinSize"); + BList* buf = ObjFunctionSummands(); + SetObjFunctionSummands(new BList(2)); + AddObjFunctionSummand(1.0, fRight); + AddObjFunctionSummand(1.0, fBottom); + SolveLayout(); + SetObjFunctionSummands(buf); + UpdateObjFunction(); + + if (Result() == UNBOUNDED) + return Area::kMinSize; + if (Result() != OPTIMAL) { + Save("failed-layout.txt"); + printf("Could not solve the layout specification (%d). Saved specification in file failed-layout.txt", Result()); + } + + return BSize(Right()->Value() - Left()->Value(), Bottom()->Value() - Top()->Value()); +} + + +/** + * Caculates the maximum size. + */ +BSize +BALMLayout::CalculateMaxSize() +{ + printf("CalculateMaxSize"); + BList* buf = ObjFunctionSummands(); + SetObjFunctionSummands(new BList(2)); + AddObjFunctionSummand(-1.0, fRight); + AddObjFunctionSummand(-1.0, fBottom); + SolveLayout(); + SetObjFunctionSummands(buf); + UpdateObjFunction(); + + if (Result() == UNBOUNDED) + return Area::kMaxSize; + if (Result() != OPTIMAL) { + Save("failed-layout.txt"); + printf("Could not solve the layout specification (%d). Saved specification in file failed-layout.txt", Result()); + } + + return BSize(Right()->Value() - Left()->Value(), Bottom()->Value() - Top()->Value()); +} + + +/** + * Caculates the preferred size. + */ +BSize +BALMLayout::CalculatePreferredSize() +{ + printf("CalculatePreferredSize"); + SolveLayout(); + if (Result() != OPTIMAL) { + Save("failed-layout.txt"); + printf("Could not solve the layout specification (%d). Saved specification in file failed-layout.txt", Result()); + } + + return BSize(Right()->Value() - Left()->Value(), Bottom()->Value() - Top()->Value()); +} + diff --git a/src/libs/alm/Column.cpp b/src/libs/alm/Column.cpp new file mode 100644 index 0000000000..693fb8c597 --- /dev/null +++ b/src/libs/alm/Column.cpp @@ -0,0 +1,218 @@ +#include "Column.h" +#include "BALMLayout.h" +#include "OperatorType.h" +#include "XTab.h" + +#include + + +/** + * The left boundary of the column. + */ +XTab* +Column::Left() const +{ + return fLeft; +} + + +/** + * The right boundary of the column. + */ +XTab* +Column::Right() const +{ + return fRight; +} + + +/** + * Gets the column directly to the left of this column. + */ +Column* +Column::Previous() const +{ + return fPrevious; +} + + +/** + * Sets the column directly to the left of this column. + * May be null. + */ +void +Column::SetPrevious(Column* value) +{ + // if there should be no column directly left of this column, then we have to + // separate any such column and can remove any constraint that was used + // to glue this column to it + if (value == NULL) { + if (fPrevious == NULL) return; + fPrevious->fNext = NULL; + fPrevious->fNextGlue = NULL; + fPrevious = NULL; + delete fPreviousGlue; + fPreviousGlue = NULL; + return; + } + + // otherwise we have to set up the pointers and the glue constraint accordingly + if (value->fNext != NULL) + value->SetNext(NULL); + if (fPrevious != NULL) + SetPrevious(NULL); + + fPrevious = value; + fPrevious->fNext = this; + value->fNextGlue = value->fRight->IsEqual(fLeft); + fPreviousGlue = value->fNextGlue; +} + + +/** + * Gets the column directly to the right of this column. + */ +Column* +Column::Next() const +{ + return fNext; +} + + +/** + * Sets the column directly to the right of this column. + * May be null. + */ +void +Column::SetNext(Column* value) +{ + // if there should be no column directly right of this column, then we have to + // separate any such column and can remove any constraint that was used + // to glue this column to it + if (value == NULL) { + if (fNext == NULL) return; + fNext->fPrevious = NULL; + fNext->fPreviousGlue = NULL; + fNext = NULL; + delete fNextGlue; + fNextGlue = NULL; + return; + } + + // otherwise we have to set up the pointers and the glue constraint accordingly + if (value->fPrevious != NULL) + value->SetPrevious(NULL); + if (fNext != NULL) + SetNext(NULL); + + fNext = value; + fNext->fPrevious = this; + value->fPreviousGlue = fRight->IsEqual(value->fLeft); + fNextGlue = value->fPreviousGlue; +} + + +//~ string Column::ToString() { + //~ return "Column(" + fLeft.ToString() + ", " + fRight.ToString() + ")"; +//~ } + + +/** + * Inserts the given column directly to the left of this column. + * + * @param column the column to insert + */ +void +Column::InsertBefore(Column* column) +{ + SetPrevious(column->fPrevious); + SetNext(column); +} + + +/** + * Inserts the given column directly to the right of this column. + * + * @param column the column to insert + */ +void +Column::InsertAfter(Column* column) +{ + SetNext(column->fNext); + SetPrevious(column); +} + + +/** + * Constrains this column to have the same width as the given column. + * + * @param column the column that should have the same width + * @return the resulting same-width constraint + */ +Constraint* +Column::HasSameWidthAs(Column* column) +{ + BList* coeffs = new BList(4); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(-1.0)); + + BList* vars = new BList(4); + vars->AddItem(fLeft); + vars->AddItem(fRight); + vars->AddItem(column->fLeft); + vars->AddItem(column->fRight); + + Constraint* constraint = fLS->AddConstraint(coeffs, vars, OperatorType(EQ), 0.0); + fConstraints->AddItem(constraint); + return constraint; +} + + +/** + * Gets the constraints. + */ +BList* +Column::Constraints() const +{ + return fConstraints; +} + + +/** + * Sets the constraints. + */ +void +Column::SetConstraints(BList* constraints) +{ + fConstraints = constraints; +} + + +/** + * Destructor. + * Removes the column from the specification. + */ +Column::~Column() +{ + if (fPrevious != NULL) + fPrevious->SetNext(fNext); + for (int32 i = 0; i < fConstraints->CountItems(); i++) + delete (Constraint*)fConstraints->ItemAt(i); + delete fLeft; + delete fRight; +} + + +/** + * Constructor. + */ +Column::Column(BALMLayout* ls) +{ + fLS = ls; + fLeft = new XTab(ls); + fRight = new XTab(ls); + fConstraints = new BList(1); +} + diff --git a/src/libs/alm/Jamfile b/src/libs/alm/Jamfile new file mode 100644 index 0000000000..b599a2ca97 --- /dev/null +++ b/src/libs/alm/Jamfile @@ -0,0 +1,17 @@ +SubDir HAIKU_TOP src libs alm ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UseLibraryHeaders lp_solve linprog alm ; + +SharedLibrary libalm.so : + Area.cpp + Column.cpp + BALMLayout.cpp + Row.cpp + XTab.cpp + YTab.cpp + : + be liblpsolve55.so liblinprog.so +; + diff --git a/src/libs/alm/Row.cpp b/src/libs/alm/Row.cpp new file mode 100644 index 0000000000..e75ae68f7d --- /dev/null +++ b/src/libs/alm/Row.cpp @@ -0,0 +1,220 @@ +#include "Row.h" +#include "BALMLayout.h" +#include "OperatorType.h" +#include "YTab.h" + +#include + + +/** + * The top boundary of the row. + */ +YTab* +Row::Top() const +{ + return fTop; +} + + +/** + * The bottom boundary of the row. + */ +YTab* +Row::Bottom() const +{ + return fBottom; +} + + +/** + * Gets the row directly above this row. + */ +Row* +Row::Previous() const +{ + return fPrevious; +} + + +/** + * Sets the row directly above this row. + * May be null. + */ +void +Row::SetPrevious(Row* value) +{ + // if there should be no row directly above this row, then we have to + // separate any such row and can remove any constraint that was used + // to glue this row to it + if (value == NULL) { + if (fPrevious == NULL) + return; + fPrevious->fNext = NULL; + fPrevious->fNextGlue = NULL; + fPrevious = NULL; + delete fPreviousGlue; + fPreviousGlue = NULL; + return; + } + + // otherwise we have to set up the pointers and the glue constraint accordingly + if (value->fNext != NULL) + value->SetNext(NULL); + if (fPrevious != NULL) + SetPrevious(NULL); + + fPrevious = value; + fPrevious->fNext = this; + value->fNextGlue = value->fBottom->IsEqual(fTop); + fPreviousGlue = value->fNextGlue; +} + + +/** + * Gets the row directly below this row. + */ +Row* +Row::Next() const +{ + return fNext; +} + + +/** + * Sets the row directly below this row. + * May be null. + */ +void +Row::SetNext(Row* value) +{ + // if there should be no row directly below this row, then we have to + // separate any such row and can remove any constraint that was used + // to glue this row to it + if (value == NULL) { + if (fNext == NULL) + return; + fNext->fPrevious = NULL; + fNext->fPreviousGlue = NULL; + fNext = NULL; + delete fNextGlue; + fNextGlue = NULL; + return; + } + + // otherwise we have to set up the pointers and the glue constraint accordingly + if (value->fPrevious != NULL) + value->SetPrevious(NULL); + if (fNext != NULL) + SetNext(NULL); + + fNext = value; + fNext->fPrevious = this; + value->fPreviousGlue = fBottom->IsEqual(value->fTop); + fNextGlue = value->fPreviousGlue; +} + + +//~ string Row::ToString() { + //~ return "Row(" + fTop.ToString() + ", " + fBottom.ToString() + ")"; +//~ } + + +/** + * Inserts the given row directly above this row. + * + * @param row the row to insert + */ +void +Row::InsertBefore(Row* row) +{ + SetPrevious(row->fPrevious); + SetNext(row); +} + + +/** + * Inserts the given row directly below this row. + * + * @param row the row to insert + */ +void +Row::InsertAfter(Row* row) +{ + SetNext(row->fNext); + SetPrevious(row); +} + + +/** + * Constrains this row to have the same height as the given row. + * + * @param row the row that should have the same height + * @return the resulting same-height constraint + */ +Constraint* +Row::HasSameHeightAs(Row* row) +{ + BList* coeffs = new BList(4); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(-1.0)); + + BList* vars = new BList(4); + vars->AddItem(fTop); + vars->AddItem(fBottom); + vars->AddItem(row->fTop); + vars->AddItem(row->fBottom); + + Constraint* constraint = fLS->AddConstraint(coeffs, vars, OperatorType(EQ), 0.0); + fConstraints->AddItem(constraint); + return constraint; +} + + +/** + * Gets the constraints. + */ +BList* +Row::Constraints() const +{ + return fConstraints; +} + + +/** + * Sets the constraints. + */ +void +Row::SetConstraints(BList* constraints) +{ + fConstraints = constraints; +} + + +/** + * Destructor. + * Removes the row from the specification. + */ +Row::~Row() +{ + if (fPrevious != NULL) + fPrevious->SetNext(fNext); + for (int32 i = 0; i < fConstraints->CountItems(); i++) + delete (Constraint*)fConstraints->ItemAt(i); + delete fTop; + delete fBottom; +} + + +/** + * Constructor. + */ +Row::Row(BALMLayout* ls) +{ + fLS = ls; + fTop = new YTab(ls); + fBottom = new YTab(ls); + fConstraints = new BList(1); +} + diff --git a/src/libs/alm/XTab.cpp b/src/libs/alm/XTab.cpp new file mode 100644 index 0000000000..7bd7304fec --- /dev/null +++ b/src/libs/alm/XTab.cpp @@ -0,0 +1,13 @@ +#include "XTab.h" +#include "BALMLayout.h" + + +/** + * Constructor. + */ +XTab::XTab(BALMLayout* ls) + : Variable(ls) +{ + fLeftLink = false; +} + diff --git a/src/libs/alm/YTab.cpp b/src/libs/alm/YTab.cpp new file mode 100644 index 0000000000..8ce68a03fd --- /dev/null +++ b/src/libs/alm/YTab.cpp @@ -0,0 +1,13 @@ +#include "YTab.h" +#include "BALMLayout.h" + + +/** + * Constructor. + */ +YTab::YTab(BALMLayout* ls) + : Variable(ls) +{ + fTopLink = false; +} + diff --git a/src/libs/linprog/Constraint.cpp b/src/libs/linprog/Constraint.cpp new file mode 100644 index 0000000000..24f9a07747 --- /dev/null +++ b/src/libs/linprog/Constraint.cpp @@ -0,0 +1,206 @@ +#include "Constraint.h" +#include "LinearSpec.h" +#include "Variable.h" + +#include "lp_lib.h" + + +/** + * Gets the index of the constraint. + * + * @return the index of the constraint + */ +int32 +Constraint::Index() +{ + int32 i = fLS->Constraints()->IndexOf(this); + if (i == -1) + printf("Constraint not part of fLS->Constraints()."); + return i + 1; +} + + +/** + * Gets the coefficients of the constraint. + * + * @return the coefficients of the constraint + */ +BList* +Constraint::Coeffs() +{ + return fCoeffs; +} + + +/** + * Gets the variables of the constraint. + * + * @return the variables of the constraint + */ +BList* +Constraint::Vars() +{ + return fVars; +} + + +/** + * Changes the left side of the constraint, i.e. its coefficients and variables. + * There must be exactly one coefficient for each variable. + * + * @param coeffs the new coefficients + * @param vars the new variables + */ +void +Constraint::ChangeLeftSide(BList* coeffs, BList* vars) +{ + int32 sizeCoeffs = coeffs->CountItems(); + int32 sizeVars = vars->CountItems(); + if (sizeCoeffs != sizeVars) + printf("Number of coefficients and number of variables in a constraint must be equal."); + + fCoeffs = coeffs; + fVars = vars; + + double coeffsArray[sizeCoeffs]; + for (int32 i = 0; i < sizeCoeffs; i++) + coeffsArray[i] = *(double*)coeffs->ItemAt(i); + + int vIndexes[sizeCoeffs]; + for (int32 i = 0; i < sizeVars; i++) + vIndexes[i] = ((Variable*)vars->ItemAt(i))->Index(); + + if (!set_rowex(fLS->LP(), this->Index(), sizeCoeffs, &coeffsArray[0], &vIndexes[0])) + printf("Error in set_rowex."); + + fLS->RemovePresolved(); +} + + +/** + * Gets the operator used for this constraint. + * + * @return the operator used for this constraint + */ +OperatorType +Constraint::Op() +{ + return fOp; +} + + +/** + * Sets the operator used for this constraint. + * + * @param value operator + */ +void +Constraint::SetOp(OperatorType value) +{ + fOp = value; + if (!set_constr_type(fLS->LP(), this->Index(), + ((fOp == OperatorType(EQ)) ? EQ + : (fOp == OperatorType(GE)) ? GE + : LE))) + printf("Error in set_constr_type."); + + fLS->RemovePresolved(); +} + + +/** + * Gets the constant value that is on the right side of the operator. + * + * @return the constant value that is on the right side of the operator + */ +double +Constraint::RightSide() +{ + return fRightSide; +} + + +/** + * Sets the constant value that is on the right side of the operator. + * + * @param value constant value that is on the right side of the operator + */ +void +Constraint::SetRightSide(double value) +{ + fRightSide = value; + if (!set_rh(fLS->LP(), Index(), fRightSide)) + printf("Error in set_rh."); + + fLS->RemovePresolved(); +} + + +// Needs to be fixed. Use BString. Substring? +//~ string Constraint::ToString() { + //~ string s = ""; + //~ for (int32 i = 0; i < fVars->CountItems(); i++) + //~ s += (double)fCoeffs->ItemAt(i) + "*" + (Variable*)fVars->ItemAt(i).ToString() + " + "; + //~ s = s.Substring(0, s.Length - 2); + //~ if (Op == OperatorType.EQ) s += "= "; + //~ else if (Op == OperatorType.GE) s += ">= "; + //~ else s += "<= "; + //~ s += rightSide.ToString(); + //~ return s; +//~ } + + +/** + * Destructor. + * Removes the constraint from its specification. + */ +Constraint::~Constraint() +{ + del_constraint(fLS->LP(), Index()); + delete fCoeffs; + delete fVars; + fLS->Constraints()->RemoveItem(this); +} + + +/** + * Default constructor. + */ +Constraint::Constraint() {} + + +/** + * Constructor. + */ +Constraint::Constraint(LinearSpec* ls, BList* coeffs, BList* vars, OperatorType op, + double rightSide) +{ + + int32 sizeCoeffs = coeffs->CountItems(); + int32 sizeVars = vars->CountItems(); + if (sizeCoeffs != sizeVars) + printf("Number of coefficients and number of variables in a constraint must be equal."); + + fLS = ls; + fCoeffs = coeffs; + fVars = vars; + fOp = op; + fRightSide = rightSide; + + double coeffsArray[sizeCoeffs]; + for (int32 i = 0; i < sizeCoeffs; i++) + coeffsArray[i] = *(double*)coeffs->ItemAt(i); + + int vIndexes[sizeCoeffs]; + for (int32 i = 0; i < sizeVars; i++) + vIndexes[i] = ((Variable*)vars->ItemAt(i))->Index(); + + if (!add_constraintex(ls->LP(), sizeCoeffs, &coeffsArray[0], &vIndexes[0], + ((op == OperatorType(EQ)) ? EQ + : (op == OperatorType(GE)) ? GE + : LE), rightSide)) + printf("Error in add_constraintex."); + + ls->Constraints()->AddItem(this); +} + diff --git a/src/libs/linprog/Jamfile b/src/libs/linprog/Jamfile new file mode 100644 index 0000000000..6ad66ce3b2 --- /dev/null +++ b/src/libs/linprog/Jamfile @@ -0,0 +1,17 @@ +SubDir HAIKU_TOP src libs linprog ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UseLibraryHeaders lp_solve linprog ; + +SharedLibrary liblinprog.so : + Constraint.cpp + LinearSpec.cpp + ObjFunctionSummand.cpp + PenaltyFunction.cpp + SoftConstraint.cpp + Variable.cpp + : + be liblpsolve55.so +; + diff --git a/src/libs/linprog/LinearSpec.cpp b/src/libs/linprog/LinearSpec.cpp new file mode 100644 index 0000000000..e4bd13576c --- /dev/null +++ b/src/libs/linprog/LinearSpec.cpp @@ -0,0 +1,736 @@ +#include "LinearSpec.h" +#include "Constraint.h" +#include "ObjFunctionSummand.h" +#include "PenaltyFunction.h" +#include "SoftConstraint.h" +#include "Variable.h" + +#include "lp_lib.h" + + +/** + * Constructor. + * Creates a new specification for a linear programming problem. + */ +LinearSpec::LinearSpec() +{ + fLP = make_lp(0, 0); + if (fLP == NULL) + printf("Couldn't construct a new model."); + set_verbose(fLP, 1); + + fObjFunctionSummands = new BList(1); + fVariables = new BList(1); + fConstraints = new BList(1); + fColumns = 0; + fLpPresolved = NULL; + fOptimization = MINIMIZE; + fResult = ERROR; + fObjectiveValue = NULL; +} + + +/** + * Destructor. + * Removes the specification. + */ +LinearSpec::~LinearSpec() +{ + delete_lp(fLP); +} + + +/** + * Updates the objective function. + */ +void +LinearSpec::UpdateObjFunction() +{ + int32 size = fObjFunctionSummands->CountItems();; + double coeffs[size]; + int vIndexes[size]; + ObjFunctionSummand* current; + for (int32 i = 0; i < size; i++) { + current = (ObjFunctionSummand*)fObjFunctionSummands->ItemAt(i); + coeffs[i] = current->Coeff(); + vIndexes[i] = current->Var()->Index(); + } + + if (!set_obj_fnex(fLP, size, &coeffs[0], &vIndexes[0])) + printf("Error in set_obj_fnex."); + + RemovePresolved(); +} + + +/** + * Sets the objective function. + * + * @param coeffs the objective function's coefficients + * @param vars the objective function's variables + */ +void +LinearSpec::SetObjFunction(BList* coeffs, BList* vars) +{ + int32 sizeCoeffs = coeffs->CountItems(); + int32 sizeVars = vars->CountItems(); + if (sizeCoeffs != sizeVars) + printf("Number of coefficients and number of fVariables in objective function must be equal."); + + fObjFunctionSummands = new BList(1); + for (int32 i = 0; i < sizeCoeffs; i++) + fObjFunctionSummands->AddItem(new ObjFunctionSummand(this, + *(double*)coeffs->ItemAt(i), (Variable*)vars->ItemAt(i))); + + UpdateObjFunction(); +} + + +/** + * Adds a new summand to the objective function. + * + * @param coeff the summand's coefficient + * @param var the summand's variable + * @return the new summand + */ +ObjFunctionSummand* +LinearSpec::AddObjFunctionSummand(double coeff, Variable* var) +{ + ObjFunctionSummand* s = new ObjFunctionSummand(this, coeff, var); + fObjFunctionSummands->AddItem(s); + UpdateObjFunction(); + return s; +} + + +/** + * Adds a new variable to the specification. + * + * @return the new variable + */ +Variable* +LinearSpec::AddVariable() +{ + return new Variable(this); +} + + +/** + * Adds a new hard linear constraint to the specification. + * + * @param coeffs the constraint's coefficients + * @param vars the constraint's variables + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @return the new constraint + */ +Constraint* +LinearSpec::AddConstraint(BList* coeffs, BList* vars, OperatorType op, + double rightSide) +{ + Constraint* c = new Constraint(this, coeffs, vars, op, rightSide); + RemovePresolved(); + return c; +} + + +/** + * Adds a new hard linear constraint to the specification with a single summand. + * + * @param coeff1 the constraint's first coefficient + * @param var1 the constraint's first variable + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @return the new constraint + */ +Constraint* +LinearSpec::AddConstraint(double coeff1, Variable* var1, + OperatorType op, double rightSide) +{ + BList* coeffs = new BList(1); + coeffs->AddItem(new double(coeff1)); + BList* vars = new BList(1); + vars->AddItem(var1); + Constraint* c = AddConstraint(coeffs, vars, op, rightSide); + return c; +} + + +/** + * Adds a new hard linear constraint to the specification with two summands. + * + * @param coeff1 the constraint's first coefficient + * @param var1 the constraint's first variable + * @param coeff2 the constraint's second coefficient + * @param var2 the constraint's second variable + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @return the new constraint + */ +Constraint* +LinearSpec::AddConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, OperatorType op, double rightSide) +{ + BList* coeffs = new BList(2); + coeffs->AddItem(new double(coeff1)); + coeffs->AddItem(new double(coeff2)); + BList* vars = new BList(2); + vars->AddItem(var1); + vars->AddItem(var2); + Constraint* c = AddConstraint(coeffs, vars, op, rightSide); + return c; +} + + +/** + * Adds a new hard linear constraint to the specification with three summands. + * + * @param coeff1 the constraint's first coefficient + * @param var1 the constraint's first variable + * @param coeff2 the constraint's second coefficient + * @param var2 the constraint's second variable + * @param coeff3 the constraint's third coefficient + * @param var3 the constraint's third variable + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @return the new constraint + */ +Constraint* +LinearSpec::AddConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, double coeff3, Variable* var3, + OperatorType op, double rightSide) +{ + BList* coeffs = new BList(3); + coeffs->AddItem(new double(coeff1)); + coeffs->AddItem(new double(coeff2)); + coeffs->AddItem(new double(coeff3)); + BList* vars = new BList(3); + vars->AddItem(var1); + vars->AddItem(var2); + vars->AddItem(var3); + Constraint* c = AddConstraint(coeffs, vars, op, rightSide); + return c; +} + + +/** + * Adds a new hard linear constraint to the specification with four summands. + * + * @param coeff1 the constraint's first coefficient + * @param var1 the constraint's first variable + * @param coeff2 the constraint's second coefficient + * @param var2 the constraint's second variable + * @param coeff3 the constraint's third coefficient + * @param var3 the constraint's third variable + * @param coeff4 the constraint's fourth coefficient + * @param var4 the constraint's fourth variable + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @return the new constraint + */ +Constraint* +LinearSpec::AddConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, double coeff3, Variable* var3, + double coeff4, Variable* var4, OperatorType op, double rightSide) +{ + BList* coeffs = new BList(4); + coeffs->AddItem(new double(coeff1)); + coeffs->AddItem(new double(coeff2)); + coeffs->AddItem(new double(coeff3)); + coeffs->AddItem(new double(coeff4)); + BList* vars = new BList(4); + vars->AddItem(var1); + vars->AddItem(var2); + vars->AddItem(var3); + vars->AddItem(var4); + Constraint* c = AddConstraint(coeffs, vars, op, rightSide); + return c; +} + + +/** + * Adds a new soft linear constraint to the specification. + * i.e. a constraint that does not always have to be satisfied. + * + * @param coeffs the constraint's coefficients + * @param vars the constraint's variables + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution + * @param penaltyPos the coefficient penalizing positive deviations from the exact solution + */ +SoftConstraint* +LinearSpec::AddSoftConstraint(BList* coeffs, BList* vars, OperatorType op, + double rightSide, double penaltyNeg, double penaltyPos) +{ + SoftConstraint* c = new SoftConstraint(this, coeffs, vars, op, rightSide, + penaltyNeg, penaltyPos); + + RemovePresolved(); + return c; +} + + +/** + * Adds a new soft linear constraint to the specification with a single summand. + * + * @param coeff1 the constraint's first coefficient + * @param var1 the constraint's first variable + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution + * @param penaltyPos the coefficient penalizing positive deviations from the exact solution + */ +SoftConstraint* +LinearSpec::AddSoftConstraint(double coeff1, Variable* var1, + OperatorType op, double rightSide, double penaltyNeg, double penaltyPos) +{ + BList* coeffs = new BList(1); + coeffs->AddItem(new double(coeff1)); + BList* vars = new BList(1); + vars->AddItem(var1); + SoftConstraint* c = AddSoftConstraint(coeffs, vars, op, rightSide, + penaltyNeg, penaltyPos); + return c; +} + + +/** + * Adds a new soft linear constraint to the specification with two summands. + * + * @param coeff1 the constraint's first coefficient + * @param var1 the constraint's first variable + * @param coeff2 the constraint's second coefficient + * @param var2 the constraint's second variable + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution + * @param penaltyPos the coefficient penalizing positive deviations from the exact solution + */ +SoftConstraint* +LinearSpec::AddSoftConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, OperatorType op, double rightSide, + double penaltyNeg, double penaltyPos) +{ + BList* coeffs = new BList(2); + coeffs->AddItem(new double(coeff1)); + coeffs->AddItem(new double(coeff2)); + BList* vars = new BList(2); + vars->AddItem(var1); + vars->AddItem(var2); + SoftConstraint* c = AddSoftConstraint(coeffs, vars, op, rightSide, + penaltyNeg, penaltyPos); + return c; +} + + +/** + * Adds a new soft linear constraint to the specification with three summands. + * + * @param coeff1 the constraint's first coefficient + * @param var1 the constraint's first variable + * @param coeff2 the constraint's second coefficient + * @param var2 the constraint's second variable + * @param coeff3 the constraint's third coefficient + * @param var3 the constraint's third variable + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution + * @param penaltyPos the coefficient penalizing positive deviations from the exact solution + */ +SoftConstraint* +LinearSpec::AddSoftConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, double coeff3, Variable* var3, + OperatorType op, double rightSide, double penaltyNeg, double penaltyPos) +{ + BList* coeffs = new BList(3); + coeffs->AddItem(new double(coeff1)); + coeffs->AddItem(new double(coeff2)); + coeffs->AddItem(new double(coeff3)); + BList* vars = new BList(3); + vars->AddItem(var1); + vars->AddItem(var2); + vars->AddItem(var3); + SoftConstraint* c = AddSoftConstraint(coeffs, vars, op, rightSide, + penaltyNeg, penaltyPos); + return c; +} + + +/** + * Adds a new soft linear constraint to the specification with four summands. + * + * @param coeff1 the constraint's first coefficient + * @param var1 the constraint's first variable + * @param coeff2 the constraint's second coefficient + * @param var2 the constraint's second variable + * @param coeff3 the constraint's third coefficient + * @param var3 the constraint's third variable + * @param coeff4 the constraint's fourth coefficient + * @param var4 the constraint's fourth variable + * @param op the constraint's operand + * @param rightSide the constant value on the constraint's right side + * @param penaltyNeg the coefficient penalizing negative deviations from the exact solution + * @param penaltyPos the coefficient penalizing positive deviations from the exact solution + */ +SoftConstraint* +LinearSpec::AddSoftConstraint(double coeff1, Variable* var1, + double coeff2, Variable* var2, double coeff3, Variable* var3, + double coeff4, Variable* var4, OperatorType op, double rightSide, + double penaltyNeg, double penaltyPos) +{ + BList* coeffs = new BList(4); + coeffs->AddItem(new double(coeff1)); + coeffs->AddItem(new double(coeff2)); + coeffs->AddItem(new double(coeff3)); + coeffs->AddItem(new double(coeff4)); + BList* vars = new BList(4); + vars->AddItem(var1); + vars->AddItem(var2); + vars->AddItem(var3); + vars->AddItem(var4); + SoftConstraint* c = AddSoftConstraint(coeffs, vars, op, rightSide, + penaltyNeg, penaltyPos); + return c; +} + + +/** + * Adds a new penalty function to the specification. + * + * @param var the penalty function's variable + * @param xs the penalty function's sampling points + * @param gs the penalty function's gradients + * @return the new penalty function + */ +PenaltyFunction* +LinearSpec::AddPenaltyFunction(Variable* var, BList* xs, BList* gs) +{ + return new PenaltyFunction(this, var, xs, gs); +} + + +/** + * Remove a cached presolved model, if existent. + * This is automatically done each time after the model has been changed, + * to avoid an old cached presolved model getting out of sync. + */ +void +LinearSpec::RemovePresolved() +{ + if (fLpPresolved == NULL) + return; + delete_lp(fLpPresolved); + fLpPresolved = NULL; +} + + +/** + * Creates and caches a simplified version of the linear programming problem, + * where redundant rows, columns and constraints are removed, + * if it has not been created before. + * Then, the simplified problem is solved. + * + * @return the result of the solving attempt + */ +ResultType +LinearSpec::Presolve() +{ + bigtime_t start, end; + start = system_time(); + + if (fLpPresolved == NULL) { + fLpPresolved = copy_lp(fLP); + set_presolve(fLpPresolved, PRESOLVE_ROWS | PRESOLVE_COLS | PRESOLVE_LINDEP, + get_presolveloops(fLpPresolved)); + } + + fResult = (ResultType)solve(fLpPresolved); + fObjectiveValue = get_objective(fLpPresolved); + + if (fResult == OPTIMAL) { + int32 size = fVariables->CountItems(); + for (int32 i = 0; i < size; i++) { + Variable* current = (Variable*)fVariables->ItemAt(i); + current->SetValue(get_var_primalresult(fLpPresolved, + get_Norig_rows(fLpPresolved) + current->Index())); + } + } + + end = system_time(); + fSolvingTime = (end - start) / 1000.0; + + return fResult; +} + + +/** + * Tries to solve the linear programming problem. + * If a cached simplified version of the problem exists, it is used instead. + * + * @return the result of the solving attempt + */ +ResultType +LinearSpec::Solve() +{ + if (fLpPresolved != NULL) + return Presolve(); + + bigtime_t start, end; + start = system_time(); + + fResult = (ResultType)solve(fLP); + fObjectiveValue = get_objective(fLP); + + if (fResult == OPTIMAL) { + int32 size = fVariables->CountItems(); + double x[size]; + if (!get_variables(fLP, &x[0])) + printf("Error in get_variables."); + + int32 i = 0; + while (i < size) { + ((Variable*)fVariables->ItemAt(i))->SetValue(x[i]); + i++; + } + } + + end = system_time(); + fSolvingTime = (end - start) / 1000.0; + + return fResult; +} + + +/** + * Writes the specification into a text file. + * The file will be overwritten if it exists. + * + * @param fname the file name + */ +void +LinearSpec::Save(char* fname) +{ + write_lp(fLP, fname); +} + + +/** + * Gets the number of columns. + * + * @return the number of columns + */ +int32 +LinearSpec::Columns() const +{ + return fColumns; +} + + +/** + * Sets the number of columns. + * + * @param value the number of columns + */ +void +LinearSpec::SetColumns(int32 value) +{ + fColumns = value; +} + + +/** + * Gets the current optimization. + * The default is minimization. + * + * @return the current optimization + */ +OptimizationType +LinearSpec::Optimization() const +{ + return fOptimization; +} + + +/** + * Sets whether the solver should minimize or maximize the objective function. + * The default is minimization. + * + * @param optimization the optimization type + */ +void +LinearSpec::SetOptimization(OptimizationType value) +{ + fOptimization = value; + if (fOptimization == MINIMIZE) + set_minim(fLP); + else + set_maxim(fLP); +} + + +/** + * Gets the lpsolve variable. + * + * @return the lpsolve variable + */ +lprec* +LinearSpec::LP() const +{ + return fLP; +} + + +/** + * Sets the lpsolve variable. + * + * @param value the lpsolve variable + */ +void +LinearSpec::SetLP(lprec* value) +{ + fLP = value; +} + + +/** + * Gets the objective function summand. + * + * @return the objective function summand + */ +BList* +LinearSpec::ObjFunctionSummands() const +{ + return fObjFunctionSummands; +} + + +/** + * Sets the objective function summand. + * + * @param value the objective function summand + */ +void +LinearSpec::SetObjFunctionSummands(BList* value) +{ + fObjFunctionSummands = value; +} + + +/** + * Gets the the variables. + * + * @return the variables + */ +BList* +LinearSpec::Variables() const +{ + return fVariables; +} + + +/** + * Sets the the variables. + * + * @param value the variables + */ +void +LinearSpec::SetVariables(BList* value) +{ + fVariables = value; +} + + +/** + * Gets the constraints. + * + * @return the constraints + */ +BList* +LinearSpec::Constraints() const +{ + return fConstraints; +} + + +/** + * Sets the constraints. + * + * @param value the constraints + */ +void LinearSpec::SetConstraints(BList* value) { + fConstraints = value; +} + + +/** + * Gets the result type. + * + * @return the result type + */ +ResultType +LinearSpec::Result() const +{ + return fResult; +} + + +/** + * Sets the result type. + * + * @param value the result type + */ +void +LinearSpec::SetResult(ResultType value) +{ + fResult = value; +} + + +/** + * Gets the objective value. + * + * @return the objective value + */ +double +LinearSpec::ObjectiveValue() const +{ + return fObjectiveValue; +} + + +/** + * Sets the objective value. + * + * @param value the objective value + */ +void +LinearSpec::SetObjectiveValue(double value) +{ + fObjectiveValue = value; +} + + +/** + * Gets the solving time. + * + * @return the solving time + */ +double +LinearSpec::SolvingTime() const +{ + return fSolvingTime; +} + + +/** + * Sets the solving time. + * + * @param value the solving time + */ +void +LinearSpec::SetSolvingTime(double value) +{ + fSolvingTime = value; +} + diff --git a/src/libs/linprog/ObjFunctionSummand.cpp b/src/libs/linprog/ObjFunctionSummand.cpp new file mode 100644 index 0000000000..64383c7c3f --- /dev/null +++ b/src/libs/linprog/ObjFunctionSummand.cpp @@ -0,0 +1,76 @@ +#include "ObjFunctionSummand.h" +#include "Variable.h" +#include "LinearSpec.h" + + +/** + * Gets the summmand's coefficient. + * + * @return the summand's coefficient + */ +double +ObjFunctionSummand::Coeff() +{ + return fCoeff; +} + + +/** + * Sets the summmand's coefficient. + * + * @param coeff coefficient + */ +void +ObjFunctionSummand::SetCoeff(double coeff) +{ + fCoeff = coeff; + fLS->UpdateObjFunction(); +} + + +/** + * Gets the summand's variable. + * + * @return the summand's variable + */ +Variable* +ObjFunctionSummand::Var() +{ + return fVar; +} + + +/** + * Sets the summand's variable. + * + * @param var variable + */ +void +ObjFunctionSummand::SetVar(Variable* var) +{ + fVar = var; + fLS->UpdateObjFunction(); +} + + +/** + * Destructor. + * Removes the summand from the objective function. + */ +ObjFunctionSummand::~ObjFunctionSummand() +{ + fLS->ObjFunctionSummands()->RemoveItem(this); + fLS->UpdateObjFunction(); +} + + +/** + * Constructor. + */ +ObjFunctionSummand::ObjFunctionSummand(LinearSpec* ls, double coeff, Variable* var) +{ + fLS = ls; + fCoeff = coeff; + fVar = var; +} + diff --git a/src/libs/linprog/PenaltyFunction.cpp b/src/libs/linprog/PenaltyFunction.cpp new file mode 100644 index 0000000000..f115af6dde --- /dev/null +++ b/src/libs/linprog/PenaltyFunction.cpp @@ -0,0 +1,116 @@ +#include "PenaltyFunction.h" +#include "Constraint.h" +#include "ObjFunctionSummand.h" +#include "OperatorType.h" +#include "Variable.h" +#include "LinearSpec.h" + + +/** + * Constructor. + */ +PenaltyFunction::PenaltyFunction(LinearSpec* ls, Variable* var, BList* xs, BList* gs) +{ + int32 sizeXs = xs->CountItems(); + int32 sizeGs = gs->CountItems(); + if (var->LS() != ls) + printf("The variable must belong to the same linear specification as the penalty function."); + if (sizeXs + 1 != sizeGs) + printf("The number of sampling points must be exactly one less than the number of gradients."); + for (int32 i = 1; i < sizeGs; i++) { + if (*(double*)(gs->ItemAt(i - 1)) > *(double*)(gs->ItemAt(i))) + printf("Penalty function must be concave."); + } + + fVar = var; + fXs = xs; + fGs = gs; + fConstraints = new BList(1); + fObjFunctionSummands = new BList(1); + + BList* coeffs = new BList(1); + coeffs->AddItem(new double(1.0)); + + BList* vars = new BList(1); + vars->AddItem(var); + + fConstraints->AddItem(ls->AddSoftConstraint(coeffs, vars, OperatorType(EQ), + *(double*)(xs->ItemAt(0)), -*(double*)(gs->ItemAt(0)), + *(double*)(gs->ItemAt(1)))); + + for (int32 i = 1; i < sizeGs; i++) { + Variable* dPos = ls->AddVariable(); + + BList* coeffs = new BList(2); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(-1.0)); + + BList* vars = new BList(2); + vars->AddItem(var); + vars->AddItem(dPos); + + fConstraints->AddItem(ls->AddConstraint(coeffs, vars, OperatorType(LE), + *(double*)(xs->ItemAt(i)))); + + fObjFunctionSummands->AddItem(ls->AddObjFunctionSummand( + *(double*)(gs->ItemAt(i + 1)) - *(double*)(gs->ItemAt(i)), dPos)); + } +} + + +/** + * Destructor. + * Removes all constraints and summands from the penalty function. + */ +PenaltyFunction::~PenaltyFunction() +{ + int32 sizeConstraints = fConstraints->CountItems(); + for (int32 i = 0; i < sizeConstraints; i++) { + Constraint* currentConstraint = (Constraint*)fConstraints->ItemAt(i); + delete currentConstraint; + } + + int32 sizeObjFunctionSummands = fObjFunctionSummands->CountItems(); + for (int32 i = 0; i < sizeObjFunctionSummands; i++) { + ObjFunctionSummand* currentObjFunctionSummand = + (ObjFunctionSummand*)fObjFunctionSummands->ItemAt(i); + delete currentObjFunctionSummand; + } +} + + +/** + * Gets the variable. + * + * @return the variable + */ +const Variable* +PenaltyFunction::Var() const +{ + return fVar; +} + + +/** + * Gets the sampling points. + * + * @return the sampling points + */ +const BList* +PenaltyFunction::Xs() const +{ + return fXs; +} + + +/** + * Gets the sampling gradients. + * + * @return the sampling gradients + */ +const +BList* PenaltyFunction::Gs() const +{ + return fGs; +} + diff --git a/src/libs/linprog/SoftConstraint.cpp b/src/libs/linprog/SoftConstraint.cpp new file mode 100644 index 0000000000..f9930e689f --- /dev/null +++ b/src/libs/linprog/SoftConstraint.cpp @@ -0,0 +1,235 @@ +#include "SoftConstraint.h" +#include "ObjFunctionSummand.h" +#include "Variable.h" +#include "LinearSpec.h" + +#include "lp_lib.h" + + +/** + * Changes the left side of the soft constraint, i.e. its coefficients and variables. + * There must be exactly one coefficient for each variable. + * + * @param coeffs the constraint's coefficients + * @param vars the constraint's variables + */ +void +SoftConstraint::ChangeLeftSide(BList* coeffs, BList* vars) +{ + int32 sizeCoeffs = coeffs->CountItems(); + int32 sizeVars = vars->CountItems(); + if (sizeCoeffs != sizeVars) + printf("Number of coefficients and number of variables in a constraint must be equal."); + + fCoeffs = coeffs; + fVars = vars; + + int vIndexes[sizeCoeffs + 2]; + double coeffs2[sizeCoeffs + 2]; + + int32 i; + for (i = 0; i < sizeVars; i++) { + vIndexes[i] = ((Variable*)vars->ItemAt(i))->Index(); + coeffs2[i] = *(double*)coeffs->ItemAt(i); + } + + if (fOp != OperatorType(LE)) { + vIndexes[i] = fDNegSummand->Var()->Index(); + coeffs2[i] = 1.0; + i++; + } + + if (fOp != OperatorType(GE)) { + vIndexes[i] = fDPosSummand->Var()->Index(); + coeffs2[i] = -1.0; + i++; + } + + if (!set_rowex(fLS->LP(), this->Index(), i, &coeffs2[0], &vIndexes[0])) + printf("Error in set_rowex."); + + fLS->RemovePresolved(); +} + + +/** + * Gets the operator used for this constraint. + * + * @return the operator used for this constraint + */ +OperatorType +SoftConstraint::Op() +{ + return fOp; +} + + +/** + * Sets the operator used for this constraint. + * + * @param value operator type + */ +void +SoftConstraint::SetOp(OperatorType value) +{ + fOp = value; + ChangeLeftSide(fCoeffs, fVars); +} + + +/** + * Gets the coefficient of negative summand. + * + * @return the coefficient of negative summand. + */ +double +SoftConstraint::PenaltyNeg() +{ + return fDNegSummand->Coeff(); +} + + +/** + * The penalty coefficient for positive deviations from the soft constraint's exact solution,  + * i.e. if the left side is too large. + * + * @param value coefficient of negative penalty double + */ +void +SoftConstraint::SetPenaltyNeg(double value) +{ + if (value == fDNegSummand->Coeff()) + return; + fDNegSummand->SetCoeff(value); + fLS->UpdateObjFunction(); +} + + +/** + * Gets the coefficient of positive summand. + * + * @return the coefficient of positive summand. + */ +double +SoftConstraint::PenaltyPos() +{ + return fDPosSummand->Coeff(); +} + + +/** + * The penalty coefficient for negative deviations from the soft constraint's exact solution, + * i.e. if the left side is too small. + * + * @param value coefficient of positive penalty double + */ +void +SoftConstraint::SetPenaltyPos(double value) +{ + if (value == fDPosSummand->Coeff()) + return; + fDPosSummand->SetCoeff(value); + fLS->UpdateObjFunction(); +} + + +/** + * Returns positive and negative penalty coefficient as string. + */ +// Needs to be fixed. +//~ string SoftConstraint::ToString() { + //~ return base.ToString() + //~ + "; PenaltyNeg=" + PenaltyNeg() + //~ + "; PenaltyPos=" + PenaltyPos(); +//~ } + + +/** + * Gets the slack variable for the negative variations. + * + * @return the slack variable for the negative variations + */ +Variable* +SoftConstraint::DNeg() const +{ + return fDNeg; +} + + +/** + * Gets the slack variable for the positive variations. + * + * @return the slack variable for the positive variations + */ +Variable* +SoftConstraint::DPos() const +{ + return fDPos; +} + + +/** + * Destructor. + * Removes the soft constraint from its specification. + */ +SoftConstraint::~SoftConstraint() +{ + delete fDNegSummand->Var(); + delete fDPosSummand->Var(); + delete fDNegSummand; + delete fDPosSummand; +} + + +/** + * Constructor. + */ +SoftConstraint::SoftConstraint(LinearSpec* ls, BList* coeffs, BList* vars, OperatorType op, + double rightSide, double penaltyNeg, double penaltyPos) +{ + int32 sizeCoeffs = coeffs->CountItems(); + int32 sizeVars = vars->CountItems(); + if (sizeCoeffs != sizeVars) + printf("Number of coefficients and number of variables in a constraint must be equal."); + + fLS = ls; + fCoeffs = coeffs; + fVars = vars; + fOp = op; + fRightSide = rightSide; + + fDNeg = new Variable(ls); + fDPos = new Variable(ls); + fDNegSummand = ls->AddObjFunctionSummand(penaltyNeg, DNeg()); + fDPosSummand = ls->AddObjFunctionSummand(penaltyPos, DPos()); + + int vIndexes[sizeCoeffs + 2]; + double coeffs2[sizeCoeffs + 2]; + + int32 i; + for (i=0; i < sizeVars; i++) { + vIndexes[i] = ((Variable*)vars->ItemAt(i))->Index(); + coeffs2[i] = *(double*)coeffs->ItemAt(i); + } + + if (fOp != OperatorType(LE)) { + vIndexes[i] = fDNegSummand->Var()->Index(); + coeffs2[i] = 1.0; + i++; + } + + if (fOp != OperatorType(GE)) { + vIndexes[i] = fDPosSummand->Var()->Index(); + coeffs2[i] = -1.0; + i++; + } + + if (!add_constraintex(ls->LP(), i, &coeffs2[0], &vIndexes[0], + ((fOp == OperatorType(EQ)) ? EQ + : (fOp == OperatorType(GE)) ? GE + : LE), rightSide)) + printf("Error in add_constraintex."); + + ls->Constraints()->AddItem(this); +} + diff --git a/src/libs/linprog/Variable.cpp b/src/libs/linprog/Variable.cpp new file mode 100644 index 0000000000..97d3404417 --- /dev/null +++ b/src/libs/linprog/Variable.cpp @@ -0,0 +1,244 @@ +#include "Variable.h" +#include "Constraint.h" +#include "LinearSpec.h" +#include "OperatorType.h" + +#include "lp_lib.h" + +#include // for DBL_MAX + + +/** + * Gets index of the variable. + * + * @return the index of the variable + */ +int32 +Variable::Index() +{ + int32 i = fLS->Variables()->IndexOf(this); + if (i == -1) + printf("Variable not part of fLS->Variables()."); + return i + 1; +} + + +/** + * Gets the current linear specification. + * + * @return the current linear specification + */ +LinearSpec* +Variable::LS() const +{ + return fLS; +} + + +/** + * Sets the current linear specification. + * + * @param value the current linear specification + */ +void +Variable::SetLS(LinearSpec* value) +{ + fLS = value; +} + + +/** + * Gets the value. + * + * @return the value + */ +double +Variable::Value() const +{ + return fValue; +} + + +/** + * Sets the value. + * + * @param value the value + */ +void +Variable::SetValue(double value) +{ + fValue = value; +} + + +/** + * Gets the minimum value of the variable. + * + * @return the minimum value of variable + */ +double +Variable::Min() const +{ + return fMin; +} + + +/** + * Sets the minimum value of the variable. + * + * @param min minimum value + */ +void +Variable::SetMin(double min) +{ + fMin = min; + set_bounds(fLS->LP(), this->Index(), fMin, fMax); +} + + +/** + * Gets the maximum value of the variable. + * + * @return the maximum value of variable + */ +double +Variable::Max() const +{ + return fMax; +} + + +/** + * Sets the maximum value of the variable. + * + * @param max maximum value + */ +void +Variable::SetMax(double max) +{ + fMax = max; + set_bounds(fLS->LP(), this->Index(), fMin, fMax); +} + + +/** + * Sets the minimum and maximum values of the variable. + * + * @param min minimum value + * @param max maximum value + */ +void +Variable::SetRange(double min, double max) +{ + fMin = min; + fMax = max; + set_bounds(fLS->LP(), this->Index(), fMin, fMax); +} + + +/** + * Returns index of the variable as String. + * E.g. "Var2" + * + * @return the String index of the variable + */ +//~ string Variable::ToString() { + //~ return "Var" + Index(); +//~ } + + +/** + * Adds a constraint that sets this variable equal to the given one. + * + * @param var variable that should have the same value + * @return the new equality constraint + */ +Constraint* +Variable::IsEqual(Variable* var) +{ + BList* coeffs = new BList(2); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(-1.0)); + + BList* vars = new BList(2); + vars->AddItem(this); + vars->AddItem(var); + + return fLS->AddConstraint(coeffs, vars, OperatorType(EQ), 0.0); +} + + +/** + * Adds a constraint that sets this variable smaller or equal to the given one. + * + * @param var variable that should have a larger or equal value + * @return the new constraint + */ +Constraint* +Variable::IsSmallerOrEqual(Variable* var) +{ + BList* coeffs = new BList(2); + coeffs->AddItem(new double(1.0)); + coeffs->AddItem(new double(-1.0)); + + BList* vars = new BList(2); + vars->AddItem(this); + vars->AddItem(var); + + return fLS->AddConstraint(coeffs, vars, OperatorType(LE), 0.0); +} + + +/** + * Adds a constraint that sets this variable greater or equal to the given one. + * + * @param var variable that should have a smaller or equal value + * @return the new constraint + */ +Constraint* +Variable::IsGreaterorEqual(Variable* var) +{ + BList* coeffs = new BList(2); + coeffs->AddItem(new double(-1.0)); + coeffs->AddItem(new double(1.0)); + + BList* vars = new BList(2); + vars->AddItem(var); + vars->AddItem(this); + + return fLS->AddConstraint(coeffs, vars, OperatorType(GE), 0.0); +} + + +/** + * Constructor. + */ +Variable::Variable(LinearSpec* ls) +{ + fMin = 0; + fMax = DBL_MAX; + fValue = NULL; + fLS = ls; + + ls->Variables()->AddItem(this); + + int32 size = ls->Variables()->CountItems(); + if (size > ls->Columns()) { + double d = 0; + int i = 0; + if (!add_columnex(ls->LP(), 0, &d, &i)) + printf("Error in add_columnex."); + } +} + + +/** + * Destructor. + * Removes the variable from its specification. + */ +Variable::~Variable() +{ + del_column(fLS->LP(), this->Index()); + fLS->Variables()->RemoveItem(this); +} + diff --git a/src/tests/Jamfile b/src/tests/Jamfile index a896bd1752..7ccb5b3dae 100644 --- a/src/tests/Jamfile +++ b/src/tests/Jamfile @@ -29,5 +29,6 @@ SubInclude HAIKU_TOP src tests apps ; SubInclude HAIKU_TOP src tests bin ; SubInclude HAIKU_TOP src tests system ; SubInclude HAIKU_TOP src tests kits ; +SubInclude HAIKU_TOP src tests libs ; SubInclude HAIKU_TOP src tests misc ; SubInclude HAIKU_TOP src tests servers ; diff --git a/src/tests/libs/Jamfile b/src/tests/libs/Jamfile new file mode 100644 index 0000000000..2c580ac1ae --- /dev/null +++ b/src/tests/libs/Jamfile @@ -0,0 +1,6 @@ +SubDir HAIKU_TOP src tests libs ; + +SubInclude HAIKU_TOP src tests libs lp_solve ; +SubInclude HAIKU_TOP src tests libs linprog ; +SubInclude HAIKU_TOP src tests libs alm ; + diff --git a/src/tests/libs/alm/Jamfile b/src/tests/libs/alm/Jamfile new file mode 100644 index 0000000000..7421cfc438 --- /dev/null +++ b/src/tests/libs/alm/Jamfile @@ -0,0 +1,24 @@ +SubDir HAIKU_TOP src tests libs alm ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UseLibraryHeaders lp_solve linprog alm ; + +Application table_test : + TableTest.cpp + : + be liblpsolve55.so liblinprog.so libalm.so +; + +Application test1 : + Test1.cpp + : + be liblpsolve55.so be liblinprog.so libalm.so +; + +Application test2 : + Test2.cpp + : + be liblpsolve55.so be liblinprog.so libalm.so +; + diff --git a/src/tests/libs/alm/TableTest.cpp b/src/tests/libs/alm/TableTest.cpp new file mode 100644 index 0000000000..dc1bfc8f73 --- /dev/null +++ b/src/tests/libs/alm/TableTest.cpp @@ -0,0 +1,70 @@ + +#include +#include +#include +#include + +#include "Area.h" +#include "Column.h" +#include "BALMLayout.h" +#include "Row.h" + + +using namespace BALM; + +class TableTestWindow : public BWindow { +public: + TableTestWindow(BRect frame) : BWindow(frame, "TableTest", B_TITLED_WINDOW, + B_QUIT_ON_WINDOW_CLOSE) { + + BALMLayout* fLS = new BALMLayout(); + + SetLayout(fLS); + + fLS->SetPerformancePath("/boot/home/Desktop/table_test_performance.txt"); + + Column* c1 = fLS->AddColumn(fLS->Left(), fLS->Right()); + Row* r1 = fLS->AddRow(fLS->Top(), NULL); + Row* r3 = fLS->AddRow(NULL, fLS->Bottom()); + r1->SetNext(r3); + Row* r2 = fLS->AddRow(); + r2->InsertAfter(r1); + + BButton* b1 = new BButton("A1"); + Area* a1 = fLS->AddArea(r1, c1, b1); + a1->SetHAlignment(B_ALIGN_LEFT); + a1->SetVAlignment(B_ALIGN_TOP); + + BButton* b2 = new BButton("A2"); + Area* a2 = fLS->AddArea(r2, c1, b2); + a2->SetHAlignment(B_ALIGN_HORIZONTAL_CENTER); + a2->SetVAlignment(B_ALIGN_VERTICAL_CENTER); + + BButton* b3 = new BButton("A3"); + Area* a3 = fLS->AddArea(r3, c1, b3); + a3->SetHAlignment(B_ALIGN_RIGHT); + a3->SetVAlignment(B_ALIGN_BOTTOM); + + r2->HasSameHeightAs(r1); + r3->HasSameHeightAs(r1); + + Show(); + } +}; + + +class TableTest : public BApplication { +public: + TableTest() : BApplication("application/x-vnd.haiku.table-test") { + BRect frameRect; + frameRect.Set(100, 100, 400, 400); + TableTestWindow* theWindow = new TableTestWindow(frameRect); + } +}; + + +int main() { + TableTest test; + test.Run(); + return 0; +} diff --git a/src/tests/libs/alm/Test1.cpp b/src/tests/libs/alm/Test1.cpp new file mode 100644 index 0000000000..925dafc848 --- /dev/null +++ b/src/tests/libs/alm/Test1.cpp @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#include "Area.h" +#include "BALMLayout.h" +#include "OperatorType.h" +#include "XTab.h" +#include "YTab.h" + + +using namespace BALM; + +class Test1Window : public BWindow { +public: + Test1Window(BRect frame) : BWindow(frame, "Test1", B_TITLED_WINDOW, + B_QUIT_ON_WINDOW_CLOSE) { + + fLS = new BALMLayout(); + + SetLayout(fLS); + + button1 = new BButton("button1"); + button2 = new BButton("button2"); + button3 = new BButton("button3"); + + fLS->SetPerformancePath("/boot/home/Desktop/test1_performance.txt"); + SetBALMLayout(); + + Show(); + } + + + void SetBALMLayout() { + XTab* x1 = fLS->AddXTab(); + YTab* y1 = fLS->AddYTab(); + + fLS->AddArea(fLS->Left(), fLS->Top(), x1, y1, button1); + fLS->AddArea(x1, fLS->Top(), fLS->Right(), y1, button2); + fLS->AddArea(fLS->Left(), y1, fLS->Right(), fLS->Bottom(), button3); + + //~ BList* coeffs1 = new BList(2); + //~ coeffs1->AddItem(new double(2.0)); + //~ coeffs1->AddItem(new double(-1.0)); + //~ BList* vars1 = new BList(2); + //~ vars1->AddItem(x1); + //~ vars1->AddItem(fLS->Right()); + fLS->AddConstraint(2.0, x1, -1.0, fLS->Right(), OperatorType(EQ), 0.0); + + //~ BList* coeffs2 = new BList(2); + //~ coeffs2->AddItem(new double(2.0)); + //~ coeffs2->AddItem(new double(-1.0)); + //~ BList* vars2 = new BList(2); + //~ vars2->AddItem(y1); + //~ vars2->AddItem(fLS->Bottom()); + fLS->AddConstraint(2.0, y1, -1.0, fLS->Bottom(), OperatorType(EQ), 0.0); + } + + +private: + BALMLayout* fLS; + BButton* button1; + BButton* button2; + BButton* button3; +}; + + +class Test1 : public BApplication { +public: + Test1() : BApplication("application/x-vnd.haiku.test1") { + BRect frameRect; + frameRect.Set(100, 100, 392, 366); + Test1Window* theWindow = new Test1Window(frameRect); + } +}; + + +int main() { + Test1 test; + test.Run(); + return 0; +} diff --git a/src/tests/libs/alm/Test2.cpp b/src/tests/libs/alm/Test2.cpp new file mode 100644 index 0000000000..637b9c0ea8 --- /dev/null +++ b/src/tests/libs/alm/Test2.cpp @@ -0,0 +1,162 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include "Area.h" +#include "BALMLayout.h" +#include "OperatorType.h" +#include "XTab.h" +#include "YTab.h" + + +using namespace BALM; + +class Test2Window : public BWindow { +public: + Test2Window(BRect frame) : BWindow(frame, "Test2", B_TITLED_WINDOW, + B_QUIT_ON_WINDOW_CLOSE) { + + fLS = new BALMLayout(); + + SetLayout(fLS); + + button1 = new BButton("button1"); + button2 = new BButton("button2"); + button3 = new BButton("button3"); + button4 = new BButton("button4"); + button5 = new BButton("button5"); + button6 = new BButton("button6"); + checkedListBox1 = new BButton("checkedListBox1"); + textBox1 = new BButton("textBox1"); + textBox2 = new BButton("textBox2"); + richTextBox1 = new BButton("richTextBox1"); + //~ textBox1 = new BTextView(frame, "textBox1", NULL, NULL); + //~ textBox2 = new BTextView(frame, "textBox2", NULL, NULL); + //~ richTextBox1 = new BTextControl(NULL, "richTextBox1", NULL); + listView1 = new BButton("listView1"); + label1 = new BStringView(frame, "label1", "label1"); + label2 = new BStringView(frame, "label2", "label2"); + label3 = new BStringView(frame, "label3", "label3"); + + fLS->SetPerformancePath("/boot/home/Desktop/test2_performance.txt"); + SetBALMLayout(); + + Show(); + } + + + void SetBALMLayout() { + XTab* x1 = fLS->AddXTab(); + XTab* x2 = fLS->AddXTab(); + XTab* x3 = fLS->AddXTab(); + YTab* y1 = fLS->AddYTab(); + YTab* y2 = fLS->AddYTab(); + YTab* y3 = fLS->AddYTab(); + YTab* y4 = fLS->AddYTab(); + YTab* y5 = fLS->AddYTab(); + + fLS->AddArea(fLS->Left(), fLS->Top(), x1, y1, button1); + fLS->AddArea(x1, fLS->Top(), x2, y1, button2); + fLS->AddArea(fLS->Left(), y1, x1, y2, button3); + fLS->AddArea(x1, y1, x2, y2, button4); + fLS->AddArea(fLS->Left(), y2, x1, y3, button5); + fLS->AddArea(x1, y2, x2, y3, button6); + + //~ BList* coeffs1 = new BList(2); + //~ coeffs1->AddItem(new double(2.0)); + //~ coeffs1->AddItem(new double(-1.0)); + //~ BList* vars1 = new BList(2); + //~ vars1->AddItem(x1); + //~ vars1->AddItem(x2); + //~ fLS->AddConstraint(coeffs1, vars1, OperatorType(EQ), 0.0); + + fLS->AddConstraint(2.0, x1, -1.0, x2, OperatorType(EQ), 0.0); + + //~ BList* coeffs2 = new BList(2); + //~ coeffs2->AddItem(new double(2.0)); + //~ coeffs2->AddItem(new double(-1.0)); + //~ BList* vars2 = new BList(2); + //~ vars2->AddItem(y1); + //~ vars2->AddItem(y2); + fLS->AddConstraint(2.0, y1, -1.0, y2, OperatorType(EQ), 0.0); + + //~ BList* coeffs3 = new BList(3); + //~ coeffs3->AddItem(new double(1.0)); + //~ coeffs3->AddItem(new double(1.0)); + //~ coeffs3->AddItem(new double(-1.0)); + //~ BList* vars3 = new BList(3); + //~ vars3->AddItem(y1); + //~ vars3->AddItem(y2); + //~ vars3->AddItem(y3); + fLS->AddConstraint(1.0, y1, 1.0, y2, -1.0, y3, OperatorType(EQ), 0.0); + + fLS->AddArea(fLS->Left(), y3, x2, y4, checkedListBox1); + fLS->AddArea(x2, fLS->Top(), fLS->Right(), y2, textBox1); + fLS->AddArea(fLS->Left(), y4, x3, y5, listView1); + fLS->AddArea(x3, y2, fLS->Right(), y5, textBox2); + + Area* richTextBox1Area = fLS->AddArea(x2, y2, x3, y4, richTextBox1); + richTextBox1Area->SetLeftInset(10); + richTextBox1Area->SetTopInset(10); + richTextBox1Area->SetRightInset(10); + richTextBox1Area->SetBottomInset(10); + + Area* label1Area = fLS->AddArea(fLS->Left(), y5, x2, fLS->Bottom(), label1); + label1Area->SetHAlignment(B_ALIGN_LEFT); + label1Area->SetTopInset(4); + label1Area->SetBottomInset(4); + + Area* label2Area = fLS->AddArea(x2, y5, x3, fLS->Bottom(), label2); + label2Area->SetHAlignment(B_ALIGN_HORIZONTAL_CENTER); + label2Area->SetTopInset(4); + label2Area->SetBottomInset(4); + + Area* label3Area = fLS->AddArea(x3, y5, fLS->Right(), fLS->Bottom(), label3); + label3Area->SetHAlignment(B_ALIGN_RIGHT); + label3Area->SetTopInset(4); + label3Area->SetBottomInset(4); + } + + +private: + BALMLayout* fLS; + BButton* button1; + BButton* button2; + BButton* button3; + BButton* button4; + BButton* button5; + BButton* button6; + BButton* checkedListBox1; + BButton* textBox1; + BButton* textBox2; + BButton* richTextBox1; + //~ BTextView* textBox1; + //~ BTextView* textBox2; + //~ BTextControl* richTextBox1; + BButton* listView1; + BStringView* label1; + BStringView* label2; + BStringView* label3; +}; + + +class Test2 : public BApplication { +public: + Test2() : BApplication("application/x-vnd.haiku.test2") { + BRect frameRect; + frameRect.Set(100, 100, 610, 456); + Test2Window* theWindow = new Test2Window(frameRect); + } +}; + + +int main() { + Test2 test; + test.Run(); + return 0; +} diff --git a/src/tests/libs/linprog/Jamfile b/src/tests/libs/linprog/Jamfile new file mode 100644 index 0000000000..5706eb620a --- /dev/null +++ b/src/tests/libs/linprog/Jamfile @@ -0,0 +1,11 @@ +SubDir HAIKU_TOP src tests libs linprog ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UseLibraryHeaders lp_solve linprog ; + +SimpleTest linprog : + Program.cpp + : + be liblpsolve55.so liblinprog.so +; diff --git a/src/tests/libs/linprog/Program.cpp b/src/tests/libs/linprog/Program.cpp new file mode 100644 index 0000000000..ccfb015d74 --- /dev/null +++ b/src/tests/libs/linprog/Program.cpp @@ -0,0 +1,67 @@ + +#include +#include + +#include "Constraint.h" +#include "LinearSpec.h" +#include "OperatorType.h" +#include "Variable.h" + +#include + + +void PrintVars(LinearSpec* ls) { + int32 size = ls->Variables()->CountItems(); + Variable* variable; + for (int i = 0; i < size; i++) { + variable = (Variable*)ls->Variables()->ItemAt(i); + printf("%f ", variable->Value()); + } + printf("%d\n", ls->Result()); +} + + +void Test1() { + LinearSpec* ls = new LinearSpec(); + Variable* x1 = ls->AddVariable(); + Variable* x2 = ls->AddVariable(); + + BList* coeffs1 = new BList(1); + coeffs1->AddItem(new double(1.0)); + BList* vars1 = new BList(1); + vars1->AddItem(x1); + Constraint* c1 = ls->AddConstraint(coeffs1, vars1, OperatorType(LE), 108); + + BList* coeffs2 = new BList(1); + coeffs2->AddItem(new double(1.0)); + BList* vars2 = new BList(1); + vars2->AddItem(x2); + Constraint* c2 = ls->AddConstraint(coeffs2, vars2, OperatorType(GE), 113); + + BList* coeffs3 = new BList(2); + coeffs3->AddItem(new double(1.0)); + coeffs3->AddItem(new double(1.0)); + BList* vars3 = new BList(2); + vars3->AddItem(x1); + vars3->AddItem(x2); + ls->SetObjFunction(coeffs3, vars3); + ls->Solve(); + PrintVars(ls); + + delete c2; + ls->Solve(); + PrintVars(ls); + + BList* coeffs4 = new BList(1); + coeffs4->AddItem(new double(1.0)); + BList* vars4 = new BList(1); + vars4->AddItem(x2); + c2 = ls->AddConstraint(coeffs4, vars4, OperatorType(GE), 113); + ls->Solve(); + PrintVars(ls); +} + + +int main() { + Test1(); +} diff --git a/src/tests/libs/lp_solve/Jamfile b/src/tests/libs/lp_solve/Jamfile new file mode 100644 index 0000000000..9e12c00cba --- /dev/null +++ b/src/tests/libs/lp_solve/Jamfile @@ -0,0 +1,12 @@ +SubDir HAIKU_TOP src tests libs lp_solve ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UseLibraryHeaders lp_solve ; + +SimpleTest lp_solve : + demo.c + : + liblpsolve55.so +; + diff --git a/src/tests/libs/lp_solve/demo.c b/src/tests/libs/lp_solve/demo.c new file mode 100644 index 0000000000..b82057c0c9 --- /dev/null +++ b/src/tests/libs/lp_solve/demo.c @@ -0,0 +1,146 @@ +/* demo.c */ + +#include "lp_lib.h" + +int demo() +{ + lprec *lp; + int Ncol, *colno = NULL, j, ret = 0; + REAL *row = NULL; + + /* We will build the model row by row + So we start with creating a model with 0 rows and 2 columns */ + Ncol = 2; /* there are two variables in the model */ + lp = make_lp(0, Ncol); + if(lp == NULL) + ret = 1; /* couldn't construct a new model... */ + + if(ret == 0) { + /* let us name our variables. Not required, but can be useful for debugging */ + set_col_name(lp, 1, "x"); + set_col_name(lp, 2, "y"); + + /* create space large enough for one row */ + colno = (int *) malloc(Ncol * sizeof(*colno)); + row = (REAL *) malloc(Ncol * sizeof(*row)); + if((colno == NULL) || (row == NULL)) + ret = 2; + } + + if(ret == 0) { + set_add_rowmode(lp, TRUE); /* makes building the model faster if it is done rows by row */ + + /* construct first row (120 x + 210 y <= 15000) */ + j = 0; + + colno[j] = 1; /* first column */ + row[j++] = 120; + + colno[j] = 2; /* second column */ + row[j++] = 210; + + /* add the row to lpsolve */ + if(!add_constraintex(lp, j, row, colno, LE, 15000)) + ret = 3; + } + + if(ret == 0) { + /* construct second row (110 x + 30 y <= 4000) */ + j = 0; + + colno[j] = 1; /* first column */ + row[j++] = 110; + + colno[j] = 2; /* second column */ + row[j++] = 30; + + /* add the row to lpsolve */ + if(!add_constraintex(lp, j, row, colno, LE, 4000)) + ret = 3; + } + + if(ret == 0) { + /* construct third row (x + y <= 75) */ + j = 0; + + colno[j] = 1; /* first column */ + row[j++] = 1; + + colno[j] = 2; /* second column */ + row[j++] = 1; + + /* add the row to lpsolve */ + if(!add_constraintex(lp, j, row, colno, LE, 75)) + ret = 3; + } + + if(ret == 0) { + set_add_rowmode(lp, FALSE); /* rowmode should be turned off again when done building the model */ + + /* set the objective function (143 x + 60 y) */ + j = 0; + + colno[j] = 1; /* first column */ + row[j++] = 143; + + colno[j] = 2; /* second column */ + row[j++] = 60; + + /* set the objective in lpsolve */ + if(!set_obj_fnex(lp, j, row, colno)) + ret = 4; + } + + if(ret == 0) { + /* set the object direction to maximize */ + set_maxim(lp); + + /* just out of curioucity, now show the model in lp format on screen */ + /* this only works if this is a console application. If not, use write_lp and a filename */ + write_LP(lp, stdout); + /* write_lp(lp, "model.lp"); */ + + /* I only want to see important messages on screen while solving */ + set_verbose(lp, IMPORTANT); + + /* Now let lpsolve calculate a solution */ + ret = solve(lp); + if(ret == OPTIMAL) + ret = 0; + else + ret = 5; + } + + if(ret == 0) { + /* a solution is calculated, now lets get some results */ + + /* objective value */ + printf("Objective value: %f\n", get_objective(lp)); + + /* variable values */ + get_variables(lp, row); + for(j = 0; j < Ncol; j++) + printf("%s: %f\n", get_col_name(lp, j + 1), row[j]); + + /* we are done now */ + } + + /* free allocated memory */ + if(row != NULL) + free(row); + if(colno != NULL) + free(colno); + + if(lp != NULL) { + /* clean up such that all used memory by lpsolve is freed */ + delete_lp(lp); + } + + return(ret); +} + +int main() +{ + demo(); +} +