SCIP Doxygen Documentation
Loading...
Searching...
No Matches
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;
68
69 heur = SCIPfindHeur(scip, "cyckerlin");
70
71 if( heur == NULL )
72 return SCIP_OKAY;
73
75
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;
399 SCIP_Real max;
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 {
527 objective = max;
528 }
529 else
530 {
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}*/
738
739 assert(heur != NULL);
740 assert(scip != NULL);
741
743
744 /* get heuristic data */
746
747 assert(heurdata != NULL);
748
749 SCIPfreeMemoryArray(scip, &(heurdata->candidates));
750
751 /* free heuristic data */
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}*/
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 */
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}*/
787
788 assert(heur != NULL);
789 assert(scip != NULL);
790
791 /* get heuristic's data */
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;
811 int i;
812
813 assert(heur != NULL);
814 assert(scip != NULL);
815 assert(result != NULL);
816
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;
852
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 DEFAULT_RANDSEED
#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 SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur,)
Definition scip_heur.c:183
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 SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur,)
Definition scip_heur.c:167
void SCIPheurSetTimingmask(SCIP_HEUR *heur, SCIP_HEURTIMING timingmask)
Definition heur.c:1507
SCIP_RETCODE SCIPsetHeurExitsol(SCIP *scip, SCIP_HEUR *heur,)
Definition scip_heur.c:247
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition scip_heur.c:263
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur,)
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 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
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition misc.c:10223
#define HEUR_TIMING
return SCIP_OKAY
#define HEUR_FREQOFS
#define HEUR_DESC
#define HEUR_DISPCHAR
#define HEUR_MAXDEPTH
#define HEUR_PRIORITY
#define HEUR_NAME
#define HEUR_FREQ
#define HEUR_USESSUBSCIP
SCIPcreateSol(scip, &heurdata->sol, heur))
SCIPfreeRandom(scip, &heurdata->randnumgen)
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 void computeIrrevMat(SCIP_Real **clustering, SCIP_Real **qmatrix, SCIP_Real **cmatrix, int nbins, int ncluster)
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)
static SCIP_RETCODE getSolutionValues(SCIP *scip, SCIP_SOL *bestsol, SCIP_Real **solclustering, SCIP_Bool **binfixed, int *clusterofbin, int *nbinsincluster)
#define MAXPERMUTATIONS
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)
Improvement heuristic that trades bin-variables between clusters.
int c
SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE))
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
SCIP_RETCODE assignVars(SCIP *scip, SCIP_SOL *sol, SCIP_Real **clustering, int nbins, int ncluster)
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)
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)
#define SCIP_DECL_HEURCOPY(x)
Definition type_heur.h:97
struct SCIP_HeurData SCIP_HEURDATA
Definition type_heur.h:77
struct SCIP_Heur SCIP_HEUR
Definition type_heur.h:76
#define SCIP_DECL_HEURINIT(x)
Definition type_heur.h:113
#define SCIP_DECL_HEURFREE(x)
Definition type_heur.h:105
#define SCIP_DECL_HEUREXITSOL(x)
Definition type_heur.h:143
#define SCIP_DECL_HEUREXEC(x)
Definition type_heur.h:163
struct SCIP_RandNumGen SCIP_RANDNUMGEN
Definition type_misc.h:127
@ 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_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
struct SCIP_Var SCIP_VAR
Definition type_var.h:166