1 // Copyright (c) 1997-2007  ETH Zurich (Switzerland).
2 // All rights reserved.
3 //
4 // This file is part of CGAL (www.cgal.org).
5 //
6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/QP_solver/include/CGAL/QP_solver/QP_basis_inverse_impl.h $
7 // $Id: QP_basis_inverse_impl.h a91f023 2021-01-29T10:05:48+01:00 Sébastien Loriot
8 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
9 //
10 //
11 // Author(s)     : Sven Schoenherr
12 //                 Bernd Gaertner <gaertner@inf.ethz.ch>
13 //                 Franz Wessendorp
14 //                 Kaspar Fischer
15 
16 namespace CGAL {
17 
18 // =============================
19 // class implementation (cont'd)
20 // =============================
21 
22 // creation and initialization
23 // ---------------------------
24 // set-up
25 template < class ET_, class Is_LP_ >
26 void  QP_basis_inverse<ET_,Is_LP_>::
set(int n,int m,int nr_equalities)27 set( int n, int m, int nr_equalities)
28 {
29     CGAL_qpe_assertion( n >= 0);
30     CGAL_qpe_assertion( m >= 0);
31     b = s = 0;
32     // l is the maximum size of the basis in phase I
33     l = (std::min)( n+nr_equalities+1, m);
34     if ( ! M.empty()) M.clear();
35     set( Is_LP());
36 
37     if ( ! x_l.empty()) x_l.clear();
38     if ( ! x_x.empty()) x_x.clear();
39 
40     x_l.insert( x_l.end(), l, et0);
41     x_x.insert( x_x.end(), l, et0); // has to grow later QP-case
42 
43     if ( ! tmp_l.empty()) tmp_l.clear();
44     if ( ! tmp_x.empty()) tmp_x.clear();
45 
46     tmp_l.insert( tmp_l.end(), l, et0);
47     tmp_x.insert( tmp_x.end(), l, et0); // has to grow later QP-case
48 
49 }
50 
51 // update functions
52 // ----------------
53 // leaving of original variable (update type U2)
54 template < class ET_, class Is_LP_ >
55 void  QP_basis_inverse<ET_,Is_LP_>::
leave_original()56 leave_original( )
57 {
58     // assert QP case
59     Assert_compile_time_tag( Tag_false(), Is_LP());
60 
61     // determine new denominator (`z')
62     --b;
63     ET    z     = M[ l+b][ l+b];
64     bool  z_neg = ( z < et0);
65     CGAL_qpe_assertion( z != et0);
66 
67     // update matrix in place
68     update_inplace_QP( M[ l+b].begin(), M[ l+b].begin()+l,
69                        -z, ( z_neg ? d : -d));
70 
71     // store new denominator
72     d = ( z_neg ? -z : z);
73     CGAL_qpe_assertion( d > et0);
74 
75     CGAL_qpe_debug {
76         if ( vout.verbose()) print();
77     }
78 }
79 
80 // entering of slack variable (update type U3)
81 template < class ET_, class Is_LP_ >
82 void  QP_basis_inverse<ET_,Is_LP_>::
enter_slack()83 enter_slack( )
84 {
85     // assert QP case
86     Assert_compile_time_tag( Tag_false(), Is_LP());
87 
88     // determine new denominator (`z')
89     --s;
90     ET    z     = M[ s][ s];
91     bool  z_neg = ( z < et0);
92     CGAL_qpe_assertion( z != et0);
93 
94     // update matrix in place
95     typename Matrix::iterator  col_it;
96     typename Row   ::iterator    x_it;
97     unsigned int               col;
98     for (   col = 0,   col_it = M.begin()+l,   x_it = x_x.begin();
99             col < b;
100           ++col,     ++col_it,               ++x_it              ) {
101         *x_it = (*col_it)[ s];
102     }
103     update_inplace_QP( M[ s].begin(), x_x.begin(), -z, ( z_neg ? d : -d));
104 
105     // store new denominator
106     d = ( z_neg ? -z : z);
107     CGAL_qpe_assertion( d > et0);
108 
109     CGAL_qpe_debug {
110         if ( vout.verbose()) print();
111     }
112 }
113 
114 // replacing of original by slack variable (update type U8)
115 template < class ET_, class Is_LP_ >
116 void  QP_basis_inverse<ET_,Is_LP_>::
enter_slack_leave_original()117 enter_slack_leave_original( )
118 {
119     // assert LP case or phase I
120     CGAL_qpe_assertion( is_LP || is_phaseI);
121 
122     // update matrix in-place
123     // ----------------------
124     typename Matrix::iterator  matrix_it;
125     typename Row   ::iterator       x_it;
126     unsigned int                     row;
127 
128     // QP (in phase I)?
129     matrix_it = M.begin();
130     if ( is_QP) matrix_it += l;
131 
132     // get last column of basis inverse (store it in 'x_x')
133     --s; --b;
134     for (   row = 0,   x_it = x_x.begin();
135             row < s;
136           ++row,     ++x_it,               ++matrix_it) {
137         *x_it = (*matrix_it)[ b];
138     }
139     ET    z     = (*matrix_it)[ b];
140     bool  z_neg = ( z < et0);
141     CGAL_qpe_assertion( z != et0);
142 
143     // update matrix
144     update_inplace_LP( matrix_it->begin(), x_x.begin(), -z, ( z_neg ? d : -d));
145 
146     // store new denominator
147     // ---------------------
148     d = ( z_neg ? -z : z);
149     CGAL_qpe_assertion( d > et0);
150 
151     CGAL_qpe_debug {
152         if ( vout.verbose()) print();
153     }
154 }
155 
156 
157 // replacing of original by original variable with precondition in QP-case
158 // for phaseII                               (update type UZ_1)
159 template < class ET_, class Is_LP_ >
160 template < class ForwardIterator >
161 void  QP_basis_inverse<ET_,Is_LP_>::
z_replace_original_by_original(ForwardIterator y_l_it,ForwardIterator y_x_it,const ET & s_delta,const ET & s_nu,unsigned int k_i)162 z_replace_original_by_original(ForwardIterator y_l_it,
163                                ForwardIterator y_x_it, const ET& s_delta,
164                                const ET& s_nu, unsigned int k_i)
165 {
166 
167     // assert QP case and phaseII
168     CGAL_qpe_assertion(is_QP && is_phaseII);
169 
170 
171     // prepare \hat{k}_{1} -scalar
172     ET  hat_k_1 = *(y_x_it + k_i);
173 
174     // prepare \hat{\rho} -vector in x_l, x_x
175     copy_row_in_B_O(x_l.begin(), x_x.begin(), k_i);
176 
177     // prepare \hat{v} -vector in tmp_l, tmp_x
178 
179     // tmp_l -part
180     std::transform(y_l_it, (y_l_it+s), x_l.begin(), tmp_l.begin(),
181         [&s_delta](const ET& v1, const ET& v2){ return std::plus<ET>()(v1, s_delta * v2); });
182     // tmp_x -part
183     std::transform(y_x_it, (y_x_it+b), x_x.begin(), tmp_x.begin(),
184         [&s_delta](const ET& v1, const ET& v2){ return std::plus<ET>()(v1, s_delta * v2); });
185     tmp_x[k_i] -= d;
186 
187     // prepare \hat{k}_{2} -scalar
188     ET  hat_k_2 = s_nu - (et2 * s_delta * hat_k_1);
189 
190     CGAL_qpe_assertion( d != et0);
191 
192     // update matrix in place
193     z_update_inplace(x_l.begin(), x_x.begin(), tmp_l.begin(), tmp_x.begin(),
194                       hat_k_1 * hat_k_1, -hat_k_2, -hat_k_1, d*d);
195 
196     // store new denominator
197     d = CGAL::integral_division(hat_k_1 * hat_k_1, d);
198 
199     CGAL_qpe_assertion( d > et0);
200 
201     CGAL_qpe_debug {
202         if ( vout.verbose()) print();
203     }
204 
205 }
206 
207 
208 // replacing of original by slack variable with precondition in QP-case
209 // for phaseII                               (update type UZ_2)
210 template < class ET_, class Is_LP_ >
211 void  QP_basis_inverse<ET_,Is_LP_>::
z_replace_original_by_slack()212 z_replace_original_by_slack( )
213 {
214 
215     // assert QP case and phaseII
216     CGAL_qpe_assertion(is_QP && is_phaseII);
217 
218     // adapt s and b
219     --s; --b;
220 
221     // prepare \hat{\rho} -vector in x_l, x_x
222     copy_row_in_B_O(x_l.begin(), x_x.begin(), b);
223 
224     // prepare \hat{\varrho} -vector in tmp_l, tmp_x
225     copy_row_in_C(tmp_l.begin(), tmp_x.begin(), s);
226 
227     // prepare \hat{\kappa} -scalar
228     ET  hat_kappa = M[l+b][s];
229 
230     // prepare \hat{\xi} -scalar
231     ET hat_xi = M[s][s];
232 
233     CGAL_qpe_assertion( d != et0);
234 
235     // update matrix in place
236     z_update_inplace(x_l.begin(), x_x.begin(), tmp_l.begin(), tmp_x.begin(),
237                            hat_kappa * hat_kappa, hat_xi, -hat_kappa, d * d);
238 
239     // store new denominator
240     d = CGAL::integral_division(hat_kappa * hat_kappa, d);
241 
242     CGAL_qpe_assertion( d > et0);
243 
244     CGAL_qpe_debug {
245         if ( vout.verbose()) print();
246     }
247 
248 }
249 
250 
251 // replacing of slack by original variable with precondition in QP-case
252 // for phaseII                               (update type UZ_3)
253 template < class ET_, class Is_LP_ >
254 template < class ForwardIterator >
255 void  QP_basis_inverse<ET_,Is_LP_>::
z_replace_slack_by_original(ForwardIterator y_l_it,ForwardIterator y_x_it,ForwardIterator u_x_it,const ET & hat_kappa,const ET & hat_nu)256 z_replace_slack_by_original(ForwardIterator y_l_it,
257                             ForwardIterator y_x_it,
258                                         ForwardIterator u_x_it, const ET& hat_kappa,
259                                     const ET& hat_nu)
260 {
261     // assert QP case and phaseII
262     CGAL_qpe_assertion(is_QP && is_phaseII);
263 
264     // get copies of y_l_it and y_x_it for later use
265     ForwardIterator y_l_it_copy = y_l_it;
266     ForwardIterator y_x_it_copy = y_x_it;
267 
268     CGAL_qpe_assertion( d != et0);
269 
270     // prepare \hat{\phi}
271 
272     // prepare \hat{\varphi} -vector in x_l, x_x
273     multiply(u_x_it, u_x_it, x_l.begin(), x_x.begin(), Tag_false(),
274              Tag_false());
275 
276     // prepare \hat{\kappa} -scalar
277 
278     // prepare \hat{\nu} -scalar
279 
280     // update matrix in place
281     z_update_inplace(x_l.begin(), x_x.begin(), y_l_it, y_x_it,
282                      hat_kappa * hat_kappa, -hat_nu, hat_kappa, d * d);
283 
284     // append new rows and columns
285     // ---------------------------
286     typename Row   ::iterator  row_it, x_l_it, x_x_it;
287     typename Matrix::iterator  matrix_it;
288     unsigned int               count;
289 
290     // insert new row and column at the end of block P
291     CGAL_qpe_assertion(M.size()>=s+1);
292     if (M[s].size()==0) {
293         // row has to be filled first
294         M[s].insert(M[s].end(), s+1, et0);
295     }
296 
297 
298     // P-block: left of diagonal (including element on diagonal)
299     y_l_it = y_l_it_copy;
300     for (  row_it = M[s].begin(), x_l_it = x_l.begin();
301            row_it != M[s].end() - 1;
302          ++row_it,  ++x_l_it,  ++y_l_it                ) {
303         *row_it =
304           CGAL::integral_division((hat_nu * *x_l_it)-(hat_kappa * *y_l_it), d);
305     }
306     *row_it = -hat_nu;
307 
308     // Q-block
309     y_x_it = y_x_it_copy;
310     for (  matrix_it = M.begin()+l, count = 0, x_x_it = x_x.begin();
311            count < b;
312          ++matrix_it,  ++count, ++x_x_it, ++y_x_it                  ) {
313         (*matrix_it)[s] =
314           CGAL::integral_division((hat_nu * *x_x_it) - (hat_kappa * *y_x_it), d);
315     }
316 
317     // insert new row and column at the end of blocks Q and R
318     ensure_physical_row(l+b);
319 
320     // Q-block
321     for (  row_it = M[l+b].begin(), count = 0, x_l_it = x_l.begin();
322            count < s;
323          ++row_it,  ++count,  ++x_l_it                              ) {
324         *row_it = CGAL::integral_division(-hat_kappa * *x_l_it, d);
325     }
326     *row_it = hat_kappa;
327 
328     // R-block
329     for (  row_it = M[l+b].begin()+l, count = 0, x_x_it = x_x.begin();
330            count < b;
331          ++row_it,  ++count,  ++x_x_it                                ) {
332         *row_it = CGAL::integral_division(-hat_kappa * *x_x_it, d);
333     }
334     *row_it = et0;
335 
336     //adapt s and b
337     ++s; ++b;
338 
339     // store new denominator
340     d = CGAL::integral_division(hat_kappa * hat_kappa, d);
341 
342     CGAL_qpe_assertion( d > et0);
343 
344     CGAL_qpe_debug {
345         if ( vout.verbose()) print();
346     }
347 
348 }
349 
350 
351 // replacing of slack by slack variable with precondition in QP-case
352 // for phaseII                               (update type UZ_4)
353 template < class ET_, class Is_LP_ >
354 template < class ForwardIterator >
355 void  QP_basis_inverse<ET_,Is_LP_>::
z_replace_slack_by_slack(ForwardIterator u_x_it,unsigned int k_j)356 z_replace_slack_by_slack(ForwardIterator u_x_it, unsigned int k_j)
357 {
358 
359     // assert QP case and phaseII
360     CGAL_qpe_assertion(is_QP && is_phaseII);
361 
362     // prepare \hat{v} -vector in x_l, x_x
363     multiply(u_x_it, u_x_it, x_l.begin(), x_x.begin(),Tag_false(),
364              Tag_false());
365     x_l[k_j] -= d;
366 
367     // prepare \hat{\varrho} -vector in tmp_l, tmp_x
368     copy_row_in_C(tmp_l.begin(), tmp_x.begin(), k_j);
369 
370     // prepare \hat{k}_{1} -scalar
371     ET  hat_k_1 = inner_product_x(tmp_x.begin(), u_x_it);
372 
373     // prepare \hat{k}_{3} -scalar
374     ET  hat_k_3 = -M[k_j][k_j];
375 
376     CGAL_qpe_assertion( d != et0);
377 
378     // update matrix in place
379     z_update_inplace(x_l.begin(), x_x.begin(), tmp_l.begin(), tmp_x.begin(),
380                      hat_k_1 * hat_k_1, -hat_k_3, -hat_k_1, d * d);
381 
382     // store new denominator
383     d = CGAL::integral_division(hat_k_1 * hat_k_1, d);
384 
385     CGAL_qpe_assertion( d > et0);
386 
387     CGAL_qpe_debug {
388         if ( vout.verbose()) print();
389     }
390 
391 }
392 
393 
394 // copying of reduced basis inverse row in (upper) C-half
395 template < class ET_, class Is_LP_ >
396 template < class OutIt >
397 void  QP_basis_inverse<ET_,Is_LP_>::
copy_row_in_C(OutIt y_l_it,OutIt y_x_it,unsigned int r)398 copy_row_in_C(OutIt y_l_it, OutIt y_x_it, unsigned int r)
399 {
400     typename Matrix::const_iterator  matrix_it;
401     typename Row   ::const_iterator     row_it;
402     unsigned int  count;
403 
404     // P-block: left of diagonal (including element on diagonal)
405     matrix_it = M.begin()+r;
406     for (  row_it = matrix_it->begin();
407            row_it != matrix_it->end();
408          ++row_it, ++y_l_it            ) {
409         *y_l_it = *row_it;
410     }
411 
412     // P-block: right of diagonal (excluding element on diagonal)
413     for (  matrix_it = M.begin()+r+1, count = r+1;
414            count < s;
415          ++matrix_it,  ++count,  ++y_l_it         ) {
416         *y_l_it = (*matrix_it)[r];
417     }
418 
419     // Q-block
420     for (  matrix_it = M.begin()+l, count = 0;
421            count < b;
422          ++matrix_it,  ++count,  ++y_x_it     ) {
423         *y_x_it = (*matrix_it)[r];
424     }
425 }
426 
427 
428 // copying of reduced basis inverse row in (lower) B_O-half
429 template < class ET_, class Is_LP_ >
430 template < class OutIt >
431 void  QP_basis_inverse<ET_,Is_LP_>::
copy_row_in_B_O(OutIt y_l_it,OutIt y_x_it,unsigned int r)432 copy_row_in_B_O(OutIt y_l_it, OutIt y_x_it, unsigned int r)
433 {
434     typename Matrix::const_iterator  matrix_it;
435     typename Row   ::const_iterator     row_it;
436     unsigned int  count;
437 
438     // Q-block
439     matrix_it = M.begin()+l+r;
440     for (  row_it = matrix_it->begin(), count = 0;
441            count < s;
442          ++row_it,  ++count,  ++y_l_it           ) {
443         *y_l_it = *row_it;
444     }
445 
446     // R-block: left of diagonal (including element on diagonal)
447     for (  row_it = matrix_it->begin()+l;
448            row_it != matrix_it->end();
449          ++row_it,  ++y_x_it            ) {
450         *y_x_it = *row_it;
451     }
452 
453     // R-block: right of diagonal (excluding element on diagonal)
454     for (  matrix_it = M.begin()+l+r+1, count = r+1;
455            count < b;
456          ++matrix_it,  ++count,  ++y_x_it           ) {
457         *y_x_it = (*matrix_it)[l+r];
458     }
459 
460 }
461 
462 template < class ET_, class Is_LP_ >
463 template < class ForIt >
464 void  QP_basis_inverse<ET_,Is_LP_>::
z_update_inplace(ForIt psi1_l_it,ForIt psi1_x_it,ForIt psi2_l_it,ForIt psi2_x_it,const ET & omega0,const ET & omega1,const ET & omega2,const ET & omega3)465 z_update_inplace( ForIt psi1_l_it, ForIt psi1_x_it,
466                   ForIt psi2_l_it, ForIt psi2_x_it,
467                      const ET& omega0, const ET& omega1,
468                          const ET& omega2, const ET& omega3)
469 {
470     typename Matrix::      iterator  matrix_it;
471     typename Row   ::      iterator     row_it;
472     typename Row   ::const_iterator      y_it1_r, y_it1_c, y_it2_r, y_it2_c;
473 
474     unsigned int  row, col, k = l+b;
475     ET           u_elem;
476 
477     // rows: 0..s-1  ( P )
478     for (  row = 0, matrix_it = M.begin(),
479            y_it1_r = psi1_l_it,  y_it2_r = psi2_l_it;
480            row < s;
481          ++row, ++matrix_it, ++y_it1_r, ++y_it2_r  ) {
482 
483         // columns: 0..row  ( P )
484         for (   row_it =  matrix_it->begin(),
485                 y_it1_c = psi1_l_it,  y_it2_c = psi2_l_it;
486                 row_it != matrix_it->end();
487               ++row_it,  ++y_it1_c,  ++y_it2_c            ) {
488 
489             u_elem = (*y_it1_r * *y_it2_c) + (*y_it2_r * *y_it1_c);
490             u_elem *= omega2;
491             u_elem += omega1 * *y_it1_r * *y_it1_c;
492             update_entry( *row_it, omega0, u_elem, omega3);
493         }
494     }
495 
496     // rows: l..k-1  ( Q R )
497     for (  row = l, matrix_it = M.begin()+l,
498            y_it1_r = psi1_x_it,  y_it2_r = psi2_x_it;
499            row != k;
500          ++row,  ++matrix_it,  ++y_it1_r,  ++y_it2_r ) {
501 
502         // columns: 0..s-1  ( Q )
503         for (   col = 0,   row_it =  matrix_it->begin(),
504                 y_it1_c = psi1_l_it,  y_it2_c = psi2_l_it;
505                 col < s;
506               ++col, ++row_it,  ++y_it1_c,  ++y_it2_c     ){
507 
508             u_elem = (*y_it1_r * *y_it2_c) + (*y_it2_r * *y_it1_c);
509                u_elem *= omega2;
510                u_elem += omega1 * *y_it1_r * *y_it1_c;
511                update_entry( *row_it, omega0, u_elem, omega3);
512         }
513 
514         // columns: l..k-1  ( R )
515         for (  row_it = matrix_it->begin()+l,
516                y_it1_c = psi1_x_it,  y_it2_c = psi2_x_it;
517                row_it != matrix_it->end();
518              ++row_it,  ++y_it1_c,  ++y_it2_c            ){
519 
520             u_elem = (*y_it1_r * *y_it2_c) + (*y_it2_r * *y_it1_c);
521             u_elem *= omega2;
522                 u_elem += omega1 * *y_it1_r * *y_it1_c;
523             update_entry( *row_it, omega0, u_elem, omega3);
524         }
525 
526     }
527 
528 }
529 
530 
531 // swap functions
532 // --------------
533 // swap variable ``to the end'' of R
534 template < class ET_, class Is_LP_ >                            // LP case
535 void  QP_basis_inverse<ET_,Is_LP_>::
swap_variable(unsigned int j,Tag_true)536 swap_variable( unsigned int j, Tag_true)
537 {
538     unsigned int  k = b-1;
539     if ( j == k) return;
540 
541     // swap rows
542     // ---------
543     typename Row::iterator   row_j_it = M[ j].begin();
544     typename Row::iterator   row_k_it = M[ k].begin();
545     unsigned int  count;
546 
547     // swap entries 0..b-1 (row <-> row) [in Q]
548     for (   count = 0;
549             count < b;
550           ++count,     ++row_j_it, ++row_k_it) {
551         std::iter_swap( row_j_it, row_k_it);
552     }
553 }
554 
555 template < class ET_, class Is_LP_ >                            // QP case
556 void  QP_basis_inverse<ET_,Is_LP_>::
swap_variable(unsigned int j,Tag_false)557 swap_variable( unsigned int j, Tag_false)
558 {
559     unsigned int  i = l+j, k = l+b-1;
560     if ( i == k) return;
561 
562     // swap rows and columns
563     // ---------------------
564     typename    Row::iterator   row_i_it = M[ i].begin();
565     typename    Row::iterator   row_k_it = M[ k].begin();
566     typename Matrix::iterator  matrix_it = M.begin()+(i+1);
567     unsigned int  count;
568 
569     // swap entries 0..s-1 (row <-> row) [in Q]
570     for (   count = 0;
571             count < s;
572           ++count,     ++row_i_it, ++row_k_it) {
573         std::iter_swap( row_i_it, row_k_it);
574     }
575 
576     if ( is_phaseII) {
577 
578         // swap entries l..i-1 (row <-> row) [in R]
579         for (   count = l,   row_i_it += l-s,   row_k_it += l-s;
580                 count < i;
581               ++count,     ++row_i_it,        ++row_k_it       ) {
582             std::iter_swap( row_i_it, row_k_it);
583         }
584 
585         // swap entries i+1..k-1 (column <-> row) [in R]
586         for ( ++count,                        ++row_k_it;
587                 count < k;
588               ++count,     ++matrix_it,       ++row_k_it) {
589             std::swap( ( *matrix_it)[ i], *row_k_it);
590         }
591 
592         // swap entries i,i with k,k (entry <-> entry) [in R]
593         std::iter_swap( row_i_it, row_k_it);
594     }
595 }
596 
597 // swap constraint ``to the end'' of P
598 template < class ET_, class Is_LP_ >                            // LP case
599 void  QP_basis_inverse<ET_,Is_LP_>::
swap_constraint(unsigned int i,Tag_true)600 swap_constraint( unsigned int i, Tag_true)
601 {
602     unsigned int  k = s-1;
603     if ( i == k) return;
604 
605     // swap columns
606     // ------------
607     typename Matrix::iterator  matrix_it = M.begin();
608     unsigned int  count;
609 
610     // swap entries 0..s-1 (column <-> column) [in Q]
611     for (   count = 0;
612             count < s;
613           ++count,     ++matrix_it) {
614         std::swap( ( *matrix_it)[ i], ( *matrix_it)[ k]);
615     }
616 }
617 
618 template < class ET_, class Is_LP_ >                            // QP case
619 void  QP_basis_inverse<ET_,Is_LP_>::
swap_constraint(unsigned int i,Tag_false)620 swap_constraint( unsigned int i, Tag_false)
621 {
622 
623     if ( i == s-1) return;
624 
625     // swap rows and columns
626     // ---------------------
627     typename    Row::iterator   row_i_it = M[ i].begin();
628     typename    Row::iterator   row_k_it = M[ s-1].begin();
629     typename Matrix::iterator  matrix_it = M.begin()+i;
630     unsigned int  count;
631 
632     if ( is_phaseI) {
633 
634         // skip empty P
635         matrix_it =M.begin() + l;
636 
637     } else {
638 
639         // swap entries 0..i-1 (row <-> row) [in P]
640         for (   count =  0;
641                 count < i;
642               ++count,      ++row_i_it, ++row_k_it) {
643             std::iter_swap( row_i_it, row_k_it);
644         }
645 
646         // swap entries i+1..s-2 (column <-> row) [in P]
647         for ( count = i + 1, ++matrix_it, ++row_k_it;
648                 count < s-1;
649               ++count,     ++matrix_it, ++row_k_it) {
650             std::swap( ( *matrix_it)[ i], *row_k_it);
651         }
652         // the remaining two entries to be swapped on the main diagonal
653         std::swap(M[i][i], M[s-1][s-1]);
654 
655         // advance to Q
656         matrix_it = M.begin() + l;
657     }
658 
659     // swap entries l..l+b (column <-> column) [in Q]
660     for (   count = 0;
661             count < b;
662           ++count,     ++matrix_it) {
663         std::swap( ( *matrix_it)[ i], ( *matrix_it)[ s-1]);
664     }
665 }
666 
667 // diagnostic output
668 // -----------------
669 template < class ET_, class Is_LP_ >
670 void  QP_basis_inverse<ET_,Is_LP_>::
print()671 print( )
672 {
673     // P
674     if ( is_LP || is_phaseII) {
675         for ( unsigned int row = 0; row < s; ++row) {
676             std::copy( M[ row].begin(),
677                        M[ row].begin() + ( is_LP ? s : row+1),
678                        std::ostream_iterator<ET>( vout.out(), " "));
679             vout.out() << std::endl;
680         }
681         if ( is_QP) vout.out() << "= = = = = = = = = =" << std::endl;
682     }
683 
684     // Q & R
685     if ( is_QP) {
686         for ( unsigned int row = l; row < l+b; ++row) {
687             std::copy( M[ row].begin(), M[ row].begin()+s,
688                        std::ostream_iterator<ET>( vout.out(), " "));
689             if ( is_phaseII) {
690                 vout.out() << "|| ";
691                 std::copy( M[ row].begin()+l, M[ row].end(),
692                            std::ostream_iterator<ET>( vout.out(), " "));
693             }
694             vout.out() << std::endl;
695         }
696     }
697     vout.out() << "denominator = " << d << std::endl;
698 }
699 
700 } //namespace CGAL
701 
702 // ===== EOF ==================================================================
703