xref: /haiku/src/libs/linprog/LayoutOptimizer.cpp (revision a0ad88e0020787e69b41080af9d707db42aad924)
1 /*
2  * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3  * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "LayoutOptimizer.h"
9 
10 #include <new>
11 #include <stdio.h>
12 #include <string.h>
13 
14 #include <AutoDeleter.h>
15 
16 
17 //#define TRACE_LAYOUT_OPTIMIZER	1
18 #if TRACE_LAYOUT_OPTIMIZER
19 #	define TRACE(format...)	printf(format)
20 #	define TRACE_ONLY(x)	x
21 #else
22 #	define TRACE(format...)
23 #	define TRACE_ONLY(x)
24 #endif
25 #define TRACE_ERROR(format...)	fprintf(stderr, format)
26 
27 using std::nothrow;
28 
29 
30 /*!	\class BPrivate::Layout::LayoutOptimizer
31 
32 	Given a set of layout constraints, a feasible solution, and a desired
33 	(non-)solution this class finds an optimal solution. The optimization
34 	criterion is to minimize the norm of the difference to the desired
35 	(non-)solution.
36 
37 	It does so by implementing an active set method algorithm. The basic idea
38 	is to start with the subset of the constraints that are barely satisfied by
39 	the feasible solution, i.e. including all equality constraints and those
40 	inequality constraints that are still satisfied, if restricted to equality
41 	constraints. This set is called active set, the contained constraints active
42 	constraints.
43 
44 	Considering all of the active constraints equality constraints a new
45 	solution is computed, which still satisfies all those equality constraints
46 	and is optimal with respect to the optimization criterion.
47 
48 	If the new solution equals the previous one, we find the inequality
49 	constraint that, by keeping it in the active set, prevents us most from
50 	further optimizing the solution. If none really does, we're done, having
51 	found the globally optimal solution. Otherwise we remove the found
52 	constraint from the active set and try again.
53 
54 	If the new solution does not equal the previous one, it might violate one
55 	or more of the inactive constraints. If that is the case, we add the
56 	most-violated constraint to the active set and adjust the new solution such
57 	that barely satisfies that constraint. Otherwise, we don't adjust the
58 	computed solution. With the adjusted respectively unadjusted solution
59 	we enter the next iteration, i.e. by computing a new optimal solution with
60 	respect to the active set.
61 */
62 
63 
64 // #pragma mark - vector and matrix operations
65 
66 
67 // is_zero
68 static inline bool
69 is_zero(double* x, int n)
70 {
71 	for (int i = 0; i < n; i++) {
72 		if (!fuzzy_equals(x[i], 0))
73 			return false;
74 	}
75 
76 	return true;
77 }
78 
79 
80 // add_vectors
81 static inline void
82 add_vectors(double* x, const double* y, int n)
83 {
84 	for (int i = 0; i < n; i++)
85 		x[i] += y[i];
86 }
87 
88 
89 // add_vectors_scaled
90 static inline void
91 add_vectors_scaled(double* x, const double* y, double scalar, int n)
92 {
93 	for (int i = 0; i < n; i++)
94 		x[i] += y[i] * scalar;
95 }
96 
97 
98 // negate_vector
99 static inline void
100 negate_vector(double* x, int n)
101 {
102 	for (int i = 0; i < n; i++)
103 		x[i] = -x[i];
104 }
105 
106 
107 // allocate_matrix
108 double**
109 BPrivate::Layout::allocate_matrix(int m, int n)
110 {
111 	double** matrix = new(nothrow) double*[m];
112 	if (!matrix)
113 		return NULL;
114 
115 	double* values = new(nothrow) double[m * n];
116 	if (!values) {
117 		delete[] matrix;
118 		return NULL;
119 	}
120 
121 	double* row = values;
122 	for (int i = 0; i < m; i++, row += n)
123 		matrix[i] = row;
124 
125 	return matrix;
126 }
127 
128 
129 // free_matrix
130 void
131 BPrivate::Layout::free_matrix(double** matrix)
132 {
133 	if (matrix) {
134 		delete[] *matrix;
135 		delete[] matrix;
136 	}
137 }
138 
139 
140 // multiply_matrix_vector
141 /*!	y = Ax
142 	A: m x n matrix
143 */
144 static inline void
145 multiply_matrix_vector(const double* const* A, const double* x, int m, int n,
146 	double* y)
147 {
148 	for (int i = 0; i < m; i++) {
149 		double sum = 0;
150 		for (int k = 0; k < n; k++)
151 			sum += A[i][k] * x[k];
152 		y[i] = sum;
153 	}
154 }
155 
156 
157 // multiply_matrices
158 /*!	c = a*b
159 */
160 static void
161 multiply_matrices(const double* const* a, const double* const* b, double** c,
162 	int m, int n, int l)
163 {
164 	for (int i = 0; i < m; i++) {
165 		for (int j = 0; j < l; j++) {
166 			double sum = 0;
167 			for (int k = 0; k < n; k++)
168 				sum += a[i][k] * b[k][j];
169 			c[i][j] = sum;
170 		}
171 	}
172 }
173 
174 
175 // transpose_matrix
176 static inline void
177 transpose_matrix(const double* const* A, double** Atrans, int m, int n)
178 {
179 	for (int i = 0; i < m; i++) {
180 		for (int k = 0; k < n; k++)
181 			Atrans[k][i] = A[i][k];
182 	}
183 }
184 
185 
186 // zero_matrix
187 void
188 BPrivate::Layout::zero_matrix(double** A, int m, int n)
189 {
190 	for (int i = 0; i < m; i++) {
191 		for (int k = 0; k < n; k++)
192 			A[i][k] = 0;
193 	}
194 }
195 
196 
197 // copy_matrix
198 void
199 BPrivate::Layout::copy_matrix(const double* const* A, double** B, int m, int n)
200 {
201 	for (int i = 0; i < m; i++) {
202 		for (int k = 0; k < n; k++)
203 			B[i][k] = A[i][k];
204 	}
205 }
206 
207 
208 static inline void
209 multiply_optimization_matrix_vector(const double* x, int n, double* y)
210 {
211 	// The matrix has the form:
212 	//  2 -1  0     ...   0  0
213 	// -1  2 -1  0  ...   .  .
214 	//  0 -1  2           .  .
215 	//  .  0     .        .  .
216 	//  .           .     0  0
217 	//  .              . -1  0
218 	//  0    ...    0 -1  2 -1
219 	//  0    ...         -1  1
220 	if (n == 1) {
221 		y[0] = x[0];
222 		return;
223 	}
224 
225 	y[0] = 2 * x[0] - x[1];
226 	for (int i = 1; i < n - 1; i++)
227 		y[i] = 2 * x[i] - x[i - 1] - x[i + 1];
228 	y[n - 1] = x[n - 1] - x[n - 2];
229 }
230 
231 
232 static inline void
233 multiply_optimization_matrix_matrix(const double* const* A, int m, int n,
234 	double** B)
235 {
236 	if (m == 1) {
237 		memcpy(B[0], A[0], n * sizeof(double));
238 		return;
239 	}
240 
241 	for (int k = 0; k < n; k++) {
242 		B[0][k] = 2 * A[0][k] - A[1][k];
243 		for (int i = 1; i < m - 1; i++)
244 			B[i][k] = 2 * A[i][k] - A[i - 1][k] - A[i + 1][k];
245 		B[m - 1][k] = A[m - 1][k] - A[m - 2][k];
246 	}
247 }
248 
249 
250 template<typename Type>
251 static inline void
252 swap(Type& a, Type& b)
253 {
254 	Type c = a;
255 	a = b;
256 	b = c;
257 }
258 
259 
260 // #pragma mark - algorithms
261 
262 
263 bool
264 BPrivate::Layout::solve(double** a, int n, double* b)
265 {
266 	// index array for row permutation
267 	// Note: We could eliminate it, if we would permutate the row pointers of a.
268 	int indices[n];
269 	for (int i = 0; i < n; i++)
270 		indices[i] = i;
271 
272 	// forward elimination
273 	for (int i = 0; i < n - 1; i++) {
274 		// find pivot
275 		int pivot = i;
276 		double pivotValue = fabs(a[indices[i]][i]);
277 		for (int j = i + 1; j < n; j++) {
278 			int index = indices[j];
279 			double value = fabs(a[index][i]);
280 			if (value > pivotValue) {
281 				pivot = j;
282 				pivotValue = value;
283 			}
284 		}
285 
286 		if (fuzzy_equals(pivotValue, 0)) {
287 			TRACE_ERROR("solve(): matrix is not regular\n");
288 			return false;
289 		}
290 
291 		if (pivot != i) {
292 			swap(indices[i], indices[pivot]);
293 			swap(b[i], b[pivot]);
294 		}
295 		pivot = indices[i];
296 
297 		// eliminate
298 		for (int j = i + 1; j < n; j++) {
299 			int index = indices[j];
300 			double q = -a[index][i] / a[pivot][i];
301 			a[index][i] = 0;
302 			for (int k = i + 1; k < n; k++)
303 				a[index][k] += a[pivot][k] * q;
304 			b[j] += b[i] * q;
305 		}
306 	}
307 
308 	// backwards substitution
309 	for (int i = n - 1; i >= 0; i--) {
310 		int index = indices[i];
311 		double sum = b[i];
312 		for (int j = i + 1; j < n; j++)
313 			sum -= a[index][j] * b[j];
314 
315 		b[i] = sum / a[index][i];
316 	}
317 
318 	return true;
319 }
320 
321 
322 int
323 BPrivate::Layout::compute_dependencies(double** a, int m, int n,
324 	bool* independent)
325 {
326 	// index array for row permutation
327 	// Note: We could eliminate it, if we would permutate the row pointers of a.
328 	int indices[m];
329 	for (int i = 0; i < m; i++)
330 		indices[i] = i;
331 
332 	// forward elimination
333 	int iterations = (m > n ? n : m);
334 	int i = 0;
335 	int column = 0;
336 	for (; i < iterations && column < n; i++) {
337 		// find next pivot
338 		int pivot = i;
339 		do {
340 			double pivotValue = fabs(a[indices[i]][column]);
341 			for (int j = i + 1; j < m; j++) {
342 				int index = indices[j];
343 				double value = fabs(a[index][column]);
344 				if (value > pivotValue) {
345 					pivot = j;
346 					pivotValue = value;
347 				}
348 			}
349 
350 			if (!fuzzy_equals(pivotValue, 0))
351 				break;
352 
353 			column++;
354 		} while (column < n);
355 
356 		if (column == n)
357 			break;
358 
359 		if (pivot != i)
360 			swap(indices[i], indices[pivot]);
361 		pivot = indices[i];
362 
363 		independent[pivot] = true;
364 
365 		// eliminate
366 		for (int j = i + 1; j < m; j++) {
367 			int index = indices[j];
368 			double q = -a[index][column] / a[pivot][column];
369 			a[index][column] = 0;
370 			for (int k = column + 1; k < n; k++)
371 				a[index][k] += a[pivot][k] * q;
372 		}
373 
374 		column++;
375 	}
376 
377 	for (int j = i; j < m; j++)
378 		independent[indices[j]] = false;
379 
380 	return i;
381 }
382 
383 
384 // remove_linearly_dependent_rows
385 int
386 BPrivate::Layout::remove_linearly_dependent_rows(double** A, double** temp,
387 	bool* independentRows, int m, int n)
388 {
389 	// copy to temp
390 	copy_matrix(A, temp, m, n);
391 
392 	int count = compute_dependencies(temp, m, n, independentRows);
393 	if (count == m)
394 		return count;
395 
396 	// remove the rows
397 	int index = 0;
398 	for (int i = 0; i < m; i++) {
399 		if (independentRows[i]) {
400 			if (index < i) {
401 				for (int k = 0; k < n; k++)
402 					A[index][k] = A[i][k];
403 			}
404 			index++;
405 		}
406 	}
407 
408 	return count;
409 }
410 
411 
412 /*!	QR decomposition using Householder transformations.
413 */
414 bool
415 qr_decomposition(double** a, int m, int n, double* d, double** q)
416 {
417 	if (m < n)
418 		return false;
419 
420 	for (int j = 0; j < n; j++) {
421 		// inner product of the first vector x of the (j,j) minor
422 		double innerProductU = 0;
423 		for (int i = j + 1; i < m; i++)
424 			innerProductU = innerProductU + a[i][j] * a[i][j];
425 		double innerProduct = innerProductU + a[j][j] * a[j][j];
426 		if (fuzzy_equals(innerProduct, 0)) {
427 			TRACE_ERROR("qr_decomposition(): 0 column %d\n", j);
428 			return false;
429 		}
430 
431 		// alpha (norm of x with opposite signedness of x_1) and thus r_{j,j}
432 		double alpha = (a[j][j] < 0 ? sqrt(innerProduct) : -sqrt(innerProduct));
433 		d[j] = alpha;
434 
435 		double beta = 1 / (alpha * a[j][j] - innerProduct);
436 
437 		// u = x - alpha * e_1
438 		// (u is a[j..n][j])
439 		a[j][j] -= alpha;
440 
441 		// left-multiply A_k with Q_k, thus obtaining a row of R and the A_{k+1}
442 		// for the next iteration
443 		for (int k = j + 1; k < n; k++) {
444 			double sum = 0;
445 			for (int i = j; i < m; i++)
446 				sum += a[i][j] * a[i][k];
447 			sum *= beta;
448 
449 			for (int i = j; i < m; i++)
450 				a[i][k] += a[i][j] * sum;
451 		}
452 
453 		// v = u/|u|
454 		innerProductU += a[j][j] * a[j][j];
455 		double beta2 = -2 / innerProductU;
456 
457 		// right-multiply Q with Q_k
458 		// Q_k = I - 2vv^T
459 		// Q * Q_k = Q - 2 * Q * vv^T
460 		if (j == 0) {
461 			for (int k = 0; k < m; k++) {
462 				for (int i = 0; i < m; i++)
463 					q[k][i] = beta2 * a[k][0] * a[i][0];
464 
465 				q[k][k] += 1;
466 			}
467 		} else {
468 			for (int k = 0; k < m; k++) {
469 				double sum = 0;
470 				for (int i = j; i < m; i++)
471 					sum += q[k][i] * a[i][j];
472 				sum *= beta2;
473 
474 				for (int i = j; i < m; i++)
475 					q[k][i] += sum * a[i][j];
476 			}
477 		}
478 	}
479 
480 	return true;
481 }
482 
483 
484 // MatrixDeleter
485 struct MatrixDelete {
486 	inline void operator()(double** matrix)
487 	{
488 		BPrivate::Layout::free_matrix(matrix);
489 	}
490 };
491 typedef BPrivate::AutoDeleter<double*, MatrixDelete> MatrixDeleter;
492 
493 
494 // #pragma mark - LayoutOptimizer
495 
496 
497 // constructor
498 LayoutOptimizer::LayoutOptimizer(const ConstraintList& list,
499 	int32 variableCount)
500 	:
501 	fTemp1(NULL),
502 	fTemp2(NULL),
503 	fZtrans(NULL),
504 	fQ(NULL),
505 	fSoftConstraints(NULL),
506 	fG(NULL),
507 	fDesired(NULL)
508 {
509 	SetConstraints(list, variableCount);
510 }
511 
512 
513 // destructor
514 LayoutOptimizer::~LayoutOptimizer()
515 {
516 	_MakeEmpty();
517 }
518 
519 
520 bool
521 LayoutOptimizer::SetConstraints(const ConstraintList& list, int32 variableCount)
522 {
523 	fConstraints = list;
524 	int32 constraintCount = fConstraints.CountItems();
525 
526 	if (fVariableCount != variableCount) {
527 		_MakeEmpty();
528 		_Init(variableCount, constraintCount);
529 	}
530 
531 	zero_matrix(fSoftConstraints, constraintCount, fVariableCount);
532 	double rightSide[constraintCount];
533 	// set up soft constraint matrix
534 	for (int32 c = 0; c < fConstraints.CountItems(); c++) {
535 		Constraint* constraint = fConstraints.ItemAt(c);
536 		if (!constraint->IsSoft()) {
537 			rightSide[c] = 0;
538 			continue;
539 		}
540 		rightSide[c] = _RightSide(constraint);
541 		SummandList* summands = constraint->LeftSide();
542 		for (int32 s = 0; s < summands->CountItems(); s++) {
543 			Summand* summand = summands->ItemAt(s);
544 			int32 variable = summand->Var()->Index();
545 			if (constraint->Op() == LinearProgramming::kLE)
546 				fSoftConstraints[c][variable] = -summand->Coeff();
547 			else
548 				fSoftConstraints[c][variable] = summand->Coeff();
549 		}
550 	}
551 
552 	// create G
553 	transpose_matrix(fSoftConstraints, fTemp1, constraintCount, fVariableCount);
554 	multiply_matrices(fTemp1, fSoftConstraints, fG, fVariableCount,
555 		constraintCount, constraintCount);
556 
557 	// create d
558 	multiply_matrix_vector(fTemp1, rightSide, fVariableCount, constraintCount,
559 		fDesired);
560 	negate_vector(fDesired, fVariableCount);
561 
562 	return true;
563 }
564 
565 
566 // InitCheck
567 status_t
568 LayoutOptimizer::InitCheck() const
569 {
570 	if (!fTemp1 || !fTemp2 || !fZtrans || !fQ || !fSoftConstraints || !fG
571 		|| !fDesired)
572 		return B_NO_MEMORY;
573 	return B_OK;
574 }
575 
576 
577 double
578 LayoutOptimizer::_ActualValue(Constraint* constraint, double* values) const
579 {
580 	SummandList* summands = constraint->LeftSide();
581 	double value = 0;
582 	for (int32 s = 0; s < summands->CountItems(); s++) {
583 		Summand* summand = summands->ItemAt(s);
584 		int32 variable = summand->Var()->Index();
585 		value += values[variable] * summand->Coeff();
586 	}
587 	if (constraint->Op() == LinearProgramming::kLE)
588 		return -value;
589 	return value;
590 }
591 
592 
593 double
594 LayoutOptimizer::_RightSide(Constraint* constraint)
595 {
596 	if (constraint->Op() == LinearProgramming::kLE)
597 		return -constraint->RightSide();
598 	return constraint->RightSide();
599 }
600 
601 
602 void
603 LayoutOptimizer::_MakeEmpty()
604 {
605 	free_matrix(fTemp1);
606 	free_matrix(fTemp2);
607 	free_matrix(fZtrans);
608 	free_matrix(fSoftConstraints);
609 	free_matrix(fQ);
610 	free_matrix(fG);
611 
612 	delete[] fDesired;
613 }
614 
615 
616 void
617 LayoutOptimizer::_Init(int32 variableCount, int32 nConstraints)
618 {
619 	fVariableCount = variableCount;
620 
621 	fTemp1 = allocate_matrix(nConstraints, nConstraints);
622 	fTemp2 = allocate_matrix(nConstraints, nConstraints);
623 	fZtrans = allocate_matrix(nConstraints, fVariableCount);
624 	fSoftConstraints = allocate_matrix(nConstraints, fVariableCount);
625 	fQ = allocate_matrix(nConstraints, fVariableCount);
626 	fG = allocate_matrix(nConstraints, nConstraints);
627 
628 	fDesired = new(std::nothrow) double[fVariableCount];
629 }
630 
631 
632 // Solve
633 /*!	Solves the quadratic program (QP) given by the constraints added via
634 	AddConstraint(), the additional constraint \sum_{i=0}^{n-1} x_i = size,
635 	and the optimization criterion to minimize
636 	\sum_{i=0}^{n-1} (x_i - desired[i])^2.
637 	The \a values array must contain a feasible solution when called and will
638 	be overwritten with the optimial solution the method computes.
639 */
640 bool
641 LayoutOptimizer::Solve(double* values)
642 {
643 	if (values == NULL)
644 		return false;
645 
646 	int32 constraintCount = fConstraints.CountItems();
647 
648 	// allocate the active constraint matrix and its transposed matrix
649 	fActiveMatrix = allocate_matrix(constraintCount, fVariableCount);
650 	fActiveMatrixTemp = allocate_matrix(constraintCount, fVariableCount);
651 	MatrixDeleter _(fActiveMatrix);
652 	MatrixDeleter _2(fActiveMatrixTemp);
653 	if (!fActiveMatrix || !fActiveMatrixTemp)
654 		return false;
655 
656 	bool success = _Solve(values);
657 	return success;
658 }
659 
660 
661 // _Solve
662 bool
663 LayoutOptimizer::_Solve(double* values)
664 {
665 	int32 constraintCount = fConstraints.CountItems();
666 
667 TRACE_ONLY(
668 	TRACE("constraints:\n");
669 	for (int32 i = 0; i < constraintCount; i++) {
670 		TRACE(" %-2ld:  ", i);
671 		fConstraints.ItemAt(i)->PrintToStream();
672 	}
673 )
674 
675 	// our QP is supposed to be in this form:
676 	//   min_x 1/2x^TGx + x^Td
677 	//   s.t. a_i^Tx = b_i,  i \in E
678 	//        a_i^Tx >= b_i, i \in I
679 
680 	// init our initial x
681 	double x[fVariableCount];
682 	for (int i = 0; i < fVariableCount; i++)
683 		x[i] = values[i];
684 
685 	// init d
686 	// Note that the values of d and of G result from rewriting the
687 	// ||x - desired|| we actually want to minimize.
688 	double d[fVariableCount];
689 	for (int i = 0; i < fVariableCount; i++)
690 		d[i] = fDesired[i];
691 
692 	// init active set
693 	ConstraintList activeConstraints(constraintCount);
694 
695 	for (int32 i = 0; i < constraintCount; i++) {
696 		Constraint* constraint = (Constraint*)fConstraints.ItemAt(i);
697 		if (constraint->IsSoft())
698 			continue;
699 		double actualValue = _ActualValue(constraint, x);
700 		TRACE("constraint %ld: actual: %f  constraint: %f\n", i, actualValue,
701 			_RightSide(constraint));
702 		if (fuzzy_equals(actualValue, _RightSide(constraint)))
703 			activeConstraints.AddItem(constraint);
704 	}
705 
706 	// The main loop: Each iteration we try to get closer to the optimum
707 	// solution. We compute a vector p that brings our x closer to the optimum.
708 	// We do that by computing the QP resulting from our active constraint set,
709 	// W^k. Afterward each iteration we adjust the active set.
710 TRACE_ONLY(int iteration = 0;)
711 	while (true) {
712 TRACE_ONLY(
713 		TRACE("\n[iteration %d]\n", iteration++);
714 		TRACE("active set:\n");
715 		for (int32 i = 0; i < activeConstraints.CountItems(); i++) {
716 			TRACE("  ");
717 			activeConstraints.ItemAt(i)->PrintToStream();
718 		}
719 )
720 
721 		// solve the QP:
722 		//   min_p 1/2p^TGp + g_k^Tp
723 		//   s.t. a_i^Tp = 0
724 		//   with a_i \in activeConstraints
725 		//        g_k = Gx_k + d
726 		//        p = x - x_k
727 
728 		int32 activeCount = activeConstraints.CountItems();
729 		if (activeCount == 0) {
730 			TRACE_ERROR("Solve(): Error: No more active constraints!\n");
731 			return false;
732 		}
733 
734 		// construct a matrix from the active constraints
735 		int am = activeCount;
736 		const int an = fVariableCount;
737 		bool independentRows[activeCount];
738 		zero_matrix(fActiveMatrix, am, an);
739 
740 		for (int32 i = 0; i < activeCount; i++) {
741 			Constraint* constraint = activeConstraints.ItemAt(i);
742 			SummandList* summands = constraint->LeftSide();
743 			for (int32 s = 0; s < summands->CountItems(); s++) {
744 				Summand* summand = summands->ItemAt(s);
745 				int32 variable = summand->Var()->Index();
746 				if (constraint->Op() == LinearProgramming::kLE)
747 					fActiveMatrix[i][variable] = -summand->Coeff();
748 				else
749 					fActiveMatrix[i][variable] = summand->Coeff();
750 			}
751 		}
752 
753 // TODO: The fActiveMatrix is sparse (max 2 entries per row). There should be
754 // some room for optimization.
755 		am = remove_linearly_dependent_rows(fActiveMatrix, fActiveMatrixTemp,
756 			independentRows, am, an);
757 
758 		// gxd = G * x + d
759 		double gxd[fVariableCount];
760 		multiply_matrix_vector(fG, x, fVariableCount, fVariableCount, gxd);
761 		add_vectors(gxd, d, fVariableCount);
762 
763 		double p[fVariableCount];
764 		if (!_SolveSubProblem(gxd, am, p))
765 			return false;
766 
767 		if (is_zero(p, fVariableCount)) {
768 			// compute Lagrange multipliers lambda_i
769 			// if lambda_i >= 0 for all i \in W^k \union inequality constraints,
770 			// then we're done.
771 			// Otherwise remove the constraint with the smallest lambda_i
772 			// from the active set.
773 			// The derivation of the Lagrangian yields:
774 			//   \sum_{i \in W^k}(lambda_ia_i) = Gx_k + d
775 			// Which is an system we can solve:
776 			//   A^Tlambda = Gx_k + d
777 
778 			// A^T is over-determined, hence we need to reduce the number of
779 			// rows before we can solve it.
780 			bool independentColumns[an];
781 			double** aa = fTemp1;
782 			transpose_matrix(fActiveMatrix, aa, am, an);
783 			const int aam = remove_linearly_dependent_rows(aa, fTemp2,
784 				independentColumns, an, am);
785 			const int aan = am;
786 			if (aam != aan) {
787 				// This should not happen, since A has full row rank.
788 				TRACE_ERROR("Solve(): Transposed A has less linear independent "
789 					"rows than it has columns!\n");
790 				return false;
791 			}
792 
793 			// also reduce the number of rows on the right hand side
794 			double lambda[aam];
795 			int index = 0;
796 			for (int i = 0; i < an; i++) {
797 				if (independentColumns[i])
798 					lambda[index++] = gxd[i];
799 			}
800 
801 			bool success = solve(aa, aam, lambda);
802 			if (!success) {
803 				// Impossible, since we've removed all linearly dependent rows.
804 				TRACE_ERROR("Solve(): Failed to compute lambda!\n");
805 				return false;
806 			}
807 
808 			// find min lambda_i (only, if it's < 0, though)
809 			double minLambda = 0;
810 			int minIndex = -1;
811 			index = 0;
812 			for (int i = 0; i < activeCount; i++) {
813 				if (independentRows[i]) {
814 					Constraint* constraint
815 						= (Constraint*)activeConstraints.ItemAt(i);
816 					if (constraint->Op() != LinearProgramming::kEQ) {
817 						if (lambda[index] < minLambda) {
818 							minLambda = lambda[index];
819 							minIndex = i;
820 						}
821 					}
822 
823 					index++;
824 				}
825 			}
826 
827 			// if the min lambda is >= 0, we're done
828 			if (minIndex < 0 || fuzzy_equals(minLambda, 0)) {
829 				_SetResult(x, values);
830 				return true;
831 			}
832 
833 			// remove i from the active set
834 			activeConstraints.RemoveItemAt(minIndex);
835 		} else {
836 			// compute alpha_k
837 			double alpha = 1;
838 			int barrier = -1;
839 			// if alpha_k < 1, add a barrier constraint to W^k
840 			for (int32 i = 0; i < constraintCount; i++) {
841 				Constraint* constraint = (Constraint*)fConstraints.ItemAt(i);
842 				if (activeConstraints.HasItem(constraint))
843 					continue;
844 
845 				double divider = _ActualValue(constraint, p);
846 				if (divider > 0 || fuzzy_equals(divider, 0))
847 					continue;
848 
849 				// (b_i - a_i^Tx_k) / a_i^Tp_k
850 				double alphaI = _RightSide(constraint)
851 					- _ActualValue(constraint, x);
852 				alphaI /= divider;
853 				if (alphaI < alpha) {
854 					alpha = alphaI;
855 					barrier = i;
856 				}
857 			}
858 			TRACE("alpha: %f, barrier: %d\n", alpha, barrier);
859 
860 			if (alpha < 1)
861 				activeConstraints.AddItem(fConstraints.ItemAt(barrier));
862 
863 			// x += p * alpha;
864 			add_vectors_scaled(x, p, alpha, fVariableCount);
865 		}
866 	}
867 }
868 
869 
870 bool
871 LayoutOptimizer::_SolveSubProblem(const double* d, int am, double* p)
872 {
873 	// We have to solve the QP subproblem:
874 	//   min_p 1/2p^TGp + d^Tp
875 	//   s.t. a_i^Tp = 0
876 	//   with a_i \in activeConstraints
877 	//
878 	// We use the null space method, i.e. we find matrices Y and Z, such that
879 	// AZ = 0 and [Y Z] is regular. Then with
880 	//   p = Yp_Y + Zp_z
881 	// we get
882 	//   p_Y = 0
883 	// and
884 	//  (Z^TGZ)p_Z = -(Z^TYp_Y + Z^Tg) = -Z^Td
885 	// which is a linear equation system, which we can solve.
886 
887 	const int an = fVariableCount;
888 
889 	// we get Y and Z by QR decomposition of A^T
890 	double tempD[am];
891 	double** const Q = fQ;
892 	transpose_matrix(fActiveMatrix, fTemp1, am, an);
893 	bool success = qr_decomposition(fTemp1, an, am, tempD, Q);
894 	if (!success) {
895 		TRACE_ERROR("Solve(): QR decomposition failed!\n");
896 		return false;
897 	}
898 
899 	// Z is the (1, m + 1) minor of Q
900 	const int zm = an;
901 	const int zn = an - am;
902 
903 	double* Z[zm];
904 	for (int i = 0; i < zm; i++)
905 		Z[i] = Q[i] + am;
906 
907 	// solve (Z^TGZ)p_Z = -Z^Td
908 
909 	// Z^T
910 	transpose_matrix(Z, fZtrans, zm, zn);
911 	// rhs: -Z^T * d;
912 	double pz[zm];
913 	multiply_matrix_vector(fZtrans, d, zn, zm, pz);
914 	negate_vector(pz, zn);
915 
916 	// fTemp2 = Ztrans * G * Z
917 	multiply_matrices(fG, Z, fTemp1, zm, fVariableCount, zn);
918 	multiply_matrices(fZtrans, fTemp1, fTemp2, zn, zm, zn);
919 
920 	success = solve(fTemp2, zn, pz);
921 	if (!success) {
922 		TRACE_ERROR("Solve(): Failed to solve() system for p_Z\n");
923 		return false;
924 	}
925 
926 	// p = Z * pz;
927 	multiply_matrix_vector(Z, pz, zm, zn, p);
928 
929 	return true;
930 }
931 
932 
933 // _SetResult
934 void
935 LayoutOptimizer::_SetResult(const double* x, double* values)
936 {
937 	for (int i = 1; i < fVariableCount; i++)
938 		values[i] = x[i];
939 }
940