1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file heur_sync.c
17 * @ingroup DEFPLUGINS_HEUR
18 * @brief primal heuristic that adds solutions from synchronization
19 * @author Leona Gottwald
20 *
21 * This heuristic takes solutions during synchronization and then adds them.
22 */
23
24 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
25
26 #include <assert.h>
27 #include <string.h>
28
29 #include "scip/heur_sync.h"
30 #include "scip/scip.h"
31
32
33 #define HEUR_NAME "sync"
34 #define HEUR_DESC "heuristic for synchronizing solution"
35 #define HEUR_DISPCHAR 'S'
36 #define HEUR_PRIORITY -3000000 /* should process after all other heuristics */
37 #define HEUR_FREQ -1
38 #define HEUR_FREQOFS 0
39 #define HEUR_MAXDEPTH -1
40 #define HEUR_TIMING SCIP_HEURTIMING_DURINGLPLOOP | SCIP_HEURTIMING_BEFOREPRESOL | SCIP_HEURTIMING_BEFORENODE
41 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
42
43
44 /*
45 * Data structures
46 */
47
48
49 /** primal heuristic data */
50 struct SCIP_HeurData
51 {
52 SCIP_SOL** sols; /**< storing solutions passed to heuristic sorted by objective value */
53 int nsols; /**< number of soluions stored */
54 int maxnsols; /**< maximum number of solutions that can be stored */
55 };
56
57
58 /*
59 * Callback methods of primal heuristic
60 */
61
62 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
63 static
SCIP_DECL_HEURFREE(heurFreeSync)64 SCIP_DECL_HEURFREE(heurFreeSync)
65 { /*lint --e{715}*/
66 SCIP_HEURDATA* heurdata;
67
68 assert( heur != NULL );
69 assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
70 assert( scip != NULL );
71
72 SCIPdebugMessage("free method of sync primal heuristic.\n");
73
74 /* get heuristic data */
75 heurdata = SCIPheurGetData(heur);
76 assert(heurdata != NULL);
77 assert(heurdata->nsols == 0);
78 SCIPfreeBlockMemoryArray(scip, &heurdata->sols, heurdata->maxnsols);
79 SCIPfreeBlockMemory(scip, &heurdata);
80
81 return SCIP_OKAY;
82 }
83
84
85 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
86 static
SCIP_DECL_HEUREXITSOL(heurExitSync)87 SCIP_DECL_HEUREXITSOL(heurExitSync)
88 { /*lint --e{715}*/
89 SCIP_HEURDATA* heurdata;
90 int i;
91
92 assert( heur != NULL );
93 assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 );
94 assert( scip != NULL );
95
96 SCIPdebugMessage("exit method of sync primal heuristic.\n");
97
98 /* get heuristic data */
99 heurdata = SCIPheurGetData(heur);
100 assert(heurdata != NULL);
101
102 /* free solution if one is still present */
103 for( i = 0; i < heurdata->nsols; ++i )
104 {
105 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sols[i]) );
106 }
107 heurdata->nsols = 0;
108 return SCIP_OKAY;
109 }
110
111
112 /** execution method of primal heuristic */
113 static
SCIP_DECL_HEUREXEC(heurExecSync)114 SCIP_DECL_HEUREXEC(heurExecSync)
115 { /*lint --e{715}*/
116 SCIP_HEURDATA* heurdata;
117 SCIP_Bool stored;
118 int i;
119
120 assert(heur != NULL);
121 assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
122 assert(scip != NULL);
123 assert(result != NULL);
124 assert(SCIPheurGetFreq(heur) == 1);
125
126 SCIPheurSetFreq(heur, -1);
127
128 /* get heuristic data */
129 heurdata = SCIPheurGetData(heur);
130 assert(heurdata != NULL);
131 assert(heurdata->nsols > 0);
132
133 SCIPdebugMessage("exec method of sync primal heuristic.\n");
134 *result = SCIP_DIDNOTFIND;
135 for( i = 0; i < heurdata->nsols; ++i )
136 {
137 SCIP_CALL( SCIPtrySolFree(scip, &heurdata->sols[i], FALSE, FALSE, FALSE, FALSE, FALSE, &stored) );
138 if( stored )
139 *result = SCIP_FOUNDSOL;
140 }
141
142 heurdata->nsols = 0;
143
144 return SCIP_OKAY;
145 }
146
147 /*
148 * primal heuristic specific interface methods
149 */
150
151 /** creates the sync primal heuristic and includes it in SCIP */
SCIPincludeHeurSync(SCIP * scip)152 SCIP_RETCODE SCIPincludeHeurSync(
153 SCIP* scip /**< SCIP data structure */
154 )
155 {
156 SCIP_HEURDATA* heurdata;
157 SCIP_HEUR* heur;
158
159 /* create heuristic data */
160 SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
161 SCIP_CALL( SCIPgetIntParam(scip, "concurrent/sync/maxnsols", &heurdata->maxnsols) );
162 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &heurdata->sols, heurdata->maxnsols) );
163 heurdata->nsols = 0;
164
165 /* include primal heuristic */
166 SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
167 HEUR_NAME, HEUR_DESC, HEUR_DISPCHAR, HEUR_PRIORITY, HEUR_FREQ, HEUR_FREQOFS,
168 HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecSync, heurdata) );
169
170 assert(heur != NULL);
171
172 /* set non-NULL pointers to callback methods */
173 SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeSync) );
174 SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitSync) );
175
176 return SCIP_OKAY;
177 }
178
179
180 /** pass solution to sync heuristic */
SCIPheurSyncPassSol(SCIP * scip,SCIP_HEUR * heur,SCIP_SOL * sol)181 SCIP_RETCODE SCIPheurSyncPassSol(
182 SCIP* scip, /**< SCIP data structure */
183 SCIP_HEUR* heur, /**< sync heuristic */
184 SCIP_SOL* sol /**< solution to be passed */
185 )
186 {
187 SCIP_HEURDATA* heurdata;
188 SCIP_Real solobj;
189 int i;
190 assert(scip != NULL);
191 assert(heur != NULL);
192 assert(sol != NULL);
193 assert(strcmp(HEUR_NAME, SCIPheurGetName(heur)) == 0);
194
195 /* get heuristic data */
196 heurdata = SCIPheurGetData(heur);
197 assert(heurdata != NULL);
198
199 SCIPsolSetHeur(sol, heur);
200 solobj = SCIPgetSolTransObj(scip, sol);
201
202 /* check if we have an empty space in the solution array or
203 * if we need to discard the worst solution
204 */
205 if( heurdata->nsols < heurdata->maxnsols )
206 {
207 /* if the maximum number of solutions is not yet reached just
208 * insert the solution sorted by its objective value */
209 i = heurdata->nsols++;
210
211 while( i > 0 && solobj > SCIPgetSolTransObj(scip, heurdata->sols[i - 1]) )
212 {
213 heurdata->sols[i] = heurdata->sols[i - 1];
214 --i;
215 }
216 heurdata->sols[i] = sol;
217 }
218 else
219 {
220 /* already have reached the maximum number of solutions so
221 * we need to check if the solution is better than a previous
222 * one and free the worst solution to make room for it if that
223 * is the case
224 */
225 i = 0;
226 while( i < heurdata->nsols && solobj < SCIPgetSolTransObj(scip, heurdata->sols[i]) )
227 {
228 if( i > 0 )
229 {
230 heurdata->sols[i - 1] = heurdata->sols[i];
231 }
232 else
233 {
234 SCIP_CALL( SCIPfreeSol(scip, &heurdata->sols[i]) );
235 }
236
237 ++i;
238 }
239 /* check if solution must be inserted or discarded */
240 if( i > 0)
241 {
242 /* found position to insert the solution sorted by objective value */
243 heurdata->sols[i-1] = sol;
244 }
245 else
246 {
247 /* solution is not better just discard it */
248 SCIP_CALL( SCIPfreeSol(scip, &sol) );
249 }
250 }
251 assert(heurdata->nsols > 0);
252 assert(heurdata->nsols <= heurdata->maxnsols);
253
254 SCIPheurSetFreq(heur, 1);
255
256 return SCIP_OKAY;
257 }
258