1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2009 Henrik Tidefelt
19 #include "quadratic_programs.h"
21 #include <gsl/gsl_linalg.h>
22 #include <gsl/gsl_blas.h>
23 #include <gsl/gsl_cblas.h>
25 using namespace Shapes
;
33 //#define TRACEFIGS // generate output on stdout that gives a graphical picture of the operation
36 #include "mathematicarepresentation.h"
37 size_t polytope_distance_generator_form_CallCount
= 0;
48 /* Since an active constraint implies that the corresponding variable is zero, the
49 * subproblems are not concerned with these variables at all.
51 void polytope_distance_generator_form_sub( const size_t dim
,
52 const double ** g1Begin
, const double ** g1End
,
53 const double ** g2Begin
, const double ** g2End
,
56 double * d1
, double * d2
,
57 double * work
); /* allocated memory of size max( dim * ( n1 + n2 - 2 ) + ( n1 + n2 - 2 )^2 + 2 * dim + n1 + n2 )*/
59 void polytope_distance_generator_form_sub_Gilbert( const size_t dim
,
60 const double ** g1Begin
, const double ** g1End
,
61 const double ** g2Begin
, const double ** g2End
,
63 double * d1
, double * d2
);
65 void polytope_distance_generator_form_diff( const size_t dim
,
66 const double ** g1Begin
, const double ** g1End
,
67 const double ** g2Begin
, const double ** g2End
,
68 const double * x1
, const double * x2
,
71 void polytope_distance_generator_form_costs( const size_t dim
,
72 const double ** g1Begin
, const double ** g1End
,
73 const double ** g2Begin
, const double ** g2End
,
76 double * dualCostAccum
, /* This value is updated as an accumulated maximum. */
77 double * work
); /* Just needs to be of size (dim) */
79 /* This function will compute orthogonal vectors spanning the nullspaces of vectors of ones.
80 * Memorey will be reused, but never returned.
81 * Given argument n, it returns a pointer to an array of ( n - 1 ) pointers, each pointing to an
82 * array of doubles of length n.
84 const double ** polytope_distance_generator_form_kernel( size_t n
);
93 DeleteOnExit( T
* mem
) : mem_( mem
) { }
94 ~DeleteOnExit( ){ delete mem_
; }
100 Computation::polytope_distance_generator_form( const size_t dim
,
101 const size_t n1
, const double * g1
,
102 const size_t n2
, const double * g2
,
103 double * costLower
, double * costUpper
,
104 double stopLower
, double stopUpper
,
105 double gapTolAbs
, double gapTolRel
,
109 double * y1
, double * y2
,
110 QPSolverStatus
* status
)
112 /* In case we for some reason would return without setting status properly... */
113 status
->code
= QP_ERROR
;
114 status
->error
= QP_ERROR_UNDEFINED
;
118 stopLower
= std::numeric_limits
< double >::max( );
120 /* stopUpper < 0 gives a test that will never be true. */
137 /* Since the dual cost is not strictly increasing, we must compute the accumulative max of all dual costs.
138 * Since the cost cannot be negative, it is safe to initialize with 0.
144 ( costLower
!= 0 && stopLower
< std::numeric_limits
< double >::max( ) )
145 || ( costUpper
!= 0 && stopUpper
> 0 )
146 || ( costLower
!= 0 && costUpper
!= 0 && ( gapTolAbs
>= 0 || gapTolRel
>= 0 ) );
148 /*-------------------------------------------------------------------------*/
149 /* Allocate memory: this section should be removed later and free memory
150 should be passed as a pointer */
151 /*-------------------------------------------------------------------------*/
152 const double ** gMem
= new const double * [ n1
+ n2
];
153 DeleteOnExit
< const double * > gMemDeleter( gMem
);
154 const double ** g1InactiveBegin
= gMem
;
155 const double ** g1InactiveEnd
= g1InactiveBegin
+ n1
;
156 const double ** g1ActiveEnd
= g1InactiveEnd
;
157 const double ** g2InactiveBegin
= gMem
+ n1
;
158 const double ** g2InactiveEnd
= g2InactiveBegin
+ n2
;
159 const double ** g2ActiveEnd
= g2InactiveEnd
;
160 double * xMem
= new double[ 5 * ( n1
+ n2
) ];
161 DeleteOnExit
< double > xMemDeleter( xMem
);
162 /* The x1 and x2 variables correspond to the generators in the order they appear in the sets defined above.
163 * The elements that corresponds to generators with active constraints are zero by definition, and
164 * do not have to be zero in memory.
167 double * x2
= x1
+ n1
;
168 /* Similarly, only the last part of the Lagrange multiplier vectors are actually used.
170 double * lm1
= x2
+ n2
;
171 double * lm2
= lm1
+ n1
;
172 /* ... and only the first part of the subproblem step vectors.
174 double * d1
= lm2
+ n2
;
175 double * d2
= d1
+ n1
;
176 double * x1short
= d2
+ n2
;
177 double * x2short
= x1short
+ n1
;
178 double * x1long
= x2short
+ n2
;
179 double * x2long
= x1long
+ n1
;
181 const double xInit
= 1. / n1
;
183 const double * src
= g1
;
184 for( const double ** dst
= g1InactiveBegin
; dst
!= g1InactiveEnd
; ++dst
, src
+= dim
, ++xDst
)
191 const double xInit
= 1. / n2
;
193 const double * src
= g2
;
194 for( const double ** dst
= g2InactiveBegin
; dst
!= g2InactiveEnd
; ++dst
, src
+= dim
, ++xDst
)
200 double * yDiff
= new double[ dim
];
201 DeleteOnExit
< double > xDiffDeleter( yDiff
);
202 double * yDiffEnd
= yDiff
+ dim
;
204 double * sub_work
= new double[ ( dim
+ n1
+ n2
- 2 ) * ( n1
+ n2
- 2 ) + 2 * dim
+ n1
+ n2
];
205 DeleteOnExit
< double > sub_workDeleter( sub_work
);
208 ++polytope_distance_generator_form_CallCount
;
209 std::cerr
<< "Polytope distance call count: " << polytope_distance_generator_form_CallCount
<< std::endl
;
210 if( polytope_distance_generator_form_CallCount
<= 10 )
212 std::cerr
<< "=== Problem number " << polytope_distance_generator_form_CallCount
<< " ===" << std::endl
;
213 Computation::polytope_distance_generator_form_write_data( std::cerr
,
217 std::cerr
<< "========================" << std::endl
;
223 std::cout
<< "##echo Invalid program, dimension of metric space is not two!" << std::endl
;
225 bool tracefigPageOpen
= false;
226 std::cout
<< "#catalog.[setbboxgroup 'a]" << std::endl
;
228 std::cout
<< std::fixed
<< "g1: ";
229 const double * begin
= g1
;
230 const double * end
= begin
+ dim
* n1
;
231 for( const double * gSrc
= begin
; gSrc
!= end
; gSrc
+= dim
)
238 for( const double * src
= gSrc
; src
!= gSrc
+ dim
; ++src
)
244 std::cout
<< "(" << *src
<< "bp)" ;
248 std::cout
<< std::endl
;
252 const double * begin
= g2
;
253 const double * end
= begin
+ dim
* n2
;
254 for( const double * gSrc
= begin
; gSrc
!= end
; gSrc
+= dim
)
261 for( const double * src
= gSrc
; src
!= gSrc
+ dim
; ++src
)
267 std::cout
<< "(" << *src
<< "bp)" ;
271 std::cout
<< std::endl
;
275 bool checkNextCost
= true;
276 /* The number of iterations is theoretically bounded by the number of possible combinations of activated constraints. Here, we know that
277 * one can never activate all constraints in a polytope, leading to the following bound.
279 const size_t maxIter
= ( (2<<(n1
-1)) - 1 ) * ( (2<<(n2
-1)) - 1 );
280 for( size_t iterCount
= 0; ; ++iterCount
)
282 if( iterCount
> maxIter
)
284 status
->code
= QP_FAIL
;
285 status
->failure
= QP_FAIL_ITER
;
287 std::cerr
<< "Early return: Maximum number of iterations exceeded." << std::endl
;
290 if( tracefigPageOpen
)
292 std::cout
<< ")" << std::endl
;
293 tracefigPageOpen
= false;
299 if( tracefigPageOpen
)
301 std::cout
<< ")" << std::endl
;
302 tracefigPageOpen
= false;
304 std::cout
<< "#catalog << @text_size:5bp | ( newGroup" << std::endl
;
305 tracefigPageOpen
= true;
306 std::cout
<< " << @stroking:RGB_RED&@width:2bp | [[range '0 [duration g1]].foldl \\ p e → p & [spot [g1 1*e].p] null]" << std::endl
307 << " << @stroking:RGB_GREEN&@width:2bp | [[range '0 [duration g2]].foldl \\ p e → p & [spot [g2 1*e].p] null]" << std::endl
308 << " << @dash:[dashpattern 2bp 2bp]&@width:0.3bp | [stroke [controlling_hull g1] & [controlling_hull g2]]" << std::endl
;
309 for( const double ** gSrc
= g1InactiveEnd
; gSrc
!= g2ActiveEnd
; ++gSrc
)
311 if( gSrc
== g1ActiveEnd
)
313 gSrc
= g2InactiveEnd
- 1;
316 std::cout
<< " << [stroke [circle 2bp] >> [shift (" ;
317 for( const double * src
= *gSrc
; src
!= *gSrc
+ dim
; ++src
)
323 std::cout
<< "(" << *src
<< "bp)" ;
325 std::cout
<< ")]]" << std::endl
;
327 std::cout
<< " << @stroking:RGB_BLUE | [stroke (" ;
328 polytope_distance_generator_form_diff( dim
,
329 g1InactiveBegin
, g1InactiveEnd
,
330 g2InactiveBegin
, g2InactiveBegin
,
333 for( const double * src
= yDiff
; src
!= yDiff
+ dim
; ++src
)
339 std::cout
<< "(" << -*src
<< "bp)" ;
341 std::cout
<< ")--(" ;
342 polytope_distance_generator_form_diff( dim
,
343 g1InactiveBegin
, g1InactiveBegin
,
344 g2InactiveBegin
, g2InactiveEnd
,
347 for( const double * src
= yDiff
; src
!= yDiff
+ dim
; ++src
)
353 std::cout
<< "(" << *src
<< "bp)" ;
355 std::cout
<< ")]" << std::endl
;
357 size_t nInactive1
= g1InactiveEnd
- g1InactiveBegin
;
358 size_t nInactive2
= g2InactiveEnd
- g2InactiveBegin
;
359 polytope_distance_generator_form_diff( dim
,
360 g1InactiveBegin
, g1InactiveEnd
,
361 g2InactiveBegin
, g2InactiveEnd
,
364 if( checkCost
&& checkNextCost
)
366 /* All generators are used here, not only those of inactive constraints. */
367 polytope_distance_generator_form_costs( dim
,
368 g1InactiveBegin
, g1ActiveEnd
,
369 g2InactiveBegin
, g2ActiveEnd
,
375 std::cerr
<< "Interation: " << iterCount
+ 1 << std::endl
;
376 std::cerr
<< "Cost: " << *costLower
<< " -- " << *costUpper
<< std::endl
;
379 if( costUpper
!= 0 && costLower
!= 0 )
381 if( *costUpper
- *costLower
< gapTolAbs
)
383 status
->code
= QP_OK
;
384 status
->termination
= QP_OK_GAP_ABS
;
385 status
->iterations
= iterCount
;
388 if( *costUpper
- *costLower
< gapTolRel
* *costUpper
)
390 status
->code
= QP_OK
;
391 status
->termination
= QP_OK_GAP_REL
;
392 status
->iterations
= iterCount
;
396 if( costUpper
!= 0 && *costUpper
< stopUpper
)
398 status
->code
= QP_OK
;
399 status
->termination
= QP_OK_UPPER
;
400 status
->iterations
= iterCount
;
403 if( costLower
!= 0 && *costLower
> stopLower
)
405 status
->code
= QP_OK
;
406 status
->termination
= QP_OK_LOWER
;
407 status
->iterations
= iterCount
;
411 checkNextCost
= true;
412 polytope_distance_generator_form_sub( dim
,
413 g1InactiveBegin
, g1InactiveEnd
,
414 g2InactiveBegin
, g2InactiveEnd
,
420 std::cerr
<< "Delta: " << Helpers::mathematicaFormat( nInactive1
, 1, d1
)
421 << " " << Helpers::mathematicaFormat( nInactive2
, 1, d2
) << std::endl
;
424 /* Compute squared norm of subproblem step. */
425 double stepNorm2
= 0;
428 double * end
= d1
+ nInactive1
;
429 for( ; src
!= end
; ++src
)
431 stepNorm2
+= (*src
) * (*src
);
436 double * end
= d2
+ nInactive2
;
437 for( ; src
!= end
; ++src
)
439 stepNorm2
+= (*src
) * (*src
);
442 if( stepNorm2
< xTol
)
444 /* No step taken in sub-problem. Are there any constraints to drop? */
445 /* Compute lagrange multipliers.
446 * Note that the lagrange multipliers of the inactive constraints are only used for temporary storage.
447 * Normalizing yDiff will only scale the Langrange multipliers, and by normalizing yDiff we give
448 * the Lagrange multiplier tolerance (lmTol) a geometric interpretation; lmTol becomes a gap tolerance which
449 * is linear in the distance (not distance squared).
451 polytope_distance_generator_form_diff( dim
,
452 g1InactiveBegin
, g1InactiveEnd
,
453 g2InactiveBegin
, g2InactiveEnd
,
457 /* Normalize yDiff. */
458 double lengthSquared
= 0;
459 for( const double * src
= yDiff
; src
!= yDiffEnd
; ++src
)
461 lengthSquared
+= (*src
) * (*src
);
463 const double yDiffScaling
= 1. / sqrt( lengthSquared
);
464 for( double * dst
= yDiff
; dst
!= yDiffEnd
; ++dst
)
466 *dst
*= yDiffScaling
;
470 /* Initialize with negative gradient. */
471 double * lmDst
= lm1
;
472 for( const double ** gSrc
= g1InactiveBegin
; gSrc
!= g1ActiveEnd
; ++gSrc
, ++lmDst
)
475 const double * ySrc
= yDiff
;
476 const double * src
= *gSrc
;
477 for( ; ySrc
!= yDiffEnd
; ++ySrc
, ++src
)
479 tmp
-= (*ySrc
) * (*src
);
483 /* Let nu be the dual variable of the given equality constraint (all variables sum to 1). */
485 double nu
= 0; /* Initialize to avoid compiler warnings. */
486 double * lmInactiveEnd
= lm1
+ nInactive1
;
487 double * lmPtr
= lm1
;
488 for( ; lmPtr
!= lmInactiveEnd
; ++lmPtr
)
490 double lmAbs
= fabs( *lmPtr
);
497 /* Then the remaining Lagrange multipliers follow. */
498 double * lmActiveEnd
= lm1
+ n1
;
499 for( ; lmPtr
!= lmActiveEnd
; ++lmPtr
)
506 /* Compute Lagrange multipliers for the second polytope in the same way... up to sign changes. */
507 double * lmDst
= lm2
;
508 for( const double ** gSrc
= g2InactiveBegin
; gSrc
!= g2ActiveEnd
; ++gSrc
, ++lmDst
)
511 const double * ySrc
= yDiff
;
512 const double * src
= *gSrc
;
513 for( ; ySrc
!= yDiffEnd
; ++ySrc
, ++src
)
515 tmp
+= (*ySrc
) * (*src
); /* Note sign! */
520 double nu
= 0; /* Initialize to avoid compiler warnings. */
521 double * lmInactiveEnd
= lm2
+ nInactive2
;
522 double * lmPtr
= lm2
;
523 for( ; lmPtr
!= lmInactiveEnd
; ++lmPtr
)
525 double lmAbs
= fabs( *lmPtr
);
532 double * lmActiveEnd
= lm2
+ n2
;
533 for( ; lmPtr
!= lmActiveEnd
; ++lmPtr
)
540 std::cerr
<< "lambda: " << Helpers::mathematicaFormat( n1
- nInactive1
, 1, lm1
+ nInactive1
)
541 << " " << Helpers::mathematicaFormat( n2
- nInactive2
, 1, lm2
+ nInactive2
) << std::endl
;
545 const double * lambdaSrc
= lm1
+ nInactive1
;
546 for( const double ** gSrc
= g1InactiveEnd
; gSrc
!= g2ActiveEnd
; ++gSrc
, ++lambdaSrc
)
548 if( gSrc
== g1ActiveEnd
)
550 gSrc
= g2InactiveEnd
- 1;
551 lambdaSrc
= lm2
+ nInactive2
- 1;
554 std::cout
<< " << @nonstroking:[gray 0.5] | (newText << `" << std::scientific
<< std::setprecision(1) << *lambdaSrc
<< std::fixed
<< "´) >> [shift (0,3bp)+(" ;
555 for( const double * src
= *gSrc
; src
!= *gSrc
+ dim
; ++src
)
561 std::cout
<< "(" << *src
<< "bp)" ;
563 std::cout
<< ")]" << std::endl
;
568 bool dropped
= false;
570 const double * lmSrc
= lm1
+ nInactive1
;
571 const double * lmEnd
= lm1
+ n1
;
572 const double ** gSrc
= g1InactiveEnd
;
573 double * xDst
= x1
+ nInactive1
;
574 for( ; lmSrc
!= lmEnd
; ++lmSrc
, ++gSrc
)
576 if( *lmSrc
< -lmTol
)
579 * Swap the generator out of the active set, so that it appears at the end
580 * of the inactive set.
582 const double * gTmp
= *g1InactiveEnd
;
583 *g1InactiveEnd
= *gSrc
;
587 /* Since the constraint has been active, the corresponding variable has been zero.
597 const double * lmSrc
= lm2
+ nInactive2
;
598 const double * lmEnd
= lm2
+ n2
;
599 const double ** gSrc
= g2InactiveEnd
;
600 double * xDst
= x2
+ nInactive2
;
601 for( ; lmSrc
!= lmEnd
; ++lmSrc
, ++gSrc
)
603 if( *lmSrc
< -lmTol
)
606 * Swap the generator out of the active set, so that it appears at the end
607 * of the inactive set.
609 const double * gTmp
= *g2InactiveEnd
;
610 *g2InactiveEnd
= *gSrc
;
614 /* Since the constraint has been active, the corresponding variable has been zero.
625 /* We reached optimum!
627 status
->code
= QP_OK
;
628 status
->termination
= QP_OK_LM
;
629 status
->iterations
= iterCount
;
632 /* If we dropped some constraint, we just return to the top of the loop.
633 * No need to re-normalize variables since added variables are exactly zero.
635 checkNextCost
= false; /* No need to check the cost in the next iteration since no step was made. */
639 /* Find inactive constraints that limit the step length in each polytope. */
641 const double ** gStop1
= 0;
643 const double ** gSrc
= g1InactiveBegin
;
644 const double ** gEnd
= g1InactiveEnd
;
645 const double * dSrc
= d1
;
646 const double * xSrc
= x1
;
647 for( ; gSrc
!= gEnd
; ++gSrc
, ++dSrc
, ++xSrc
)
649 double denom
= -*dSrc
;
652 double sTmp
= *xSrc
/ denom
;
662 const double ** gStop2
= 0;
664 const double ** gSrc
= g2InactiveBegin
;
665 const double ** gEnd
= g2InactiveEnd
;
666 const double * dSrc
= d2
;
667 const double * xSrc
= x2
;
668 for( ; gSrc
!= gEnd
; ++gSrc
, ++dSrc
, ++xSrc
)
670 double denom
= -*dSrc
;
673 double sTmp
= *xSrc
/ denom
;
683 /* In a basic active set algorithm, one uses only the smaller of s1 and s2, but here
684 * we actually use both, if that gives further decrease in the objective function.
686 double sShort
= ( s1
< s2
) ? s1
: s2
;
688 const double * xSrc
= x1
;
689 const double * xEnd
= x1
+ nInactive1
;
690 const double * dSrc
= d1
;
691 double * dst
= x1short
;
692 for( ; xSrc
!= xEnd
; ++xSrc
, ++dSrc
, ++dst
)
694 *dst
= *xSrc
+ sShort
* (*dSrc
);
698 const double * xSrc
= x2
;
699 const double * xEnd
= x2
+ nInactive2
;
700 const double * dSrc
= d2
;
701 double * dst
= x2short
;
702 for( ; xSrc
!= xEnd
; ++xSrc
, ++dSrc
, ++dst
)
704 *dst
= *xSrc
+ sShort
* (*dSrc
);
707 double shortCost
= 0;
708 polytope_distance_generator_form_diff( dim
,
709 g1InactiveBegin
, g1InactiveEnd
,
710 g2InactiveBegin
, g2InactiveEnd
,
713 for( const double * src
= yDiff
; src
!= yDiffEnd
; ++src
)
715 shortCost
+= (*src
) * (*src
);
720 const double * xSrc
= x1
;
721 const double * xEnd
= x1
+ nInactive1
;
722 const double * dSrc
= d1
;
723 double * dst
= x1long
;
724 for( ; xSrc
!= xEnd
; ++xSrc
, ++dSrc
, ++dst
)
726 *dst
= *xSrc
+ s1
* (*dSrc
);
729 polytope_distance_generator_form_diff( dim
,
730 g1InactiveBegin
, g1InactiveEnd
,
731 g2InactiveBegin
, g2InactiveEnd
,
734 for( const double * src
= yDiff
; src
!= yDiffEnd
; ++src
)
736 longCost
+= (*src
) * (*src
);
739 if( longCost
> shortCost
)
741 /* Dont make long step. */
748 const double * xSrc
= x2
;
749 const double * xEnd
= x2
+ nInactive2
;
750 const double * dSrc
= d2
;
751 double * dst
= x2long
;
752 for( ; xSrc
!= xEnd
; ++xSrc
, ++dSrc
, ++dst
)
754 *dst
= *xSrc
+ s2
* (*dSrc
);
757 polytope_distance_generator_form_diff( dim
,
758 g1InactiveBegin
, g1InactiveEnd
,
759 g2InactiveBegin
, g2InactiveEnd
,
762 for( const double * src
= yDiff
; src
!= yDiffEnd
; ++src
)
764 longCost
+= (*src
) * (*src
);
767 if( longCost
> shortCost
)
769 /* Dont make long step. */
775 /* Update variables and active constraints.
776 * Important: variables first, or we will get a mess!
779 const double * xSrc
= x1
;
780 const double * xEnd
= x1
+ nInactive1
;
781 const double * dSrc
= d1
;
783 for( ; xSrc
!= xEnd
; ++xSrc
, ++dSrc
, ++dst
)
785 *dst
= *xSrc
+ s1
* (*dSrc
);
790 /* Swap constraints, and swap variables in the same way. New variable is zero by construction. */
792 const double * gTmp
= *gStop1
;
793 *gStop1
= *g1InactiveEnd
;
794 *g1InactiveEnd
= gTmp
;
795 *( x1
+ ( gStop1
- g1InactiveBegin
) ) = *( x1
+ ( g1InactiveEnd
- g1InactiveBegin
) );
798 const double * xSrc
= x2
;
799 const double * xEnd
= x2
+ nInactive2
;
800 const double * dSrc
= d2
;
802 for( ; xSrc
!= xEnd
; ++xSrc
, ++dSrc
, ++dst
)
804 *dst
= *xSrc
+ s2
* (*dSrc
);
809 /* Swap constraints, and swap variables in the same way. New variable is zero by construction. */
811 const double * gTmp
= *gStop2
;
812 *gStop2
= *g2InactiveEnd
;
813 *g2InactiveEnd
= gTmp
;
814 *( x2
+ ( gStop2
- g2InactiveBegin
) ) = *( x2
+ ( g2InactiveEnd
- g2InactiveBegin
) );
820 if( tracefigPageOpen
)
822 std::cout
<< ")" << std::endl
;
823 tracefigPageOpen
= false;
827 /* Compute final cost. */
829 polytope_distance_generator_form_diff( dim
,
830 g1InactiveBegin
, g1InactiveEnd
,
831 g2InactiveBegin
, g2InactiveEnd
,
834 polytope_distance_generator_form_costs( dim
,
835 g1InactiveBegin
, g1ActiveEnd
,
836 g2InactiveBegin
, g2ActiveEnd
,
842 std::cerr
<< "Terminating with final cost: " << *costLower
<< " -- " << *costUpper
<< std::endl
;
846 /* Compute final point in each polytope. */
850 double * yEnd
= y
+ dim
;
851 for( double * dst
= y
; dst
!= yEnd
; ++dst
)
855 const double * xSrc
= x1
;
856 for( const double ** gSrc
= g1InactiveBegin
; gSrc
!= g1InactiveEnd
; ++gSrc
, ++xSrc
)
859 const double * src
= *gSrc
;
860 for( double * dst
= y
; dst
!= yEnd
; ++dst
, ++src
)
862 *dst
+= xVal
* (*src
);
869 double * yEnd
= y
+ dim
;
870 for( double * dst
= y
; dst
!= yEnd
; ++dst
)
874 const double * xSrc
= x2
;
875 for( const double ** gSrc
= g2InactiveBegin
; gSrc
!= g2InactiveEnd
; ++gSrc
, ++xSrc
)
878 const double * src
= *gSrc
;
879 for( double * dst
= y
; dst
!= yEnd
; ++dst
, ++src
)
881 *dst
+= xVal
* (*src
);
888 Computation::polytope_distance_generator_form_diff( const size_t dim
,
889 const double ** g1Begin
, const double ** g1End
,
890 const double ** g2Begin
, const double ** g2End
,
891 const double * x1
, const double * x2
,
894 double * yDiffEnd
= yDiff
+ dim
;
895 for( double * dst
= yDiff
; dst
!= yDiffEnd
; ++dst
)
900 const double * xSrc
= x2
;
901 for( const double ** gSrc
= g2Begin
; gSrc
!= g2End
; ++gSrc
, ++xSrc
)
904 const double * src
= *gSrc
;
905 for( double * dst
= yDiff
; dst
!= yDiffEnd
; ++dst
, ++src
)
907 *dst
+= xVal
* (*src
);
912 const double * xSrc
= x1
;
913 for( const double ** gSrc
= g1Begin
; gSrc
!= g1End
; ++gSrc
, ++xSrc
)
916 const double * src
= *gSrc
;
917 for( double * dst
= yDiff
; dst
!= yDiffEnd
; ++dst
, ++src
)
919 *dst
-= xVal
* (*src
);
926 Computation::polytope_distance_generator_form_costs( const size_t dim
,
927 const double ** g1Begin
, const double ** g1End
,
928 const double ** g2Begin
, const double ** g2End
,
929 const double * yDiff
,
931 double * dualCostAccum
,
934 const double * yDiffEnd
= yDiff
+ dim
;
937 for( const double * src
= yDiff
; src
!= yDiffEnd
; ++src
)
939 pCost
+= (*src
) * (*src
);
942 if( primalCost
!= 0 )
947 if( dualCostAccum
== 0 )
952 double * n
= work
; /* Normalaized normal to planes separating the two polytopes. */
953 double * nEnd
= work
+ dim
;
955 /* Normalize yDiff and store in n. */
956 double yDiffScale
= 1. / sqrt( pCost
);
958 for( const double * src
= yDiff
; src
!= yDiffEnd
; ++src
, ++dst
)
960 *dst
= yDiffScale
* (*src
);
964 /* Find dual cost by projecting generators onto n. */
965 double min2
= std::numeric_limits
< double >::max( );
967 for( const double ** gSrc
= g2Begin
; gSrc
!= g2End
; ++gSrc
)
970 const double * src
= *gSrc
;
971 for( const double * nSrc
= n
; nSrc
!= nEnd
; ++nSrc
, ++src
)
973 tmp
+= (*nSrc
) * (*src
);
975 min2
= std::min( min2
, tmp
);
979 double max1
= -std::numeric_limits
< double >::max( );
981 for( const double ** gSrc
= g1Begin
; gSrc
!= g1End
; ++gSrc
)
984 const double * src
= *gSrc
;
985 for( const double * nSrc
= n
; nSrc
!= nEnd
; ++nSrc
, ++src
)
987 tmp
+= (*nSrc
) * (*src
);
989 max1
= std::max( max1
, tmp
);
993 double diff
= min2
- max1
;
996 *dualCostAccum
= std::max( *dualCostAccum
, diff
* diff
);
1002 Computation::polytope_distance_generator_form_sub( const size_t dim
,
1003 const double ** g1Begin
, const double ** g1End
,
1004 const double ** g2Begin
, const double ** g2End
,
1005 const double * yDiff
,
1007 double * d1
, double * d2
,
1010 size_t n1
= g1End
- g1Begin
;
1011 size_t n2
= g2End
- g2Begin
;
1012 double * d1End
= d1
+ n1
;
1013 double * d2End
= d2
+ n2
;
1014 for( double * dst
= d1
; dst
!= d1End
; ++dst
)
1018 for( double * dst
= d2
; dst
!= d2End
; ++dst
)
1022 if( n1
== 1 && n2
== 1 ) /* They must never be less than 1! */
1024 /* If there is only one inactive constraint in a polytope, the corresponding variable is in fact locked to 1.
1025 * Henece, we cannot move in that polytope. If we can't move in either polytope, there is nothing to optimize.
1026 * We have already set the result to 0.
1030 const double ** N1
= Computation::polytope_distance_generator_form_kernel( n1
);
1031 const double ** N2
= Computation::polytope_distance_generator_form_kernel( n2
);
1034 y_gsl
.data
= const_cast< double * >( yDiff
);
1040 work
+= ( d_gsl
.size
= n1
+ n2
- 2 );
1043 if( dim
>= n1
+ n2
- 2 )
1045 /* Over-determined case. SVD of A can be computed as usual. */
1048 work
+= ( A
.size1
= dim
) * ( A
.size2
= A
.tda
= n1
+ n2
- 2 );
1051 work
+= ( V
.size1
= n1
+ n2
- 2 ) * ( V
.size2
= V
.tda
= n1
+ n2
- 2 );
1054 work
+= ( S
.size
= n1
+ n2
- 2 );
1057 SV_work
.data
= work
;
1058 work
+= ( SV_work
.size
= n1
+ n2
- 2 );
1061 /* Populate A with data.
1062 * The data access here can be improved. */
1065 double * ARowStart
= A
.data
;
1066 for( size_t row
= 0; row
< dim
; ++row
, ARowStart
+= A
.tda
)
1068 const double ** NcolStart
= N1
;
1069 const double ** NcolEnd
= N1
+ n1
- 1;
1070 double * Adst
= ARowStart
;
1071 for( ; NcolStart
!= NcolEnd
; ++NcolStart
, ++Adst
)
1074 const double ** gcolStart
= g1Begin
;
1075 const double ** gcolEnd
= g1End
;
1076 const double * Nsrc
= *NcolStart
;
1077 for( ; gcolStart
!= gcolEnd
; ++gcolStart
, ++Nsrc
)
1079 tmp
+= (*((*gcolStart
) + row
)) * (*Nsrc
);
1087 double * ARowStart
= A
.data
+ ( n1
- 1 );
1088 for( size_t row
= 0; row
< dim
; ++row
, ARowStart
+= A
.tda
)
1090 const double ** NcolStart
= N2
;
1091 const double ** NcolEnd
= N2
+ n2
- 1;
1092 double * Adst
= ARowStart
;
1093 for( ; NcolStart
!= NcolEnd
; ++NcolStart
, ++Adst
)
1096 const double ** gcolStart
= g2Begin
;
1097 const double ** gcolEnd
= g2End
;
1098 const double * Nsrc
= *NcolStart
;
1099 for( ; gcolStart
!= gcolEnd
; ++gcolStart
, ++Nsrc
)
1101 tmp
-= (*((*gcolStart
) + row
)) * (*Nsrc
); /* Note the sign! */
1108 gsl_linalg_SV_decomp( & A
, & V
, & S
, & SV_work
);
1110 /* Truncate small singular values. */
1111 double * dst
= S
.data
;
1112 double * end
= S
.data
+ S
.size
;
1113 const double sigmaCut
= sigmaTol
* (*dst
);
1115 for( ; dst
!= end
; ++dst
)
1117 if( *dst
< sigmaCut
)
1122 for( ; dst
!= end
; ++dst
)
1127 gsl_linalg_SV_solve( & A
, & V
, & S
, & y_gsl
, & d_gsl
);
1131 /* Under-determined case. Need to transpose A to compute SVD. */
1134 work
+= ( A
.size1
= n1
+ n2
- 2 ) * ( A
.size2
= A
.tda
= dim
);
1137 work
+= ( V
.size1
= dim
) * ( V
.size2
= V
.tda
= dim
);
1140 work
+= ( S
.size
= dim
);
1143 SV_work
.data
= work
;
1144 work
+= ( SV_work
.size
= dim
);
1147 /* Populate A with data.
1148 * The data access here can be improved. */
1151 double * AColStart
= A
.data
;
1152 for( size_t row
= 0; row
< dim
; ++row
, ++AColStart
)
1154 const double ** NcolStart
= N1
;
1155 const double ** NcolEnd
= N1
+ n1
- 1;
1156 double * Adst
= AColStart
;
1157 for( ; NcolStart
!= NcolEnd
; ++NcolStart
, Adst
+= A
.tda
)
1160 const double ** gcolStart
= g1Begin
;
1161 const double ** gcolEnd
= g1End
;
1162 const double * Nsrc
= *NcolStart
;
1163 for( ; gcolStart
!= gcolEnd
; ++gcolStart
, ++Nsrc
)
1165 tmp
+= (*((*gcolStart
) + row
)) * (*Nsrc
);
1173 double * AColStart
= A
.data
+ ( n1
- 1 ) * A
.tda
;
1174 for( size_t row
= 0; row
< dim
; ++row
, ++AColStart
)
1176 const double ** NcolStart
= N2
;
1177 const double ** NcolEnd
= N2
+ n2
- 1;
1178 double * Adst
= AColStart
;
1179 for( ; NcolStart
!= NcolEnd
; ++NcolStart
, Adst
+= A
.tda
)
1182 const double ** gcolStart
= g2Begin
;
1183 const double ** gcolEnd
= g2End
;
1184 const double * Nsrc
= *NcolStart
;
1185 for( ; gcolStart
!= gcolEnd
; ++gcolStart
, ++Nsrc
)
1187 tmp
-= (*((*gcolStart
) + row
)) * (*Nsrc
); /* Note the sign! */
1194 gsl_linalg_SV_decomp( & A
, & V
, & S
, & SV_work
);
1196 /* Truncate small singular values. */
1197 double * dst
= S
.data
;
1198 double * end
= S
.data
+ S
.size
;
1199 const double sigmaCut
= sigmaTol
* (*dst
);
1201 for( ; dst
!= end
; ++dst
)
1203 if( *dst
< sigmaCut
)
1208 for( ; dst
!= end
; ++dst
)
1213 /* Now, instead of using
1214 * gsl_linalg_SV_solve( & A, & V, & S, & y_gsl, & d_gsl );
1215 * we must solve the equation ourselves since the decomposition is transposed.
1217 gsl_blas_dgemv( CblasTrans
, 1, & V
, & y_gsl
, 0, & SV_work
);
1219 const double * src
= S
.data
;
1220 const double * srcEnd
= S
.data
+ S
.size
;
1221 double * dst
= SV_work
.data
;
1222 for( ; src
!= srcEnd
; ++src
, ++dst
)
1234 gsl_blas_dgemv( CblasNoTrans
, 1, & A
, & SV_work
, 0, & d_gsl
);
1238 /* Compute output variables. */
1242 double * dstEnd
= d1
+ n1
;
1243 for( ; dst
!= dstEnd
; ++dst
)
1250 double * dstEnd
= d2
+ n2
;
1251 for( ; dst
!= dstEnd
; ++dst
)
1257 /* Then add linear combination of basis vectors. */
1258 const double * dSrc
= d_gsl
.data
;
1260 const double ** NSrc
= N1
;
1261 const double ** NSrcEnd
= N1
+ ( n1
- 1 );
1262 for( ; NSrc
!= NSrcEnd
; ++NSrc
, ++dSrc
)
1266 double * dstEnd
= d1
+ n1
;
1267 const double * src
= *NSrc
;
1268 for( ; dst
!= dstEnd
; ++dst
, ++src
)
1275 const double ** NSrc
= N2
;
1276 const double ** NSrcEnd
= N2
+ ( n2
- 1 );
1277 for( ; NSrc
!= NSrcEnd
; ++NSrc
, ++dSrc
)
1281 double * dstEnd
= d2
+ n2
;
1282 const double * src
= *NSrc
;
1283 for( ; dst
!= dstEnd
; ++dst
, ++src
)
1293 Computation::polytope_distance_generator_form_sub_Gilbert( const size_t dim
,
1294 const double ** g1Begin
, const double ** g1End
,
1295 const double ** g2Begin
, const double ** g2End
,
1296 const double * yDiff
,
1297 double * d1
, double * d2
)
1303 Computation::polytope_distance_generator_form_kernel( size_t n
)
1305 static std::vector
< const double ** > mem( 0 );
1306 if( n
< mem
.size( ) )
1310 mem
.reserve( n
+ 1 );
1311 while( mem
.size( ) <= n
)
1313 size_t m
= mem
.size( );
1316 /* Invalid dimension, just skip. */
1322 /* Trivial case; kernel has dimension 0 */
1326 const double ** res
= new const double * [ m
- 1 ];
1327 gsl_matrix
* qr
= gsl_matrix_alloc( m
, m
);
1328 gsl_vector
* tau
= gsl_vector_alloc( m
);
1329 gsl_matrix_set_zero( qr
);
1330 for( size_t i
= 0; i
< m
; ++i
)
1332 gsl_matrix_set( qr
, i
, 0, 1. );
1334 gsl_matrix
* q
= gsl_matrix_alloc( m
, m
);
1335 gsl_matrix
* r
= gsl_matrix_alloc( m
, m
);
1337 gsl_linalg_QR_decomp( qr
, tau
);
1338 gsl_linalg_QR_unpack( qr
, tau
, q
, r
);
1340 const double ** dst
= res
;
1341 const double ** dstEnd
= res
+ ( m
- 1 );
1342 double * srcQStart
= q
->data
+ 1; /* Skip first column. */
1343 for( ; dst
!= dstEnd
; ++dst
, ++srcQStart
)
1345 double * v
= new double[ m
];
1347 double * vEnd
= v
+ m
;
1348 double * srcQ
= srcQStart
;
1349 for( ; v
!= vEnd
; ++v
, srcQ
+= q
->tda
)
1356 mem
.push_back( res
);
1358 gsl_matrix_free( qr
);
1359 gsl_vector_free( tau
);
1360 gsl_matrix_free( q
);
1361 gsl_matrix_free( r
);