1
0
mirror of https://github.com/qgis/QGIS.git synced 2025-04-24 00:04:42 -04:00
2013-11-18 14:28:55 +07:00

3200 lines
81 KiB
C++

/*
* libpal - Automated Placement of Labels Library
*
* Copyright (C) 2008 Maxence Laurent, MIS-TIC, HEIG-VD
* University of Applied Sciences, Western Switzerland
* http://www.hes-so.ch
*
* Contact:
* maxence.laurent <at> heig-vd <dot> ch
* or
* eric.taillard <at> heig-vd <dot> ch
*
* This file is part of libpal.
*
* libpal is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libpal is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpal. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _CRT_SECURE_NO_DEPRECATE
#ifdef _EXPORT_MAP_
#include <cstdlib>
#endif
#include <iostream>
#include <fstream>
#include <cstring>
#include <cfloat>
#include <ctime>
#include <list>
#include <limits.h> //for INT_MAX
#include <pal/pal.h>
#include <pal/palstat.h>
#include <pal/layer.h>
#include "linkedlist.hpp"
#include "rtree.hpp"
#include "feature.h"
#include "geomfunction.h"
#include "labelposition.h"
#include "problem.h"
#include "util.h"
#include "priorityqueue.h"
#define UNUSED(x) (void)x;
namespace pal
{
inline void delete_chain( Chain *chain )
{
if ( chain )
{
delete[] chain->feat;
delete[] chain->label;
delete chain;
}
}
Problem::Problem() : nblp( 0 ), all_nblp( 0 ), nbft( 0 ), displayAll( 0 ), labelpositions( NULL ), featStartId( NULL ), featNbLp( NULL ), inactiveCost( NULL ), sol( NULL )
{
bbox[0] = 0;
bbox[1] = 0;
bbox[2] = 0;
bbox[3] = 0;
featWrap = NULL;
candidates = new RTree<LabelPosition*, double, 2, double>();
candidates_sol = new RTree<LabelPosition*, double, 2, double>();
candidates_subsol = NULL;
}
Problem::~Problem()
{
int i;
if ( sol )
{
if ( sol->s )
delete[] sol->s;
delete sol;
}
if ( featWrap )
delete[] featWrap;
if ( featStartId )
delete[] featStartId;
if ( featNbLp )
delete[] featNbLp;
for ( i = 0; i < nbLabelledLayers; i++ )
delete[] labelledLayersName[i];
delete[] labelledLayersName;
for ( i = 0; i < all_nblp; i++ )
delete labelpositions[i];
if ( labelpositions )
delete[] labelpositions;
if ( inactiveCost )
delete[] inactiveCost;
delete candidates;
delete candidates_sol;
if ( candidates_subsol )
{
delete candidates_subsol;
}
}
typedef struct
{
int id;
double inactiveCost;
double nbOverlap;
} Ft;
inline bool borderSizeDec( void *l, void *r )
{
return (( SubPart* ) l )->borderSize < (( SubPart* ) r )->borderSize;
}
inline bool borderSizeInc( void *l, void *r )
{
return (( SubPart* ) l )->borderSize > (( SubPart* ) r )->borderSize;
}
inline bool increaseImportance( void *l, void *r )
{
return (( Ft* ) l )->inactiveCost < (( Ft* ) r )->inactiveCost;
}
inline bool increaseNbOverlap( void *l, void *r )
{
return (( Ft* ) l )->nbOverlap > (( Ft* ) r )->nbOverlap;
}
void Problem::reduce()
{
int i;
int j;
int k;
int counter = 0;
int lpid;
bool *ok = new bool[nblp];
bool run = true;
for ( i = 0; i < nblp; i++ )
ok[i] = false;
double amin[2];
double amax[2];
LabelPosition *lp;
LabelPosition *lp2;
while ( run )
{
run = false;
for ( i = 0; i < nbft; i++ )
{
// ok[i] = true;
for ( j = 0; j < featNbLp[i]; j++ ) // foreach candidate
{
if ( !ok[featStartId[i] + j] )
{
if (( lp = labelpositions[featStartId[i] + j] )->getNumOverlaps() == 0 ) // if candidate has no overlap
{
run = true;
ok[featStartId[i] + j] = true;
// 1) remove worse candidates from candidates
// 2) update nb_overlaps
counter += featNbLp[i] - j - 1;
for ( k = j + 1; k < featNbLp[i]; k++ )
{
lpid = featStartId[i] + k;
ok[lpid] = true;
lp2 = labelpositions[lpid];
lp2->getBoundingBox( amin, amax );
nbOverlap -= lp2->getNumOverlaps();
candidates->Search( amin, amax, LabelPosition::removeOverlapCallback, ( void* ) lp2 );
lp2->removeFromIndex( candidates );
}
//lp->removeFromIndex(candidates);
featNbLp[i] = j + 1;
break;
}
}
}
}
}
this->nblp -= counter;
#ifdef _VERBOSE_
std::cout << "problem reduce to " << nblp << " candidates which makes " << nbOverlap << " overlaps" << std::endl;
#endif
delete[] ok;
}
/**
* \brief Basic initial solution : every feature to -1
*/
void Problem::init_sol_empty()
{
int i;
if ( sol )
{
if ( sol->s )
delete[] sol->s;
delete sol;
}
sol = new Sol();
sol->s = new int[nbft];
for ( i = 0; i < nbft; i++ )
sol->s[i] = -1;
sol->cost = nbft;
}
typedef struct
{
PriorityQueue *list;
LabelPosition *lp;
RTree <LabelPosition*, double, 2, double> *candidates;
} FalpContext;
bool falpCallback2( LabelPosition *lp, void * ctx )
{
LabelPosition *lp2 = (( FalpContext* ) ctx )->lp;
PriorityQueue *list = (( FalpContext* ) ctx )->list;
if ( lp->getId() != lp2->getId() && list->isIn( lp->getId() ) && lp->isInConflict( lp2 ) )
{
list->decreaseKey( lp->getId() );
}
return true;
}
void ignoreLabel( LabelPosition *lp, PriorityQueue *list, RTree <LabelPosition*, double, 2, double> *candidates )
{
FalpContext *context = new FalpContext();
context->candidates = NULL;
context->list = list;
double amin[2];
double amax[2];
if ( list->isIn( lp->getId() ) )
{
list->remove( lp->getId() );
lp->getBoundingBox( amin, amax );
context->lp = lp;
candidates->Search( amin, amax, falpCallback2, context );
}
delete context;
}
bool falpCallback1( LabelPosition *lp, void * ctx )
{
LabelPosition *lp2 = (( FalpContext* ) ctx )->lp;
PriorityQueue *list = (( FalpContext* ) ctx )->list;
RTree <LabelPosition*, double, 2, double> *candidates = (( FalpContext* ) ctx )->candidates;
if ( lp2->isInConflict( lp ) )
{
ignoreLabel( lp, list, candidates );
}
return true;
}
/* Better initial solution
* Step one FALP (Yamamoto, Camara, Lorena 2005)
*/
void Problem::init_sol_falp()
{
#ifdef _DEBUG_
std::cout << "Init solution FALP" << std::endl;
#endif
int i, j;
int label;
PriorityQueue *list;
init_sol_empty();
list = new PriorityQueue( nblp, all_nblp, true );
double amin[2];
double amax[2];
FalpContext *context = new FalpContext();
context->candidates = candidates;
context->list = list;
LabelPosition *lp;
for ( i = 0; i < nbft; i++ )
for ( j = 0; j < featNbLp[i]; j++ )
{
label = featStartId[i] + j;
list->insert( label, ( double ) labelpositions[label]->getNumOverlaps() );
}
while ( list->getSize() > 0 ) // O (log size)
{
if ( pal->isCancelled() )
{
delete context;
delete list;
return;
}
label = list->getBest(); // O (log size)
lp = labelpositions[label];
if ( lp->getId() != label )
{
std::cout << "Error: " << lp->getId() << " <--> " << label << std::endl;
}
int probFeatId = lp->getProblemFeatureId();
sol->s[probFeatId] = label;
#ifdef _DEBUG_FULL_
std::cout << "sol->s[" << lp->probFeat << "] :" << label << std::endl;
#endif
for ( i = featStartId[probFeatId]; i < featStartId[probFeatId] + featNbLp[probFeatId]; i++ )
{
ignoreLabel( labelpositions[i], list, candidates );
}
lp->getBoundingBox( amin, amax );
context->lp = lp;
candidates->Search( amin, amax, falpCallback1, ( void* ) context );
candidates_sol->Insert( amin, amax, lp );
}
delete context;
if ( displayAll )
{
int nbOverlap;
int start_p;
LabelPosition* retainedLabel = NULL;
int p;
for ( i = 0; i < nbft; i++ ) // forearch hidden feature
{
if ( sol->s[i] == -1 )
{
nbOverlap = INT_MAX;
start_p = featStartId[i];
for ( p = 0; p < featNbLp[i]; p++ )
{
lp = labelpositions[start_p+p];
lp->resetNumOverlaps();
lp->getBoundingBox( amin, amax );
candidates_sol->Search( amin, amax, LabelPosition::countOverlapCallback, lp );
if ( lp->getNumOverlaps() < nbOverlap )
{
retainedLabel = lp;
nbOverlap = static_cast<int>( lp->getNumOverlaps() );
}
}
sol->s[i] = retainedLabel->getId();
retainedLabel->insertIntoIndex( candidates_sol );
}
}
}
delete list;
}
//#define _DEBUG_
void Problem::popmusic()
{
if ( nbft == 0 )
return;
int i;
int seed;
bool *ok = new bool[nbft];
int r = pal->popmusic_r;
SearchMethod searchMethod = pal->searchMethod;
candidates_subsol = new RTree<LabelPosition*, double, 2, double>();
double delta = 0.0;
int it = 0;
#ifdef _VERBOSE_
clock_t start_time = clock();
clock_t create_part_time;
clock_t init_sol_time;
clock_t search_time;
#endif
SubPart *current = NULL;
int subPartTotalSize = 0;
labelPositionCost = new double[all_nblp];
nbOlap = new int[all_nblp];
featWrap = new int[nbft];
memset( featWrap, -1, sizeof( int ) *nbft );
SubPart ** parts = new SubPart*[nbft];
int *isIn = new int[nbft];
memset( isIn, 0, sizeof( int ) *nbft );
for ( i = 0; i < nbft; i++ )
{
parts[i] = subPart( r, i, isIn );
subPartTotalSize += parts[i]->subSize;
ok[i] = false;
}
delete[] isIn;
sort(( void** ) parts, nbft, borderSizeInc );
//sort ((void**)parts, nbft, borderSizeDec);
#ifdef _VERBOSE_
create_part_time = clock();
std::cout << " SubPart (averagesize: " << subPartTotalSize / nbft << ") creation: " << ( double )( create_part_time - start_time ) / ( double ) CLOCKS_PER_SEC << std::endl;
#endif
init_sol_falp();
#ifdef _VERBOSE_
init_sol_time = clock();
std::cout << " Compute initial solution: " << ( double )( init_sol_time - create_part_time ) / ( double ) CLOCKS_PER_SEC;
#endif
solution_cost();
#ifdef _VERBOSE_
std::cerr << "\t" << sol->cost << "\t" << nbActive << "\t" << ( double ) nbActive / ( double ) nbft;
std::cout << " (solution cost: " << sol->cost << ", nbDisplayed: " << nbActive << "(" << ( double ) nbActive / ( double ) nbft << "%)" << std::endl;
#endif
int popit = 0;
seed = 0;
while ( true )
{
it++;
/* find the next seed not ok */
for ( i = ( seed + 1 ) % nbft; ok[i] && i != seed; i = ( i + 1 ) % nbft )
;
if ( i == seed && ok[seed] )
{
current = NULL; // everything is OK :-)
break;
}
else
{
seed = i;
current = parts[seed];
}
// update sub part solution
candidates_subsol->RemoveAll();
for ( i = 0; i < current->subSize; i++ )
{
current->sol[i] = sol->s[current->sub[i]];
if ( current->sol[i] != -1 )
{
labelpositions[current->sol[i]]->insertIntoIndex( candidates_subsol );
}
}
switch ( searchMethod )
{
//case branch_and_bound :
//delta = current->branch_and_bound_search();
// break;
case POPMUSIC_TABU :
delta = popmusic_tabu( current );
break;
case POPMUSIC_TABU_CHAIN :
delta = popmusic_tabu_chain( current );
break;
case POPMUSIC_CHAIN :
delta = popmusic_chain( current );
break;
default:
#ifdef _VERBOSE_
std::cerr << "Unknown search method..." << std::endl;
#endif
return;
}
popit++;
if ( delta > EPSILON )
{
/* Update solution */
#ifdef _DEBUG_FULL_
std::cout << "Update solution from subpart, current cost:" << std::endl;
solution_cost();
std::cout << "Delta > EPSILON: update solution" << std::endl;
std::cout << "after modif cost:" << std::endl;
solution_cost();
#endif
for ( i = 0; i < current->borderSize; i++ )
{
ok[current->sub[i]] = false;
}
for ( i = current->borderSize; i < current->subSize; i++ )
{
if ( sol->s[current->sub[i]] != -1 )
{
labelpositions[sol->s[current->sub[i]]]->removeFromIndex( candidates_sol );
}
sol->s[current->sub[i]] = current->sol[i];
if ( current->sol[i] != -1 )
{
labelpositions[current->sol[i]]->insertIntoIndex( candidates_sol );
}
ok[current->sub[i]] = false;
}
}
else // not improved
{
#ifdef _DEBUG_FULL_
std::cout << "subpart not improved" << std::endl;
#endif
ok[seed] = true;
}
}
solution_cost();
#ifdef _VERBOSE_
search_time = clock();
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;
std::cerr << "\t" << subPartTotalSize;
if ( searchMethod == POPMUSIC_TABU )
std::cerr << "\tpop_tabu\t";
else if ( searchMethod == POPMUSIC_TABU_CHAIN )
std::cerr << "\tpop_tabu_chain\t";
else if ( searchMethod == POPMUSIC_CHAIN )
std::cerr << "\tpop_chain\t";
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;
#endif
delete[] labelPositionCost;
delete[] nbOlap;
for ( i = 0; i < nbft; i++ )
{
delete[] parts[i]->sub;
delete[] parts[i]->sol;
delete parts[i];
}
delete[] parts;
delete[] ok;
return;
}
#undef _DEBUG_
typedef struct
{
LinkedList<int> *queue;
int *isIn;
LabelPosition *lp;
} SubPartContext;
bool subPartCallback( LabelPosition *lp, void *ctx )
{
int *isIn = (( SubPartContext* ) ctx )->isIn;
LinkedList<int> *queue = (( SubPartContext* ) ctx )->queue;
int id = lp->getProblemFeatureId();
if ( !isIn[id] && lp->isInConflict((( SubPartContext* ) ctx )->lp ) )
{
queue->push_back( id );
isIn[id] = 1;
}
return true;
}
/* Select a sub part, expected size of r, from seed */
SubPart * Problem::subPart( int r, int featseed, int *isIn )
{
LinkedList<int> *queue = new LinkedList<int> ( intCompare );
LinkedList<int> *ri = new LinkedList<int> ( intCompare );
int *sub;
int id;
register int featS;
register int p;
int i;
int n = 0;
int nb = 0;
double amin[2];
double amax[2];
SubPartContext context;
context.queue = queue;
context.isIn = isIn;
queue->push_back( featseed );
isIn[featseed] = 1;
LabelPosition *lp;
while ( ri->size() < r && queue->size() > 0 )
{
id = queue->pop_front();
ri->push_back( id );
featS = featStartId[id];
p = featNbLp[id];
for ( i = featS; i < featS + p; i++ ) // foreach candidat of feature 'id'
{
lp = labelpositions[i];
lp->getBoundingBox( amin, amax );
context.lp = lp;
candidates->Search( amin, amax, subPartCallback, ( void* ) &context );
}
}
nb = queue->size();
n = ri->size();
sub = new int[n+nb];
i = 0;
while ( queue->size() > 0 )
{
sub[i] = queue->pop_front();
isIn[sub[i]] = 0;
i++;
}
while ( ri->size() > 0 )
{
sub[i] = ri->pop_front();
isIn[sub[i]] = 0;
i++;
}
delete queue;
delete ri;
SubPart *subPart = new SubPart();
subPart->probSize = n;
subPart->borderSize = nb;
subPart->subSize = n + nb;
subPart->sub = sub;
subPart->sol = new int [subPart->subSize];
subPart->seed = featseed;
return subPart;
}
/** From SubPart.cpp ***/
double Problem::compute_feature_cost( SubPart *part, int feat_id, int label_id, int *nbOverlap )
{
double cost;
*nbOverlap = 0;
LabelPosition::CountContext context;
context.inactiveCost = inactiveCost;
context.nbOv = nbOverlap;
context.cost = &cost;
double amin[2];
double amax[2];
LabelPosition *lp;
cost = 0.0;
if ( label_id >= 0 ) // is the feature displayed ?
{
lp = labelpositions[label_id];
lp->getBoundingBox( amin, amax );
context.lp = lp;
candidates_subsol->Search( amin, amax, LabelPosition::countFullOverlapCallback, ( void* ) &context );
cost += lp->getCost();
}
else
{
cost = inactiveCost[part->sub[feat_id]];
//(*nbOverlap)++;
}
return cost;
}
double Problem::compute_subsolution_cost( SubPart *part, int *s, int *nbOverlap )
{
int i;
double cost = 0.0;
int nbO = 0;
*nbOverlap = 0;
for ( i = 0; i < part->subSize; i++ )
{
cost += compute_feature_cost( part, i, s[i], &nbO );
*nbOverlap += nbO;
}
return cost;
}
typedef struct _Triple
{
int feat_id;
int label_id;
double cost;
int nbOverlap;
} Triple;
bool decreaseCost( void *tl, void *tr )
{
return (( Triple* ) tl )->cost < (( Triple* ) tr )->cost;
}
bool increaseCost( void *tl, void *tr )
{
return (( Triple* ) tl )->cost > (( Triple* ) tr )->cost;
}
inline 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 )
{
if ( *candidateFactor > candidateBaseFactor )
*candidateFactor /= reductionFactor;
if ( iteration % m == 0 )
{
*tenure = minTabuTSize + ( int )( tabuFactor * nbOverlap );
*candidateListSize = minCandidateListSize + ( int )( *candidateFactor * nbOverlap );
if ( *candidateListSize > n )
*candidateListSize = n;
}
}
inline void actualizeCandidateList( int nbOverlap, int *candidateListSize, double candidateBaseFactor,
double *candidateFactor, int minCandidateListSize, double growingFactor, int n )
{
candidateBaseFactor += 0;
if ( *candidateListSize < n )
*candidateFactor = *candidateFactor * growingFactor;
*candidateListSize = minCandidateListSize + ( int )( *candidateFactor * nbOverlap );
if ( *candidateListSize > n )
*candidateListSize = n;
}
typedef struct
{
LabelPosition *lp;
Triple **candidates;
double *labelPositionCost;
int *nbOlap;
double diff_cost;
int *featWrap;
int *sol;
int borderSize;
} UpdateContext;
bool updateCandidatesCost( LabelPosition *lp, void *context )
{
UpdateContext *ctx = ( UpdateContext* ) context;
if ( ctx->lp->isInConflict( lp ) )
{
ctx->labelPositionCost[lp->getId()] += ctx->diff_cost;
if ( ctx->diff_cost > 0 )
ctx->nbOlap[lp->getId()]++;
else
ctx->nbOlap[lp->getId()]--;
int feat_id = ctx->featWrap[ctx->lp->getProblemFeatureId()];
int feat_id2;
if ( feat_id >= 0 && ctx->sol[feat_id] == lp->getId() ) // this label is in use
{
if (( feat_id2 = feat_id - ctx->borderSize ) >= 0 )
{
ctx->candidates[feat_id2]->cost += ctx->diff_cost;
ctx->candidates[feat_id2]->nbOverlap--;
}
}
}
return true;
}
double Problem::popmusic_tabu( SubPart *part )
{
#ifdef _DEBUG_FULL_
std::cout << "Subpart: Tabu Search" << std::endl;
#endif
int probSize = part->probSize;
int borderSize = part->borderSize;
int subSize = part->subSize;
int *sub = part->sub;
int *sol = part->sol;
Triple **candidateList = new Triple*[probSize];
Triple **candidateListUnsorted = new Triple*[probSize];
int * best_sol = new int[subSize];
double cur_cost;
double best_cost;
double initial_cost;
int *tabu_list = new int[probSize];
int i;
int j;
int itwImp;
int it = 0;
int max_it;
int stop_it;
double delta;
double delta_min;
bool authorized;
int feat_id;
int feat_sub_id;
int label_id;
int p;
int choosed_feat;
int choosed_label;
int candidateId;
int nbOverlap = 0;
//int nbOverlapLabel;
int tenure = 10; //
int m = 50; // m [10;50]
int minTabuTSize = 9; // min_t [2;10]
double tabuFactor = 0.5; // p_t [0.1;0.8]
int minCandidateListSize = 18; // min_c [2;20]
double candidateBaseFactor = 0.73; // p_base [0.1;0.8]
double growingFactor = 15; // fa [5;20]
double reductionFactor = 1.3; // f_r [1.1;1.5]
int candidateListSize = minCandidateListSize;
double candidateFactor = candidateBaseFactor;
int first_lp;
//double EPSILON = 0.000001;
max_it = probSize * pal->tabuMaxIt;
itwImp = probSize * pal->tabuMinIt;
stop_it = itwImp;
max_it = probSize * pal->tabuMaxIt;
cur_cost = 0.0;
nbOverlap = 0;
int lp;
for ( i = 0; i < subSize; i++ )
featWrap[sub[i]] = i;
for ( i = 0; i < subSize; i++ )
{
j = featStartId[sub[i]];
for ( lp = 0; lp < featNbLp[sub[i]]; lp++ )
{
it = j + lp;
//std::cerr << "it = " << j << " + " << lp << std::endl;
// std::cerr << "it/nblp:" << it << "/" << all_nblp << std::endl;
labelPositionCost[it] = compute_feature_cost( part, i, it, & ( nbOlap[it] ) );
//std::cerr << "nbOlap[" << it << "] : " << nbOlap[it] << std::endl;
}
}
first_lp = ( displayAll ? 0 : -1 );
for ( i = 0; i < probSize; i++ )
{
tabu_list[i] = -1; // nothing is tabu
candidateList[i] = new Triple();
candidateList[i]->feat_id = i + borderSize;
candidateList[i]->label_id = sol[i+borderSize];
candidateListUnsorted[i] = candidateList[i];
if ( sol[i+borderSize] >= 0 )
{
j = sol[i+borderSize];
candidateList[i]->cost = labelPositionCost[j];
candidateList[i]->nbOverlap = nbOlap[j];
}
else
{
candidateList[i]->cost = inactiveCost[sub[i+borderSize]];
candidateList[i]->nbOverlap = 1;
}
}
for ( i = 0; i < subSize; i++ )
{
if ( sol[i] == -1 )
{
cur_cost += inactiveCost[sub[i]];
}
else
{
nbOverlap += nbOlap[sol[i]];
cur_cost += labelPositionCost[sol[i]];
}
}
sort(( void** ) candidateList, probSize, decreaseCost );
best_cost = cur_cost;
initial_cost = cur_cost;
memcpy( best_sol, sol, sizeof( int ) *( subSize ) );
// START TABU
it = 0;
while ( it < stop_it && best_cost >= EPSILON )
{
#ifdef _DEBUG_FULL_
std::cout << " ITERATION : " << it << " stop: " << stop_it << std::endl;
#endif
actualizeTabuCandidateList( m, it, nbOverlap, &candidateListSize, candidateBaseFactor, &candidateFactor, minCandidateListSize, reductionFactor, minTabuTSize, tabuFactor, &tenure, probSize );
delta_min = DBL_MAX;
choosed_feat = -1;
choosed_label = -2;
candidateId = -1;
// foreach retained Candidate
for ( i = 0; i < candidateListSize; i++ )
{
feat_id = candidateList[i]->feat_id;
feat_sub_id = sub[feat_id];
label_id = candidateList[i]->label_id;
int oldPos = ( label_id < 0 ? -1 : label_id - featStartId[feat_sub_id] );
p = featNbLp[feat_sub_id];
/* label -1 means inactive feature */
// foreach labelposition of feature minus the one in the solution
for ( j = first_lp; j < p; j++ )
{
if ( j != oldPos )
{
if ( sol[feat_id] < 0 )
{
delta = -inactiveCost[feat_sub_id];
}
else
{
delta = -labelPositionCost[sol[feat_id]];
delta -= nbOlap[sol[feat_id]] * ( inactiveCost[feat_sub_id] + labelpositions[label_id]->getCost() );
}
if ( j >= 0 )
{
delta += labelPositionCost[featStartId[feat_sub_id] + j];
delta += nbOlap[featStartId[feat_sub_id] + j] * ( inactiveCost[feat_sub_id] + labelpositions[featStartId[feat_sub_id] + j]->getCost() );
}
else
{
delta += inactiveCost[feat_sub_id];
}
#ifdef _DEBUG_FULL_
std::cout << " test moving " << oldPos << " to " << featStartId[feat_sub_id] + j << std::endl;
std::cout << " new pos makes " << nbOlap[featStartId[feat_sub_id] + j] << " overlaps" << std::endl;
std::cout << " delta is : " << delta << std::endl;
#endif
// move is authorized wether the feat isn't taboo or whether the move give a new best solution
authorized = ( tabu_list[feat_id - borderSize] <= it ) || ( cur_cost + delta < best_cost );
#ifdef _DEBUG_FULL_
if ( tabu_list[feat_id - borderSize] > it )
{
std::cout << " Move is tabu" << std::endl;
}
else
{
std::cout << " Move is ok" << std::endl;
}
#endif
if ( delta < delta_min && authorized )
{
#ifdef _DEBUG_FULL_
std::cout << " keep move" << std::endl;
std::cout << " choosed_feat: " << feat_id << std::endl;
if ( j == -1 )
std::cout << " choosed_label: " << j << std::endl;
else
std::cout << " choosed_label: " << featStartId[feat_sub_id] + j << std::endl;
std::cout << " delta: " << delta << std::endl;
#endif
choosed_feat = feat_id;
if ( j == -1 )
choosed_label = -1;
else
choosed_label = featStartId[feat_sub_id] + j;
delta_min = delta;
candidateId = i;
}
#ifdef _DEBUG_FULL_
else if ( !authorized )
{
std::cout << " tabu" << std::endl;
}
else
{
std::cout << " no good enough" << std::endl;
}
#endif
}
}
}
// if a modification has been retained
if ( choosed_feat >= 0 )
{
#ifdef _DEBUG_FULL_
std::cout << " Apply move:" << std::endl;
std::cout << " feat: " << choosed_feat << std::endl;
std::cout << " label: " << choosed_label << std::endl;
std::cout << " delta: " << delta_min << std::endl << std::endl;
#endif
// update the solution and update tabu list
int old_label = sol[choosed_feat];
tabu_list[choosed_feat-borderSize] = it + tenure;
sol[choosed_feat] = choosed_label;
candidateList[candidateId]->label_id = choosed_label;
if ( old_label != -1 )
labelpositions[old_label]->removeFromIndex( candidates_subsol );
/* re-compute all labelpositioncost that overlap with old an new label */
double local_inactive = inactiveCost[sub[choosed_feat]];
if ( choosed_label != -1 )
{
candidateList[candidateId]->cost = labelPositionCost[choosed_label];
candidateList[candidateId]->nbOverlap = nbOlap[choosed_label];
}
else
{
candidateList[candidateId]->cost = local_inactive;
candidateList[candidateId]->nbOverlap = 1;
}
cur_cost += delta_min;
double amin[2];
double amax[2];
LabelPosition *lp;
UpdateContext context;
context.candidates = candidateListUnsorted;
context.labelPositionCost = labelPositionCost;
context.nbOlap = nbOlap;
context.featWrap = featWrap;
context.sol = sol;
context.borderSize = borderSize;
if ( old_label >= 0 )
{
lp = labelpositions[old_label];
lp->getBoundingBox( amin, amax );
context.diff_cost = -local_inactive - labelpositions[old_label]->getCost();
context.lp = labelpositions[old_label];
candidates->Search( amin, amax, updateCandidatesCost, &context );
}
if ( choosed_label >= 0 )
{
lp = labelpositions[choosed_label];
lp->getBoundingBox( amin, amax );
context.diff_cost = local_inactive + labelpositions[choosed_label]->getCost();
context.lp = labelpositions[choosed_label];
candidates->Search( amin, amax, updateCandidatesCost, &context );
lp->insertIntoIndex( candidates_subsol );
}
sort(( void** ) candidateList, probSize, decreaseCost );
if ( best_cost - cur_cost > EPSILON ) // new best sol
{
best_cost = cur_cost;
memcpy( best_sol, sol, sizeof( int ) *( subSize ) );
stop_it = it + itwImp;
if ( stop_it > max_it )
stop_it = max_it;
}
}
else
{
/* no feature was selected : increase candidate list size*/
actualizeCandidateList( nbOverlap, &candidateListSize, candidateBaseFactor,
&candidateFactor, minCandidateListSize, growingFactor, probSize );
}
#ifdef _DEBUG_FULL_
std::cout << "cost : " << cur_cost << std::endl;
int nbover;
std::cout << "computed cost: " << compute_subsolution_cost( part, sol, &nbover ) << std::endl;
std::cout << "best_cost: " << best_cost << std::endl << std::endl;
#endif
it++;
}
memcpy( sol, best_sol, sizeof( int ) *( subSize ) );
for ( i = 0; i < subSize; i++ )
featWrap[sub[i]] = -1;
for ( i = 0; i < probSize; i++ )
delete candidateList[i];
delete[] candidateList;
delete[] candidateListUnsorted;
delete[] best_sol;
delete[] tabu_list;
/* Return delta */
return initial_cost - best_cost;
}
typedef struct
{
LabelPosition *lp;
int *tmpsol;
int *featWrap;
int *feat;
int borderSize;
LinkedList<ElemTrans*> *currentChain;
LinkedList<int> *conflicts;
double *delta_tmp;
double *inactiveCost;
} ChainContext;
bool chainCallback( LabelPosition *lp, void *context )
{
ChainContext *ctx = ( ChainContext* ) context;
#ifdef _DEBUG_FULL_
std::cout << "chainCallback" << std::endl;
std::cout << " lp from rtree: " << lp << std::endl;
std::cout << " lpid from rtree: " << lp->id << std::endl;
std::cout << " lpco from rtree: " << lp->cost << std::endl;
std::cout << " lp from context: " << ctx->lp << std::endl;
std::cout << " lpid from context: " << ctx->lp->id << std::endl;
std::cout << " lpco from context: " << ctx->lp->cost << std::endl;
std::cout << " delta_tmp: " << ctx->delta_tmp << std::endl;
std::cout << " *delta_tmp: " << *ctx->delta_tmp << std::endl;
std::cout << " inactiveCost: " << ctx->inactiveCost << std::endl;
#endif
#ifdef _DEBUG_FULL_
std::cout << "ejChCallBack: " << lp->id << "<->" << ctx->lp->id << std::endl;
#endif
if ( lp->isInConflict( ctx->lp ) )
{
#ifdef _DEBUG_FULL_
std::cout << "ejChCallBack: " << lp->id << "<->" << ctx->lp->id << std::endl;
std::cout << " Conflictual..." << std::endl;
#endif
int feat, rfeat;
bool sub = ctx->featWrap != NULL;
feat = lp->getProblemFeatureId();
if ( sub )
{
rfeat = feat;
feat = ctx->featWrap[feat];
}
else
rfeat = feat;
#ifdef _DEBUG_FULL_
std::cout << " feat: " << feat << std::endl;
std::cout << " sol: " << ctx->tmpsol[feat] << "/" << lp->id << std::endl;
std::cout << " border:" << ctx->borderSize << std::endl;
#endif
if ( feat >= 0 && ctx->tmpsol[feat] == lp->getId() )
{
if ( sub && feat < ctx->borderSize )
{
#ifdef _DEBUG_FULL_
std::cout << " Cannot touch border (throw) !" << std::endl;
#endif
throw - 2;
}
}
// is there any cycles ?
Cell<ElemTrans*> *cur = ctx->currentChain->getFirst();
while ( cur )
{
if ( cur->item->feat == feat )
{
#ifdef _DEBUG_FULL_
std::cout << "Cycle into chain (throw) !" << std::endl;
#endif
throw - 1;
}
cur = cur->next;
}
if ( !ctx->conflicts->isIn( feat ) )
{
ctx->conflicts->push_back( feat );
*ctx->delta_tmp += lp->getCost() + ctx->inactiveCost[rfeat];
}
}
return true;
}
inline Chain *Problem::chain( SubPart *part, int seed )
{
int i;
int j;
int lid;
//int probSize = part->probSize;
int borderSize = part->borderSize;
int subSize = part->subSize;
int *sub = part->sub;
int *sol = part->sol;
register int subseed;
double delta;
double delta_min;
double delta_best = DBL_MAX;
double delta_tmp;
int next_seed;
int retainedLabel;
Chain *retainedChain = NULL;
int max_degree = pal->ejChainDeg;
int seedNbLp;
LinkedList<ElemTrans*> *currentChain = new LinkedList<ElemTrans*> ( ptrETCompare );
LinkedList<int> *conflicts = new LinkedList<int> ( intCompare );
int *tmpsol = new int[subSize];
memcpy( tmpsol, sol, sizeof( int ) *subSize );
LabelPosition *lp;
double amin[2];
double amax[2];
ChainContext context;
context.featWrap = featWrap;
context.borderSize = borderSize;
context.tmpsol = tmpsol;
context.inactiveCost = inactiveCost;
context.feat = NULL;
context.currentChain = currentChain;
context.conflicts = conflicts;
context.delta_tmp = &delta_tmp;
delta = 0;
while ( seed != -1 )
{
subseed = sub[seed];
seedNbLp = featNbLp[subseed];
delta_min = DBL_MAX;
#ifdef _DEBUG_FULL_
std::cout << "New seed: " << seed << "/" << subseed << std::endl;
#endif
next_seed = -1;
retainedLabel = -2;
if ( tmpsol[seed] == -1 )
delta -= inactiveCost[subseed];
else
delta -= labelpositions[tmpsol[seed]]->getCost();
// TODO modify to handle displayAll param
for ( i = -1; i < seedNbLp; i++ )
{
try
{
// Skip active label !
if ( !( tmpsol[seed] == -1 && i == -1 ) && i + featStartId[subseed] != tmpsol[seed] )
{
if ( i != -1 )
{
lid = featStartId[subseed] + i;
delta_tmp = delta;
lp = labelpositions[lid];
// evaluate conflicts graph in solution after moving seed's label
lp->getBoundingBox( amin, amax );
context.lp = lp;
if ( conflicts->size() != 0 )
std::cerr << "Conflicts not empty !!" << std::endl;
// search ative conflicts and count them
candidates_subsol->Search( amin, amax, chainCallback, ( void* ) &context );
#ifdef _DEBUG_FULL_
std::cout << "Conflicts:" << conflicts->size() << std::endl;
#endif
// no conflict -> end of chain
if ( conflicts->size() == 0 )
{
if ( !retainedChain || delta + labelpositions[lid]->getCost() < delta_best )
{
if ( retainedChain )
{
delete[] retainedChain->label;
delete[] retainedChain->feat;
}
else
{
retainedChain = new Chain(); // HERE
}
delta_best = delta + labelpositions[lid]->getCost();
retainedChain->degree = currentChain->size() + 1;
retainedChain->feat = new int[retainedChain->degree]; // HERE
retainedChain->label = new int[retainedChain->degree]; // HERE
Cell<ElemTrans*> *current = currentChain->getFirst();
ElemTrans* move;
j = 0;
while ( current )
{
move = current->item;
retainedChain->feat[j] = move->feat;
retainedChain->label[j] = move->new_label;
current = current->next;
j++;
}
retainedChain->feat[j] = seed;
retainedChain->label[j] = lid;
retainedChain->delta = delta + labelpositions[retainedChain->label[j]]->getCost();
}
}
// another feature can be ejected
else if ( conflicts->size() == 1 )
{
if ( delta_tmp < delta_min )
{
delta_min = delta_tmp;
retainedLabel = lid;
next_seed = conflicts->pop_front();
}
else
{
conflicts->pop_front();
}
}
else
{
// A lot of conflict : make them inactive and store chain
Chain *newChain = new Chain(); // HERE
newChain->degree = currentChain->size() + 1 + conflicts->size();
newChain->feat = new int[newChain->degree]; // HERE
newChain->label = new int[newChain->degree]; // HERE
Cell<ElemTrans*> *current = currentChain->getFirst();
ElemTrans* move;
j = 0;
while ( current )
{
move = current->item;
newChain->feat[j] = move->feat;
newChain->label[j] = move->new_label;
current = current->next;
j++;
}
newChain->feat[j] = seed;
newChain->label[j] = lid;
newChain->delta = delta + labelpositions[newChain->label[j]]->getCost();
j++;
while ( conflicts->size() > 0 )
{
int ftid = conflicts->pop_front();
newChain->feat[j] = ftid;
newChain->label[j] = -1;
newChain->delta += inactiveCost[sub[ftid]];
j++;
}
if ( newChain->delta < delta_best )
{
if ( retainedChain )
delete_chain( retainedChain );
delta_best = newChain->delta;
retainedChain = newChain;
}
else
{
delete_chain( newChain );
}
}
}
else // Current label == -1 end of chain ...
{
if ( !retainedChain || delta + inactiveCost[subseed] < delta_best )
{
if ( retainedChain )
{
delete[] retainedChain->label;
delete[] retainedChain->feat;
}
else
retainedChain = new Chain(); // HERE
delta_best = delta + inactiveCost[subseed];
retainedChain->degree = currentChain->size() + 1;
retainedChain->feat = new int[retainedChain->degree]; // HERE
retainedChain->label = new int[retainedChain->degree]; // HERE
Cell<ElemTrans*> *current = currentChain->getFirst();
ElemTrans* move;
j = 0;
while ( current )
{
move = current->item;
retainedChain->feat[j] = move->feat;
retainedChain->label[j] = move->new_label;
current = current->next;
j++;
}
retainedChain->feat[j] = seed;
retainedChain->label[j] = -1;
retainedChain->delta = delta + inactiveCost[subseed];
}
}
}
}
catch ( int i )
{
#ifdef _DEBUG_FULL_
std::cout << "catch int " << i << std::endl;
#else
UNUSED( i );
#endif
while ( conflicts->size() > 0 )
conflicts->pop_front();
}
} // end foreach labelposition
if ( next_seed == -1 )
{
seed = -1;
}
else if ( currentChain->size() > max_degree )
{
#ifdef _VERBOSE_
std::cout << "Max degree reached !! (" << max_degree << ")" << std::endl;
#endif
seed = -1;
}
else
{
ElemTrans *et = new ElemTrans();
et->feat = seed;
et->old_label = tmpsol[seed];
et->new_label = retainedLabel;
currentChain->push_back( et );
if ( et->old_label != -1 )
{
labelpositions[et->old_label]->removeFromIndex( candidates_subsol );
}
if ( et->new_label != -1 )
{
labelpositions[et->new_label]->insertIntoIndex( candidates_subsol );
}
tmpsol[seed] = retainedLabel;
delta += labelpositions[retainedLabel]->getCost();
seed = next_seed;
}
}
while ( currentChain->size() > 0 )
{
ElemTrans* et = currentChain->pop_front();
if ( et->new_label != -1 )
{
labelpositions[et->new_label]->removeFromIndex( candidates_subsol );
}
if ( et->old_label != -1 )
{
labelpositions[et->old_label]->insertIntoIndex( candidates_subsol );
}
delete et;
}
delete currentChain;
delete[] tmpsol;
delete conflicts;
return retainedChain;
}
inline Chain *Problem::chain( int seed )
{
int i;
int j;
int lid;
double delta;
double delta_min;
double delta_best = DBL_MAX;
double delta_tmp;
int next_seed;
int retainedLabel;
Chain *retainedChain = NULL;
int max_degree = pal->ejChainDeg;
int seedNbLp;
LinkedList<ElemTrans*> *currentChain = new LinkedList<ElemTrans*> ( ptrETCompare );
LinkedList<int> *conflicts = new LinkedList<int> ( intCompare );
int *tmpsol = new int[nbft];
memcpy( tmpsol, sol->s, sizeof( int ) *nbft );
LabelPosition *lp;
double amin[2];
double amax[2];
ChainContext context;
context.featWrap = NULL;
context.borderSize = 0;
context.tmpsol = tmpsol;
context.inactiveCost = inactiveCost;
context.feat = NULL;
context.currentChain = currentChain;
context.conflicts = conflicts;
context.delta_tmp = &delta_tmp;
delta = 0;
while ( seed != -1 )
{
seedNbLp = featNbLp[seed];
delta_min = DBL_MAX;
next_seed = -1;
retainedLabel = -2;
// sol[seed] is ejected
if ( tmpsol[seed] == -1 )
delta -= inactiveCost[seed];
else
delta -= labelpositions[tmpsol[seed]]->getCost();
for ( i = -1; i < seedNbLp; i++ )
{
try
{
// Skip active label !
if ( !( tmpsol[seed] == -1 && i == -1 ) && i + featStartId[seed] != tmpsol[seed] )
{
if ( i != -1 ) // new_label
{
lid = featStartId[seed] + i;
delta_tmp = delta;
lp = labelpositions[lid];
// evaluate conflicts graph in solution after moving seed's label
lp->getBoundingBox( amin, amax );
context.lp = lp;
if ( conflicts->size() != 0 )
std::cerr << "Conflicts not empty" << std::endl;
candidates_sol->Search( amin, amax, chainCallback, ( void* ) &context );
// no conflict -> end of chain
if ( conflicts->size() == 0 )
{
if ( !retainedChain || delta + labelpositions[lid]->getCost() < delta_best )
{
if ( retainedChain )
{
delete[] retainedChain->label;
delete[] retainedChain->feat;
}
else
{
retainedChain = new Chain();
}
delta_best = delta + labelpositions[lid]->getCost();
retainedChain->degree = currentChain->size() + 1;
retainedChain->feat = new int[retainedChain->degree];
retainedChain->label = new int[retainedChain->degree];
Cell<ElemTrans*> *current = currentChain->getFirst();
ElemTrans* move;
j = 0;
while ( current )
{
move = current->item;
retainedChain->feat[j] = move->feat;
retainedChain->label[j] = move->new_label;
current = current->next;
j++;
}
retainedChain->feat[j] = seed;
retainedChain->label[j] = lid;
retainedChain->delta = delta + labelpositions[lid]->getCost();
}
}
// another feature can be ejected
else if ( conflicts->size() == 1 )
{
if ( delta_tmp < delta_min )
{
delta_min = delta_tmp;
retainedLabel = lid;
next_seed = conflicts->pop_front();
}
else
{
conflicts->pop_front();
}
}
else
{
// A lot of conflict : make them inactive and store chain
Chain *newChain = new Chain();
newChain->degree = currentChain->size() + 1 + conflicts->size();
newChain->feat = new int[newChain->degree];
newChain->label = new int[newChain->degree];
Cell<ElemTrans*> *current = currentChain->getFirst();
ElemTrans* move;
j = 0;
while ( current )
{
move = current->item;
newChain->feat[j] = move->feat;
newChain->label[j] = move->new_label;
current = current->next;
j++;
}
// add the current candidates into the chain
newChain->feat[j] = seed;
newChain->label[j] = lid;
newChain->delta = delta + labelpositions[newChain->label[j]]->getCost();
j++;
// hide all conflictual candidates
while ( conflicts->size() > 0 )
{
int ftid = conflicts->pop_front();
newChain->feat[j] = ftid;
newChain->label[j] = -1;
newChain->delta += inactiveCost[ftid];
j++;
}
if ( newChain->delta < delta_best )
{
if ( retainedChain )
delete_chain( retainedChain );
delta_best = newChain->delta;
retainedChain = newChain;
}
else
{
delete_chain( newChain );
}
}
}
else // Current label == -1 end of chain ...
{
if ( !retainedChain || delta + inactiveCost[seed] < delta_best )
{
if ( retainedChain )
{
delete[] retainedChain->label;
delete[] retainedChain->feat;
}
else
retainedChain = new Chain();
delta_best = delta + inactiveCost[seed];
retainedChain->degree = currentChain->size() + 1;
retainedChain->feat = new int[retainedChain->degree];
retainedChain->label = new int[retainedChain->degree];
Cell<ElemTrans*> *current = currentChain->getFirst();
ElemTrans* move;
j = 0;
while ( current )
{
move = current->item;
retainedChain->feat[j] = move->feat;
retainedChain->label[j] = move->new_label;
current = current->next;
j++;
}
retainedChain->feat[j] = seed;
retainedChain->label[j] = -1;
retainedChain->delta = delta + inactiveCost[seed];
}
}
}
}
catch ( int i )
{
#ifdef _DEBUG_FULL_
std::cout << "catch Cycle in chain" << std::endl;
#else
UNUSED( i );
#endif
while ( conflicts->size() > 0 )
conflicts->pop_front();
}
} // end foreach labelposition
if ( next_seed == -1 )
{
seed = -1;
}
else if ( currentChain->size() > max_degree )
{
std::cout << "Max degree reached !! (" << max_degree << ")" << std::endl;
seed = -1;
}
else
{
ElemTrans *et = new ElemTrans();
et->feat = seed;
et->old_label = tmpsol[seed];
et->new_label = retainedLabel;
currentChain->push_back( et );
if ( et->old_label != -1 )
{
labelpositions[et->old_label]->removeFromIndex( candidates_sol );
}
if ( et->new_label != -1 )
{
labelpositions[et->new_label]->insertIntoIndex( candidates_sol );
}
tmpsol[seed] = retainedLabel;
delta += labelpositions[retainedLabel]->getCost();
seed = next_seed;
}
}
while ( currentChain->size() > 0 )
{
ElemTrans* et = currentChain->pop_front();
if ( et->new_label != -1 )
{
labelpositions[et->new_label]->removeFromIndex( candidates_sol );
}
if ( et->old_label != -1 )
{
labelpositions[et->old_label]->insertIntoIndex( candidates_sol );
}
delete et;
}
delete currentChain;
delete[] tmpsol;
delete conflicts;
return retainedChain;
}
/**
* POPMUSIC, chain
*/
double Problem::popmusic_chain( SubPart *part )
{
int i;
//int j;
int probSize = part->probSize;
int borderSize = part->borderSize;
int subSize = part->subSize;
int *sub = part->sub;
int *sol = part->sol;
int *best_sol = new int[subSize];
for ( i = 0; i < subSize; i++ )
{
featWrap[sub[i]] = i;
best_sol[i] = sol[i];
}
double initial_cost;
double cur_cost = 0;
double best_cost = 0;
int nbOverlap = 0;
int seed;
int featOv;
int lid;
int fid;
int *tabu_list = new int[subSize];
Chain *current_chain = NULL;
//int itC;
int it;
int stop_it;
int maxit;
int itwimp; // iteration without improvment
int tenure = pal->tenure;
for ( i = 0; i < subSize; i++ )
{
cur_cost += compute_feature_cost( part, i, sol[i], &featOv );
nbOverlap += featOv;
}
initial_cost = cur_cost;
best_cost = cur_cost;
it = 0;
maxit = probSize * pal->tabuMaxIt;
itwimp = probSize * pal->tabuMinIt;;
stop_it = itwimp;
// feature on border always are tabu
for ( i = 0; i < borderSize; i++ )
tabu_list[i] = maxit; // border always are taboo
for ( i = 0; i < probSize; i++ )
tabu_list[i+borderSize] = -1; // others aren't
while ( it < stop_it )
{
seed = ( it % probSize ) + borderSize;
current_chain = chain( part, seed );
if ( current_chain )
{
/* we accept a modification only if the seed is not tabu or
* if the nmodification will generate a new best solution */
if ( tabu_list[seed] < it || ( cur_cost + current_chain->delta ) - best_cost < 0.0 )
{
for ( i = 0; i < current_chain->degree; i++ )
{
fid = current_chain->feat[i];
lid = current_chain->label[i];
if ( sol[fid] >= 0 )
{
labelpositions[sol[fid]]->removeFromIndex( candidates_subsol );
}
sol[fid] = lid;
if ( sol[fid] >= 0 )
{
labelpositions[lid]->insertIntoIndex( candidates_subsol );
}
tabu_list[fid] = it + tenure;
}
cur_cost += current_chain->delta;
#ifdef _DEBUG_FULL_
std::cout << "cur->cost: " << cur_cost << std::endl;
int kov;
std::cout << "computed cost: " << compute_subsolution_cost( part, sol, &kov ) << std::endl << std::endl;
#endif
/* check if new solution is a new best solution */
if ( best_cost - cur_cost > EPSILON )
{
best_cost = cur_cost;
memcpy( best_sol, sol, sizeof( int ) *subSize );
stop_it = ( it + itwimp > maxit ? maxit : it + itwimp );
}
}
delete_chain( current_chain );
}
it++;
}
memcpy( sol, best_sol, sizeof( int ) *subSize );
/*
for (i=borderSize;i<subSize;i++){
chain = chain (part, i);
if (chain){
if (chain->delta < 0.0){
best_cost += chain->delta;
for (j=0;j<chain->degree;j++){
fid = chain->feat[j];
lid = chain->label[j];
sol[fid] = lid;
}
}
delete_chain(chain);
}
}
*/
for ( i = 0; i < subSize; i++ )
featWrap[sub[i]] = -1;
delete[] best_sol;
delete[] tabu_list;
return initial_cost - best_cost;
}
/**
*
* POPMUSIC, Tabu search with chain'
*
*/
double Problem::popmusic_tabu_chain( SubPart *part )
{
int i;
int probSize = part->probSize;
int borderSize = part->borderSize;
int subSize = part->subSize;
int *sub = part->sub;
int *sol = part->sol;
int *best_sol = new int[subSize];
for ( i = 0; i < subSize; i++ )
{
featWrap[sub[i]] = i;
}
double initial_cost;
double cur_cost = 0;
double best_cost = 0;
int nbOverlap = 0;
int seed;
int featOv;
int lid;
int fid;
int *tmpsol = new int[subSize];
int *tabu_list = new int[subSize];
Chain *retainedChain = NULL;
Chain *current_chain = NULL;
int itC;
int it;
int stop_it;
int maxit;
int itwimp;
int tenure = pal->tenure;
//int deltaIt = 0;
Triple **candidates = new Triple*[probSize];
Triple **candidatesUnsorted = new Triple*[probSize];
LinkedList<int> *conflicts = new LinkedList<int> ( intCompare );
for ( i = 0; i < subSize; i++ )
{
cur_cost += compute_feature_cost( part, i, sol[i], &featOv );
nbOverlap += featOv;
}
initial_cost = cur_cost;
best_cost = cur_cost;
it = 0;
maxit = probSize * pal->tabuMaxIt;
itwimp = probSize * pal->tabuMinIt;;
stop_it = itwimp;
for ( i = 0; i < borderSize; i++ )
tabu_list[i] = maxit;
for ( i = 0; i < probSize; i++ )
{
tabu_list[i+borderSize] = -1;
candidates[i] = new Triple();
candidates[i]->feat_id = i + borderSize;
candidatesUnsorted[i] = candidates[i];
candidates[i]->cost = ( sol[i+borderSize] == -1 ? inactiveCost[i+borderSize] : labelpositions[sol[i+borderSize]]->getCost() );
}
sort(( void** ) candidates, probSize, decreaseCost );
int candidateListSize;
candidateListSize = int ( pal->candListSize * ( double ) probSize + 0.5 );
if ( candidateListSize > probSize )
candidateListSize = probSize;
#ifdef _DEBUG_FULL_
int nbOv;
std::cout << std::endl << "Initial solution cost " << cur_cost << std::endl;
std::cout << "Computed: " << compute_subsolution_cost( part, sol, &nbOv );
std::cout << "NbOverlap: " << nbOv << std::endl;
#endif
while ( it < stop_it )
{
retainedChain = NULL;
#ifdef _DEBUG_FULL_
std::cout << std::endl << std::endl << candidateListSize << std::endl;
#endif
for ( itC = 0; itC < candidateListSize; itC++ )
{
seed = candidates[itC]->feat_id;
#ifdef _DEBUG_FULL_
std::cout << "new candidates:" << std::endl;
#endif
current_chain = chain( part, seed );
#ifdef _DEBUG_FULL_
std::cout << "get chain:" << current_chain << std::endl;
#endif
if ( current_chain )
{
// seed is not taboo or chain give us a new best solution
if ( tabu_list[seed] < it || ( cur_cost + current_chain->delta ) - best_cost < 0.0 )
{
if ( !retainedChain )
{
retainedChain = current_chain;
#ifdef _DEBUG_FULL_
std::cout << "New chain, delta = " << current_chain->delta << std::endl;
#endif
}
else if ( current_chain->delta - retainedChain->delta < EPSILON )
{
delete_chain( retainedChain );
retainedChain = current_chain;
#ifdef _DEBUG_FULL_
std::cout << "New best chain, delta = " << current_chain->delta << std::endl;
#endif
}
else
{
#ifdef _DEBUG_FULL_
std::cout << "chain rejected..." << std::endl;
#endif
delete_chain( current_chain );
}
}
else
{
#ifdef _DEBUG_FULL_
std::cout << "chain rejected, tabu and/or delta = " << current_chain->delta << std::endl;
#endif
delete_chain( current_chain );
}
}
#ifdef _DEBUG_FULL_
else
{
std::cout << "no chain !!" << std::endl;
}
#endif
} // end foreach candidates
if ( retainedChain /*&& retainedChain->delta <= 0*/ )
{
#ifdef _DEBUG_FULL_
std::cout << it << " retained chain's degree: " << retainedChain->degree;
std::cout << " and delta: " << retainedChain->delta << std::endl;
#endif
for ( i = 0; i < retainedChain->degree; i++ )
{
fid = retainedChain->feat[i];
lid = retainedChain->label[i];
#ifdef _DEBUG_FULL_
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;
#endif
if ( sol[fid] >= 0 )
labelpositions[sol[fid]]->removeFromIndex( candidates_subsol );
sol[fid] = lid;
if ( lid >= 0 )
labelpositions[lid]->insertIntoIndex( candidates_subsol );
tabu_list[fid] = it + tenure;
#ifdef _DEBUG_FULL_
std::cout << "fid: " << fid << std::endl;
std::cout << "borderSize: " << borderSize << std::endl;
std::cout << "lid: " << lid << std::endl;
std::cout << "sub[fid]: " << sub[fid] << std::endl;
std::cout << "inactivecosr[sub[fid]]: " << inactiveCost[sub[fid]] << std::endl;
if ( lid > -1 )
{
std::cout << "label[lid]: " << labelpositions[lid] << std::endl;
std::cout << "label[lid]->cost: " << labelpositions[lid]->cost << std::endl;
}
#endif
candidatesUnsorted[fid-borderSize]->cost = ( lid == -1 ? inactiveCost[sub[fid]] : labelpositions[lid]->getCost() );
}
#ifdef _DEBUG_FULL_
std::cout << std::endl;
#endif
//std::cout << "old solution cost:" << cur_cost << std::endl;
cur_cost += retainedChain->delta;
//std::cout << "new solution cost:" << cur_cost << std::endl;
//int nbOv;
//std::cout << "computed solution cost:" << compute_subsolution_cost (part, sol, &nbOv) << std::endl;
//std::cout << "Overlap: " << nbOv << std::endl;
delete_chain( retainedChain );
if ( best_cost - cur_cost > EPSILON )
{
#ifdef _DEBUG_FULL_
std::cout << "new_best" << std::endl;
#endif
best_cost = cur_cost;
memcpy( best_sol, sol, sizeof( int ) *subSize );
stop_it = ( it + itwimp > maxit ? maxit : it + itwimp );
}
sort(( void** ) candidates, probSize, decreaseCost );
}
#ifdef _DEBUG_FULL_
else
{
std::cout << it << " no chain" << std::endl << std::endl;
}
#endif
it++;
}
memcpy( sol, best_sol, sizeof( int ) *subSize );
delete conflicts;
for ( i = 0; i < probSize; i++ )
delete candidates[i];
delete[] candidates;
delete[] candidatesUnsorted;
for ( i = 0; i < subSize; i++ )
featWrap[sub[i]] = -1;
delete[] best_sol;
delete[] tmpsol;
delete[] tabu_list;
return initial_cost - best_cost;
}
bool checkCallback( LabelPosition *lp, void *ctx )
{
LinkedList<LabelPosition*> *list = ( LinkedList<LabelPosition*>* ) ctx;
list->push_back( lp );
return true;
}
void Problem::check_solution()
{
LabelPosition *lp;
int *solution = new int[nbft];
double amin[2];
double amax[2];
amin[0] = bbox[0];
amin[1] = bbox[1];
amax[0] = bbox[2];
amax[1] = bbox[3];
LinkedList<LabelPosition*> *list = new LinkedList<LabelPosition*> ( ptrLPosCompare );
candidates_sol->Search( amin, amax, checkCallback, ( void* ) list );
std::cerr << "Check Solution" << std::endl;
int i;
int nbActive = 0;
for ( i = 0; i < nbft; i++ )
{
solution[i] = -1;
if ( sol->s[i] >= 0 )
nbActive++;
}
if ( list->size() != nbActive )
{
std::cerr << "Error in solution !!!!" << std::endl;
}
while ( list->size() > 0 )
{
lp = list->pop_front();
int probFeatId = lp->getProblemFeatureId();
if ( solution[probFeatId] >= 0 )
{
std::cerr << "Doublon : " << probFeatId << " "
<< solution[probFeatId] << "<->"
<< lp->getId() << std::endl;
}
solution[probFeatId] = lp->getId();
//std::cout << "lp->id:" << lp->id <<;
}
for ( i = 0; i < nbft; i++ )
{
if ( solution[i] != sol->s[i] )
{
std::cerr << "Feat " << i << " : " << solution[i] << "<-->" << sol->s[i] << std::endl;
}
}
}
typedef struct _nokContext
{
LabelPosition *lp;
bool *ok;
int *wrap;
} NokContext;
bool nokCallback( LabelPosition *lp, void *context )
{
LabelPosition *lp2 = (( NokContext* ) context )->lp;
bool *ok = (( NokContext* ) context )->ok;
int *wrap = (( NokContext* ) context )->wrap;
if ( lp2->isInConflict( lp ) )
{
if ( wrap )
{
ok[wrap[lp->getProblemFeatureId()]] = false;
}
else
{
ok[lp->getProblemFeatureId()] = false;
}
}
return true;
}
#if 0
// tabu,
void Problem::chain_search()
{
int i;
int *best_sol = new int[nbft];
double initial_cost;
double cur_cost = 0;
double best_cost = 0;
int nbOverlap = 0;
int seed;
int featOv;
int lid;
int fid;
int *tabu_list = new int[nbft];
Chain *current_chain = NULL;
int it;
int stop_it;
int maxit;
int itwimp; // iteration without improvment
int tenure = pal->tenure;
//tenure = 0;
#ifdef _VERBOSE_
clock_t start_time = clock();
clock_t init_sol_time;
clock_t search_time;
#endif
init_sol_falp();
#ifdef _VERBOSE_
std::cout << " Compute initial solution: " << ( double )(( init_sol_time = clock() ) - start_time ) / ( double ) CLOCKS_PER_SEC;
#endif
solution_cost();
#ifdef _VERBOSE_
std::cerr << "\t" << sol->cost << "\t" << nbActive << "\t" << ( double ) nbActive / ( double ) nbft;
std::cout << " (solution cost: " << sol->cost << ", nbDisplayed: " << nbActive << "(" << double( nbActive ) / nbft << "%)" << std::endl;
#endif
cur_cost = sol->cost;
initial_cost = cur_cost;
best_cost = cur_cost;
memcpy( best_sol, sol->s, sizeof( int ) *nbft );
it = 0;
maxit = nbft * pal->tabuMaxIt;
itwimp = nbft * pal->tabuMinIt;;
stop_it = itwimp;
for ( i = 0; i < nbft; i++ )
tabu_list[i] = -1; // others aren't
while ( it < stop_it )
{
seed = ( it % nbft );
if (( current_chain = chain( seed ) ) )
{
/* we accept a modification only if the seed is not tabu or
* if the nmodification will generate a new best solution */
if ( tabu_list[seed] < it || ( cur_cost + current_chain->delta ) - best_cost < -EPSILON )
{
for ( i = 0; i < current_chain->degree; i++ )
{
fid = current_chain->feat[i];
lid = current_chain->label[i];
if ( sol->s[fid] >= 0 )
{
labelpositions[sol->s[fid]]->removeFromIndex( candidates_sol );
}
sol->s[fid] = lid;
if ( sol->s[fid] >= 0 )
{
labelpositions[lid]->insertIntoIndex( candidates_sol );
}
tabu_list[fid] = it + tenure;
}
cur_cost += current_chain->delta;
#ifdef _DEBUG_
std::cout << "cur->cost: " << cur_cost << std::endl;
solution_cost();
std::cout << "computed cost: " << sol->cost << std::endl << std::endl;
#endif
/* check if new solution is a new best solution */
//std::cout << "Costs : " << cur_cost <<" <--> " << best_cost << std::endl;
if ( best_cost - cur_cost > EPSILON )
{
//std::cout << "New best : " << cur_cost <<" <--> " << best_cost << std::endl;
//std::cout << "New best" << std::endl;
best_cost = cur_cost;
memcpy( best_sol, sol->s, sizeof( int ) *nbft );
stop_it = ( it + itwimp > maxit ? maxit : it + itwimp );
}
}
delete_chain( current_chain );
}
it++;
}
memcpy( sol->s, best_sol, sizeof( int ) *nbft );
candidates_sol->RemoveAll();
for ( i = 0; i < nbft; i++ )
if ( sol->s[i] != -1 )
labelpositions[sol->s[i]]->insertIntoIndex( candidates_sol );
std::cout << "Cost : " << cur_cost << std::endl;
solution_cost();
#ifdef _VERBOSE_
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;
std::cerr << "\tna\tchain" << "\tna\t" << it << "\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;
#endif
delete[] best_sol;
delete[] tabu_list;
return;
}
#endif
void Problem::chain_search()
{
if ( nbft == 0 )
return;
int i;
int seed;
bool *ok = new bool[nbft];
int fid;
int lid;
#ifdef _VERBOSE_
clock_t start_time = clock();
clock_t init_sol_time;
clock_t search_time;
#endif
int popit = 0;
double amin[2];
double amax[2];
NokContext context;
context.ok = ok;
context.wrap = NULL;
Chain *retainedChain;
featWrap = NULL;
for ( i = 0; i < nbft; i++ )
{
ok[i] = false;
}
//initialization();
init_sol_falp();
//check_solution();
#ifdef _VERBOSE_
std::cout << " Compute initial solution: " << ( double )(( init_sol_time = clock() ) - start_time ) / ( double ) CLOCKS_PER_SEC;
#endif
solution_cost();
#ifdef _VERBOSE_
std::cerr << "\t" << sol->cost << "\t" << nbActive << "\t" << ( double ) nbActive / ( double ) nbft;
std::cout << " (solution cost: " << sol->cost << ", nbDisplayed: " << nbActive << "(" << double( nbActive ) / nbft << "%)" << std::endl;
#endif
int iter = 0;
while ( true )
{
//check_solution();
for ( seed = ( iter + 1 ) % nbft;
ok[seed] && seed != iter;
seed = ( seed + 1 ) % nbft )
;
// All seeds are OK
if ( seed == iter )
{
break;
}
iter = ( iter + 1 ) % nbft;
#ifdef _DEBUG_FULL_
std::cout << "Seed for it " << popit << " is " << seed << std::endl;
#endif
retainedChain = chain( seed );
if ( retainedChain && retainedChain->delta < - EPSILON )
{
#ifdef _DEBUG_FULL_
std::cout << "chain's degree & delta : " << retainedChain->degree << " " << retainedChain->delta << std::endl;
#endif
// apply modification
for ( i = 0; i < retainedChain->degree; i++ )
{
fid = retainedChain->feat[i];
lid = retainedChain->label[i];
#ifdef _DEBUG_FULL_
std::cout << " " << i << " :" << fid << " " << lid << std::endl;
std::cout << " sol->s[fid]: " << sol->s[fid] << " <=> " << lid << std::endl;
if ( sol->s[fid] == -1 || lid == -1 )
std::cout << "feat inactive :" << inactiveCost[fid] << std::endl;
if ( sol->s[fid] >= 0 )
std::cout << "old cost : " << labelpositions[sol->s[fid]]->cost << std::endl;
if ( lid >= 0 )
std::cout << "new cost : " << labelpositions[lid]->cost << std::endl;
#endif
if ( sol->s[fid] >= 0 )
{
LabelPosition *old = labelpositions[sol->s[fid]];
old->removeFromIndex( candidates_sol );
old->getBoundingBox( amin, amax );
context.lp = old;
candidates->Search( amin, amax, nokCallback, &context );
}
sol->s[fid] = lid;
if ( sol->s[fid] >= 0 )
{
labelpositions[lid]->insertIntoIndex( candidates_sol );
}
ok[fid] = false;
}
sol->cost += retainedChain->delta;
#ifdef _DEBUG_FULL_
std::cout << "Expected cost: " << sol->cost << std::endl;
solution_cost();
std::cout << "chain iteration " << popit << ": " << sol->cost << ", " << retainedChain->delta << ", " << retainedChain->degree << std::endl;
#endif
}
else
{
// no chain or the one is not god enough
ok[seed] = true;
}
delete_chain( retainedChain );
popit++;
}
#ifdef _DEBUG_FULL_
std::cout << "Cur_cost: " << sol->cost << std::endl;
sol->cost = 0;
#endif
solution_cost();
#ifdef _VERBOSE_
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;
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;
#endif
delete[] ok;
return;
}
#if 0
double Problem::popmusic_chain( SubPart *part )
{
int i;
int probSize = part->probSize;
int borderSize = part->borderSize;
int subSize = part->subSize;
int *sub = part->sub;
int *sol = part->sol;
int *best_sol = new int[subSize];
for ( i = 0; i < subSize; i++ )
{
featWrap[sub[i]] = i;
best_sol[i] = sol[i];
}
double initial_cost;
double cur_cost = 0;
int nbOverlap = 0;
int seed;
int featOv;
int lid;
int fid;
bool *ok = new bool[subSize];
Chain *retainedChain = NULL;
int c;
double amin[2];
double amax[2];
NokContext context;
context.ok = ok;
context.feat = NULL;
context.wrap = featWrap;
//int itC;
int iter = 0, it = 0;
for ( i = 0; i < subSize; i++ )
{
cur_cost += compute_feature_cost( part, i, sol[i], &featOv );
nbOverlap += featOv;
}
initial_cost = cur_cost;
#ifdef _DEBUG_FULL_
cout << "Popmusic_chain" << std::endl;
std::cout << " initial cost" << initial_cost << std::endl;
#endif
// feature on border are ok
for ( i = 0; i < borderSize; i++ )
ok[i] = true; // border is ok
for ( i = 0; i < probSize; i++ )
ok[i+borderSize] = false; // others aren't
while ( true )
{
for ( seed = ( iter + 1 ) % probSize;
ok[seed + borderSize] && seed != iter;
seed = ( seed + 1 ) % probSize );
if ( seed == iter )
break;
iter = ( iter + 1 ) % probSize;
seed = seed + borderSize;
retainedChain = chain( part, seed );
#ifdef _DEBUG_FULL_
std::cout << " seed: " << seed << "(" << seed - borderSize << " / " << probSize << ")" << std::endl;
std::cout << " chain(seed)";
if ( retainedChain )
{
std::cout << " delta: " << retainedChain->delta << std::endl;
}
else
std::cout << ": undef" << std::endl;
#endif
if ( retainedChain && retainedChain->delta < -EPSILON )
{
#ifdef _DEBUG_FULL_
std::cout << " chain accepted " << std::endl;
#endif
for ( i = 0; i < retainedChain->degree; i++ )
{
fid = retainedChain->feat[i];
lid = retainedChain->label[i];
if ( sol[fid] >= 0 )
{
LabelPosition *old = labelpositions[sol[fid]];
old->removeFromIndex( candidates_subsol );
old->getBoundingBox( amin, amax );
context.lp = old;
candidates->Search( amin, amax, nokCallback, &context );
}
sol[fid] = lid;
if ( sol[fid] >= 0 )
labelpositions[lid]->insertIntoIndex( candidates_subsol );
ok[fid] = false;
}
cur_cost += retainedChain->delta;
#ifdef _DEBUG_FULL_
std::cout << " cur->cost: " << cur_cost << std::endl;
int kov;
std::cout << " computed cost: " << compute_subsolution_cost( part, sol, &kov ) << std::endl << std::endl;
#endif
}
else
{
ok[seed] = true;
}
delete_chain( retainedChain );
it++;
}
for ( i = 0; i < subSize; i++ )
featWrap[sub[i]] = -1;
delete[] ok;
#ifdef _DEBUG_FULL_
std::cout << "Final cost : " << cur_cost << " (" << initial_cost - cur_cost << ")" << std::endl;
#endif
return initial_cost - cur_cost;
}
//#undef _DEBUG_FULL_
#endif
bool Problem::compareLabelArea( pal::LabelPosition* l1, pal::LabelPosition* l2 )
{
return l1->getWidth() * l1->getHeight() > l2->getWidth() * l2->getHeight();
}
std::list<LabelPosition*> * Problem::getSolution( bool returnInactive )
{
int i;
std::list<LabelPosition*> *solList = new std::list<LabelPosition*>();
if ( nbft == 0 )
{
return solList;
}
for ( i = 0; i < nbft; i++ )
{
if ( sol->s[i] != -1 )
{
solList->push_back( labelpositions[sol->s[i]] ); // active labels
}
else if ( returnInactive
|| labelpositions[featStartId[i]]->getFeaturePart()->getLayer()->getDisplayAll()
|| labelpositions[featStartId[i]]->getFeaturePart()->getAlwaysShow() )
{
solList->push_back( labelpositions[featStartId[i]] ); // unplaced label
}
}
// if features collide, order by size, so smaller ones appear on top
if ( returnInactive )
{
solList->sort( compareLabelArea );
}
return solList;
}
PalStat * Problem::getStats()
{
int i, j;
PalStat *stats = new PalStat();
stats->nbObjects = nbft;
stats->nbLabelledObjects = 0;
stats->nbLayers = nbLabelledLayers;
stats->layersName = new char*[stats->nbLayers];
stats->layersNbObjects = new int[stats->nbLayers];
stats->layersNbLabelledObjects = new int[stats->nbLayers];
for ( i = 0; i < stats->nbLayers; i++ )
{
stats->layersName[i] = new char[strlen( labelledLayersName[i] ) + 1];
strcpy( stats->layersName[i], labelledLayersName[i] );
stats->layersNbObjects[i] = 0;
stats->layersNbLabelledObjects[i] = 0;
}
char *lyrName;
int k;
for ( i = 0; i < nbft; i++ )
{
lyrName = labelpositions[featStartId[i]]->getLayerName();
k = -1;
for ( j = 0; j < stats->nbLayers; j++ )
{
if ( strcmp( lyrName, stats->layersName[j] ) == 0 )
{
k = j;
break;
}
}
if ( k != -1 )
{
stats->layersNbObjects[k]++;
if ( sol->s[i] >= 0 )
{
stats->layersNbLabelledObjects[k]++;
stats->nbLabelledObjects++;
}
}
else
{
std::cerr << "Error unknown layers while computing stats: " << lyrName << std::endl;
}
}
return stats;
}
void Problem::post_optimization()
{
#if 0
/*
* this->sol => s[nbFeature] s[i] = quel label pour la feat. i
* this->labelpositions => tout les candidats à la suite pour toute les feature
* labelpositions[sol->s[i]] => label choisi pour la feat. i (attention sol->s[i] peut == -1 pour indiquer que le label est pas affiché)
*
* this->featStartId => featStartId[i] indice du premier candidate dans labelposiiton pour la feat. i
* this->feat => a quel feat correspond un candidats (feat[labelId] == feature id)
*
*
*
*
* labelpositon[i]->geometry == la geometrie qui correspond au label (possible que ça soit NULL) dans ce cas c'est labelpositions[i]->feature qui doit etre utilisée (normalement c'est que pour les points)
*
*
*
* L'appel a cette méthode est fait dans pal->labeller
*
*/
Feature *feature;
LabelPosition *lp;
int i, j;
double xrm, yrm;
std::ofstream solution( "solution.raw" );
solution << "GeomType ; nbPoints ; label length ; label height ; down-left X ; down-left Y ; rotation (rad) ; points list" << std::endl;
for ( i = 0; i < nbft; i++ )
{
if ( sol->s[i] >= 0 )
{
lp = labelpositions[sol->s[i]];
if ( lp->feature->layer->label_unit == PIXEL )
{
xrm = px2meters( lp->feature->label_x, pal->dpi, scale );
yrm = px2meters( lp->feature->label_y, pal->dpi, scale );
}
else
{
xrm = lp->feature->label_x;
yrm = lp->feature->label_y;
}
}
else
{
lp = labelpositions[featStartId[i]];
xrm = yrm = 0;
}
feature = lp->feature;
if ( sol->s[i] >= 0 )
{
solution << feature->type << ";" << feature->nbPoints << ";" << xrm << ";" << yrm
<< ";" << lp->x[0] << ";" << lp->y[0] << ";" << lp->alpha << ";";
}
else
{
solution << feature->type << ";" << feature->nbPoints << ";0;0;0;0;0;";
}
for ( j = 0; j < feature->nbPoints; j++ )
{
solution << feature->x[j] << " " << feature->y[j] << " ";
}
solution << std::endl;
}
solution.close();
#endif
}
void Problem::solution_cost()
{
#ifdef _DEBUG_FULL_
std::cout << "Global solution evaluation" << std::endl;
#endif
sol->cost = 0.0;
nbActive = 0;
int nbOv;
int i;
LabelPosition::CountContext context;
context.inactiveCost = inactiveCost;
context.nbOv = &nbOv;
context.cost = &sol->cost;
double amin[2];
double amax[2];
LabelPosition *lp;
int nbHidden = 0;
for ( i = 0; i < nbft; i++ )
{
if ( sol->s[i] == -1 )
{
sol->cost += inactiveCost[i];
nbHidden++;
}
else
{
nbOv = 0;
lp = labelpositions[sol->s[i]];
lp->getBoundingBox( amin, amax );
context.lp = lp;
candidates_sol->Search( amin, amax, LabelPosition::countFullOverlapCallback, &context );
sol->cost += lp->getCost();
if ( nbOv == 0 )
nbActive++;
}
}
#ifdef _DEBUG_
if ( nbActive + nbHidden != nbft )
{
std::cout << "Conflicts in solution: " << nbHidden / 2 << std::endl;
}
std::cout << "nbActive and free: " << nbActive << " (" << double( nbActive ) / double( nbft ) << " %)" << std::endl;
std::cout << "solution cost:" << sol->cost << std::endl;
#endif
}
#ifdef _EXPORT_MAP_
void Problem::drawLabels( std::ofstream &svgmap )
{
int i;
svgmap << "<g inkscape:label=\"labels\"" << std::endl
<< "inkscape:groupmode=\"layer\"" << std::endl
<< "id=\"label_layer\">" << std::endl << std::endl;
for ( i = 0; i < nbft; i++ )
{
if ( sol->s[i] >= 0 )
{
LabelPosition *lp = labelpositions[sol->s[i]];
toSVGPath( 4, 3, lp->x, lp->y, pal->getDpi(), scale, convert2pt( bbox[0], scale, pal->getDpi() ), convert2pt( bbox[3], scale, pal->getDpi() ), "label", lp->feature->uid, svgmap );
}
}
svgmap << "</g>" << std::endl;
}
#endif
} // namespace