xref: /haiku/src/libs/linprog/Constraint.cpp (revision ac078a5b110045de12089052a685a6a080545db1)
1 /*
2  * Copyright 2007-2008, Christof Lutteroth, lutteroth@cs.auckland.ac.nz
3  * Copyright 2007-2008, James Kim, jkim202@ec.auckland.ac.nz
4  * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include "Constraint.h"
10 
11 #include <new>
12 #include <stdio.h>
13 
14 #include "LinearSpec.h"
15 #include "Variable.h"
16 
17 
18 // Toggle debug output
19 //#define DEBUG_CONSTRAINT
20 
21 #ifdef DEBUG_CONSTRAINT
22 #	define STRACE(x) debug_printf x
23 #else
24 #	define STRACE(x) ;
25 #endif
26 
27 
28 /**
29  * Gets the index of the constraint.
30  *
31  * @return the index of the constraint
32  */
33 int32
34 Constraint::Index() const
35 {
36 	int32 i = fLS->Constraints().IndexOf(this);
37 	if (i == -1)
38 		STRACE(("Constraint not part of fLS->Constraints()."));
39 
40 	return i;
41 }
42 
43 
44 /**
45  * Gets the left side of the constraint.
46  *
47  * @return pointer to a BList containing the summands on the left side of the constraint
48  */
49 SummandList*
50 Constraint::LeftSide()
51 {
52 	return fLeftSide;
53 }
54 
55 
56 /**
57  * Sets the summands on the left side of the constraint.
58  * The old summands are NOT deleted.
59  *
60  * @param summands	a BList containing the Summand objects that make up the new left side
61  */
62 void
63 Constraint::SetLeftSide(SummandList* summands)
64 {
65 	if (!fIsValid)
66 		return;
67 
68 	fLeftSide = summands;
69 	fLS->UpdateLeftSide(this);
70 }
71 
72 
73 void
74 Constraint::SetLeftSide(double coeff1, Variable* var1)
75 {
76 	if (!fIsValid)
77 		return;
78 
79 	for (int i=0; i<fLeftSide->CountItems(); i++)
80 		delete fLeftSide->ItemAt(i);
81 	fLeftSide->MakeEmpty();
82 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1));
83 	fLS->UpdateLeftSide(this);
84 }
85 
86 
87 void
88 Constraint::SetLeftSide(double coeff1, Variable* var1,
89 	double coeff2, Variable* var2)
90 {
91 	if (!fIsValid)
92 		return;
93 
94 	for (int i=0; i<fLeftSide->CountItems(); i++)
95 		delete fLeftSide->ItemAt(i);
96 	fLeftSide->MakeEmpty();
97 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1));
98 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff2, var2));
99 	fLS->UpdateLeftSide(this);
100 }
101 
102 
103 void
104 Constraint::SetLeftSide(double coeff1, Variable* var1,
105 	double coeff2, Variable* var2,
106 	double coeff3, Variable* var3)
107 {
108 	if (!fIsValid)
109 		return;
110 
111 	for (int i=0; i<fLeftSide->CountItems(); i++)
112 		delete fLeftSide->ItemAt(i);
113 	fLeftSide->MakeEmpty();
114 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1));
115 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff2, var2));
116 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff3, var3));
117 	fLS->UpdateLeftSide(this);
118 }
119 
120 
121 void
122 Constraint::SetLeftSide(double coeff1, Variable* var1,
123 	double coeff2, Variable* var2,
124 	double coeff3, Variable* var3,
125 	double coeff4, Variable* var4)
126 {
127 	if (!fIsValid)
128 		return;
129 
130 	for (int i=0; i<fLeftSide->CountItems(); i++)
131 		delete fLeftSide->ItemAt(i);
132 	fLeftSide->MakeEmpty();
133 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1));
134 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff2, var2));
135 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff3, var3));
136 	fLeftSide->AddItem(new(std::nothrow) Summand(coeff4, var4));
137 	fLS->UpdateLeftSide(this);
138 }
139 
140 
141 /**
142  * Gets the operator used for this constraint.
143  *
144  * @return the operator used for this constraint
145  */
146 OperatorType
147 Constraint::Op()
148 {
149 	return fOp;
150 }
151 
152 
153 /**
154  * Sets the operator used for this constraint.
155  *
156  * @param value	operator
157  */
158 void
159 Constraint::SetOp(OperatorType value)
160 {
161 	if (!fIsValid)
162 		return;
163 
164 	fOp = value;
165 	fLS->UpdateOperator(this);
166 }
167 
168 
169 /**
170  * Gets the constant value that is on the right side of the operator.
171  *
172  * @return the constant value that is on the right side of the operator
173  */
174 double
175 Constraint::RightSide() const
176 {
177 	return fRightSide;
178 }
179 
180 
181 /**
182  * Sets the constant value that is on the right side of the operator.
183  *
184  * @param value	constant value that is on the right side of the operator
185  */
186 void
187 Constraint::SetRightSide(double value)
188 {
189 	if (!fIsValid)
190 		return;
191 
192 	if (fRightSide == value)
193 		return;
194 
195 	fRightSide = value;
196 
197 	fLS->UpdateRightSide(this);
198 }
199 
200 
201 /**
202  * Gets the penalty coefficient for negative deviations.
203  *
204  * @return the penalty coefficient
205  */
206 double
207 Constraint::PenaltyNeg() const
208 {
209 	return fPenaltyNeg;
210 }
211 
212 
213 /**
214  * The penalty coefficient for negative deviations from the soft constraint's exact solution,&nbsp;
215  * i.e. if the left side is too large.
216  *
217  * @param value	coefficient of negative penalty <code>double</code>
218  */
219 void
220 Constraint::SetPenaltyNeg(double value)
221 {
222 	fPenaltyNeg = value;
223 
224 	fLS->UpdateLeftSide(this);
225 }
226 
227 
228 /**
229  * Gets the penalty coefficient for positive deviations.
230  *
231  * @return the penalty coefficient
232  */
233 double
234 Constraint::PenaltyPos() const
235 {
236 	return fPenaltyPos;
237 }
238 
239 
240 /**
241  * The penalty coefficient for negative deviations from the soft constraint's
242  * exact solution, i.e. if the left side is too small.
243  * @param value	coefficient of positive penalty <code>double</code>
244  */
245 void
246 Constraint::SetPenaltyPos(double value)
247 {
248 	fPenaltyPos = value;
249 
250 	fLS->UpdateLeftSide(this);
251 }
252 
253 
254 const char*
255 Constraint::Label()
256 {
257 	return fLabel.String();
258 }
259 
260 
261 void
262 Constraint::SetLabel(const char* label)
263 {
264 	fLabel = label;
265 }
266 
267 
268 /**
269  * Gets the slack variable for the negative variations.
270  *
271  * @return the slack variable for the negative variations
272  */
273 Variable*
274 Constraint::DNeg() const
275 {
276 	if (fDNegObjSummand == NULL)
277 		return NULL;
278 	return fDNegObjSummand->Var();
279 }
280 
281 
282 /**
283  * Gets the slack variable for the positive variations.
284  *
285  * @return the slack variable for the positive variations
286  */
287 Variable*
288 Constraint::DPos() const
289 {
290 	if (fDPosObjSummand == NULL)
291 		return NULL;
292 	return fDPosObjSummand->Var();
293 }
294 
295 
296 bool
297 Constraint::IsSoft() const
298 {
299 	if (fPenaltyNeg > 0. && fOp != kLE)
300 		return true;
301 
302 	if (fPenaltyPos > 0. && fOp != kGE)
303 		return true;
304 	return false;
305 }
306 
307 
308 bool
309 Constraint::IsValid()
310 {
311 	return fIsValid;
312 }
313 
314 
315 void
316 Constraint::Invalidate()
317 {
318 	STRACE(("Constraint::Invalidate() on %d\n", this));
319 
320 	if (!fIsValid)
321 		return;
322 
323 	fIsValid = false;
324 	fLS->RemoveConstraint(this, false);
325 }
326 
327 
328 BString
329 Constraint::ToString() const
330 {
331 	BString string;
332 	string << "Constraint ";
333 	string << fLabel;
334 	string << "(" << (int32)this << "): ";
335 
336 	if (fIsValid) {
337 		for (int i = 0; i < fLeftSide->CountItems(); i++) {
338 			Summand* s = static_cast<Summand*>(fLeftSide->ItemAt(i));
339 			string << (float)s->Coeff() << "*";
340 			string << "x";
341 			string << s->Var()->Index() - 1;
342 			string << " ";
343 		}
344 		string << ((fOp == kEQ) ? "== "
345 			: (fOp == kGE) ? ">= "
346 			: (fOp == kLE) ? "<= "
347 			: "?? ");
348 		string << (float)fRightSide;
349 		string << " PenaltyPos=" << (float)PenaltyPos();
350 		string << " PenaltyNeg=" << (float)PenaltyNeg();
351 	} else
352 		string << "invalid";
353 	return string;
354 }
355 
356 
357 void
358 Constraint::PrintToStream()
359 {
360 	BString string = ToString();
361 	printf("%s\n", string.String());
362 }
363 
364 
365 /**
366  * Constructor.
367  */
368 Constraint::Constraint(LinearSpec* ls, SummandList* summands, OperatorType op,
369 	double rightSide, double penaltyNeg, double penaltyPos)
370 	:
371 	fLS(ls),
372 	fLeftSide(summands),
373 	fOp(op),
374 	fRightSide(rightSide),
375 	fPenaltyNeg(penaltyNeg),
376 	fPenaltyPos(penaltyPos),
377 	fDNegObjSummand(NULL),
378 	fDPosObjSummand(NULL),
379 	fIsValid(true)
380 {
381 
382 }
383 
384 
385 /**
386  * Destructor.
387  * Removes the constraint from its specification and deletes all the summands.
388  */
389 Constraint::~Constraint()
390 {
391 	Invalidate();
392 
393 	for (int32 i = 0; i < fLeftSide->CountItems(); i++)
394 		delete (Summand*)fLeftSide->ItemAt(i);
395 	delete fLeftSide;
396 	fLeftSide = NULL;
397 }
398 
399