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