xref: /haiku/src/libs/linprog/LinearSpec.cpp (revision a906d0a031e721e2f2ec9d95274103e74a3a774f)
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 "LinearSpec.h"
10 
11 #include <new>
12 
13 
14 /**
15  * Constructor.
16  * Creates a new specification for a linear programming problem.
17  */
18 LinearSpec::LinearSpec()
19 	:
20 	fLpPresolved(NULL),
21 	fOptimization(MINIMIZE),
22 	fObjFunction(new(std::nothrow) SummandList()),
23 	fResult(ERROR),
24 	fObjectiveValue(NAN),
25 	fSolvingTime(NAN)
26 {
27 	fLP = make_lp(0, 0);
28 	if (fLP == NULL)
29 		printf("Couldn't construct a new model.");
30 
31 	// minimize the objective functions, this is the default of lp_solve so we
32 	// don't have to do it here:
33 	// set_minim(fLP);
34 
35 	set_verbose(fLP, 1);
36 }
37 
38 
39 /**
40  * Destructor.
41  * Removes the specification and deletes all constraints,
42  * objective function summands and variables.
43  */
44 LinearSpec::~LinearSpec()
45 {
46 	_RemovePresolved();
47 	for (int32 i = 0; i < fConstraints.CountItems(); i++)
48 		delete (Constraint*)fConstraints.ItemAt(i);
49 	for (int32 i = 0; i < fObjFunction->CountItems(); i++)
50 		delete (Summand*)fObjFunction->ItemAt(i);
51 	while (fVariables.CountItems() > 0)
52 		RemoveVariable(fVariables.ItemAt(0));
53 
54 	delete_lp(fLP);
55 
56 	delete fObjFunction;
57 }
58 
59 
60 /**
61  * Adds a new variable to the specification.
62  *
63  * @return the new variable
64  */
65 Variable*
66 LinearSpec::AddVariable()
67 {
68 	Variable* variable = new(std::nothrow) Variable(this);
69 	if (!variable)
70 		return NULL;
71 	if (!AddVariable(variable)) {
72 		delete variable;
73 		return NULL;
74 	}
75 
76 	return variable;
77 }
78 
79 
80 bool
81 LinearSpec::AddVariable(Variable* variable)
82 {
83 	if (variable->IsValid())
84 		return false;
85 
86 	double d = 0;
87 	int i = 0;
88 
89 	if (!fVariables.AddItem(variable))
90 		return false;
91 	if (add_columnex(fLP, 0, &d, &i) == 0) {
92 		fVariables.RemoveItem(variable);
93 		return false;
94 	}
95 
96 	if (!SetRange(variable, variable->Min(), variable->Max())) {
97 		RemoveVariable(variable, false);
98 		return false;
99 	}
100 
101 	variable->fIsValid = true;
102 	return true;
103 }
104 
105 
106 bool
107 LinearSpec::RemoveVariable(Variable* variable, bool deleteVariable)
108 {
109 	int32 index = IndexOf(variable);
110 	if (index < 0)
111 		return false;
112 
113 	if (!del_column(fLP, index))
114 		return false;
115 	fVariables.RemoveItemAt(index - 1);
116 	variable->fIsValid = false;
117 
118 	// invalidate all constraints that use this variable
119 	ConstraintList markedForInvalidation;
120 	const ConstraintList& constraints = Constraints();
121 	for (int i = 0; i < constraints.CountItems(); i++) {
122 		Constraint* constraint = constraints.ItemAt(i);
123 
124 		if (!constraint->IsValid())
125 			continue;
126 
127 		SummandList* summands = constraint->LeftSide();
128 		for (int j = 0; j < summands->CountItems(); j++) {
129 			Summand* summand = summands->ItemAt(j);
130 			if (summand->Var() == variable) {
131 				markedForInvalidation.AddItem(constraint);
132 				break;
133 			}
134 		}
135 	}
136 	for (int i = 0; i < markedForInvalidation.CountItems(); i++)
137 		markedForInvalidation.ItemAt(i)->Invalidate();
138 
139 
140 	if (deleteVariable)
141 		delete variable;
142 	return true;
143 }
144 
145 
146 int32
147 LinearSpec::IndexOf(const Variable* variable) const
148 {
149 	int32 i = fVariables.IndexOf(variable);
150 	if (i == -1) {
151 		printf("Variable 0x%p not part of fLS->Variables().\n", variable);
152 		return -1;
153 	}
154 	return i + 1;
155 }
156 
157 
158 bool
159 LinearSpec::SetRange(Variable* variable, double min, double max)
160 {
161 	return set_bounds(fLP, IndexOf(variable), min, max);
162 }
163 
164 
165 bool
166 LinearSpec::AddConstraint(Constraint* constraint)
167 {
168 	SummandList* summands = constraint->LeftSide();
169 	OperatorType op = constraint->Op();
170 	double rightSide = constraint->RightSide();
171 	double penaltyNeg = constraint->PenaltyNeg();
172 	double penaltyPos = constraint->PenaltyPos();
173 
174 	double coeffs[summands->CountItems() + 2];
175 	int varIndexes[summands->CountItems() + 2];
176 	int32 nCoefficient = 0;
177 	for (; nCoefficient < summands->CountItems(); nCoefficient++) {
178 		Summand* s = summands->ItemAt(nCoefficient);
179 		coeffs[nCoefficient] = s->Coeff();
180 		varIndexes[nCoefficient] = s->Var()->Index();
181 	}
182 
183 	if (penaltyNeg != INFINITY && penaltyNeg != 0. && op != OperatorType(LE)) {
184 		constraint->fDNegObjSummand
185 			= new(std::nothrow) Summand(constraint->PenaltyNeg(),
186 				AddVariable());
187 		fObjFunction->AddItem(constraint->fDNegObjSummand);
188 		varIndexes[nCoefficient] = constraint->fDNegObjSummand->Var()->Index();
189 		coeffs[nCoefficient] = 1.0;
190 		nCoefficient++;
191 	}
192 
193 	if (penaltyPos != INFINITY && penaltyPos != 0. && op != OperatorType(GE)) {
194 		constraint->fDPosObjSummand
195 			= new(std::nothrow) Summand(constraint->PenaltyPos(),
196 				AddVariable());
197 		fObjFunction->AddItem(constraint->fDPosObjSummand);
198 		varIndexes[nCoefficient] = constraint->fDPosObjSummand->Var()->Index();
199 		coeffs[nCoefficient] = -1.0;
200 		nCoefficient++;
201 	}
202 
203 	if (!add_constraintex(fLP, nCoefficient, &coeffs[0], &varIndexes[0],
204 			(op == OperatorType(EQ) ? EQ : (op == OperatorType(GE)) ? GE
205 				: LE), rightSide))
206 		return false;
207 
208 	UpdateObjectiveFunction();
209 	fConstraints.AddItem(constraint);
210 
211 	return true;
212 }
213 
214 
215 bool
216 LinearSpec::RemoveConstraint(Constraint* constraint, bool deleteConstraint)
217 {
218 	if (constraint->fDNegObjSummand) {
219 		fObjFunction->RemoveItem(constraint->fDNegObjSummand);
220 		delete constraint->fDNegObjSummand->Var();
221 		delete constraint->fDNegObjSummand;
222 		constraint->fDNegObjSummand = NULL;
223 	}
224 	if (constraint->fDPosObjSummand) {
225 		fObjFunction->RemoveItem(constraint->fDPosObjSummand);
226 		delete constraint->fDPosObjSummand->Var();
227 		delete constraint->fDPosObjSummand;
228 		constraint->fDPosObjSummand = NULL;
229 	}
230 
231 	del_constraint(fLP, constraint->Index());
232 	fConstraints.RemoveItem(constraint);
233 	constraint->fIsValid = false;
234 
235 	if (deleteConstraint)
236 		delete constraint;
237 	return true;
238 }
239 
240 
241 bool
242 LinearSpec::UpdateLeftSide(Constraint* constraint)
243 {
244 	if (!constraint->IsValid())
245 		return false;
246 
247 	SummandList* leftSide = constraint->LeftSide();
248 	OperatorType op = constraint->Op();
249 
250 	double coeffs[leftSide->CountItems() + 2];
251 	int varIndexes[leftSide->CountItems() + 2];
252 	int32 i;
253 	for (i = 0; i < leftSide->CountItems(); i++) {
254 		Summand* s = leftSide->ItemAt(i);
255 		coeffs[i] = s->Coeff();
256 		varIndexes[i] = s->Var()->Index();
257 	}
258 
259 	if (constraint->fDNegObjSummand != NULL && op != OperatorType(LE)) {
260 		varIndexes[i] = constraint->fDNegObjSummand->Var()->Index();
261 		coeffs[i] = 1.0;
262 		i++;
263 	}
264 
265 	if (constraint->fDPosObjSummand != NULL && op != OperatorType(GE)) {
266 		varIndexes[i] = constraint->fDPosObjSummand->Var()->Index();
267 		coeffs[i] = -1.0;
268 		i++;
269 	}
270 
271 	if (!set_rowex(fLP, constraint->Index(), i, &coeffs[0],
272 		&varIndexes[0]))
273 		return false;
274 
275 	UpdateObjectiveFunction();
276 	_RemovePresolved();
277 	return true;
278 }
279 
280 
281 bool
282 LinearSpec::UpdateRightSide(Constraint* constraint)
283 {
284 	if (!set_rh(fLP, constraint->Index(), constraint->RightSide()))
285 		return false;
286 
287 	_RemovePresolved();
288 	return true;
289 }
290 
291 
292 bool
293 LinearSpec::UpdateOperator(Constraint* constraint)
294 {
295 	OperatorType op = constraint->Op();
296 	if (!set_constr_type(fLP, constraint->Index(),
297 		(op == OperatorType(EQ)) ? EQ : (op == OperatorType(GE)) ? GE
298 			: LE))
299 		return false;
300 
301 	_RemovePresolved();
302 	return true;
303 }
304 
305 
306 /**
307  * Adds a new hard linear constraint to the specification.
308  *
309  * @param coeffs		the constraint's coefficients
310  * @param vars			the constraint's variables
311  * @param op			the constraint's operand
312  * @param rightSide	the constant value on the constraint's right side
313  * @return the new constraint
314  */
315 Constraint*
316 LinearSpec::AddConstraint(SummandList* summands, OperatorType op,
317 	double rightSide)
318 {
319 	return AddConstraint(summands, op, rightSide, INFINITY, INFINITY);
320 }
321 
322 
323 /**
324  * Adds a new hard linear constraint to the specification with a single summand.
325  *
326  * @param coeff1		the constraint's first coefficient
327  * @param var1			the constraint's first variable
328  * @param op			the constraint's operand
329  * @param rightSide	the constant value on the constraint's right side
330  * @return the new constraint
331  */
332 Constraint*
333 LinearSpec::AddConstraint(double coeff1, Variable* var1,
334 	OperatorType op, double rightSide)
335 {
336 	return AddConstraint(coeff1, var1, op, rightSide, INFINITY, INFINITY);
337 }
338 
339 
340 /**
341  * Adds a new hard linear constraint to the specification with two summands.
342  *
343  * @param coeff1		the constraint's first coefficient
344  * @param var1			the constraint's first variable
345  * @param coeff2		the constraint's second coefficient
346  * @param var2			the constraint's second variable
347  * @param op			the constraint's operand
348  * @param rightSide	the constant value on the constraint's right side
349  * @return the new constraint
350  */
351 Constraint*
352 LinearSpec::AddConstraint(double coeff1, Variable* var1,
353 	double coeff2, Variable* var2, OperatorType op, double rightSide)
354 {
355 	return AddConstraint(coeff1, var1, coeff2, var2, op, rightSide, INFINITY,
356 		INFINITY);
357 }
358 
359 
360 /**
361  * Adds a new hard linear constraint to the specification with three summands.
362  *
363  * @param coeff1		the constraint's first coefficient
364  * @param var1			the constraint's first variable
365  * @param coeff2		the constraint's second coefficient
366  * @param var2			the constraint's second variable
367  * @param coeff3		the constraint's third coefficient
368  * @param var3			the constraint's third variable
369  * @param op			the constraint's operand
370  * @param rightSide	the constant value on the constraint's right side
371  * @return the new constraint
372  */
373 Constraint*
374 LinearSpec::AddConstraint(double coeff1, Variable* var1,
375 		double coeff2, Variable* var2, double coeff3, Variable* var3,
376 		OperatorType op, double rightSide)
377 {
378 	return AddConstraint(coeff1, var1, coeff2, var2, coeff3, var3, op,
379 		rightSide, INFINITY, INFINITY);
380 }
381 
382 
383 /**
384  * Adds a new hard linear constraint to the specification with four summands.
385  *
386  * @param coeff1		the constraint's first coefficient
387  * @param var1			the constraint's first variable
388  * @param coeff2		the constraint's second coefficient
389  * @param var2			the constraint's second variable
390  * @param coeff3		the constraint's third coefficient
391  * @param var3			the constraint's third variable
392  * @param coeff4		the constraint's fourth coefficient
393  * @param var4			the constraint's fourth variable
394  * @param op			the constraint's operand
395  * @param rightSide	the constant value on the constraint's right side
396  * @return the new constraint
397  */
398 Constraint*
399 LinearSpec::AddConstraint(double coeff1, Variable* var1,
400 		double coeff2, Variable* var2, double coeff3, Variable* var3,
401 		double coeff4, Variable* var4, OperatorType op, double rightSide)
402 {
403 	return AddConstraint(coeff1, var1, coeff2, var2, coeff3, var3, coeff4, var4,
404 		op, rightSide, INFINITY, INFINITY);
405 }
406 
407 
408 /**
409  * Adds a new soft linear constraint to the specification.
410  * i.e. a constraint that does not always have to be satisfied.
411  *
412  * @param coeffs		the constraint's coefficients
413  * @param vars			the constraint's variables
414  * @param op			the constraint's operand
415  * @param rightSide		the constant value on the constraint's right side
416  * @param penaltyNeg	the coefficient penalizing negative deviations from the exact solution
417  * @param penaltyPos	the coefficient penalizing positive deviations from the exact solution
418  */
419 Constraint*
420 LinearSpec::AddConstraint(SummandList* summands, OperatorType op,
421 		double rightSide, double penaltyNeg, double penaltyPos)
422 {
423 	return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
424 }
425 
426 
427 /**
428  * Adds a new soft linear constraint to the specification with a single summand.
429  *
430  * @param coeff1		the constraint's first coefficient
431  * @param var1			the constraint's first variable
432  * @param op			the constraint's operand
433  * @param rightSide		the constant value on the constraint's right side
434  * @param penaltyNeg	the coefficient penalizing negative deviations from the exact solution
435  * @param penaltyPos	the coefficient penalizing positive deviations from the exact solution
436  */
437 Constraint*
438 LinearSpec::AddConstraint(double coeff1, Variable* var1,
439 		OperatorType op, double rightSide, double penaltyNeg, double penaltyPos)
440 {
441 	SummandList* summands = new(std::nothrow) SummandList(1);
442 	if (!summands)
443 		return NULL;
444 	summands->AddItem(new(std::nothrow) Summand(coeff1, var1));
445 	if (!_CheckSummandList(summands))
446 		return NULL;
447 	return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
448 }
449 
450 
451 /**
452  * Adds a new soft linear constraint to the specification with two summands.
453  *
454  * @param coeff1		the constraint's first coefficient
455  * @param var1			the constraint's first variable
456  * @param coeff2		the constraint's second coefficient
457  * @param var2			the constraint's second variable
458  * @param op			the constraint's operand
459  * @param rightSide		the constant value on the constraint's right side
460  * @param penaltyNeg	the coefficient penalizing negative deviations from the exact solution
461  * @param penaltyPos	the coefficient penalizing positive deviations from the exact solution
462  */
463 Constraint*
464 LinearSpec::AddConstraint(double coeff1, Variable* var1,
465 	double coeff2, Variable* var2, OperatorType op, double rightSide,
466 	double penaltyNeg, double penaltyPos)
467 {
468 	SummandList* summands = new(std::nothrow) SummandList(2);
469 	if (!summands)
470 		return NULL;
471 	summands->AddItem(new(std::nothrow) Summand(coeff1, var1));
472 	summands->AddItem(new(std::nothrow) Summand(coeff2, var2));
473 	if (!_CheckSummandList(summands))
474 		return NULL;
475 	return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
476 }
477 
478 
479 /**
480  * Adds a new soft linear constraint to the specification with three summands.
481  *
482  * @param coeff1		the constraint's first coefficient
483  * @param var1			the constraint's first variable
484  * @param coeff2		the constraint's second coefficient
485  * @param var2			the constraint's second variable
486  * @param coeff3		the constraint's third coefficient
487  * @param var3			the constraint's third variable
488  * @param op			the constraint's operand
489  * @param rightSide		the constant value on the constraint's right side
490  * @param penaltyNeg	the coefficient penalizing negative deviations from the exact solution
491  * @param penaltyPos	the coefficient penalizing positive deviations from the exact solution
492  */
493 Constraint*
494 LinearSpec::AddConstraint(double coeff1, Variable* var1,
495 	double coeff2, Variable* var2, double coeff3, Variable* var3,
496 	OperatorType op, double rightSide, double penaltyNeg, double penaltyPos)
497 {
498 	SummandList* summands = new(std::nothrow) SummandList(2);
499 	if (!summands)
500 		return NULL;
501 	summands->AddItem(new(std::nothrow) Summand(coeff1, var1));
502 	summands->AddItem(new(std::nothrow) Summand(coeff2, var2));
503 	summands->AddItem(new(std::nothrow) Summand(coeff3, var3));
504 	if (!_CheckSummandList(summands))
505 		return NULL;
506 	return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
507 }
508 
509 
510 /**
511  * Adds a new soft linear constraint to the specification with four summands.
512  *
513  * @param coeff1		the constraint's first coefficient
514  * @param var1			the constraint's first variable
515  * @param coeff2		the constraint's second coefficient
516  * @param var2			the constraint's second variable
517  * @param coeff3		the constraint's third coefficient
518  * @param var3			the constraint's third variable
519  * @param coeff4		the constraint's fourth coefficient
520  * @param var4			the constraint's fourth variable
521  * @param op			the constraint's operand
522  * @param rightSide		the constant value on the constraint's right side
523  * @param penaltyNeg	the coefficient penalizing negative deviations from the exact solution
524  * @param penaltyPos	the coefficient penalizing positive deviations from the exact solution
525  */
526 Constraint*
527 LinearSpec::AddConstraint(double coeff1, Variable* var1,
528 	double coeff2, Variable* var2, double coeff3, Variable* var3,
529 	double coeff4, Variable* var4, OperatorType op, double rightSide,
530 	double penaltyNeg, double penaltyPos)
531 {
532 	SummandList* summands = new(std::nothrow) SummandList(2);
533 	if (!summands)
534 		return NULL;
535 	summands->AddItem(new(std::nothrow) Summand(coeff1, var1));
536 	summands->AddItem(new(std::nothrow) Summand(coeff2, var2));
537 	summands->AddItem(new(std::nothrow) Summand(coeff3, var3));
538 	summands->AddItem(new(std::nothrow) Summand(coeff4, var4));
539 	if (!_CheckSummandList(summands))
540 		return NULL;
541 	return _AddConstraint(summands, op, rightSide, penaltyNeg, penaltyPos);
542 }
543 
544 
545 /**
546  * Adds a new penalty function to the specification.
547  *
548  * @param var	the penalty function's variable
549  * @param xs	the penalty function's sampling points
550  * @param gs	the penalty function's gradients
551  * @return the new penalty function
552  */
553 PenaltyFunction*
554 LinearSpec::AddPenaltyFunction(Variable* var, BList* xs, BList* gs)
555 {
556 	return new(std::nothrow) PenaltyFunction(this, var, xs, gs);
557 }
558 
559 
560 /**
561  * Gets the objective function.
562  *
563  * @return SummandList containing the objective function's summands
564  */
565 SummandList*
566 LinearSpec::ObjectiveFunction()
567 {
568 	return fObjFunction;
569 }
570 
571 
572 SummandList*
573 LinearSpec::SwapObjectiveFunction(SummandList* objFunction)
574 {
575 	SummandList* list = fObjFunction;
576 	fObjFunction = objFunction;
577 	UpdateObjectiveFunction();
578 	return list;
579 }
580 
581 
582 /**
583  * Sets a new objective function.
584  *
585  * @param summands	SummandList containing the objective function's summands
586  */
587 void
588 LinearSpec::SetObjectiveFunction(SummandList* objFunction)
589 {
590 	for (int32 i = 0; i < fObjFunction->CountItems(); i++)
591 		delete (Summand*)fObjFunction->ItemAt(i);
592 	delete fObjFunction;
593 
594 	fObjFunction = objFunction;
595 	UpdateObjectiveFunction();
596 }
597 
598 
599 /**
600  * Updates the internal representation of the objective function.
601  * Must be called whenever the summands of the objective function are changed.
602  */
603 void
604 LinearSpec::UpdateObjectiveFunction()
605 {
606 	int32 size = fObjFunction->CountItems();
607 	double coeffs[size];
608 	int varIndexes[size];
609 	Summand* current;
610 	for (int32 i = 0; i < size; i++) {
611 		current = (Summand*)fObjFunction->ItemAt(i);
612 		coeffs[i] = current->Coeff();
613 		varIndexes[i] = current->Var()->Index();
614 	}
615 
616 	if (!set_obj_fnex(fLP, size, &coeffs[0], &varIndexes[0]))
617 		printf("Error in set_obj_fnex.\n");
618 
619 	_RemovePresolved();
620 }
621 
622 
623 bool
624 LinearSpec::_CheckSummandList(SummandList* list)
625 {
626 	bool ok = true;
627 	for (int i = 0; i < list->CountItems(); i++) {
628 		if (list->ItemAt(i) == NULL) {
629 			ok = false;
630 			break;
631 		}
632 	}
633 	if (ok)
634 		return true;
635 
636 	for (int i = 0; i < list->CountItems(); i++)
637 		delete list->ItemAt(i);
638 	delete list;
639 	return false;
640 }
641 
642 
643 Constraint*
644 LinearSpec::_AddConstraint(SummandList* leftSide, OperatorType op,
645 	double rightSide, double penaltyNeg, double penaltyPos)
646 {
647 	Constraint* constraint = new(std::nothrow) Constraint(this, leftSide,
648 		op, rightSide, penaltyNeg, penaltyPos);
649 	if (constraint == NULL)
650 		return NULL;
651 	if (!AddConstraint(constraint)) {
652 		delete constraint;
653 		return NULL;
654 	}
655 	_RemovePresolved();
656 	return constraint;
657 }
658 
659 
660 /**
661  * Remove a cached presolved model, if existent.
662  * This is automatically done each time after the model has been changed,
663  * to avoid an old cached presolved model getting out of sync.
664  */
665 void
666 LinearSpec::_RemovePresolved()
667 {
668 	if (fLpPresolved == NULL)
669 		return;
670 	delete_lp(fLpPresolved);
671 	fLpPresolved = NULL;
672 }
673 
674 
675 /**
676  * Creates and caches a simplified version of the linear programming problem,
677  * where redundant rows, columns and constraints are removed,
678  * if it has not been created before.
679  * Then, the simplified problem is solved.
680  *
681  * @return the result of the solving attempt
682  */
683 ResultType
684 LinearSpec::_Presolve()
685 {
686 	bigtime_t start, end;
687 	start = system_time();
688 
689 	if (fLpPresolved == NULL) {
690 		fLpPresolved = copy_lp(fLP);
691 		set_presolve(fLpPresolved, PRESOLVE_ROWS | PRESOLVE_COLS
692 			| PRESOLVE_LINDEP, get_presolveloops(fLpPresolved));
693 	}
694 
695 	fResult = (ResultType)solve(fLpPresolved);
696 	fObjectiveValue = get_objective(fLpPresolved);
697 
698 	if (fResult == OPTIMAL) {
699 		int32 size = fVariables.CountItems();
700 		for (int32 i = 0; i < size; i++) {
701 			Variable* current = (Variable*)fVariables.ItemAt(i);
702 			current->SetValue(get_var_primalresult(fLpPresolved,
703 					get_Norig_rows(fLpPresolved) + current->Index()));
704 		}
705 	}
706 
707 	end = system_time();
708 	fSolvingTime = (end - start) / 1000.0;
709 
710 	return fResult;
711 }
712 
713 
714 /**
715  * Tries to solve the linear programming problem.
716  * If a cached simplified version of the problem exists, it is used instead.
717  *
718  * @return the result of the solving attempt
719  */
720 ResultType
721 LinearSpec::Solve()
722 {
723 	if (fLpPresolved != NULL)
724 		return _Presolve();
725 
726 	bigtime_t start, end;
727 	start = system_time();
728 
729 	fResult = (ResultType)solve(fLP);
730 	fObjectiveValue = get_objective(fLP);
731 
732 	if (fResult == OPTIMAL) {
733 		int32 size = fVariables.CountItems();
734 		double x[size];
735 		if (!get_variables(fLP, &x[0]))
736 			printf("Error in get_variables.\n");
737 
738 		int32 i = 0;
739 		while (i < size) {
740 			((Variable*)fVariables.ItemAt(i))->SetValue(x[i]);
741 			i++;
742 		}
743 	}
744 
745 	end = system_time();
746 	fSolvingTime = (end - start) / 1000.0;
747 
748 	return fResult;
749 }
750 
751 
752 /**
753  * Writes the specification into a text file.
754  * The file will be overwritten if it exists.
755  *
756  * @param fname	the file name
757  */
758 void
759 LinearSpec::Save(const char* fileName)
760 {
761 	// TODO: Constness should be fixed in liblpsolve API.
762 	write_lp(fLP, const_cast<char*>(fileName));
763 }
764 
765 
766 /**
767  * Gets the current optimization.
768  * The default is minimization.
769  *
770  * @return the current optimization
771  */
772 OptimizationType
773 LinearSpec::Optimization() const
774 {
775 	return fOptimization;
776 }
777 
778 
779 /**
780  * Sets whether the solver should minimize or maximize the objective function.
781  * The default is minimization.
782  *
783  * @param optimization	the optimization type
784  */
785 void
786 LinearSpec::SetOptimization(OptimizationType value)
787 {
788 	fOptimization = value;
789 	if (fOptimization == MINIMIZE)
790 		set_minim(fLP);
791 	else
792 		set_maxim(fLP);
793 }
794 
795 
796 /**
797  * Gets the constraints.
798  *
799  * @return the constraints
800  */
801 const ConstraintList&
802 LinearSpec::Constraints() const
803 {
804 	return fConstraints;
805 }
806 
807 
808 /**
809  * Gets the result type.
810  *
811  * @return the result type
812  */
813 ResultType
814 LinearSpec::Result() const
815 {
816 	return fResult;
817 }
818 
819 
820 /**
821  * Gets the objective value.
822  *
823  * @return the objective value
824  */
825 double
826 LinearSpec::ObjectiveValue() const
827 {
828 	return fObjectiveValue;
829 }
830 
831 
832 /**
833  * Gets the solving time.
834  *
835  * @return the solving time
836  */
837 double
838 LinearSpec::SolvingTime() const
839 {
840 	return fSolvingTime;
841 }
842 
843 
844 LinearSpec::operator BString() const
845 {
846 	BString string;
847 	GetString(string);
848 	return string;
849 }
850 
851 
852 void
853 LinearSpec::GetString(BString& string) const
854 {
855 	string << "LinearSpec " << (int32)this << ":\n";
856 	for (int i = 0; i < fVariables.CountItems(); i++) {
857 		Variable* variable = static_cast<Variable*>(fVariables.ItemAt(i));
858 		variable->GetString(string);
859 		string << "=" << (float)variable->Value() << " ";
860 	}
861 	string << "\n";
862 	for (int i = 0; i < fConstraints.CountItems(); i++) {
863 		Constraint* c = static_cast<Constraint*>(fConstraints.ItemAt(i));
864 		string << i << ": ";
865 		c->GetString(string);
866 		string << "\n";
867 	}
868 	string << "Result=";
869 	if (fResult==-1)
870 		string << "ERROR";
871 	else if (fResult==0)
872 		string << "OPTIMAL";
873 	else if (fResult==1)
874 		string << "SUBOPTIMAL";
875 	else if (fResult==2)
876 		string << "INFEASIBLE";
877 	else if (fResult==3)
878 		string << "UNBOUNDED";
879 	else if (fResult==4)
880 		string << "DEGENERATE";
881 	else if (fResult==5)
882 		string << "NUMFAILURE";
883 	else
884 		string << fResult;
885 	string << " SolvingTime=" << (float)fSolvingTime << "ms";
886 }
887 
888