SCIP

    Solving Constraint Integer Programs

    heur_cyckerlin.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file heur_cyckerlin.c
    26 * @brief improvement heuristic that exchanges binary variables between clusters.
    27 * Similar to the famous kernighan/lin heuristic for graph partitioning
    28 * @author Leon Eifler
    29 */
    30
    31/*---+---- 1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    33#include "heur_cyckerlin.h"
    34#include "probdata_cyc.h"
    35#include "scip/pub_misc.h"
    36
    37#define HEUR_NAME "cyckerlin"
    38#define HEUR_DESC "switch heuristic that tries to improve solution by trading states betweeen clusters"
    39#define HEUR_DISPCHAR '@'
    40#define HEUR_PRIORITY 500
    41#define HEUR_FREQ 10
    42#define HEUR_FREQOFS 0
    43#define HEUR_MAXDEPTH -1
    44#define MAXPERMUTATIONS 5
    45#define DEFAULT_RANDSEED 177 /**< random seed */
    46#define HEUR_TIMING SCIP_HEURTIMING_BEFORENODE
    47#define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
    48
    49struct SCIP_HeurData
    50{
    51 SCIP_SOL** candidates;
    52 int ncandidates;
    53 int candlength;
    54};
    55
    56/*
    57 * Local methods
    58 */
    59
    60/** external method that adds a solution to the list of candidate-solutions that should be improved */
    62 SCIP* scip, /**< SCIP data structure */
    63 SCIP_SOL* sol /**< the given solution */
    64 )
    65{
    66 SCIP_HEUR* heur;
    67 SCIP_HEURDATA* heurdata;
    68
    69 heur = SCIPfindHeur(scip, "cyckerlin");
    70
    71 if( heur == NULL )
    72 return SCIP_OKAY;
    73
    74 heurdata = SCIPheurGetData(heur);
    75
    76 assert(heurdata != NULL);
    77 assert(sol != NULL);
    78
    79 /* realloc candidate array, if necessary */
    80 if( heurdata->candlength - 1 <= heurdata->ncandidates )
    81 {
    82 SCIP_CALL( SCIPreallocMemoryArray(scip, &(heurdata->candidates), (SCIP_Longint) heurdata->candlength * 2) );
    83 heurdata->candlength *= 2;
    84 }
    85
    86 heurdata->candidates[heurdata->ncandidates] = sol;
    87 heurdata->ncandidates++;
    88
    89 return SCIP_OKAY;
    90}
    91
    92
    93/** get the bin-var assignment from scip and save it as a matrix */
    94static
    96 SCIP* scip, /**< SCIP data structure */
    97 SCIP_SOL* bestsol, /**< the solution */
    98 SCIP_Real** solclustering, /**< matrix to save the bin-vars*/
    99 SCIP_Bool** binfixed, /**< matrix to save if a bin is fixed in scip */
    100 int* clusterofbin, /**< array containing the cluster of each bin */
    101 int* nbinsincluster /**< number of bins in each cluster */
    102 )
    103{
    104 SCIP_VAR*** binvars;
    105 int nbins;
    106 int ncluster;
    107 int i;
    108 int c;
    109
    110 assert(bestsol != NULL);
    111
    112 nbins = SCIPcycGetNBins(scip);
    113 ncluster = SCIPcycGetNCluster(scip);
    114 binvars = SCIPcycGetBinvars(scip);
    115
    116 assert(nbins > 0 && ncluster > 0 && nbins > ncluster);
    117 assert(binvars != NULL);
    118
    119 /* get the bin-variable values from the solution */
    120 for( i = 0; i < nbins; ++i )
    121 {
    122 for( c = 0; c < ncluster; ++c )
    123 {
    124 binfixed[i][c] = FALSE;
    125
    126 if( binvars[i][c] != NULL)
    127 {
    128 if( (SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(binvars[i][c]), SCIPvarGetLbGlobal(binvars[i][c]))) )
    129 binfixed[i][c] = TRUE;
    130
    131 solclustering[i][c] = SCIPgetSolVal(scip, bestsol, binvars[i][c]);
    132
    133 if( SCIPisFeasEQ(scip, solclustering[i][c], 1.0) )
    134 {
    135 clusterofbin[i] = c;
    136 nbinsincluster[c]++;
    137 }
    138 }
    139 }
    140 }
    141
    142 return SCIP_OKAY;
    143}
    144
    145/** Set a bin to a new cluster, update the qmatrix. */
    146static
    148 SCIP_Real** solclustering, /**< the matrix with the clustering of the bins */
    149 SCIP_Real** cmatrix, /**< the transition matrix*/
    150 SCIP_Real** qmatrix, /**< the matrix containing the transition probabilities between clusters*/
    151 int newbin, /**< the bin to be changed*/
    152 int newcluster, /**< the cluster where the bin is changed*/
    153 SCIP_Bool setone, /**< TRUE if the assignment is switched from 0 to 1, FALSE if 1 to 0*/
    154 int nbins, /**< the number of bins*/
    155 int ncluster /**< the number of clusters*/
    156 )
    157{
    158 int bin;
    159 int cluster;
    160 SCIP_Real sign = setone ? 1.0 : -1.0;
    161
    162 for( cluster = 0; cluster < ncluster; ++cluster )
    163 {
    164 for( bin = 0; bin < nbins; ++bin )
    165 {
    166 if( cluster != newcluster )
    167 {
    168 qmatrix[newcluster][cluster] += sign * solclustering[bin][cluster] * cmatrix[newbin][bin];
    169 qmatrix[cluster][newcluster] += sign * solclustering[bin][cluster] * cmatrix[bin][newbin];
    170 }
    171 else
    172 {
    173 if( bin != newbin )
    174 {
    175 qmatrix[newcluster][newcluster] += sign * (cmatrix[newbin][bin] + cmatrix[bin][newbin])
    176 * solclustering[bin][cluster];
    177 }
    178 }
    179 }
    180 }
    181
    182 solclustering[newbin][newcluster] = (sign + 1.0) / 2.0;
    183}
    184
    185/** initialize the q-matrix from a given (possibly incomplete) clusterassignment */
    186static
    188 SCIP_Real** clustering, /**< the matrix containing the clusterassignment */
    189 SCIP_Real** qmatrix, /**< the returned matrix the transition probability between clusters */
    190 SCIP_Real** cmatrix, /**< the transition-matrix containg the probability-data */
    191 int nbins, /**< the number of bins */
    192 int ncluster /**< the number of possible clusters */
    193 )
    194{
    195 int i;
    196 int j;
    197 int k;
    198 int l;
    199
    200 for( k = 0; k < ncluster; ++k )
    201 {
    202 for( l = 0; l < ncluster; ++l )
    203 {
    204 qmatrix[k][l] = 0;
    205 for( i = 0; i < nbins; ++i )
    206 {
    207 for( j = 0; j < nbins; ++j )
    208 {
    209 /* as -1 and 0 are both interpreted as 0, this check is necessary. Compute x_ik*x_jl*c_ij */
    210 if( i == j )
    211 continue;
    212
    213 qmatrix[k][l] += cmatrix[i][j] * clustering[i][k] * clustering[j][l];
    214 }
    215 }
    216 }
    217 }
    218}
    219
    220/** calculate the current objective value for a q-matrix */
    221static
    223 SCIP* scip, /**< SCIP data structure */
    224 SCIP_Real** qmatrix, /**< the irreversibility matrix*/
    225 SCIP_Real scale, /**< the scaling parameter in the objective function */
    226 int ncluster /**< the number of cluster*/
    227 )
    228{
    229 SCIP_Real objective = 0.0;
    230 int c;
    231 int c2;
    232
    233 for( c = 0; c < ncluster; ++c )
    234 {
    235 c2 = ( c + 1 ) % ncluster;
    236 objective += ( qmatrix[c][c2] - qmatrix[c2][c]);
    237 objective += scale * qmatrix[c][c];
    238 }
    239
    240 /* if we have no transitions at all then irreversibility should be set to 0 */
    241 return objective;
    242}
    243
    244/** exchange another bin to a different cluster. No bin may be changed twice */
    245static
    247 SCIP* scip, /**< SCIP data structure */
    248 SCIP_Real** cmatrix, /**< the transition matrix */
    249 SCIP_Real** qmatrix, /**< the irreversibility matrix */
    250 SCIP_Real** clustering, /**< the clusterassignement */
    251 SCIP_Bool** binfixed, /**< array containing information about fixedbins */
    252 SCIP_Bool* binprocessed, /**< has the bin already been switched? */
    253 int* clusterofbin, /**< contains the cluster each bin is in at the moment */
    254 int* nbinsincluster, /**< number of bins in each cluster */
    255 int* switchedbin, /**< the bins swithced in each iteration */
    256 int* switchedcluster, /**< the cluster to witch the bin was assigned in each iteration */
    257 SCIP_Real* switchbound, /**< the objective achieved in each iteration */
    258 SCIP_Real* maxbound, /**< the best objective value so far */
    259 int* bestlength, /**< the amount of switches with the best objective value so far */
    260 int iteration /**< which iteration are we in */
    261 )
    262{
    263 SCIP_Real irrevchg;
    264 SCIP_Real cohchg;
    265 SCIP_Real maxboundlocal;
    266 SCIP_Real scale;
    267 SCIP_Real oldobjective;
    268 int bin;
    269 int k;
    270 int i;
    271 int l;
    272 int indkmin;
    273 int indlmin;
    274 int maxbin;
    275 int maxcluster;
    276 int nbins = SCIPcycGetNBins(scip);
    277 int ncluster = SCIPcycGetNCluster(scip);
    278
    279 scale = SCIPcycGetScale(scip);
    280 maxboundlocal = -SCIPinfinity(scip);
    281 oldobjective = getObjective(scip, qmatrix, scale, ncluster);
    282 maxbin = -1;
    283 maxcluster = -1;
    284
    285 assert(isPartition(scip, clustering, nbins, ncluster));
    286
    287 for( bin = 0; bin < nbins; ++bin )
    288 {
    289 if( binprocessed[bin] || nbinsincluster[clusterofbin[bin]] == 1 )
    290 continue;
    291 k = clusterofbin[bin];
    292
    293 assert(SCIPisFeasEQ(scip, clustering[bin][k], 1.0));
    294
    295 /* calculate the irreversibility and coherence after bin was moved from k to l */
    296 for( l = 0; l < ncluster; ++l )
    297 {
    298 if( binfixed[bin][k] || binfixed[bin][l] )
    299 continue;
    300
    301 if( k == l )
    302 continue;
    303
    304 if( k == 0 )
    305 indkmin = ncluster - 1;
    306 else
    307 indkmin = k - 1;
    308
    309 if( l == 0 )
    310 indlmin = ncluster - 1;
    311 else
    312 indlmin = l - 1;
    313
    314 irrevchg = 0;
    315 cohchg = 0;
    316
    317 assert(SCIPisZero(scip, clustering[bin][l]));
    318
    319 for( i = 0; i < nbins; ++i )
    320 {
    321 /*irreversibility change */
    322 irrevchg -= clustering[i][indkmin] * (cmatrix[i][bin] - cmatrix[bin][i]);
    323 irrevchg -= clustering[i][(k+1) % ncluster] * (cmatrix[bin][i] - cmatrix[i][bin]);
    324
    325 clustering[bin][k] = 0;
    326 clustering[bin][l] = 1;
    327
    328 irrevchg += clustering[i][indlmin] * (cmatrix[i][bin] - cmatrix[bin][i]);
    329 irrevchg += clustering[i][(l+1) % ncluster] * (cmatrix[bin][i] - cmatrix[i][bin]);
    330
    331 clustering[bin][k] = 1;
    332 clustering[bin][l] = 0;
    333
    334 /*coherence change */
    335 if( i != bin )
    336 {
    337 cohchg -= clustering[i][k] * (cmatrix[bin][i]+ cmatrix[i][bin]);
    338 cohchg += clustering[i][l] * (cmatrix[bin][i]+ cmatrix[i][bin]);
    339 }
    340 }
    341
    342 if( oldobjective + irrevchg + scale * cohchg > maxboundlocal )
    343 {
    344 maxboundlocal = oldobjective + irrevchg + scale * cohchg;
    345 maxbin = bin;
    346 maxcluster = l;
    347 }
    348 }
    349 }
    350
    351 if( maxbin == -1 )
    352 return FALSE;
    353
    354 assert(maxbin >= 0 && maxcluster >= 0);
    355 assert(maxbin < nbins && maxcluster < ncluster);\
    356
    357 /* assign the exchange and update all saving-structures */
    358 setBinToCluster(clustering, cmatrix, qmatrix, maxbin, clusterofbin[maxbin], FALSE, nbins, ncluster);
    359 setBinToCluster(clustering, cmatrix, qmatrix, maxbin, maxcluster, TRUE, nbins, ncluster);
    360
    361 nbinsincluster[clusterofbin[maxbin]]--;
    362 nbinsincluster[maxcluster]++;
    363
    364 clusterofbin[maxbin] = maxcluster;
    365 binprocessed[maxbin] = TRUE;
    366
    367 switchedbin[iteration] = maxbin;
    368 switchedcluster[iteration] = maxcluster;
    369 switchbound[iteration] = getObjective(scip, qmatrix, scale, ncluster);
    370
    371 if( switchbound[iteration] > *maxbound )
    372 {
    373 *maxbound = switchbound[iteration];
    374 *bestlength = iteration;
    375 }
    376
    377 return TRUE;
    378}
    379
    380/** Create a solution in scip from the clustering */
    381static
    383 SCIP* scip, /**< SCIP data structure */
    384 SCIP_HEUR* heur, /**< heuristic pointer */
    385 SCIP_Real** cmatrix, /**< the transition matrix */
    386 SCIP_Real** qmatrix, /**< the projected transition matrix using the clustering */
    387 SCIP_Bool** binfixed, /**< matrix that tells which bin-variables cannot be changed */
    388 SCIP_Real** startclustering, /**< the start-assignment */
    389 SCIP_RESULT* result, /**< result pointer */
    390 int nbins, /**< the number of states */
    391 int ncluster /**< the number of clusters */
    392 )
    393{
    394 SCIP_SOL* bestsol;
    395 SCIP_SOL* worksol;
    396 SCIP_Real** clustering;
    397 SCIP_Real** solclustering;
    398 SCIP_Bool* binprocessed;
    400 SCIP_Real objective;
    401 SCIP_Real* switchbound;
    402 SCIP_Real maxbound;
    403 SCIP_Bool heurpossible = TRUE;
    404 SCIP_Bool feasible;
    405 int c;
    406 int i;
    407 int* nbinsincluster; /*lint !e771*/
    408 int* switchedbin;
    409 int* switchedcluster;
    410 int* clusterofbin;
    411 int bestlength;
    412 int nrswitches;
    413
    414 /* allocate memory */
    415 SCIP_CALL( SCIPallocBufferArray(scip, &binprocessed, nbins) );
    416 SCIP_CALL( SCIPallocBufferArray(scip, &switchbound, nbins) );
    417 SCIP_CALL( SCIPallocBufferArray(scip, &nbinsincluster, ncluster) );
    418 SCIP_CALL( SCIPallocBufferArray(scip, &switchedbin, nbins) );
    419 SCIP_CALL( SCIPallocBufferArray(scip, &switchedcluster, nbins) );
    420 SCIP_CALL( SCIPallocBufferArray(scip, &clusterofbin, nbins) );
    421 SCIP_CALL( SCIPallocClearBufferArray(scip, &clustering, nbins) );
    422 SCIP_CALL( SCIPallocClearBufferArray(scip, &solclustering, nbins) );
    423
    424 for( i = 0; i < nbins; ++i )
    425 {
    426 SCIP_CALL( SCIPallocClearBufferArray(scip, &clustering[i], ncluster) ); /*lint !e866*/
    427 SCIP_CALL( SCIPallocClearBufferArray(scip, &solclustering[i], ncluster) ); /*lint !e866*/
    428 }
    429
    430 /* copy the solution so that we may change it and still keep the original one*/
    431 for( c = 0; c < ncluster; ++c )
    432 {
    433 nbinsincluster[c] = 0;
    434 }
    435
    436 for( i = 0; i < nbins; ++i )
    437 {
    438 for( c = 0; c < ncluster; ++c )
    439 {
    440 solclustering[i][c] = startclustering[i][c];
    441
    442 if( SCIPisFeasEQ(scip, startclustering[i][c], 1.0) )
    443 {
    444 clusterofbin[i] = c;
    445 nbinsincluster[c]++; /*lint !e771*/
    446 }
    447 }
    448
    449 binprocessed[i] = FALSE;
    450 }
    451
    452 bestsol = SCIPgetBestSol(scip);
    453
    454 while( heurpossible )
    455 {
    456 /* we run the heuristic until we cannot find any more improvement */
    457 for( c = 0; c < ncluster; ++c )
    458 {
    459 nbinsincluster[c] = 0;
    460 }
    461
    462 for( i = 0; i < nbins; ++i )
    463 {
    464 for( c = 0; c < ncluster; ++c )
    465 {
    466 clustering[i][c] = solclustering[i][c];
    467
    468 if( SCIPisFeasEQ(scip, solclustering[i][c], 1.0) )
    469 {
    470 clusterofbin[i] = c;
    471 nbinsincluster[c]++;
    472 }
    473 }
    474
    475 binprocessed[i] = FALSE;
    476 }
    477
    478 bestlength = -1;
    479 nrswitches = nbins;
    480
    481 /* initialize qmatrix */
    482 computeIrrevMat(solclustering, qmatrix, cmatrix, nbins, ncluster);
    483 maxbound = SCIPgetSolOrigObj(scip, bestsol);
    484
    485 /* main part of the heuristic. States are switched until every state has been exchanged exactly once */
    486 for( i = 0; i < nrswitches; ++i )
    487 {
    488 if( !switchNext(scip, cmatrix, qmatrix, clustering, binfixed, binprocessed, clusterofbin,
    489 nbinsincluster, switchedbin, switchedcluster, switchbound, &maxbound, &bestlength, i) )
    490 {
    491 nrswitches = i;
    492 break;
    493 }
    494 }
    495
    496 /* select the clustering with the best objective and reconstruct it from the start clustering */
    497 for( i = 0; i <= bestlength; ++i )
    498 {
    499 for( c = 0; c < ncluster; ++c )
    500 {
    501 solclustering[switchedbin[i]][c] = 0; /*lint !e771*/
    502 }
    503
    504 solclustering[switchedbin[i]][switchedcluster[i]] = 1; /*lint !e771*/
    505 clusterofbin[switchedbin[i]] = switchedcluster[i];
    506 }
    507
    508 computeIrrevMat(solclustering, qmatrix, cmatrix, nbins, ncluster);
    509 max = getObjective(scip, qmatrix, SCIPcycGetScale(scip), ncluster);
    510 objective = SCIPgetSolOrigObj(scip, bestsol);
    511 feasible = FALSE;
    512
    513 /* if the solution is an improvement we add it to scip */
    514 if( max > objective )
    515 {
    516 SCIP_CALL( SCIPcreateSol(scip, &worksol, heur) );
    517
    518 assert(isPartition(scip, solclustering, nbins, ncluster));
    519
    520 SCIP_CALL( assignVars(scip, worksol, solclustering, nbins, ncluster) );
    521 SCIP_CALL( SCIPtrySolFree(scip, &worksol, FALSE, TRUE, TRUE, TRUE, TRUE, &feasible) );
    522 }
    523
    524 if( feasible )
    525 {
    526 *result = SCIP_FOUNDSOL;
    527 objective = max;
    528 }
    529 else
    530 {
    531 *result = SCIP_DIDNOTFIND;
    532 heurpossible = FALSE;
    533 }
    534 }
    535
    536 /* free memory */
    537 for( i = 0; i < nbins; ++i )
    538 {
    539 SCIPfreeBufferArray(scip, &solclustering[i]);
    540 SCIPfreeBufferArray(scip, &clustering[i]);
    541 }
    542
    543 SCIPfreeBufferArray(scip, &solclustering);
    544 SCIPfreeBufferArray(scip, &clustering);
    545 SCIPfreeBufferArray(scip, &clusterofbin);
    546 SCIPfreeBufferArray(scip, &switchedcluster);
    547 SCIPfreeBufferArray(scip, &switchedbin);
    548 SCIPfreeBufferArray(scip, &nbinsincluster);
    549 SCIPfreeBufferArray(scip, &switchbound);
    550 SCIPfreeBufferArray(scip, &binprocessed);
    551
    552 return SCIP_OKAY;
    553}
    554
    555/** method that randomly creates a different solution from a given solution. From each cluster, half the states are
    556 * randomly selected and added to the next cluster. */
    557static
    559 SCIP* scip, /**< SCIP data structure */
    560 SCIP_Real** startclustering, /**< the solution to be permuted */
    561 SCIP_RANDNUMGEN* rnd, /**< a random number generator */
    562 int nbins, /**< the number of states */
    563 int ncluster /**< the number of clusters */
    564 )
    565{
    566 int i;
    567 int t;
    568 int c;
    569 int rndcluster;
    570 int pushed;
    571 int* binsincluster;
    572 int **bins;
    573
    574 SCIP_CALL( SCIPallocBufferArray(scip, &binsincluster, ncluster) );
    575 SCIP_CALL( SCIPallocBufferArray(scip, &bins, ncluster) );
    576
    577 for( t = 0; t < ncluster; ++t )
    578 {
    579 binsincluster[t] = 0;
    580
    581 for( i = 0; i < nbins; ++i )
    582 {
    583 if( SCIPisPositive(scip, startclustering[i][t]) )
    584 binsincluster[t]++;
    585 }
    586
    587 SCIP_CALL( SCIPallocClearBufferArray(scip, &bins[t], binsincluster[t]) ); /*lint !e866*/
    588
    589 c = 0;
    590
    591 for( i = 0; i < nbins; ++i )
    592 {
    593 if( SCIPisPositive(scip, startclustering[i][t]) )
    594 {
    595 bins[t][c] = i;
    596 c++;
    597 }
    598 }
    599 }
    600
    601 for( t = 0; t < ncluster; ++t )
    602 {
    603 pushed = 0;
    604
    605 while(pushed < binsincluster[t] / 2) /*lint !e771*/
    606 {
    607 rndcluster = bins[t][SCIPrandomGetInt(rnd, 0, binsincluster[t] - 1)];
    608
    609 if( rndcluster == nbins -1 )
    610 continue;
    611 if( SCIPisZero(scip, startclustering[rndcluster][t]) )
    612 continue;
    613
    614 startclustering[rndcluster][t] = 0;
    615 startclustering[rndcluster][phi(t,ncluster)] = 1;
    616 pushed++;
    617 }
    618
    619 SCIPfreeBufferArray(scip, &bins[t]);
    620 }
    621
    623 SCIPfreeBufferArray(scip, &binsincluster);
    624
    625 return SCIP_OKAY;
    626}
    627
    628/** executes the exchange heuristic for a given solution */
    629static
    631 SCIP* scip, /**< SCIP data structure */
    632 SCIP_HEUR* heur, /**< heuristic pointer */
    633 SCIP_SOL* sol, /**< given solution */
    634 SCIP_RESULT* result /**< result pointer */
    635 )
    636{
    637 SCIP_Real** startclustering;
    638 SCIP_Bool** binfixed;
    639 SCIP_Real** cmatrix;
    640 SCIP_Real** qmatrix;
    641 SCIP_RANDNUMGEN* rnd;
    642 int* clusterofbin;
    643 int* nbinsincluster;
    644 int nbins;
    645 int ncluster;
    646 int i;
    647 int c;
    648
    649 /* get problem variables */
    650 nbins = SCIPcycGetNBins(scip);
    651 ncluster = SCIPcycGetNCluster(scip);
    652 cmatrix = SCIPcycGetCmatrix(scip);
    654
    655 assert(nbins >= 0);
    656 assert(ncluster >= 0);
    657
    658 /* allocate Memory */
    659 SCIP_CALL( SCIPallocClearBufferArray(scip, &startclustering, nbins) );
    660 SCIP_CALL( SCIPallocClearBufferArray(scip, &clusterofbin, nbins) );
    661 SCIP_CALL( SCIPallocClearBufferArray(scip, &binfixed, nbins) );
    662 SCIP_CALL( SCIPallocClearBufferArray(scip, &qmatrix, ncluster) );
    663 SCIP_CALL( SCIPallocClearBufferArray(scip, &nbinsincluster, ncluster) );
    664
    665 for( c = 0; c < ncluster; ++c )
    666 {
    667 SCIP_CALL( SCIPallocBufferArray(scip, &qmatrix[c], ncluster) ); /*lint !e866*/
    668 }
    669 for( i = 0; i < nbins; ++i )
    670 {
    671 SCIP_CALL( SCIPallocClearBufferArray(scip, &startclustering[i], ncluster) ); /*lint !e866*/
    672 SCIP_CALL( SCIPallocClearBufferArray(scip, &binfixed[i], ncluster) ); /*lint !e866*/
    673 }
    674
    675 /* get the solution values from scip */
    676 SCIP_CALL( getSolutionValues(scip, sol, startclustering, binfixed, clusterofbin, nbinsincluster) );
    677
    678 if( isPartition(scip, startclustering, nbins, ncluster) )
    679 {
    680 SCIP_CALL( createSwitchSolution(scip, heur, cmatrix, qmatrix, binfixed, startclustering, result, nbins, ncluster) );
    681 for( i = 0; i < MAXPERMUTATIONS; ++i )
    682 {
    683 SCIP_CALL( permuteStartSolution(scip, startclustering, rnd, nbins, ncluster) );
    684
    685 assert(isPartition(scip, startclustering, nbins, ncluster));
    686
    687 SCIP_CALL( createSwitchSolution(scip, heur, cmatrix, qmatrix, binfixed, startclustering, result, nbins, ncluster) );
    688 }
    689 }
    690
    691 /* free all data-structures */
    692 for( i = 0; i < nbins; ++i )
    693 {
    694 SCIPfreeBufferArray(scip, &binfixed[i]);
    695 SCIPfreeBufferArray(scip, &startclustering[i]);
    696 }
    697
    698 for( c = 0; c < ncluster; ++c )
    699 {
    700 SCIPfreeBufferArray(scip, &qmatrix[c]);
    701 }
    702
    703 SCIPfreeBufferArray(scip, &nbinsincluster);
    704 SCIPfreeBufferArray(scip, &qmatrix);
    705 SCIPfreeBufferArray(scip, &binfixed);
    706 SCIPfreeBufferArray(scip, &clusterofbin);
    707 SCIPfreeBufferArray(scip, &startclustering);
    708
    709 SCIPfreeRandom(scip, &rnd);
    710
    711 return SCIP_OKAY;
    712}
    713
    714/*
    715 * Callback methods of primal heuristic
    716 */
    717
    718/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
    719static
    720SCIP_DECL_HEURCOPY(heurCopyCyckerlin)
    721{ /*lint --e{715}*/
    722 assert(scip != NULL);
    723 assert(heur != NULL);
    724
    726
    727 /* call inclusion method of primal heuristic */
    729
    730 return SCIP_OKAY;
    731}
    732
    733/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
    734static
    735SCIP_DECL_HEURFREE(heurFreeCyckerlin)
    736{ /*lint --e{715}*/
    737 SCIP_HEURDATA* heurdata;
    738
    739 assert(heur != NULL);
    740 assert(scip != NULL);
    741
    743
    744 /* get heuristic data */
    745 heurdata = SCIPheurGetData(heur);
    746
    747 assert(heurdata != NULL);
    748
    749 SCIPfreeMemoryArray(scip, &(heurdata->candidates));
    750
    751 /* free heuristic data */
    752 SCIPfreeBlockMemory(scip, &heurdata);
    753 SCIPheurSetData(heur, NULL);
    754
    755 return SCIP_OKAY;
    756}
    757
    758/** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
    759static
    760SCIP_DECL_HEUREXITSOL(heurExitsolCyckerlin)
    761{ /*lint --e{715}*/
    762 SCIP_HEURDATA* heurdata;
    763
    764 assert(heur != NULL);
    765 assert(scip != NULL);
    766
    768
    769 /* reset the timing mask to its default value */
    771
    772 /* get heuristic data */
    773 heurdata = SCIPheurGetData(heur);
    774
    775 assert(heurdata != NULL);
    776
    777 heurdata->candlength = 0;
    778
    779 return SCIP_OKAY;
    780}
    781
    782/** initialization method of primal heuristic (called after problem was transformed) */
    783static
    784SCIP_DECL_HEURINIT(heurInitCyckerlin)
    785{ /*lint --e{715}*/
    786 SCIP_HEURDATA* heurdata;
    787
    788 assert(heur != NULL);
    789 assert(scip != NULL);
    790
    791 /* get heuristic's data */
    792 heurdata = SCIPheurGetData(heur);
    793
    794 assert(heurdata != NULL);
    795
    796 heurdata->ncandidates = 0;
    797 heurdata->candlength = 10;
    798
    799 SCIP_CALL( SCIPallocMemoryArray(scip, &(heurdata->candidates), heurdata->candlength) );
    800
    801 return SCIP_OKAY;
    802}
    803
    804
    805/** execution method of primal heuristic */
    806static
    807SCIP_DECL_HEUREXEC(heurExecCyckerlin)
    808{ /*lint --e{715}*/
    809 SCIP_Real objective;
    810 SCIP_HEURDATA* heurdata;
    811 int i;
    812
    813 assert(heur != NULL);
    814 assert(scip != NULL);
    815 assert(result != NULL);
    816
    817 *result = SCIP_DIDNOTRUN;
    818 heurdata = SCIPheurGetData(heur);
    819
    820 assert(NULL != heurdata);
    821
    822 /* reset the timing mask to its default value (at the root node it could be different) */
    823 if( SCIPgetNNodes(scip) > 1 )
    825 for( i = 0; i < heurdata->ncandidates; i++ )
    826 {
    827 objective = SCIPgetSolOrigObj(scip, heurdata->candidates[i]);
    828
    829 if( !SCIPisZero(scip, objective) )
    830 {
    831 SCIP_CALL( runCyckerlin(scip, heur, heurdata->candidates[i], result) );
    832 }
    833
    834 heurdata->candidates[i] = NULL;
    835 }
    836
    837 heurdata->ncandidates = 0;
    838 return SCIP_OKAY;
    839}
    840
    841/*
    842 * primal heuristic specific interface methods
    843 */
    844
    845/** creates the oneopt primal heuristic and includes it in SCIP */
    847 SCIP* scip /**< SCIP data structure */
    848 )
    849{
    850 SCIP_HEUR* heur;
    851 SCIP_HEURDATA* heurdata;
    852
    853 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
    854
    855 /* include primal heuristic */
    858 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecCyckerlin, heurdata) );
    859
    860 assert(heur != NULL);
    861
    862 /* set non-NULL pointers to callback methods */
    863 SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyCyckerlin) );
    864 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeCyckerlin) );
    865 SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolCyckerlin) );
    866 SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitCyckerlin) );
    867
    868 return SCIP_OKAY;
    869}
    #define NULL
    Definition: def.h:257
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_Bool
    Definition: def.h:100
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_RETCODE SCIPsetHeurExitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXITSOL((*heurexitsol)))
    Definition: scip_heur.c:247
    SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
    Definition: scip_heur.c:167
    SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
    Definition: heur.c:1368
    SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, SCIP_HEURTIMING timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
    Definition: scip_heur.c:122
    SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
    Definition: scip_heur.c:183
    void SCIPheurSetTimingmask(SCIP_HEUR *heur, SCIP_HEURTIMING timingmask)
    Definition: heur.c:1507
    SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
    Definition: scip_heur.c:263
    SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
    Definition: scip_heur.c:199
    const char * SCIPheurGetName(SCIP_HEUR *heur)
    Definition: heur.c:1467
    void SCIPheurSetData(SCIP_HEUR *heur, SCIP_HEURDATA *heurdata)
    Definition: heur.c:1378
    #define SCIPreallocMemoryArray(scip, ptr, newnum)
    Definition: scip_mem.h:70
    #define SCIPallocMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:64
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPfreeMemoryArray(scip, ptr)
    Definition: scip_mem.h:80
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2986
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:514
    SCIP_RETCODE SCIPtrySolFree(SCIP *scip, SCIP_SOL **sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
    Definition: scip_sol.c:4114
    SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1890
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
    SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
    int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
    Definition: misc.c:10223
    static SCIP_Real getObjective(SCIP *scip, SCIP_Real **qmatrix, SCIP_Real scale, int ncluster)
    static void setBinToCluster(SCIP_Real **solclustering, SCIP_Real **cmatrix, SCIP_Real **qmatrix, int newbin, int newcluster, SCIP_Bool setone, int nbins, int ncluster)
    static SCIP_DECL_HEUREXITSOL(heurExitsolCyckerlin)
    #define HEUR_TIMING
    static void computeIrrevMat(SCIP_Real **clustering, SCIP_Real **qmatrix, SCIP_Real **cmatrix, int nbins, int ncluster)
    #define HEUR_FREQOFS
    #define HEUR_DESC
    static SCIP_RETCODE createSwitchSolution(SCIP *scip, SCIP_HEUR *heur, SCIP_Real **cmatrix, SCIP_Real **qmatrix, SCIP_Bool **binfixed, SCIP_Real **startclustering, SCIP_RESULT *result, int nbins, int ncluster)
    SCIP_RETCODE SCIPincludeHeurCycKerlin(SCIP *scip)
    static SCIP_RETCODE runCyckerlin(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol, SCIP_RESULT *result)
    #define HEUR_DISPCHAR
    #define HEUR_MAXDEPTH
    #define HEUR_PRIORITY
    static SCIP_RETCODE getSolutionValues(SCIP *scip, SCIP_SOL *bestsol, SCIP_Real **solclustering, SCIP_Bool **binfixed, int *clusterofbin, int *nbinsincluster)
    #define HEUR_NAME
    static SCIP_DECL_HEUREXEC(heurExecCyckerlin)
    #define DEFAULT_RANDSEED
    static SCIP_DECL_HEURCOPY(heurCopyCyckerlin)
    #define MAXPERMUTATIONS
    #define HEUR_FREQ
    #define HEUR_USESSUBSCIP
    static SCIP_RETCODE permuteStartSolution(SCIP *scip, SCIP_Real **startclustering, SCIP_RANDNUMGEN *rnd, int nbins, int ncluster)
    static SCIP_Bool switchNext(SCIP *scip, SCIP_Real **cmatrix, SCIP_Real **qmatrix, SCIP_Real **clustering, SCIP_Bool **binfixed, SCIP_Bool *binprocessed, int *clusterofbin, int *nbinsincluster, int *switchedbin, int *switchedcluster, SCIP_Real *switchbound, SCIP_Real *maxbound, int *bestlength, int iteration)
    SCIP_RETCODE addCandSolCyckerlin(SCIP *scip, SCIP_SOL *sol)
    static SCIP_DECL_HEURFREE(heurFreeCyckerlin)
    static SCIP_DECL_HEURINIT(heurInitCyckerlin)
    Improvement heuristic that trades bin-variables between clusters.
    INLINE Rational & max(Rational &r1, Rational &r2)
    SCIP_RETCODE assignVars(SCIP *scip, SCIP_SOL *sol, SCIP_Real **clustering, int nbins, int ncluster)
    Definition: probdata_cyc.c:88
    int SCIPcycGetNBins(SCIP *scip)
    SCIP_Real SCIPcycGetScale(SCIP *scip)
    int SCIPcycGetNCluster(SCIP *scip)
    SCIP_VAR *** SCIPcycGetBinvars(SCIP *scip)
    SCIP_Real ** SCIPcycGetCmatrix(SCIP *scip)
    SCIP_Bool isPartition(SCIP *scip, SCIP_Real **solclustering, int nbins, int ncluster)
    Definition: probdata_cyc.c:57
    problem data for cycle clustering problem
    public data structures and miscellaneous methods
    static SCIP_Real phi(SCIP *scip, SCIP_Real val, SCIP_Real lb, SCIP_Real ub)
    Definition: sepa_eccuts.c:841
    struct SCIP_HeurData SCIP_HEURDATA
    Definition: type_heur.h:77
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_FOUNDSOL
    Definition: type_result.h:56
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63