xref: /haiku/src/libs/linprog/Constraint.cpp (revision 067f47a3eed22ed903463892f1a4fc81bc237563)
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 
13 #include "LinearSpec.h"
14 #include "Variable.h"
15 
16 
17 // Toggle debug output
18 //#define DEBUG_CONSTRAINT
19 
20 #ifdef DEBUG_CONSTRAINT
21 #	define STRACE(x) debug_printf x
22 #else
23 #	define STRACE(x) ;
24 #endif
25 
26 
27 /**
28  * Gets the index of the constraint.
29  *
30  * @return the index of the constraint
31  */
32 int32
33 Constraint::Index() const
34 {
35 	int32 i = fLS->Constraints().IndexOf(this);
36 	if (i == -1) {
37 		STRACE(("Constraint not part of fLS->Constraints()."));
38 		return -1;
39 	}
40 	return i + 1;
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 	if (!fIsValid)
225 		return;
226 
227 	if (fDNegObjSummand == NULL) {
228 		fDNegObjSummand = new(std::nothrow) Summand(value, fLS->AddVariable());
229 		fLS->ObjectiveFunction()->AddItem(fDNegObjSummand);
230 		fLS->UpdateLeftSide(this);
231 		fLS->UpdateObjectiveFunction();
232 		return;
233 	}
234 
235 	if (value == fDNegObjSummand->Coeff())
236 		return;
237 
238 	fDNegObjSummand->SetCoeff(value);
239 	fLS->UpdateObjectiveFunction();
240 }
241 
242 
243 /**
244  * Gets the penalty coefficient for positive deviations.
245  *
246  * @return the penalty coefficient
247  */
248 double
249 Constraint::PenaltyPos() const
250 {
251 	return fPenaltyPos;
252 }
253 
254 
255 /**
256  * The penalty coefficient for negative deviations from the soft constraint's
257  * exact solution, i.e. if the left side is too small.
258  * @param value	coefficient of positive penalty <code>double</code>
259  */
260 void
261 Constraint::SetPenaltyPos(double value)
262 {
263 	fPenaltyPos = value;
264 
265 	if (!fIsValid)
266 		return;
267 
268 	if (fDPosObjSummand == NULL) {
269 		fDPosObjSummand = new(std::nothrow) Summand(value, fLS->AddVariable());
270 		fLS->ObjectiveFunction()->AddItem(fDPosObjSummand);
271 		fLS->UpdateLeftSide(this);
272 		fLS->UpdateObjectiveFunction();
273 		return;
274 	}
275 
276 	if (value == fDPosObjSummand->Coeff())
277 		return;
278 
279 	fDPosObjSummand->SetCoeff(value);
280 	fLS->UpdateObjectiveFunction();
281 }
282 
283 
284 const char*
285 Constraint::Label()
286 {
287 	return fLabel.String();
288 }
289 
290 
291 void
292 Constraint::SetLabel(const char* label)
293 {
294 	fLabel = label;
295 }
296 
297 
298 void
299 Constraint::WriteXML(BFile* file)
300 {
301 	if (!file->IsWritable())
302 		return;
303 
304 	char buffer[200];
305 
306 	file->Write(buffer, sprintf(buffer, "\t<constraint>\n"));
307 	file->Write(buffer, sprintf(buffer, "\t\t<leftside>\n"));
308 
309 	Summand* summand;
310 	for (int32 i = 0; i < fLeftSide->CountItems(); i++) {
311 		summand = (Summand*)fLeftSide->ItemAt(i);
312 		file->Write(buffer, sprintf(buffer, "\t\t\t<summand>\n"));
313 		file->Write(buffer, sprintf(buffer, "\t\t\t\t<coeff>%f</coeff>\n",
314 			summand->Coeff()));
315 		BString varStr = *(summand->Var());
316 		file->Write(buffer, sprintf(buffer, "\t\t\t\t<var>%s</var>\n",
317 			varStr.String()));
318 		file->Write(buffer, sprintf(buffer, "\t\t\t</summand>\n"));
319 	}
320 
321 	file->Write(buffer, sprintf(buffer, "\t\t</leftside>\n"));
322 
323 	const char* op = "??";
324 	if (fOp == OperatorType(EQ))
325 		op = "EQ";
326 	else if (fOp == OperatorType(LE))
327 		op = "LE";
328 	else if (fOp == OperatorType(GE))
329 		op = "GE";
330 
331 	file->Write(buffer, sprintf(buffer, "\t\t<op>%s</op>\n", op));
332 	file->Write(buffer, sprintf(buffer, "\t\t<rightside>%f</rightside>\n", fRightSide));
333 	//~ file->Write(buffer, sprintf(buffer, "\t\t<penaltyneg>%s</penaltyneg>\n", PenaltyNeg()));
334 	//~ file->Write(buffer, sprintf(buffer, "\t\t<penaltypos>%s</penaltypos>\n", PenaltyPos()));
335 	file->Write(buffer, sprintf(buffer, "\t</constraint>\n"));
336 }
337 
338 
339 /**
340  * Gets the slack variable for the negative variations.
341  *
342  * @return the slack variable for the negative variations
343  */
344 Variable*
345 Constraint::DNeg() const
346 {
347 	if (fDNegObjSummand == NULL)
348 		return NULL;
349 	return fDNegObjSummand->Var();
350 }
351 
352 
353 /**
354  * Gets the slack variable for the positive variations.
355  *
356  * @return the slack variable for the positive variations
357  */
358 Variable*
359 Constraint::DPos() const
360 {
361 	if (fDPosObjSummand == NULL)
362 		return NULL;
363 	return fDPosObjSummand->Var();
364 }
365 
366 
367 bool
368 Constraint::IsValid()
369 {
370 	return fIsValid;
371 }
372 
373 
374 void
375 Constraint::Invalidate()
376 {
377 	STRACE(("Constraint::Invalidate() on %d\n", this));
378 
379 	if (!fIsValid)
380 		return;
381 
382 	fIsValid = false;
383 	fLS->RemoveConstraint(this, false);
384 }
385 
386 
387 Constraint::operator BString() const
388 {
389 	BString string;
390 	GetString(string);
391 	return string;
392 }
393 
394 
395 void
396 Constraint::GetString(BString& string) const
397 {
398 	string << "Constraint ";
399 	string << fLabel;
400 	string << "(" << (int32)this << "): ";
401 
402 	if (fIsValid) {
403 		for (int i = 0; i < fLeftSide->CountItems(); i++) {
404 			Summand* s = static_cast<Summand*>(fLeftSide->ItemAt(i));
405 			string << (float)s->Coeff() << "*";
406 			s->Var()->GetString(string);
407 			string << " ";
408 		}
409 		string << ((fOp == OperatorType(EQ)) ? "== "
410 			: (fOp == OperatorType(GE)) ? ">= "
411 			: (fOp == OperatorType(LE)) ? "<= "
412 			: "?? ");
413 		string << (float)fRightSide;
414 		string << " PenaltyPos=" << (float)PenaltyPos();
415 		string << " PenaltyNeg=" << (float)PenaltyNeg();
416 	} else
417 		string << "invalid";
418 }
419 
420 
421 /**
422  * Constructor.
423  */
424 Constraint::Constraint(LinearSpec* ls, SummandList* summands, OperatorType op,
425 	double rightSide, double penaltyNeg, double penaltyPos)
426 	:
427 	fLS(ls),
428 	fLeftSide(summands),
429 	fOp(op),
430 	fRightSide(rightSide),
431 	fPenaltyNeg(penaltyNeg),
432 	fPenaltyPos(penaltyPos),
433 	fDNegObjSummand(NULL),
434 	fDPosObjSummand(NULL),
435 	fIsValid(true)
436 {
437 
438 }
439 
440 
441 /**
442  * Destructor.
443  * Removes the constraint from its specification and deletes all the summands.
444  */
445 Constraint::~Constraint()
446 {
447 	Invalidate();
448 
449 	for (int32 i = 0; i < fLeftSide->CountItems(); i++)
450 		delete (Summand*)fLeftSide->ItemAt(i);
451 	delete fLeftSide;
452 	fLeftSide = NULL;
453 }
454 
455