QGIS API Documentation  2.12.0-Lyon
problem.cpp
Go to the documentation of this file.
1 /*
2  * libpal - Automated Placement of Labels Library
3  *
4  * Copyright (C) 2008 Maxence Laurent, MIS-TIC, HEIG-VD
5  * University of Applied Sciences, Western Switzerland
6  * http://www.hes-so.ch
7  *
8  * Contact:
9  * maxence.laurent <at> heig-vd <dot> ch
10  * or
11  * eric.taillard <at> heig-vd <dot> ch
12  *
13  * This file is part of libpal.
14  *
15  * libpal is free software: you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation, either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * libpal is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with libpal. If not, see <http://www.gnu.org/licenses/>.
27  *
28  */
29 
30 #define _CRT_SECURE_NO_DEPRECATE
31 
32 #include "pal.h"
33 #include "palstat.h"
34 #include "layer.h"
35 #include "rtree.hpp"
36 #include "feature.h"
37 #include "geomfunction.h"
38 #include "labelposition.h"
39 #include "problem.h"
40 #include "util.h"
41 #include "priorityqueue.h"
42 #include "internalexception.h"
43 #include <iostream>
44 #include <fstream>
45 #include <cfloat>
46 #include <ctime>
47 #include <list>
48 #include <limits.h> //for INT_MAX
49 
50 namespace pal
51 {
52 
53  inline void delete_chain( Chain *chain )
54  {
55  if ( chain )
56  {
57  delete[] chain->feat;
58  delete[] chain->label;
59  delete chain;
60  }
61  }
62 
64  : nbLabelledLayers( 0 )
65  , nblp( 0 )
66  , all_nblp( 0 )
67  , nbft( 0 )
68  , displayAll( false )
69  , labelPositionCost( NULL )
70  , nbOlap( NULL )
71  , featStartId( NULL )
72  , featNbLp( NULL )
73  , inactiveCost( NULL )
74  , sol( NULL )
75  , nbActive( 0 )
76  , nbOverlap( 0.0 )
77  , pal( NULL )
78  {
79  bbox[0] = 0;
80  bbox[1] = 0;
81  bbox[2] = 0;
82  bbox[3] = 0;
83  featWrap = NULL;
85  candidates_sol = new RTree<LabelPosition*, double, 2, double>();
86  candidates_subsol = NULL;
87  }
88 
90  {
91  if ( sol )
92  {
93  if ( sol->s )
94  delete[] sol->s;
95  delete sol;
96  }
97 
98  if ( featWrap )
99  delete[] featWrap;
100  if ( featStartId )
101  delete[] featStartId;
102  if ( featNbLp )
103  delete[] featNbLp;
104 
105  qDeleteAll( mLabelPositions );
106  mLabelPositions.clear();
107 
108  if ( inactiveCost )
109  delete[] inactiveCost;
110 
111  delete candidates;
112  delete candidates_sol;
113 
114  if ( candidates_subsol )
115  {
116  delete candidates_subsol;
117  }
118  }
119 
120  typedef struct
121  {
122  int id;
123  double inactiveCost;
124  double nbOverlap;
125  } Ft;
126 
127 
128  inline bool borderSizeDec( void *l, void *r )
129  {
130  return (( SubPart* ) l )->borderSize < (( SubPart* ) r )->borderSize;
131  }
132 
133  inline bool borderSizeInc( void *l, void *r )
134  {
135  return (( SubPart* ) l )->borderSize > (( SubPart* ) r )->borderSize;
136  }
137 
138  inline bool increaseImportance( void *l, void *r )
139  {
140  return (( Ft* ) l )->inactiveCost < (( Ft* ) r )->inactiveCost;
141  }
142 
143  inline bool increaseNbOverlap( void *l, void *r )
144  {
145  return (( Ft* ) l )->nbOverlap > (( Ft* ) r )->nbOverlap;
146  }
147 
148 
149 
151  {
152 
153  int i;
154  int j;
155  int k;
156 
157  int counter = 0;
158 
159  int lpid;
160 
161  bool *ok = new bool[nblp];
162  bool run = true;
163 
164  for ( i = 0; i < nblp; i++ )
165  ok[i] = false;
166 
167 
168  double amin[2];
169  double amax[2];
170  LabelPosition *lp2;
171 
172  while ( run )
173  {
174  run = false;
175  for ( i = 0; i < nbft; i++ )
176  {
177  // ok[i] = true;
178  for ( j = 0; j < featNbLp[i]; j++ ) // foreach candidate
179  {
180  if ( !ok[featStartId[i] + j] )
181  {
182  if ( mLabelPositions.at( featStartId[i] + j )->getNumOverlaps() == 0 ) // if candidate has no overlap
183  {
184  run = true;
185  ok[featStartId[i] + j] = true;
186  // 1) remove worse candidates from candidates
187  // 2) update nb_overlaps
188  counter += featNbLp[i] - j - 1;
189 
190  for ( k = j + 1; k < featNbLp[i]; k++ )
191  {
192 
193  lpid = featStartId[i] + k;
194  ok[lpid] = true;
195  lp2 = mLabelPositions.at( lpid );
196 
197  lp2->getBoundingBox( amin, amax );
198 
199  nbOverlap -= lp2->getNumOverlaps();
200  candidates->Search( amin, amax, LabelPosition::removeOverlapCallback, ( void* ) lp2 );
201  lp2->removeFromIndex( candidates );
202  }
203 
204  featNbLp[i] = j + 1;
205  break;
206  }
207  }
208  }
209  }
210  }
211 
212 
213  this->nblp -= counter;
214 #ifdef _VERBOSE_
215  std::cout << "problem reduce to " << nblp << " candidates which makes " << nbOverlap << " overlaps" << std::endl;
216 #endif
217  delete[] ok;
218  }
219 
221  {
222  int i;
223 
224  if ( sol )
225  {
226  if ( sol->s )
227  delete[] sol->s;
228  delete sol;
229  }
230 
231  sol = new Sol();
232  sol->s = new int[nbft];
233 
234  for ( i = 0; i < nbft; i++ )
235  sol->s[i] = -1;
236 
237  sol->cost = nbft;
238  }
239 
240 
241 
242 
243  typedef struct
244  {
248  } FalpContext;
249 
250  bool falpCallback2( LabelPosition *lp, void * ctx )
251  {
252  LabelPosition *lp2 = (( FalpContext* ) ctx )->lp;
253  PriorityQueue *list = (( FalpContext* ) ctx )->list;
254 
255  if ( lp->getId() != lp2->getId() && list->isIn( lp->getId() ) && lp->isInConflict( lp2 ) )
256  {
257  list->decreaseKey( lp->getId() );
258  }
259  return true;
260  }
261 
262 
264  {
265 
266 
267  FalpContext *context = new FalpContext();
268  context->candidates = NULL;
269  context->list = list;
270  double amin[2];
271  double amax[2];
272 
273  if ( list->isIn( lp->getId() ) )
274  {
275  list->remove( lp->getId() );
276 
277  lp->getBoundingBox( amin, amax );
278 
279  context->lp = lp;
280  candidates->Search( amin, amax, falpCallback2, context );
281  }
282 
283  delete context;
284  }
285 
286 
287  bool falpCallback1( LabelPosition *lp, void * ctx )
288  {
289  LabelPosition *lp2 = (( FalpContext* ) ctx )->lp;
290  PriorityQueue *list = (( FalpContext* ) ctx )->list;
291  RTree <LabelPosition*, double, 2, double> *candidates = (( FalpContext* ) ctx )->candidates;
292 
293  if ( lp2->isInConflict( lp ) )
294  {
295  ignoreLabel( lp, list, candidates );
296  }
297  return true;
298  }
299 
300 
301 
302  /* Better initial solution
303  * Step one FALP (Yamamoto, Camara, Lorena 2005)
304  */
306  {
307 #ifdef _DEBUG_
308  std::cout << "Init solution FALP" << std::endl;
309 #endif
310 
311  int i, j;
312  int label;
313  PriorityQueue *list;
314 
315  init_sol_empty();
316 
317  list = new PriorityQueue( nblp, all_nblp, true );
318 
319  double amin[2];
320  double amax[2];
321 
322  FalpContext *context = new FalpContext();
323  context->candidates = candidates;
324  context->list = list;
325 
326  LabelPosition *lp;
327 
328  for ( i = 0; i < nbft; i++ )
329  for ( j = 0; j < featNbLp[i]; j++ )
330  {
331  label = featStartId[i] + j;
332  try
333  {
334  list->insert( label, ( double ) mLabelPositions.at( label )->getNumOverlaps() );
335  }
337  {
338  continue;
339  }
340  }
341 
342  while ( list->getSize() > 0 ) // O (log size)
343  {
344  if ( pal->isCancelled() )
345  {
346  delete context;
347  delete list;
348  return;
349  }
350 
351  label = list->getBest(); // O (log size)
352 
353 
354  lp = mLabelPositions.at( label );
355 
356  if ( lp->getId() != label )
357  {
358  std::cout << "Error: " << lp->getId() << " <--> " << label << std::endl;
359  }
360 
361  int probFeatId = lp->getProblemFeatureId();
362  sol->s[probFeatId] = label;
363 
364 #ifdef _DEBUG_FULL_
365  std::cout << "sol->s[" << lp->probFeat << "] :" << label << std::endl;
366 #endif
367 
368  for ( i = featStartId[probFeatId]; i < featStartId[probFeatId] + featNbLp[probFeatId]; i++ )
369  {
370  ignoreLabel( mLabelPositions.at( i ), list, candidates );
371  }
372 
373 
374  lp->getBoundingBox( amin, amax );
375 
376  context->lp = lp;
377  candidates->Search( amin, amax, falpCallback1, ( void* ) context );
378  candidates_sol->Insert( amin, amax, lp );
379  }
380 
381  delete context;
382 
383 
384 
385 
386  if ( displayAll )
387  {
388  int nbOverlap;
389  int start_p;
390  LabelPosition* retainedLabel = NULL;
391  int p;
392 
393  for ( i = 0; i < nbft; i++ ) // forearch hidden feature
394  {
395  if ( sol->s[i] == -1 )
396  {
397  nbOverlap = INT_MAX;
398  start_p = featStartId[i];
399  for ( p = 0; p < featNbLp[i]; p++ )
400  {
401  lp = mLabelPositions.at( start_p + p );
402  lp->resetNumOverlaps();
403 
404  lp->getBoundingBox( amin, amax );
405 
406 
407  candidates_sol->Search( amin, amax, LabelPosition::countOverlapCallback, lp );
408 
409  if ( lp->getNumOverlaps() < nbOverlap )
410  {
411  retainedLabel = lp;
412  nbOverlap = static_cast<int>( lp->getNumOverlaps() );
413  }
414  }
415  sol->s[i] = retainedLabel->getId();
416 
417  retainedLabel->insertIntoIndex( candidates_sol );
418 
419  }
420  }
421  }
422 
423  delete list;
424  }
425 
426 //#define _DEBUG_
428  {
429 
430  if ( nbft == 0 )
431  return;
432 
433  int i;
434  int seed;
435  bool *ok = new bool[nbft];
436 
437  int r = pal->popmusic_r;
438 
439  SearchMethod searchMethod = pal->searchMethod;
440 
441  candidates_subsol = new RTree<LabelPosition*, double, 2, double>();
442 
443  double delta = 0.0;
444 
445  int it = 0;
446 
447 #ifdef _VERBOSE_
448  clock_t start_time = clock();
449  clock_t create_part_time;
450  clock_t init_sol_time;
451  clock_t search_time;
452 #endif
453 
454  SubPart *current = NULL;
455 
456 #if _VERBOSE_
457  int subPartTotalSize = 0;
458 #endif
459 
460  labelPositionCost = new double[all_nblp];
461  nbOlap = new int[all_nblp];
462 
463  featWrap = new int[nbft];
464  memset( featWrap, -1, sizeof( int ) *nbft );
465 
466  SubPart ** parts = new SubPart*[nbft];
467  int *isIn = new int[nbft];
468 
469  memset( isIn, 0, sizeof( int ) *nbft );
470 
471 
472  for ( i = 0; i < nbft; i++ )
473  {
474  parts[i] = subPart( r, i, isIn );
475 #if _VERBOSE_
476  subPartTotalSize += parts[i]->subSize;
477 #endif
478  ok[i] = false;
479  }
480  delete[] isIn;
481  sort(( void** ) parts, nbft, borderSizeInc );
482  //sort ((void**)parts, nbft, borderSizeDec);
483 
484 #ifdef _VERBOSE_
485  create_part_time = clock();
486  std::cout << " SubPart (averagesize: " << subPartTotalSize / nbft << ") creation: " << ( double )( create_part_time - start_time ) / ( double ) CLOCKS_PER_SEC << std::endl;
487 #endif
488 
489  init_sol_falp();
490 
491 #ifdef _VERBOSE_
492  init_sol_time = clock();
493  std::cout << " Compute initial solution: " << ( double )( init_sol_time - create_part_time ) / ( double ) CLOCKS_PER_SEC;
494 #endif
495 
496  solution_cost();
497 
498 #ifdef _VERBOSE_
499  std::cerr << "\t" << sol->cost << "\t" << nbActive << "\t" << ( double ) nbActive / ( double ) nbft;
500  std::cout << " (solution cost: " << sol->cost << ", nbDisplayed: " << nbActive << "(" << ( double ) nbActive / ( double ) nbft << "%)" << std::endl;
501 #endif
502 
503 
504  int popit = 0;
505 
506  seed = 0;
507  while ( true )
508  {
509  it++;
510  /* find the next seed not ok */
511  for ( i = ( seed + 1 ) % nbft; ok[i] && i != seed; i = ( i + 1 ) % nbft )
512  ;
513 
514  if ( i == seed && ok[seed] )
515  {
516  current = NULL; // everything is OK :-)
517  break;
518  }
519  else
520  {
521  seed = i;
522  current = parts[seed];
523  }
524 
525  // update sub part solution
526  candidates_subsol->RemoveAll();
527 
528  for ( i = 0; i < current->subSize; i++ )
529  {
530  current->sol[i] = sol->s[current->sub[i]];
531  if ( current->sol[i] != -1 )
532  {
533  mLabelPositions.at( current->sol[i] )->insertIntoIndex( candidates_subsol );
534  }
535  }
536 
537  switch ( searchMethod )
538  {
539  //case branch_and_bound :
540  //delta = current->branch_and_bound_search();
541  // break;
542 
543  case POPMUSIC_TABU :
544  delta = popmusic_tabu( current );
545  break;
546  case POPMUSIC_TABU_CHAIN :
547  delta = popmusic_tabu_chain( current );
548  break;
549  case POPMUSIC_CHAIN :
550  delta = popmusic_chain( current );
551  break;
552  default:
553 #ifdef _VERBOSE_
554  std::cerr << "Unknown search method..." << std::endl;
555 #endif
556  delete[] ok;
557  delete[] parts;
558  return;
559  }
560 
561  popit++;
562 
563  if ( delta > EPSILON )
564  {
565  /* Update solution */
566 #ifdef _DEBUG_FULL_
567  std::cout << "Update solution from subpart, current cost:" << std::endl;
568  solution_cost();
569  std::cout << "Delta > EPSILON: update solution" << std::endl;
570  std::cout << "after modif cost:" << std::endl;
571  solution_cost();
572 #endif
573  for ( i = 0; i < current->borderSize; i++ )
574  {
575  ok[current->sub[i]] = false;
576  }
577 
578  for ( i = current->borderSize; i < current->subSize; i++ )
579  {
580 
581  if ( sol->s[current->sub[i]] != -1 )
582  {
583  mLabelPositions.at( sol->s[current->sub[i]] )->removeFromIndex( candidates_sol );
584  }
585 
586  sol->s[current->sub[i]] = current->sol[i];
587 
588  if ( current->sol[i] != -1 )
589  {
590  mLabelPositions.at( current->sol[i] )->insertIntoIndex( candidates_sol );
591  }
592 
593  ok[current->sub[i]] = false;
594  }
595  }
596  else // not improved
597  {
598 #ifdef _DEBUG_FULL_
599  std::cout << "subpart not improved" << std::endl;
600 #endif
601  ok[seed] = true;
602  }
603  }
604 
605  solution_cost();
606 #ifdef _VERBOSE_
607  search_time = clock();
608  std::cout << " Improved solution: " << ( double )( search_time - start_time ) / ( double ) CLOCKS_PER_SEC << " (solution cost: " << sol->cost << ", nbDisplayed: " << nbActive << " (" << ( double ) nbActive / ( double ) nbft << ")" << std::endl;
609 
610 #if _VERBOSE_
611  std::cerr << "\t" << subPartTotalSize;
612 #endif
613  if ( searchMethod == POPMUSIC_TABU )
614  std::cerr << "\tpop_tabu\t";
615  else if ( searchMethod == POPMUSIC_TABU_CHAIN )
616  std::cerr << "\tpop_tabu_chain\t";
617  else if ( searchMethod == POPMUSIC_CHAIN )
618  std::cerr << "\tpop_chain\t";
619 
620  std::cerr << r << "\t" << popit << "\t" << ( create_part_time - start_time ) / ( double ) CLOCKS_PER_SEC << "\t" << ( init_sol_time - create_part_time ) / ( double ) CLOCKS_PER_SEC << "\t" << ( search_time - init_sol_time ) / ( double ) CLOCKS_PER_SEC << "\t" << ( search_time - start_time ) / ( double ) CLOCKS_PER_SEC << "\t" << sol->cost << "\t" << nbActive << "\t" << ( double ) nbActive / ( double ) nbft;
621 
622 #endif
623 
624  delete[] labelPositionCost;
625  delete[] nbOlap;
626 
627  for ( i = 0; i < nbft; i++ )
628  {
629  delete[] parts[i]->sub;
630  delete[] parts[i]->sol;
631  delete parts[i];
632  }
633  delete[] parts;
634 
635  delete[] ok;
636 
637  return;
638  }
639 #undef _DEBUG_
640 
641  typedef struct
642  {
644  int *isIn;
646  } SubPartContext;
647 
648  bool subPartCallback( LabelPosition *lp, void *ctx )
649  {
650  int *isIn = (( SubPartContext* ) ctx )->isIn;
651  QLinkedList<int> *queue = (( SubPartContext* ) ctx )->queue;
652 
653 
654  int id = lp->getProblemFeatureId();
655  if ( !isIn[id] && lp->isInConflict((( SubPartContext* ) ctx )->lp ) )
656  {
657  queue->append( id );
658  isIn[id] = 1;
659  }
660 
661  return true;
662  }
663 
664  /* Select a sub part, expected size of r, from seed */
665  SubPart * Problem::subPart( int r, int featseed, int *isIn )
666  {
667  QLinkedList<int> *queue = new QLinkedList<int>;
669 
670  int *sub;
671 
672  int id;
673  int featS;
674  int p;
675  int i;
676 
677  int n = 0;
678  int nb = 0;
679 
680  double amin[2];
681  double amax[2];
682 
683  SubPartContext context;
684  context.queue = queue;
685  context.isIn = isIn;
686 
687  queue->append( featseed );
688  isIn[featseed] = 1;
689 
690  LabelPosition *lp;
691 
692  while ( ri->size() < r && queue->size() > 0 )
693  {
694  id = queue->takeFirst();
695  ri->append( id );
696 
697  featS = featStartId[id];
698  p = featNbLp[id];
699 
700  for ( i = featS; i < featS + p; i++ ) // foreach candidat of feature 'id'
701  {
702  lp = mLabelPositions.at( i );
703 
704  lp->getBoundingBox( amin, amax );
705 
706  context.lp = lp;
707  candidates->Search( amin, amax, subPartCallback, ( void* ) &context );
708  }
709  }
710 
711  nb = queue->size();
712  n = ri->size();
713 
714  sub = new int[n+nb];
715 
716  i = 0;
717 
718  while ( queue->size() > 0 )
719  {
720  sub[i] = queue->takeFirst();
721  isIn[sub[i]] = 0;
722  i++;
723  }
724 
725  while ( ri->size() > 0 )
726  {
727  sub[i] = ri->takeFirst();
728  isIn[sub[i]] = 0;
729  i++;
730  }
731 
732  delete queue;
733  delete ri;
734 
735  SubPart *subPart = new SubPart();
736 
737  subPart->probSize = n;
738  subPart->borderSize = nb;
739  subPart->subSize = n + nb;
740  subPart->sub = sub;
741  subPart->sol = new int [subPart->subSize];
742  subPart->seed = featseed;
743  return subPart;
744  }
745 
746  double Problem::compute_feature_cost( SubPart *part, int feat_id, int label_id, int *nbOverlap )
747  {
748  double cost;
749  *nbOverlap = 0;
750 
752  context.inactiveCost = inactiveCost;
753  context.nbOv = nbOverlap;
754  context.cost = &cost;
755 
756  double amin[2];
757  double amax[2];
758  LabelPosition *lp;
759 
760  cost = 0.0;
761 
762  if ( label_id >= 0 ) // is the feature displayed ?
763  {
764  lp = mLabelPositions.at( label_id );
765 
766  lp->getBoundingBox( amin, amax );
767 
768  context.lp = lp;
769  candidates_subsol->Search( amin, amax, LabelPosition::countFullOverlapCallback, ( void* ) &context );
770 
771  cost += lp->cost();
772  }
773  else
774  {
775  cost = inactiveCost[part->sub[feat_id]];
776  //(*nbOverlap)++;
777  }
778 
779  return cost;
780 
781  }
782 
783  double Problem::compute_subsolution_cost( SubPart *part, int *s, int *nbOverlap )
784  {
785  int i;
786  double cost = 0.0;
787  int nbO = 0;
788 
789  *nbOverlap = 0;
790 
791  for ( i = 0; i < part->subSize; i++ )
792  {
793  cost += compute_feature_cost( part, i, s[i], &nbO );
794  *nbOverlap += nbO;
795  }
796 
797  return cost;
798  }
799 
800 
801 
802  typedef struct _Triple
803  {
804  int feat_id;
805  int label_id;
806  double cost;
808  } Triple;
809 
810 
811  bool decreaseCost( void *tl, void *tr )
812  {
813  return (( Triple* ) tl )->cost < (( Triple* ) tr )->cost;
814  }
815 
816  bool increaseCost( void *tl, void *tr )
817  {
818  return (( Triple* ) tl )->cost > (( Triple* ) tr )->cost;
819  }
820 
821 
822 
823  inline void actualizeTabuCandidateList( int m, int iteration, int nbOverlap, int *candidateListSize,
824  double candidateBaseFactor, double *candidateFactor,
825  int minCandidateListSize, double reductionFactor,
826  int minTabuTSize, double tabuFactor, int *tenure, int n )
827  {
828 
829  if ( *candidateFactor > candidateBaseFactor )
830  *candidateFactor /= reductionFactor;
831 
832  if ( iteration % m == 0 )
833  {
834  *tenure = minTabuTSize + ( int )( tabuFactor * nbOverlap );
835  *candidateListSize = minCandidateListSize + ( int )( *candidateFactor * nbOverlap );
836 
837  if ( *candidateListSize > n )
838  *candidateListSize = n;
839  }
840 
841  }
842 
843 
844  inline void actualizeCandidateList( int nbOverlap, int *candidateListSize, double candidateBaseFactor,
845  double *candidateFactor, int minCandidateListSize, double growingFactor, int n )
846  {
847 
848  candidateBaseFactor += 0;
849 
850  if ( *candidateListSize < n )
851  *candidateFactor = *candidateFactor * growingFactor;
852  *candidateListSize = minCandidateListSize + ( int )( *candidateFactor * nbOverlap );
853 
854  if ( *candidateListSize > n )
855  *candidateListSize = n;
856  }
857 
858 
859 
860 
861  typedef struct
862  {
866  int *nbOlap;
867  double diff_cost;
868  int *featWrap;
869  int *sol;
871  } UpdateContext;
872 
873  bool updateCandidatesCost( LabelPosition *lp, void *context )
874  {
875  UpdateContext *ctx = ( UpdateContext* ) context;
876 
877  if ( ctx->lp->isInConflict( lp ) )
878  {
879  ctx->labelPositionCost[lp->getId()] += ctx->diff_cost;
880  if ( ctx->diff_cost > 0 )
881  ctx->nbOlap[lp->getId()]++;
882  else
883  ctx->nbOlap[lp->getId()]--;
884 
885  int feat_id = ctx->featWrap[ctx->lp->getProblemFeatureId()];
886  int feat_id2;
887  if ( feat_id >= 0 && ctx->sol[feat_id] == lp->getId() ) // this label is in use
888  {
889  if (( feat_id2 = feat_id - ctx->borderSize ) >= 0 )
890  {
891  ctx->candidates[feat_id2]->cost += ctx->diff_cost;
892  ctx->candidates[feat_id2]->nbOverlap--;
893  }
894  }
895  }
896  return true;
897  }
898 
899 
900 
901 
903  {
904 #ifdef _DEBUG_FULL_
905  std::cout << "Subpart: Tabu Search" << std::endl;
906 #endif
907 
908  int probSize = part->probSize;
909  int borderSize = part->borderSize;
910  int subSize = part->subSize;
911  int *sub = part->sub;
912  int *sol = part->sol;
913 
914  Triple **candidateList = new Triple*[probSize];
915  Triple **candidateListUnsorted = new Triple*[probSize];
916 
917  int * best_sol = new int[subSize];
918 
919  double cur_cost;
920  double best_cost;
921  double initial_cost;
922 
923  int *tabu_list = new int[probSize];
924 
925  int i;
926  int j;
927 
928  int itwImp;
929  int it = 0;
930  int max_it;
931  int stop_it;
932 
933  double delta;
934  double delta_min;
935  bool authorized;
936 
937  int feat_id;
938  int feat_sub_id;
939  int label_id;
940  int p;
941 
942  int choosed_feat;
943  int choosed_label;
944  int candidateId;
945 
946  int nbOverlap = 0;
947  //int nbOverlapLabel;
948 
949 
950  int tenure = 10; //
951  int m = 50; // m [10;50]
952 
953  int minTabuTSize = 9; // min_t [2;10]
954  double tabuFactor = 0.5; // p_t [0.1;0.8]
955 
956  int minCandidateListSize = 18; // min_c [2;20]
957 
958  double candidateBaseFactor = 0.73; // p_base [0.1;0.8]
959 
960  double growingFactor = 15; // fa [5;20]
961  double reductionFactor = 1.3; // f_r [1.1;1.5]
962 
963  int candidateListSize = minCandidateListSize;
964  double candidateFactor = candidateBaseFactor;
965 
966 
967  int first_lp;
968 
969  //double EPSILON = 0.000001;
970  max_it = probSize * pal->tabuMaxIt;
971  itwImp = probSize * pal->tabuMinIt;
972  stop_it = itwImp;
973 
974  cur_cost = 0.0;
975  nbOverlap = 0;
976 
977 
978  int lp;
979  for ( i = 0; i < subSize; i++ )
980  featWrap[sub[i]] = i;
981 
982  for ( i = 0; i < subSize; i++ )
983  {
984  j = featStartId[sub[i]];
985  for ( lp = 0; lp < featNbLp[sub[i]]; lp++ )
986  {
987  it = j + lp;
988  //std::cerr << "it = " << j << " + " << lp << std::endl;
989  // std::cerr << "it/nblp:" << it << "/" << all_nblp << std::endl;
990  labelPositionCost[it] = compute_feature_cost( part, i, it, & ( nbOlap[it] ) );
991  //std::cerr << "nbOlap[" << it << "] : " << nbOlap[it] << std::endl;
992  }
993  }
994 
995  first_lp = ( displayAll ? 0 : -1 );
996  for ( i = 0; i < probSize; i++ )
997  {
998 
999  tabu_list[i] = -1; // nothing is tabu
1000 
1001  candidateList[i] = new Triple();
1002  candidateList[i]->feat_id = i + borderSize;
1003  candidateList[i]->label_id = sol[i+borderSize];
1004 
1005  candidateListUnsorted[i] = candidateList[i];
1006 
1007  if ( sol[i+borderSize] >= 0 )
1008  {
1009  j = sol[i+borderSize];
1010  candidateList[i]->cost = labelPositionCost[j];
1011  candidateList[i]->nbOverlap = nbOlap[j];
1012  }
1013  else
1014  {
1015  candidateList[i]->cost = inactiveCost[sub[i+borderSize]];
1016  candidateList[i]->nbOverlap = 1;
1017  }
1018 
1019  }
1020 
1021 
1022  for ( i = 0; i < subSize; i++ )
1023  {
1024  if ( sol[i] == -1 )
1025  {
1026  cur_cost += inactiveCost[sub[i]];
1027  }
1028  else
1029  {
1030  nbOverlap += nbOlap[sol[i]];
1031  cur_cost += labelPositionCost[sol[i]];
1032  }
1033  }
1034 
1035  sort(( void** ) candidateList, probSize, decreaseCost );
1036 
1037  best_cost = cur_cost;
1038  initial_cost = cur_cost;
1039  memcpy( best_sol, sol, sizeof( int ) *( subSize ) );
1040 
1041  // START TABU
1042 
1043  it = 0;
1044  while ( it < stop_it && best_cost >= EPSILON )
1045  {
1046 #ifdef _DEBUG_FULL_
1047  std::cout << " ITERATION : " << it << " stop: " << stop_it << std::endl;
1048 #endif
1049  actualizeTabuCandidateList( m, it, nbOverlap, &candidateListSize, candidateBaseFactor, &candidateFactor, minCandidateListSize, reductionFactor, minTabuTSize, tabuFactor, &tenure, probSize );
1050  delta_min = DBL_MAX;
1051  choosed_feat = -1;
1052  choosed_label = -2;
1053  candidateId = -1;
1054 
1055  // foreach retained Candidate
1056  for ( i = 0; i < candidateListSize; i++ )
1057  {
1058  feat_id = candidateList[i]->feat_id;
1059  feat_sub_id = sub[feat_id];
1060  label_id = candidateList[i]->label_id;
1061 
1062  int oldPos = ( label_id < 0 ? -1 : label_id - featStartId[feat_sub_id] );
1063 
1064 
1065  p = featNbLp[feat_sub_id];
1066 
1067  /* label -1 means inactive feature */
1068  // foreach labelposition of feature minus the one in the solution
1069  for ( j = first_lp; j < p; j++ )
1070  {
1071  if ( j != oldPos )
1072  {
1073 
1074  if ( sol[feat_id] < 0 )
1075  {
1076  delta = -inactiveCost[feat_sub_id];
1077  }
1078  else
1079  {
1080  delta = -labelPositionCost[sol[feat_id]];
1081  delta -= nbOlap[sol[feat_id]] * ( inactiveCost[feat_sub_id] + mLabelPositions.at( label_id )->cost() );
1082  }
1083 
1084  if ( j >= 0 )
1085  {
1086  delta += labelPositionCost[featStartId[feat_sub_id] + j];
1087  delta += nbOlap[featStartId[feat_sub_id] + j] * ( inactiveCost[feat_sub_id] + mLabelPositions.at( featStartId[feat_sub_id] + j )->cost() );
1088  }
1089  else
1090  {
1091  delta += inactiveCost[feat_sub_id];
1092  }
1093 
1094 #ifdef _DEBUG_FULL_
1095  std::cout << " test moving " << oldPos << " to " << featStartId[feat_sub_id] + j << std::endl;
1096  std::cout << " new pos makes " << nbOlap[featStartId[feat_sub_id] + j] << " overlaps" << std::endl;
1097  std::cout << " delta is : " << delta << std::endl;
1098 #endif
1099  // move is authorized wether the feat isn't taboo or whether the move give a new best solution
1100  authorized = ( tabu_list[feat_id - borderSize] <= it ) || ( cur_cost + delta < best_cost );
1101 
1102 #ifdef _DEBUG_FULL_
1103  if ( tabu_list[feat_id - borderSize] > it )
1104  {
1105  std::cout << " Move is tabu" << std::endl;
1106  }
1107  else
1108  {
1109  std::cout << " Move is ok" << std::endl;
1110  }
1111 #endif
1112  if ( delta < delta_min && authorized )
1113  {
1114 #ifdef _DEBUG_FULL_
1115  std::cout << " keep move" << std::endl;
1116  std::cout << " choosed_feat: " << feat_id << std::endl;
1117  if ( j == -1 )
1118  std::cout << " choosed_label: " << j << std::endl;
1119  else
1120  std::cout << " choosed_label: " << featStartId[feat_sub_id] + j << std::endl;
1121 
1122  std::cout << " delta: " << delta << std::endl;
1123 #endif
1124 
1125  choosed_feat = feat_id;
1126 
1127  if ( j == -1 )
1128  choosed_label = -1;
1129  else
1130  choosed_label = featStartId[feat_sub_id] + j;
1131 
1132  delta_min = delta;
1133  candidateId = i;
1134  }
1135 #ifdef _DEBUG_FULL_
1136  else if ( !authorized )
1137  {
1138  std::cout << " tabu" << std::endl;
1139  }
1140  else
1141  {
1142  std::cout << " no good enough" << std::endl;
1143  }
1144 #endif
1145  }
1146  }
1147  }
1148 
1149  // if a modification has been retained
1150  if ( choosed_feat >= 0 )
1151  {
1152 #ifdef _DEBUG_FULL_
1153  std::cout << " Apply move:" << std::endl;
1154  std::cout << " feat: " << choosed_feat << std::endl;
1155  std::cout << " label: " << choosed_label << std::endl;
1156  std::cout << " delta: " << delta_min << std::endl << std::endl;
1157 #endif
1158  // update the solution and update tabu list
1159  int old_label = sol[choosed_feat];
1160 
1161  tabu_list[choosed_feat-borderSize] = it + tenure;
1162  sol[choosed_feat] = choosed_label;
1163  candidateList[candidateId]->label_id = choosed_label;
1164 
1165  if ( old_label != -1 )
1166  mLabelPositions.at( old_label )->removeFromIndex( candidates_subsol );
1167 
1168  /* re-compute all labelpositioncost that overlap with old an new label */
1169  double local_inactive = inactiveCost[sub[choosed_feat]];
1170 
1171  if ( choosed_label != -1 )
1172  {
1173  candidateList[candidateId]->cost = labelPositionCost[choosed_label];
1174  candidateList[candidateId]->nbOverlap = nbOlap[choosed_label];
1175  }
1176  else
1177  {
1178  candidateList[candidateId]->cost = local_inactive;
1179  candidateList[candidateId]->nbOverlap = 1;
1180  }
1181 
1182  cur_cost += delta_min;
1183 
1184  double amin[2];
1185  double amax[2];
1186  LabelPosition *lp;
1187 
1188  UpdateContext context;
1189 
1190  context.candidates = candidateListUnsorted;
1191  context.labelPositionCost = labelPositionCost;
1192  context.nbOlap = nbOlap;
1193  context.featWrap = featWrap;
1194  context.sol = sol;
1195  context.borderSize = borderSize;
1196 
1197  if ( old_label >= 0 )
1198  {
1199  lp = mLabelPositions.at( old_label );
1200 
1201  lp->getBoundingBox( amin, amax );
1202 
1203  context.diff_cost = -local_inactive - lp->cost();
1204  context.lp = lp;
1205 
1206  candidates->Search( amin, amax, updateCandidatesCost, &context );
1207  }
1208 
1209  if ( choosed_label >= 0 )
1210  {
1211  lp = mLabelPositions.at( choosed_label );
1212 
1213  lp->getBoundingBox( amin, amax );
1214 
1215  context.diff_cost = local_inactive + lp->cost();
1216  context.lp = lp;
1217 
1218 
1219  candidates->Search( amin, amax, updateCandidatesCost, &context );
1220 
1221  lp->insertIntoIndex( candidates_subsol );
1222  }
1223 
1224  sort(( void** ) candidateList, probSize, decreaseCost );
1225 
1226  if ( best_cost - cur_cost > EPSILON ) // new best sol
1227  {
1228  best_cost = cur_cost;
1229  memcpy( best_sol, sol, sizeof( int ) *( subSize ) );
1230  stop_it = it + itwImp;
1231  if ( stop_it > max_it )
1232  stop_it = max_it;
1233  }
1234  }
1235  else
1236  {
1237  /* no feature was selected : increase candidate list size*/
1238  actualizeCandidateList( nbOverlap, &candidateListSize, candidateBaseFactor,
1239  &candidateFactor, minCandidateListSize, growingFactor, probSize );
1240  }
1241 #ifdef _DEBUG_FULL_
1242  std::cout << "cost : " << cur_cost << std::endl;
1243  int nbover;
1244  std::cout << "computed cost: " << compute_subsolution_cost( part, sol, &nbover ) << std::endl;
1245  std::cout << "best_cost: " << best_cost << std::endl << std::endl;
1246 #endif
1247  it++;
1248  }
1249 
1250  memcpy( sol, best_sol, sizeof( int ) *( subSize ) );
1251 
1252  for ( i = 0; i < subSize; i++ )
1253  featWrap[sub[i]] = -1;
1254 
1255  for ( i = 0; i < probSize; i++ )
1256  delete candidateList[i];
1257 
1258  delete[] candidateList;
1259  delete[] candidateListUnsorted;
1260  delete[] best_sol;
1261  delete[] tabu_list;
1262 
1263  /* Return delta */
1264  return initial_cost - best_cost;
1265  }
1266 
1267 
1268 
1269 
1270 
1271  typedef struct
1272  {
1274  int *tmpsol;
1275  int *featWrap;
1276  int *feat;
1280  double *delta_tmp;
1281  double *inactiveCost;
1282 
1283  } ChainContext;
1284 
1285 
1286  bool chainCallback( LabelPosition *lp, void *context )
1287  {
1288  ChainContext *ctx = ( ChainContext* ) context;
1289 
1290 
1291 #ifdef _DEBUG_FULL_
1292  std::cout << "chainCallback" << std::endl;
1293  std::cout << " lp from rtree: " << lp << std::endl;
1294  std::cout << " lpid from rtree: " << lp->id << std::endl;
1295  std::cout << " lpco from rtree: " << lp->cost << std::endl;
1296  std::cout << " lp from context: " << ctx->lp << std::endl;
1297  std::cout << " lpid from context: " << ctx->lp->id << std::endl;
1298  std::cout << " lpco from context: " << ctx->lp->cost << std::endl;
1299  std::cout << " delta_tmp: " << ctx->delta_tmp << std::endl;
1300  std::cout << " *delta_tmp: " << *ctx->delta_tmp << std::endl;
1301  std::cout << " inactiveCost: " << ctx->inactiveCost << std::endl;
1302 #endif
1303 
1304 #ifdef _DEBUG_FULL_
1305  std::cout << "ejChCallBack: " << lp->id << "<->" << ctx->lp->id << std::endl;
1306 #endif
1307  if ( lp->isInConflict( ctx->lp ) )
1308  {
1309 #ifdef _DEBUG_FULL_
1310  std::cout << "ejChCallBack: " << lp->id << "<->" << ctx->lp->id << std::endl;
1311  std::cout << " Conflictual..." << std::endl;
1312 #endif
1313  int feat, rfeat;
1314  bool sub = ctx->featWrap != NULL;
1315 
1316  feat = lp->getProblemFeatureId();
1317  if ( sub )
1318  {
1319  rfeat = feat;
1320  feat = ctx->featWrap[feat];
1321  }
1322  else
1323  rfeat = feat;
1324 
1325 #ifdef _DEBUG_FULL_
1326  std::cout << " feat: " << feat << std::endl;
1327  std::cout << " sol: " << ctx->tmpsol[feat] << "/" << lp->id << std::endl;
1328  std::cout << " border:" << ctx->borderSize << std::endl;
1329 #endif
1330  if ( feat >= 0 && ctx->tmpsol[feat] == lp->getId() )
1331  {
1332  if ( sub && feat < ctx->borderSize )
1333  {
1334 #ifdef _DEBUG_FULL_
1335  std::cout << " Cannot touch border (throw) !" << std::endl;
1336 #endif
1337  throw - 2;
1338  }
1339  }
1340 
1341  // is there any cycles ?
1343  for ( cur = ctx->currentChain->begin(); cur != ctx->currentChain->end(); ++cur )
1344  {
1345  if (( *cur )->feat == feat )
1346  {
1347 #ifdef _DEBUG_FULL_
1348  std::cout << "Cycle into chain (throw) !" << std::endl;
1349 #endif
1350  throw - 1;
1351  }
1352  }
1353 
1354  if ( !ctx->conflicts->contains( feat ) )
1355  {
1356  ctx->conflicts->append( feat );
1357  *ctx->delta_tmp += lp->cost() + ctx->inactiveCost[rfeat];
1358  }
1359  }
1360  return true;
1361  }
1362 
1363  inline Chain *Problem::chain( SubPart *part, int seed )
1364  {
1365 
1366  int i;
1367  int j;
1368 
1369  int lid;
1370 
1371  //int probSize = part->probSize;
1372  int borderSize = part->borderSize;
1373  int subSize = part->subSize;
1374  int *sub = part->sub;
1375  int *sol = part->sol;
1376  int subseed;
1377 
1378  double delta;
1379  double delta_min;
1380  double delta_best = DBL_MAX;
1381  double delta_tmp;
1382 
1383  int next_seed;
1384  int retainedLabel;
1385  Chain *retainedChain = NULL;
1386 
1387  int max_degree = pal->ejChainDeg;
1388 
1389  int seedNbLp;
1390 
1392  QLinkedList<int> *conflicts = new QLinkedList<int>;
1393 
1394  int *tmpsol = new int[subSize];
1395  memcpy( tmpsol, sol, sizeof( int ) *subSize );
1396 
1397  LabelPosition *lp;
1398  double amin[2];
1399  double amax[2];
1400 
1401  ChainContext context;
1402  context.featWrap = featWrap;
1403  context.borderSize = borderSize;
1404  context.tmpsol = tmpsol;
1405  context.inactiveCost = inactiveCost;
1406  context.feat = NULL;
1407  context.currentChain = currentChain;
1408  context.conflicts = conflicts;
1409  context.delta_tmp = &delta_tmp;
1410 
1411  delta = 0;
1412  while ( seed != -1 )
1413  {
1414  subseed = sub[seed];
1415  seedNbLp = featNbLp[subseed];
1416  delta_min = DBL_MAX;
1417 #ifdef _DEBUG_FULL_
1418  std::cout << "New seed: " << seed << "/" << subseed << std::endl;
1419 #endif
1420  next_seed = -1;
1421  retainedLabel = -2;
1422 
1423 
1424  if ( tmpsol[seed] == -1 )
1425  delta -= inactiveCost[subseed];
1426  else
1427  delta -= mLabelPositions.at( tmpsol[seed] )->cost();
1428 
1429  // TODO modify to handle displayAll param
1430  for ( i = -1; i < seedNbLp; i++ )
1431  {
1432  try
1433  {
1434  // Skip active label !
1435  if ( !( tmpsol[seed] == -1 && i == -1 ) && i + featStartId[subseed] != tmpsol[seed] )
1436  {
1437  if ( i != -1 )
1438  {
1439  lid = featStartId[subseed] + i;
1440  delta_tmp = delta;
1441 
1442  lp = mLabelPositions.at( lid );
1443 
1444  // evaluate conflicts graph in solution after moving seed's label
1445  lp->getBoundingBox( amin, amax );
1446 
1447  context.lp = lp;
1448 
1449  if ( conflicts->size() != 0 )
1450  std::cerr << "Conflicts not empty !!" << std::endl;
1451 
1452  // search ative conflicts and count them
1453  candidates_subsol->Search( amin, amax, chainCallback, ( void* ) &context );
1454 
1455 #ifdef _DEBUG_FULL_
1456  std::cout << "Conflicts:" << conflicts->size() << std::endl;
1457 #endif
1458  // no conflict -> end of chain
1459  if ( conflicts->size() == 0 )
1460  {
1461  if ( !retainedChain || delta + lp->cost() < delta_best )
1462  {
1463 
1464  if ( retainedChain )
1465  {
1466  delete[] retainedChain->label;
1467  delete[] retainedChain->feat;
1468  }
1469  else
1470  {
1471  retainedChain = new Chain(); // HERE
1472  }
1473 
1474  delta_best = delta + lp->cost();
1475 
1476  retainedChain->degree = currentChain->size() + 1;
1477  retainedChain->feat = new int[retainedChain->degree]; // HERE
1478  retainedChain->label = new int[retainedChain->degree]; // HERE
1479  QLinkedList< ElemTrans* >::iterator current = currentChain->begin();
1480  ElemTrans* move;
1481  j = 0;
1482  while ( current != currentChain->end() )
1483  {
1484  move = *current;
1485  retainedChain->feat[j] = move->feat;
1486  retainedChain->label[j] = move->new_label;
1487  ++current;
1488  ++j;
1489  }
1490  retainedChain->feat[j] = seed;
1491  retainedChain->label[j] = lid;
1492  retainedChain->delta = delta + mLabelPositions.at( retainedChain->label[j] )->cost();
1493  }
1494  }
1495 
1496  // another feature can be ejected
1497  else if ( conflicts->size() == 1 )
1498  {
1499  if ( delta_tmp < delta_min )
1500  {
1501  delta_min = delta_tmp;
1502  retainedLabel = lid;
1503  next_seed = conflicts->takeFirst();
1504  }
1505  else
1506  {
1507  conflicts->takeFirst();
1508  }
1509  }
1510  else
1511  {
1512 
1513  // A lot of conflict : make them inactive and store chain
1514  Chain *newChain = new Chain(); // HERE
1515  newChain->degree = currentChain->size() + 1 + conflicts->size();
1516  newChain->feat = new int[newChain->degree]; // HERE
1517  newChain->label = new int[newChain->degree]; // HERE
1518  QLinkedList<ElemTrans*>::iterator current = currentChain->begin();
1519  ElemTrans* move;
1520  j = 0;
1521  while ( current != currentChain->end() )
1522  {
1523  move = *current;
1524  newChain->feat[j] = move->feat;
1525  newChain->label[j] = move->new_label;
1526  ++current;
1527  ++j;
1528  }
1529 
1530  newChain->feat[j] = seed;
1531  newChain->label[j] = lid;
1532  newChain->delta = delta + mLabelPositions.at( newChain->label[j] )->cost();
1533  j++;
1534 
1535 
1536  while ( conflicts->size() > 0 )
1537  {
1538  int ftid = conflicts->takeFirst();
1539  newChain->feat[j] = ftid;
1540  newChain->label[j] = -1;
1541  newChain->delta += inactiveCost[sub[ftid]];
1542  j++;
1543  }
1544 
1545  if ( newChain->delta < delta_best )
1546  {
1547  if ( retainedChain )
1548  delete_chain( retainedChain );
1549 
1550  delta_best = newChain->delta;
1551  retainedChain = newChain;
1552  }
1553  else
1554  {
1555  delete_chain( newChain );
1556  }
1557  }
1558  }
1559  else // Current label == -1 end of chain ...
1560  {
1561  if ( !retainedChain || delta + inactiveCost[subseed] < delta_best )
1562  {
1563  if ( retainedChain )
1564  {
1565  delete[] retainedChain->label;
1566  delete[] retainedChain->feat;
1567  }
1568  else
1569  retainedChain = new Chain(); // HERE
1570 
1571  delta_best = delta + inactiveCost[subseed];
1572 
1573  retainedChain->degree = currentChain->size() + 1;
1574  retainedChain->feat = new int[retainedChain->degree]; // HERE
1575  retainedChain->label = new int[retainedChain->degree]; // HERE
1576  QLinkedList<ElemTrans*>::iterator current = currentChain->begin();
1577  ElemTrans* move;
1578  j = 0;
1579  while ( current != currentChain->end() )
1580  {
1581  move = *current;
1582  retainedChain->feat[j] = move->feat;
1583  retainedChain->label[j] = move->new_label;
1584  ++current;
1585  ++j;
1586  }
1587  retainedChain->feat[j] = seed;
1588  retainedChain->label[j] = -1;
1589  retainedChain->delta = delta + inactiveCost[subseed];
1590  }
1591  }
1592  }
1593  }
1594  catch ( int i )
1595  {
1596 #ifdef _DEBUG_FULL_
1597  std::cout << "catch int " << i << std::endl;
1598 #else
1599  Q_UNUSED( i );
1600 #endif
1601  conflicts->clear();
1602  }
1603  } // end foreach labelposition
1604 
1605  if ( next_seed == -1 )
1606  {
1607  seed = -1;
1608  }
1609  else if ( currentChain->size() > max_degree )
1610  {
1611 #ifdef _VERBOSE_
1612  std::cout << "Max degree reached !! (" << max_degree << ")" << std::endl;
1613 #endif
1614  seed = -1;
1615  }
1616  else
1617  {
1618  ElemTrans *et = new ElemTrans();
1619  et->feat = seed;
1620  et->old_label = tmpsol[seed];
1621  et->new_label = retainedLabel;
1622  currentChain->append( et );
1623 
1624  if ( et->old_label != -1 )
1625  {
1626  mLabelPositions.at( et->old_label )->removeFromIndex( candidates_subsol );
1627  }
1628 
1629  if ( et->new_label != -1 )
1630  {
1631  mLabelPositions.at( et->new_label )->insertIntoIndex( candidates_subsol );
1632  }
1633 
1634  tmpsol[seed] = retainedLabel;
1635  delta += mLabelPositions.at( retainedLabel )->cost();
1636  seed = next_seed;
1637  }
1638  }
1639 
1640  while ( currentChain->size() > 0 )
1641  {
1642  ElemTrans* et = currentChain->takeFirst();
1643 
1644  if ( et->new_label != -1 )
1645  {
1646  mLabelPositions.at( et->new_label )->removeFromIndex( candidates_subsol );
1647  }
1648 
1649  if ( et->old_label != -1 )
1650  {
1651  mLabelPositions.at( et->old_label )->insertIntoIndex( candidates_subsol );
1652  }
1653 
1654  delete et;
1655  }
1656  delete currentChain;
1657 
1658  delete[] tmpsol;
1659  delete conflicts;
1660 
1661 
1662  return retainedChain;
1663  }
1664 
1665 
1666  inline Chain *Problem::chain( int seed )
1667  {
1668 
1669  int i;
1670  int j;
1671 
1672  int lid;
1673 
1674  double delta;
1675  double delta_min;
1676  double delta_best = DBL_MAX;
1677  double delta_tmp;
1678 
1679  int next_seed;
1680  int retainedLabel;
1681  Chain *retainedChain = NULL;
1682 
1683  int max_degree = pal->ejChainDeg;
1684 
1685  int seedNbLp;
1686 
1688  QLinkedList<int> *conflicts = new QLinkedList<int>;
1689 
1690  int *tmpsol = new int[nbft];
1691  memcpy( tmpsol, sol->s, sizeof( int ) *nbft );
1692 
1693  LabelPosition *lp;
1694  double amin[2];
1695  double amax[2];
1696 
1697  ChainContext context;
1698  context.featWrap = NULL;
1699  context.borderSize = 0;
1700  context.tmpsol = tmpsol;
1701  context.inactiveCost = inactiveCost;
1702  context.feat = NULL;
1703  context.currentChain = currentChain;
1704  context.conflicts = conflicts;
1705  context.delta_tmp = &delta_tmp;
1706 
1707  delta = 0;
1708  while ( seed != -1 )
1709  {
1710  seedNbLp = featNbLp[seed];
1711  delta_min = DBL_MAX;
1712 
1713  next_seed = -1;
1714  retainedLabel = -2;
1715 
1716  // sol[seed] is ejected
1717  if ( tmpsol[seed] == -1 )
1718  delta -= inactiveCost[seed];
1719  else
1720  delta -= mLabelPositions.at( tmpsol[seed] )->cost();
1721 
1722  for ( i = -1; i < seedNbLp; i++ )
1723  {
1724  try
1725  {
1726  // Skip active label !
1727  if ( !( tmpsol[seed] == -1 && i == -1 ) && i + featStartId[seed] != tmpsol[seed] )
1728  {
1729  if ( i != -1 ) // new_label
1730  {
1731  lid = featStartId[seed] + i;
1732  delta_tmp = delta;
1733 
1734  lp = mLabelPositions.at( lid );
1735 
1736  // evaluate conflicts graph in solution after moving seed's label
1737  lp->getBoundingBox( amin, amax );
1738 
1739  context.lp = lp;
1740  if ( conflicts->size() != 0 )
1741  std::cerr << "Conflicts not empty" << std::endl;
1742 
1743  candidates_sol->Search( amin, amax, chainCallback, ( void* ) &context );
1744 
1745  // no conflict -> end of chain
1746  if ( conflicts->size() == 0 )
1747  {
1748  if ( !retainedChain || delta + lp->cost() < delta_best )
1749  {
1750  if ( retainedChain )
1751  {
1752  delete[] retainedChain->label;
1753  delete[] retainedChain->feat;
1754  }
1755  else
1756  {
1757  retainedChain = new Chain();
1758  }
1759 
1760  delta_best = delta + lp->cost();
1761 
1762  retainedChain->degree = currentChain->size() + 1;
1763  retainedChain->feat = new int[retainedChain->degree];
1764  retainedChain->label = new int[retainedChain->degree];
1765  QLinkedList<ElemTrans*>::iterator current = currentChain->begin();
1766  ElemTrans* move;
1767  j = 0;
1768  while ( current != currentChain->end() )
1769  {
1770  move = *current;
1771  retainedChain->feat[j] = move->feat;
1772  retainedChain->label[j] = move->new_label;
1773  ++current;
1774  ++j;
1775  }
1776  retainedChain->feat[j] = seed;
1777  retainedChain->label[j] = lid;
1778  retainedChain->delta = delta + lp->cost();
1779  }
1780  }
1781 
1782  // another feature can be ejected
1783  else if ( conflicts->size() == 1 )
1784  {
1785  if ( delta_tmp < delta_min )
1786  {
1787  delta_min = delta_tmp;
1788  retainedLabel = lid;
1789  next_seed = conflicts->takeFirst();
1790  }
1791  else
1792  {
1793  conflicts->takeFirst();
1794  }
1795  }
1796  else
1797  {
1798 
1799  // A lot of conflict : make them inactive and store chain
1800  Chain *newChain = new Chain();
1801  newChain->degree = currentChain->size() + 1 + conflicts->size();
1802  newChain->feat = new int[newChain->degree];
1803  newChain->label = new int[newChain->degree];
1804  QLinkedList<ElemTrans*>::iterator current = currentChain->begin();
1805  ElemTrans* move;
1806  j = 0;
1807 
1808  while ( current != currentChain->end() )
1809  {
1810  move = *current;
1811  newChain->feat[j] = move->feat;
1812  newChain->label[j] = move->new_label;
1813  ++current;
1814  ++j;
1815  }
1816 
1817  // add the current candidates into the chain
1818  newChain->feat[j] = seed;
1819  newChain->label[j] = lid;
1820  newChain->delta = delta + mLabelPositions.at( newChain->label[j] )->cost();
1821  j++;
1822 
1823  // hide all conflictual candidates
1824  while ( conflicts->size() > 0 )
1825  {
1826  int ftid = conflicts->takeFirst();
1827  newChain->feat[j] = ftid;
1828  newChain->label[j] = -1;
1829  newChain->delta += inactiveCost[ftid];
1830  j++;
1831  }
1832 
1833  if ( newChain->delta < delta_best )
1834  {
1835  if ( retainedChain )
1836  delete_chain( retainedChain );
1837 
1838  delta_best = newChain->delta;
1839  retainedChain = newChain;
1840  }
1841  else
1842  {
1843  delete_chain( newChain );
1844  }
1845  }
1846 
1847  }
1848  else // Current label == -1 end of chain ...
1849  {
1850  if ( !retainedChain || delta + inactiveCost[seed] < delta_best )
1851  {
1852  if ( retainedChain )
1853  {
1854  delete[] retainedChain->label;
1855  delete[] retainedChain->feat;
1856  }
1857  else
1858  retainedChain = new Chain();
1859 
1860  delta_best = delta + inactiveCost[seed];
1861 
1862  retainedChain->degree = currentChain->size() + 1;
1863  retainedChain->feat = new int[retainedChain->degree];
1864  retainedChain->label = new int[retainedChain->degree];
1865  QLinkedList<ElemTrans*>::iterator current = currentChain->begin();
1866  ElemTrans* move;
1867  j = 0;
1868  while ( current != currentChain->end() )
1869  {
1870  move = *current;
1871  retainedChain->feat[j] = move->feat;
1872  retainedChain->label[j] = move->new_label;
1873  ++current;
1874  ++j;
1875  }
1876  retainedChain->feat[j] = seed;
1877  retainedChain->label[j] = -1;
1878  retainedChain->delta = delta + inactiveCost[seed];
1879  }
1880  }
1881  }
1882  }
1883  catch ( int i )
1884  {
1885 #ifdef _DEBUG_FULL_
1886  std::cout << "catch Cycle in chain" << std::endl;
1887 #else
1888  Q_UNUSED( i );
1889 #endif
1890  conflicts->clear();
1891  }
1892  } // end foreach labelposition
1893 
1894  if ( next_seed == -1 )
1895  {
1896  seed = -1;
1897  }
1898  else if ( currentChain->size() > max_degree )
1899  {
1900  std::cout << "Max degree reached !! (" << max_degree << ")" << std::endl;
1901  seed = -1;
1902  }
1903  else
1904  {
1905  ElemTrans *et = new ElemTrans();
1906  et->feat = seed;
1907  et->old_label = tmpsol[seed];
1908  et->new_label = retainedLabel;
1909  currentChain->append( et );
1910 
1911  if ( et->old_label != -1 )
1912  {
1913  mLabelPositions.at( et->old_label )->removeFromIndex( candidates_sol );
1914  }
1915 
1916  if ( et->new_label != -1 )
1917  {
1918  mLabelPositions.at( et->new_label )->insertIntoIndex( candidates_sol );
1919  }
1920 
1921 
1922  tmpsol[seed] = retainedLabel;
1923  delta += mLabelPositions.at( retainedLabel )->cost();
1924  seed = next_seed;
1925  }
1926  }
1927 
1928 
1929  while ( currentChain->size() > 0 )
1930  {
1931  ElemTrans* et = currentChain->takeFirst();
1932 
1933  if ( et->new_label != -1 )
1934  {
1935  mLabelPositions.at( et->new_label )->removeFromIndex( candidates_sol );
1936  }
1937 
1938  if ( et->old_label != -1 )
1939  {
1940  mLabelPositions.at( et->old_label )->insertIntoIndex( candidates_sol );
1941  }
1942 
1943  delete et;
1944  }
1945  delete currentChain;
1946 
1947  delete[] tmpsol;
1948  delete conflicts;
1949 
1950 
1951  return retainedChain;
1952  }
1953 
1955  {
1956  int i;
1957  //int j;
1958 
1959  int probSize = part->probSize;
1960  int borderSize = part->borderSize;
1961  int subSize = part->subSize;
1962  int *sub = part->sub;
1963  int *sol = part->sol;
1964 
1965  int *best_sol = new int[subSize];
1966 
1967  for ( i = 0; i < subSize; i++ )
1968  {
1969  featWrap[sub[i]] = i;
1970  best_sol[i] = sol[i];
1971  }
1972 
1973  double initial_cost;
1974  double cur_cost = 0;
1975  double best_cost = 0;
1976 
1977  // int nbOverlap = 0;
1978 
1979  int seed;
1980 
1981  int featOv;
1982 
1983  int lid;
1984  int fid;
1985 
1986  int *tabu_list = new int[subSize];
1987 
1988  Chain *current_chain = NULL;
1989 
1990  //int itC;
1991 
1992  int it;
1993  int stop_it;
1994  int maxit;
1995  int itwimp; // iteration without improvment
1996 
1997  int tenure = pal->tenure;
1998 
1999  for ( i = 0; i < subSize; i++ )
2000  {
2001  cur_cost += compute_feature_cost( part, i, sol[i], &featOv );
2002  // nbOverlap += featOv;
2003  }
2004 
2005  initial_cost = cur_cost;
2006  best_cost = cur_cost;
2007 
2008  it = 0;
2009 
2010  maxit = probSize * pal->tabuMaxIt;
2011 
2012  itwimp = probSize * pal->tabuMinIt;
2013 
2014  stop_it = itwimp;
2015 
2016  // feature on border always are tabu
2017  for ( i = 0; i < borderSize; i++ )
2018  tabu_list[i] = maxit; // border always are taboo
2019 
2020  for ( i = 0; i < probSize; i++ )
2021  tabu_list[i+borderSize] = -1; // others aren't
2022 
2023  while ( it < stop_it )
2024  {
2025  seed = ( it % probSize ) + borderSize;
2026 
2027  current_chain = chain( part, seed );
2028  if ( current_chain )
2029  {
2030 
2031  /* we accept a modification only if the seed is not tabu or
2032  * if the nmodification will generate a new best solution */
2033  if ( tabu_list[seed] < it || ( cur_cost + current_chain->delta ) - best_cost < 0.0 )
2034  {
2035 
2036  for ( i = 0; i < current_chain->degree; i++ )
2037  {
2038  fid = current_chain->feat[i];
2039  lid = current_chain->label[i];
2040 
2041  if ( sol[fid] >= 0 )
2042  {
2043  mLabelPositions.at( sol[fid] )->removeFromIndex( candidates_subsol );
2044  }
2045  sol[fid] = lid;
2046 
2047  if ( sol[fid] >= 0 )
2048  {
2049  mLabelPositions.at( lid )->insertIntoIndex( candidates_subsol );
2050  }
2051 
2052  tabu_list[fid] = it + tenure;
2053  }
2054 
2055  cur_cost += current_chain->delta;
2056 #ifdef _DEBUG_FULL_
2057  std::cout << "cur->cost: " << cur_cost << std::endl;
2058  int kov;
2059  std::cout << "computed cost: " << compute_subsolution_cost( part, sol, &kov ) << std::endl << std::endl;
2060 #endif
2061  /* check if new solution is a new best solution */
2062  if ( best_cost - cur_cost > EPSILON )
2063  {
2064  best_cost = cur_cost;
2065  memcpy( best_sol, sol, sizeof( int ) *subSize );
2066 
2067  stop_it = ( it + itwimp > maxit ? maxit : it + itwimp );
2068  }
2069  }
2070  delete_chain( current_chain );
2071  }
2072  it++;
2073  }
2074 
2075  memcpy( sol, best_sol, sizeof( int ) *subSize );
2076 
2077  /*
2078  for (i=borderSize;i<subSize;i++){
2079  chain = chain (part, i);
2080  if (chain){
2081  if (chain->delta < 0.0){
2082  best_cost += chain->delta;
2083  for (j=0;j<chain->degree;j++){
2084  fid = chain->feat[j];
2085  lid = chain->label[j];
2086  sol[fid] = lid;
2087  }
2088  }
2089 
2090  delete_chain(chain);
2091  }
2092  }
2093  */
2094 
2095  for ( i = 0; i < subSize; i++ )
2096  featWrap[sub[i]] = -1;
2097 
2098  delete[] best_sol;
2099  delete[] tabu_list;
2100 
2101 
2102  return initial_cost - best_cost;
2103  }
2104 
2106  {
2107  int i;
2108 
2109  int probSize = part->probSize;
2110  int borderSize = part->borderSize;
2111  int subSize = part->subSize;
2112  int *sub = part->sub;
2113  int *sol = part->sol;
2114 
2115  int *best_sol = new int[subSize];
2116 
2117  for ( i = 0; i < subSize; i++ )
2118  {
2119  featWrap[sub[i]] = i;
2120  }
2121 
2122  double initial_cost;
2123  double cur_cost = 0;
2124  double best_cost = 0;
2125 
2126  // int nbOverlap = 0;
2127 
2128  int seed;
2129 
2130  int featOv;
2131 
2132  int lid;
2133  int fid;
2134 
2135  int *tabu_list = new int[subSize];
2136 
2137  Chain *retainedChain = NULL;
2138  Chain *current_chain = NULL;
2139 
2140  int itC;
2141 
2142  int it;
2143  int stop_it;
2144  int maxit;
2145  int itwimp;
2146 
2147  int tenure = pal->tenure;
2148 
2149  //int deltaIt = 0;
2150 
2151  Triple **candidates = new Triple*[probSize];
2152  Triple **candidatesUnsorted = new Triple*[probSize];
2153 
2154  for ( i = 0; i < subSize; i++ )
2155  {
2156  cur_cost += compute_feature_cost( part, i, sol[i], &featOv );
2157  // nbOverlap += featOv;
2158  }
2159 
2160  initial_cost = cur_cost;
2161  best_cost = cur_cost;
2162 
2163  it = 0;
2164 
2165  maxit = probSize * pal->tabuMaxIt;
2166 
2167  itwimp = probSize * pal->tabuMinIt;
2168 
2169  stop_it = itwimp;
2170 
2171  for ( i = 0; i < borderSize; i++ )
2172  tabu_list[i] = maxit;
2173 
2174 
2175  for ( i = 0; i < probSize; i++ )
2176  {
2177  tabu_list[i+borderSize] = -1;
2178 
2179  candidates[i] = new Triple();
2180  candidates[i]->feat_id = i + borderSize;
2181  candidatesUnsorted[i] = candidates[i];
2182 
2183  candidates[i]->cost = ( sol[i+borderSize] == -1 ? inactiveCost[i+borderSize] : mLabelPositions.at( sol[i+borderSize] )->cost() );
2184  }
2185 
2186  sort(( void** ) candidates, probSize, decreaseCost );
2187 
2188  int candidateListSize;
2189  candidateListSize = int ( pal->candListSize * ( double ) probSize + 0.5 );
2190 
2191  if ( candidateListSize > probSize )
2192  candidateListSize = probSize;
2193 
2194 #ifdef _DEBUG_FULL_
2195  int nbOv;
2196  std::cout << std::endl << "Initial solution cost " << cur_cost << std::endl;
2197  std::cout << "Computed: " << compute_subsolution_cost( part, sol, &nbOv );
2198  std::cout << "NbOverlap: " << nbOv << std::endl;
2199 #endif
2200  while ( it < stop_it )
2201  {
2202  retainedChain = NULL;
2203 
2204 #ifdef _DEBUG_FULL_
2205  std::cout << std::endl << std::endl << candidateListSize << std::endl;
2206 #endif
2207  for ( itC = 0; itC < candidateListSize; itC++ )
2208  {
2209  seed = candidates[itC]->feat_id;
2210 
2211 #ifdef _DEBUG_FULL_
2212  std::cout << "new candidates:" << std::endl;
2213 #endif
2214  current_chain = chain( part, seed );
2215 
2216 #ifdef _DEBUG_FULL_
2217  std::cout << "get chain:" << current_chain << std::endl;
2218 #endif
2219  if ( current_chain )
2220  {
2221  // seed is not taboo or chain give us a new best solution
2222  if ( tabu_list[seed] < it || ( cur_cost + current_chain->delta ) - best_cost < 0.0 )
2223  {
2224  if ( !retainedChain )
2225  {
2226  retainedChain = current_chain;
2227 #ifdef _DEBUG_FULL_
2228  std::cout << "New chain, delta = " << current_chain->delta << std::endl;
2229 #endif
2230  }
2231  else if ( current_chain->delta - retainedChain->delta < EPSILON )
2232  {
2233  delete_chain( retainedChain );
2234  retainedChain = current_chain;
2235 #ifdef _DEBUG_FULL_
2236  std::cout << "New best chain, delta = " << current_chain->delta << std::endl;
2237 #endif
2238  }
2239  else
2240  {
2241 #ifdef _DEBUG_FULL_
2242  std::cout << "chain rejected..." << std::endl;
2243 #endif
2244  delete_chain( current_chain );
2245  }
2246  }
2247  else
2248  {
2249 #ifdef _DEBUG_FULL_
2250  std::cout << "chain rejected, tabu and/or delta = " << current_chain->delta << std::endl;
2251 #endif
2252  delete_chain( current_chain );
2253  }
2254  }
2255 #ifdef _DEBUG_FULL_
2256  else
2257  {
2258  std::cout << "no chain !!" << std::endl;
2259  }
2260 #endif
2261 
2262  } // end foreach candidates
2263 
2264  if ( retainedChain /*&& retainedChain->delta <= 0*/ )
2265  {
2266 #ifdef _DEBUG_FULL_
2267  std::cout << it << " retained chain's degree: " << retainedChain->degree;
2268  std::cout << " and delta: " << retainedChain->delta << std::endl;
2269 #endif
2270 
2271  for ( i = 0; i < retainedChain->degree; i++ )
2272  {
2273  fid = retainedChain->feat[i];
2274  lid = retainedChain->label[i];
2275 #ifdef _DEBUG_FULL_
2276  std::cout << fid << ": " << sol[fid] << " -> " << lid << " Costs: " << inactiveCost[fid] << ":" << ( sol[fid] != -1 ? labelpositions[sol[fid]]->cost : -1 ) << ":" << ( lid != -1 ? labelpositions[lid]->cost : -1 ) << std::endl;
2277 #endif
2278 
2279  if ( sol[fid] >= 0 )
2280  mLabelPositions.at( sol[fid] )->removeFromIndex( candidates_subsol );
2281 
2282  sol[fid] = lid;
2283 
2284  if ( lid >= 0 )
2285  mLabelPositions.at( lid )->insertIntoIndex( candidates_subsol );
2286 
2287  tabu_list[fid] = it + tenure;
2288 #ifdef _DEBUG_FULL_
2289  std::cout << "fid: " << fid << std::endl;
2290  std::cout << "borderSize: " << borderSize << std::endl;
2291  std::cout << "lid: " << lid << std::endl;
2292  std::cout << "sub[fid]: " << sub[fid] << std::endl;
2293  std::cout << "inactivecosr[sub[fid]]: " << inactiveCost[sub[fid]] << std::endl;
2294  if ( lid > -1 )
2295  {
2296  std::cout << "label[lid]: " << labelpositions[lid] << std::endl;
2297  std::cout << "label[lid]->cost: " << labelpositions[lid]->cost << std::endl;
2298  }
2299 #endif
2300  candidatesUnsorted[fid-borderSize]->cost = ( lid == -1 ? inactiveCost[sub[fid]] : mLabelPositions.at( lid )->cost() );
2301 
2302  }
2303 
2304 #ifdef _DEBUG_FULL_
2305  std::cout << std::endl;
2306 #endif
2307 
2308  //std::cout << "old solution cost:" << cur_cost << std::endl;
2309 
2310  cur_cost += retainedChain->delta;
2311 
2312  //std::cout << "new solution cost:" << cur_cost << std::endl;
2313  //int nbOv;
2314  //std::cout << "computed solution cost:" << compute_subsolution_cost (part, sol, &nbOv) << std::endl;
2315  //std::cout << "Overlap: " << nbOv << std::endl;
2316 
2317  delete_chain( retainedChain );
2318 
2319  if ( best_cost - cur_cost > EPSILON )
2320  {
2321 #ifdef _DEBUG_FULL_
2322  std::cout << "new_best" << std::endl;
2323 #endif
2324  best_cost = cur_cost;
2325  memcpy( best_sol, sol, sizeof( int ) * subSize );
2326 
2327  stop_it = ( it + itwimp > maxit ? maxit : it + itwimp );
2328  }
2329  sort(( void** ) candidates, probSize, decreaseCost );
2330 
2331 
2332  }
2333 #ifdef _DEBUG_FULL_
2334  else
2335  {
2336  std::cout << it << " no chain" << std::endl << std::endl;
2337  }
2338 #endif
2339  it++;
2340  }
2341 
2342  memcpy( sol, best_sol, sizeof( int ) *subSize );
2343 
2344  for ( i = 0; i < probSize; i++ )
2345  delete candidates[i];
2346 
2347  delete[] candidates;
2348  delete[] candidatesUnsorted;
2349 
2350  for ( i = 0; i < subSize; i++ )
2351  featWrap[sub[i]] = -1;
2352 
2353  delete[] best_sol;
2354  delete[] tabu_list;
2355 
2356 
2357  return initial_cost - best_cost;
2358  }
2359 
2360  bool checkCallback( LabelPosition *lp, void *ctx )
2361  {
2363  list->append( lp );
2364 
2365  return true;
2366  }
2367 
2368 
2369  void Problem::check_solution()
2370  {
2371  int *solution = new int[nbft];
2372 
2373  double amin[2];
2374  double amax[2];
2375 
2376  amin[0] = bbox[0];
2377  amin[1] = bbox[1];
2378  amax[0] = bbox[2];
2379  amax[1] = bbox[3];
2380 
2382 
2383  candidates_sol->Search( amin, amax, checkCallback, ( void* ) list );
2384 
2385  std::cerr << "Check Solution" << std::endl;
2386 
2387  int i;
2388  int nbActive = 0;
2389  for ( i = 0; i < nbft; i++ )
2390  {
2391  solution[i] = -1;
2392  if ( sol->s[i] >= 0 )
2393  nbActive++;
2394  }
2395 
2396  if ( list->size() != nbActive )
2397  {
2398  std::cerr << "Error in solution !!!!" << std::endl;
2399  }
2400 
2401  while ( list->size() > 0 )
2402  {
2403  LabelPosition *lp = list->takeFirst();
2404  int probFeatId = lp->getProblemFeatureId();
2405  if ( solution[probFeatId] >= 0 )
2406  {
2407  std::cerr << "Doublon : " << probFeatId << " "
2408  << solution[probFeatId] << "<->"
2409  << lp->getId() << std::endl;
2410  }
2411 
2412  solution[probFeatId] = lp->getId();
2413  //std::cout << "lp->id:" << lp->id <<;
2414  }
2415 
2416  for ( i = 0; i < nbft; i++ )
2417  {
2418  if ( solution[i] != sol->s[i] )
2419  {
2420  std::cerr << "Feat " << i << " : " << solution[i] << "<-->" << sol->s[i] << std::endl;
2421  }
2422  }
2423 
2424  delete [] solution;
2425  }
2426 
2427  typedef struct _nokContext
2428  {
2430  bool *ok;
2431  int *wrap;
2432  } NokContext;
2433 
2434  bool nokCallback( LabelPosition *lp, void *context )
2435  {
2436 
2437  LabelPosition *lp2 = (( NokContext* ) context )->lp;
2438  bool *ok = (( NokContext* ) context )->ok;
2439  int *wrap = (( NokContext* ) context )->wrap;
2440 
2441  if ( lp2->isInConflict( lp ) )
2442  {
2443  if ( wrap )
2444  {
2445  ok[wrap[lp->getProblemFeatureId()]] = false;
2446  }
2447  else
2448  {
2449  ok[lp->getProblemFeatureId()] = false;
2450  }
2451  }
2452 
2453  return true;
2454  }
2455 
2457  {
2458 
2459  if ( nbft == 0 )
2460  return;
2461 
2462  int i;
2463 
2464  int seed;
2465  bool *ok = new bool[nbft];
2466 
2467  int fid;
2468  int lid;
2469 
2470 #ifdef _VERBOSE_
2471  clock_t start_time = clock();
2472  clock_t init_sol_time;
2473  clock_t search_time;
2474 #endif
2475 
2476  int popit = 0;
2477 
2478  double amin[2];
2479  double amax[2];
2480 
2481  NokContext context;
2482 
2483  context.ok = ok;
2484  context.wrap = NULL;
2485 
2486  Chain *retainedChain;
2487 
2488  featWrap = NULL;
2489 
2490  for ( i = 0; i < nbft; i++ )
2491  {
2492  ok[i] = false;
2493  }
2494 
2495  //initialization();
2496  init_sol_falp();
2497 
2498  //check_solution();
2499 
2500 #ifdef _VERBOSE_
2501  std::cout << " Compute initial solution: " << ( double )(( init_sol_time = clock() ) - start_time ) / ( double ) CLOCKS_PER_SEC;
2502 #endif
2503 
2504  solution_cost();
2505 
2506 
2507 #ifdef _VERBOSE_
2508  std::cerr << "\t" << sol->cost << "\t" << nbActive << "\t" << ( double ) nbActive / ( double ) nbft;
2509  std::cout << " (solution cost: " << sol->cost << ", nbDisplayed: " << nbActive << "(" << double( nbActive ) / nbft << "%)" << std::endl;
2510 #endif
2511  int iter = 0;
2512 
2513  while ( true )
2514  {
2515 
2516  //check_solution();
2517 
2518  for ( seed = ( iter + 1 ) % nbft;
2519  ok[seed] && seed != iter;
2520  seed = ( seed + 1 ) % nbft )
2521  ;
2522 
2523  // All seeds are OK
2524  if ( seed == iter )
2525  {
2526  break;
2527  }
2528 
2529  iter = ( iter + 1 ) % nbft;
2530 
2531 #ifdef _DEBUG_FULL_
2532  std::cout << "Seed for it " << popit << " is " << seed << std::endl;
2533 #endif
2534 
2535  retainedChain = chain( seed );
2536 
2537  if ( retainedChain && retainedChain->delta < - EPSILON )
2538  {
2539 #ifdef _DEBUG_FULL_
2540  std::cout << "chain's degree & delta : " << retainedChain->degree << " " << retainedChain->delta << std::endl;
2541 #endif
2542  // apply modification
2543  for ( i = 0; i < retainedChain->degree; i++ )
2544  {
2545  fid = retainedChain->feat[i];
2546  lid = retainedChain->label[i];
2547 #ifdef _DEBUG_FULL_
2548  std::cout << " " << i << " :" << fid << " " << lid << std::endl;
2549  std::cout << " sol->s[fid]: " << sol->s[fid] << " <=> " << lid << std::endl;
2550  if ( sol->s[fid] == -1 || lid == -1 )
2551  std::cout << "feat inactive :" << inactiveCost[fid] << std::endl;
2552  if ( sol->s[fid] >= 0 )
2553  std::cout << "old cost : " << labelpositions[sol->s[fid]]->cost << std::endl;
2554  if ( lid >= 0 )
2555  std::cout << "new cost : " << labelpositions[lid]->cost << std::endl;
2556 #endif
2557 
2558  if ( sol->s[fid] >= 0 )
2559  {
2560  LabelPosition *old = mLabelPositions.at( sol->s[fid] );
2561  old->removeFromIndex( candidates_sol );
2562 
2563  old->getBoundingBox( amin, amax );
2564 
2565  context.lp = old;
2566  candidates->Search( amin, amax, nokCallback, &context );
2567  }
2568 
2569  sol->s[fid] = lid;
2570 
2571  if ( sol->s[fid] >= 0 )
2572  {
2573  mLabelPositions.at( lid )->insertIntoIndex( candidates_sol );
2574  }
2575 
2576  ok[fid] = false;
2577  }
2578  sol->cost += retainedChain->delta;
2579 #ifdef _DEBUG_FULL_
2580  std::cout << "Expected cost: " << sol->cost << std::endl;
2581  solution_cost();
2582  std::cout << "chain iteration " << popit << ": " << sol->cost << ", " << retainedChain->delta << ", " << retainedChain->degree << std::endl;
2583 #endif
2584  }
2585  else
2586  {
2587  // no chain or the one is not god enough
2588  ok[seed] = true;
2589  }
2590 
2591  delete_chain( retainedChain );
2592  popit++;
2593  }
2594 
2595 #ifdef _DEBUG_FULL_
2596  std::cout << "Cur_cost: " << sol->cost << std::endl;
2597  sol->cost = 0;
2598 #endif
2599 
2600  solution_cost();
2601 
2602 #ifdef _VERBOSE_
2603  std::cout << " Improved solution: " << ( double )(( search_time = clock() ) - start_time ) / ( double ) CLOCKS_PER_SEC << " (solution cost: " << sol->cost << ", nbDisplayed: " << nbActive << " (" << ( double ) nbActive / ( double ) nbft << "%)" << std::endl;
2604 
2605 
2606  std::cerr << "\tna\tchain" << "\tna\t" << popit << "\tna\t" << ( init_sol_time - start_time ) / ( double ) CLOCKS_PER_SEC << "\t" << ( search_time - init_sol_time ) / ( double ) CLOCKS_PER_SEC << "\t" << ( search_time - start_time ) / ( double ) CLOCKS_PER_SEC << "\t" << sol->cost << "\t" << nbActive << "\t" << ( double ) nbActive / ( double ) nbft;
2607 #endif
2608 
2609  delete[] ok;
2610 
2611  return;
2612  }
2613 
2615  {
2616  return l1->getWidth() * l1->getHeight() > l2->getWidth() * l2->getHeight();
2617  }
2618 
2619  std::list<LabelPosition*> * Problem::getSolution( bool returnInactive )
2620  {
2621 
2622  int i;
2623  std::list<LabelPosition*> *solList = new std::list<LabelPosition*>();
2624 
2625  if ( nbft == 0 )
2626  {
2627  return solList;
2628  }
2629 
2630  for ( i = 0; i < nbft; i++ )
2631  {
2632  if ( sol->s[i] != -1 )
2633  {
2634  solList->push_back( mLabelPositions.at( sol->s[i] ) ); // active labels
2635  }
2636  else if ( returnInactive
2637  || mLabelPositions.at( featStartId[i] )->getFeaturePart()->layer()->displayAll()
2638  || mLabelPositions.at( featStartId[i] )->getFeaturePart()->getAlwaysShow() )
2639  {
2640  solList->push_back( mLabelPositions.at( featStartId[i] ) ); // unplaced label
2641  }
2642  }
2643 
2644  // if features collide, order by size, so smaller ones appear on top
2645  if ( returnInactive )
2646  {
2647  solList->sort( compareLabelArea );
2648  }
2649 
2650  return solList;
2651  }
2652 
2654  {
2655  int i, j;
2656 
2657  PalStat *stats = new PalStat();
2658 
2659  stats->nbObjects = nbft;
2660  stats->nbLabelledObjects = 0;
2661 
2662  stats->nbLayers = nbLabelledLayers;
2663  stats->layersNbObjects = new int[stats->nbLayers];
2664  stats->layersNbLabelledObjects = new int[stats->nbLayers];
2665 
2666  for ( i = 0; i < stats->nbLayers; i++ )
2667  {
2668  stats->layersName << labelledLayersName[i];
2669  stats->layersNbObjects[i] = 0;
2670  stats->layersNbLabelledObjects[i] = 0;
2671  }
2672 
2673  QString lyrName;
2674  int k;
2675  for ( i = 0; i < nbft; i++ )
2676  {
2677  lyrName = mLabelPositions.at( featStartId[i] )->getFeaturePart()->feature()->provider()->name();
2678  k = -1;
2679  for ( j = 0; j < stats->nbLayers; j++ )
2680  {
2681  if ( lyrName == stats->layersName[j] )
2682  {
2683  k = j;
2684  break;
2685  }
2686  }
2687  if ( k != -1 )
2688  {
2689  stats->layersNbObjects[k]++;
2690  if ( sol->s[i] >= 0 )
2691  {
2692  stats->layersNbLabelledObjects[k]++;
2693  stats->nbLabelledObjects++;
2694  }
2695  }
2696  else
2697  {
2698  //std::cerr << "Error unknown layers while computing stats: " << lyrName << std::endl;
2699  }
2700  }
2701 
2702  return stats;
2703  }
2704 
2705  void Problem::solution_cost()
2706  {
2707 
2708 #ifdef _DEBUG_FULL_
2709  std::cout << "Global solution evaluation" << std::endl;
2710 #endif
2711 
2712  sol->cost = 0.0;
2713  nbActive = 0;
2714 
2715  int nbOv;
2716 
2717  int i;
2718 
2720  context.inactiveCost = inactiveCost;
2721  context.nbOv = &nbOv;
2722  context.cost = &sol->cost;
2723  double amin[2];
2724  double amax[2];
2725  LabelPosition *lp;
2726 
2727  int nbHidden = 0;
2728 
2729  for ( i = 0; i < nbft; i++ )
2730  {
2731  if ( sol->s[i] == -1 )
2732  {
2733  sol->cost += inactiveCost[i];
2734  nbHidden++;
2735  }
2736  else
2737  {
2738  nbOv = 0;
2739  lp = mLabelPositions.at( sol->s[i] );
2740 
2741  lp->getBoundingBox( amin, amax );
2742 
2743  context.lp = lp;
2744  candidates_sol->Search( amin, amax, LabelPosition::countFullOverlapCallback, &context );
2745 
2746  sol->cost += lp->cost();
2747 
2748  if ( nbOv == 0 )
2749  nbActive++;
2750  }
2751  }
2752 
2753 #ifdef _DEBUG_
2754  if ( nbActive + nbHidden != nbft )
2755  {
2756  std::cout << "Conflicts in solution: " << nbHidden / 2 << std::endl;
2757  }
2758  std::cout << "nbActive and free: " << nbActive << " (" << double( nbActive ) / double( nbft ) << " %)" << std::endl;
2759  std::cout << "solution cost:" << sol->cost << std::endl;
2760 #endif
2761  }
2762 
2763 } // namespace
double popmusic_tabu_chain(SubPart *part)
POPMUSIC, Tabu search with chain'.
Definition: problem.cpp:2105
LabelPosition * lp
Definition: problem.cpp:645
bool falpCallback2(LabelPosition *lp, void *ctx)
Definition: problem.cpp:250
static bool removeOverlapCallback(LabelPosition *lp, void *ctx)
struct pal::_nokContext NokContext
bool increaseNbOverlap(void *l, void *r)
Definition: problem.cpp:143
double getWidth() const
int probSize
of features in problem
Definition: problem.h:56
bool borderSizeInc(void *l, void *r)
Definition: problem.cpp:133
double cost
Definition: problem.h:48
double inactiveCost
Definition: problem.cpp:123
static bool countOverlapCallback(LabelPosition *lp, void *ctx)
void remove(int key)
iterator begin()
bool increaseCost(void *tl, void *tr)
Definition: problem.cpp:816
Thrown when something is added in a Full set.
double cost() const
Returns the candidate label position's geographical cost.
int degree
Definition: problem.h:84
void popmusic()
popmusic framework
Definition: problem.cpp:427
is slower and best than TABU, worse and faster than TABU_CHAIN
Definition: pal.h:69
double popmusic_chain(SubPart *part)
POPMUSIC, chain.
Definition: problem.cpp:1954
struct pal::_elementary_transformation ElemTrans
void ignoreLabel(LabelPosition *lp, PriorityQueue *list, RTree< LabelPosition *, double, 2, double > *candidates)
Definition: problem.cpp:263
void delete_chain(Chain *chain)
Definition: problem.cpp:53
QLinkedList< int > * conflicts
Definition: problem.cpp:1279
double compute_subsolution_cost(SubPart *part, int *s, int *nbOverlap)
Definition: problem.cpp:783
iterator end()
std::list< LabelPosition * > * getSolution(bool returnInactive)
Definition: problem.cpp:2619
is a little bit better than CHAIN but slower
Definition: pal.h:68
void actualizeCandidateList(int nbOverlap, int *candidateListSize, double candidateBaseFactor, double *candidateFactor, int minCandidateListSize, double growingFactor, int n)
Definition: problem.cpp:844
struct pal::_Triple Triple
bool isInConflict(LabelPosition *ls)
Check whether or not this overlap with another labelPosition.
SubPart * subPart(int r, int featseed, int *isIn)
Definition: problem.cpp:665
int getId() const
return id
void getBoundingBox(double amin[2], double amax[2]) const
Return bounding box - amin: xmin,ymin - amax: xmax,ymax.
int getProblemFeatureId() const
void chain_search()
Test with very-large scale neighborhood.
Definition: problem.cpp:2456
int * label
Definition: problem.h:87
Triple ** candidates
Definition: problem.cpp:864
bool subPartCallback(LabelPosition *lp, void *ctx)
Definition: problem.cpp:648
int id
Definition: problem.cpp:122
is the best but slowest
Definition: pal.h:67
double cost
Definition: problem.cpp:806
void seed(uint32_t value)
struct pal::_chain Chain
double compute_feature_cost(SubPart *part, int feat_id, int label_id, int *nbOverlap)
Definition: problem.cpp:746
LabelPosition * lp
Definition: problem.cpp:1273
void removeFromIndex(RTree< LabelPosition *, double, 2, double > *index)
static bool countFullOverlapCallback(LabelPosition *lp, void *ctx)
void insertIntoIndex(RTree< LabelPosition *, double, 2, double > *index)
double popmusic_tabu(SubPart *part)
Definition: problem.cpp:902
bool increaseImportance(void *l, void *r)
Definition: problem.cpp:138
bool checkCallback(LabelPosition *lp, void *ctx)
Definition: problem.cpp:2360
bool decreaseCost(void *tl, void *tr)
Definition: problem.cpp:811
void insert(int key, double p)
int * sol
sub solution
Definition: problem.h:75
RTree< LabelPosition *, double, 2, double > * candidates
Definition: problem.cpp:247
struct pal::_subpart SubPart
QLinkedList< ElemTrans * > * currentChain
Definition: problem.cpp:1278
PalStat * getStats()
Definition: problem.cpp:2653
int * sub
wrap bw sub feat and main feat
Definition: problem.h:71
int * s
Definition: problem.h:47
bool updateCandidatesCost(LabelPosition *lp, void *context)
Definition: problem.cpp:873
LabelPosition * lp
Definition: problem.cpp:863
double * inactiveCost
Definition: problem.cpp:1281
bool nokCallback(LabelPosition *lp, void *context)
Definition: problem.cpp:2434
double * delta_tmp
Definition: problem.cpp:1280
void decreaseKey(int key)
double getHeight() const
int * feat
Definition: problem.h:86
void init_sol_empty()
Basic initial solution : every feature to -1.
Definition: problem.cpp:220
void init_sol_falp()
Definition: problem.cpp:305
bool isIn(int key)
double nbOverlap
Definition: problem.cpp:124
bool chainCallback(LabelPosition *lp, void *context)
Definition: problem.cpp:1286
#define EPSILON
Definition: util.h:78
int subSize
total # features (prob + border)
Definition: problem.h:66
Summury of problem.
Definition: palstat.h:41
PriorityQueue * list
Definition: problem.cpp:245
void actualizeTabuCandidateList(int m, int iteration, int nbOverlap, int *candidateListSize, double candidateBaseFactor, double *candidateFactor, int minCandidateListSize, double reductionFactor, int minTabuTSize, double tabuFactor, int *tenure, int n)
Definition: problem.cpp:823
LabelPosition is a candidate feature label position.
Definition: labelposition.h:48
static bool compareLabelArea(pal::LabelPosition *l1, pal::LabelPosition *l2)
Definition: problem.cpp:2614
bool borderSizeDec(void *l, void *r)
Definition: problem.cpp:128
LabelPosition * lp
Definition: problem.cpp:2429
double getNumOverlaps() const
void reduce()
Definition: problem.cpp:150
QLinkedList< int > * queue
Definition: problem.cpp:643
void sort(void **items, int N, bool(*greater)(void *l, void *r))
Sort an array of pointers.
Definition: util.cpp:61
SearchMethod
Search method to use.
Definition: pal.h:64
int borderSize
of features bounding the problem
Definition: problem.h:61
bool falpCallback1(LabelPosition *lp, void *ctx)
Definition: problem.cpp:287
double * labelPositionCost
Definition: problem.cpp:865
int size() const
LabelPosition * lp
Definition: problem.cpp:246
bool contains(const T &value) const
void append(const T &value)
double delta
Definition: problem.h:85
int seed
first feat in sub part
Definition: problem.h:79
void clear()
#define tr(sourceText)