SCIP Doxygen Documentation
Loading...
Searching...
No Matches
sepa_edge.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 sepa_edge.c
26 * @brief edge-separator. Separates triangle-inequalities in cycle clustering problem
27 * @author Leon Eifler
28 */
29
30/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
31
32#include "sepa_edge.h"
33
34#include "probdata_cyc.h"
35#include "scip/cutsel_hybrid.h"
36
37#define SEPA_NAME "edge"
38#define SEPA_DESC "separator to separate triangle-inequalities in cycle-clustering application"
39#define SEPA_PRIORITY 5000
40#define SEPA_FREQ 5
41#define SEPA_MAXBOUNDDIST 0.0
42#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
43#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
44#define MAXCUTS 2000 /**< maximal number of cuts that can be added to cut pool */
45#define MAXCUTSCREATED 10000 /**< maximal number of cuts to select from */
46#define MAXROUNDS 20
47
48/** copy method for separator plugins (called when SCIP copies plugins) */
49static
50SCIP_DECL_SEPACOPY(sepaCopyEdge)
51{ /*lint --e{715}*/
52 assert(scip != NULL);
53 assert(sepa != NULL);
54
56
57 /* call inclusion method of constraint handler */
59
60 return SCIP_OKAY;
61}
62
63/** LP solution separation method of separator */
64static
65SCIP_DECL_SEPAEXECLP(sepaExeclpEdge)
66{ /*lint --e{715}*/
67 SCIP_VAR**** edgevars; /* edgevars from probdata */
68 SCIP_DIGRAPH* edgegraph; /* edgegraph from probdata */
69 char cutname[SCIP_MAXSTRLEN]; /* name of the cut */
70 SCIP_Real** sign; /* matrix of sign-permuations */
71 SCIP_Real* violation; /* array of violations */
72 SCIP_ROW** cuts; /* array of generated cuts */
73 SCIP_Real goodscorefac; /* parameters for cut-selection */
74 SCIP_Real badscorefac;
75 SCIP_Real goodmaxparall;
76 SCIP_Real maxparall;
77 SCIP_Real dircutoffdist;
78 SCIP_Real efficacyweight;
79 SCIP_Real objparalweight;
80 SCIP_Real intsuppweight;
81 int* succs1; /* successors of first state */
82 int* succs2; /* successors of second state */
83 int nstates; /* number of states */
84 int ncutscreated; /* number of generated cuts */
85 int ncutsapplied; /* number of cuts that were added to the pool */
86 int size; /* size of the cuts-array */
87 int rounds; /* number of separation rounds */
88 int states[3]; /* states in a triangle */
89 int nsuccs1; /* number of successors */
90 int nsuccs2;
91 int j; /* running indices */
92 int k;
93 int l;
94 SCIP_Bool usecutselection; /* should cut selection be uses */
95
96 rounds = SCIPsepaGetNCallsAtNode(sepa);
97 if( rounds >= MAXROUNDS )
98 {
100 return SCIP_OKAY;
101 }
102
103 edgegraph = SCIPcycGetEdgeGraph(scip);
104 edgevars = SCIPcycGetEdgevars(scip);
105 nstates = SCIPcycGetNBins(scip);
106
107 assert(nstates > 0);
108 assert(NULL != edgevars);
109 assert(NULL != edgegraph);
110
111 ncutscreated = 0;
112 ncutsapplied = 0;
113 size = MAXCUTS;
115
116 SCIP_CALL( SCIPgetBoolParam(scip, "cycleclustering/usecutselection", &usecutselection) );
117
118 SCIP_CALL( SCIPallocClearBufferArray(scip, &violation, size) );
119 SCIP_CALL( SCIPallocBufferArray(scip, &cuts, size) );
121
122 /* for some inequalities, you can swap the minus sign to any variable of the triangle */
123 for( j = 0; j < 3; ++j )
124 {
125 SCIP_CALL( SCIPallocMemoryArray(scip, &sign[j], 3) ); /*lint !e866*/
126
127 for( k = 0; k < 3; ++k )
128 {
129 sign[j][k] = 1.0;
130 }
131 sign[j][j] = -1.0;
132 }
133
134 if( SCIPcycGetNCluster(scip) > 3 )
135 {
136 /* separate edges by the valid inequality z_ij1 + z_ik1 - y_jk0 <= 1 and z_ji + z_ki - y_jk1 <= 1
137 * (minus sign can be anywhere)
138 */
139 for( states[0] = 0; states[0] < nstates && ncutscreated < MAXCUTSCREATED; ++states[0] )
140 {
141 succs1 = SCIPdigraphGetSuccessors(edgegraph, states[0]);
142 nsuccs1 = SCIPdigraphGetNSuccessors(edgegraph, states[0]);
143
144 for( j = 0; j < nsuccs1 && ncutscreated < MAXCUTSCREATED; ++j )
145 {
146 states[1] = succs1[j];
147 succs2 = SCIPdigraphGetSuccessors(edgegraph, states[1]);
148 nsuccs2 = SCIPdigraphGetNSuccessors(edgegraph, states[1]);
149
150 for( k = 0; k < nsuccs2 && ncutscreated < MAXCUTSCREATED; ++k )
151 {
152 states[2] = succs2[k];
153
154 if( !edgesExist(edgevars, states, 3) )
155 continue;
156
157 if( (states[0] != states[1] && states[0] != states[2] && states[1] > states[2]) )
158 {
159 /* permute the minus sign */
160 for( l = 0; l < 3 ; ++l )
161 {
162 violation[ncutscreated] = sign[l][0]
163 * SCIPvarGetLPSol(getEdgevar(edgevars, states[0], states[1], 1));
164 violation[ncutscreated] += sign[l][1]
165 * SCIPvarGetLPSol(getEdgevar(edgevars, states[0], states[2], 1));
166 violation[ncutscreated] += sign[l][2]
167 * SCIPvarGetLPSol(getEdgevar(edgevars, states[1], states[2], 0)) - 1;
168
169 if( violation[ncutscreated] > 0 )
170 {
171 (void)SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "trianglefw_%d_%d_%d_%d", states[0], states[1], states[2], l );
172 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &(cuts[ncutscreated]), sepa, cutname,
173 -SCIPinfinity(scip), 1.0, FALSE, FALSE, TRUE) );
174
175 SCIP_CALL( SCIPcacheRowExtensions(scip, cuts[ncutscreated]) );
176
177 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
178 getEdgevar(edgevars, states[1], states[2], 0), sign[l][2]) );
179 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
180 getEdgevar(edgevars, states[0], states[1], 1), sign[l][0]) );
181 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
182 getEdgevar(edgevars, states[0], states[2], 1), sign[l][1]) );
183
184 SCIP_CALL( SCIPflushRowExtensions(scip, cuts[ncutscreated]) );
185
186 if( ncutscreated >= size - 1 )
187 {
188 SCIP_CALL( SCIPreallocBufferArray(scip, &violation, (int) (size + MAXCUTS)) );
189 SCIP_CALL( SCIPreallocBufferArray(scip, &cuts, (int) (size + MAXCUTS)) );
190 size += MAXCUTS;
191 }
192
193 ncutscreated++;
194 }
195
196 violation[ncutscreated] = sign[l][0]
197 * SCIPvarGetLPSol(getEdgevar(edgevars, states[1], states[0], 1));
198 violation[ncutscreated] += sign[l][1]
199 * SCIPvarGetLPSol(getEdgevar(edgevars, states[2], states[0], 1));
200 violation[ncutscreated] += sign[l][2]
201 * SCIPvarGetLPSol(getEdgevar(edgevars, states[1], states[2], 0)) - 1;
202
203 if( violation[ncutscreated] > 0)
204 {
205 (void)SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "trianglebw_%d_%d_%d_%d", states[0], states[1], states[2], l );
206 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &(cuts[ncutscreated]), sepa, cutname,
207 -SCIPinfinity(scip), 1.0, FALSE, FALSE, TRUE) );
208
209 SCIP_CALL( SCIPcacheRowExtensions(scip, cuts[ncutscreated]) );
210
211 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
212 getEdgevar(edgevars, states[1], states[2], 0), sign[l][2]) );
213 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
214 getEdgevar(edgevars, states[1], states[0], 1), sign[l][0]) );
215 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
216 getEdgevar(edgevars, states[2], states[0], 1), sign[l][1]) );
217
218 SCIP_CALL( SCIPflushRowExtensions(scip, cuts[ncutscreated]) );
219
220 if( ncutscreated >= size - 1 )
221 {
222 SCIP_CALL( SCIPreallocBufferArray(scip, &violation, (int) (size + MAXCUTS)) );
223 SCIP_CALL( SCIPreallocBufferArray(scip, &cuts, (int) (size + MAXCUTS)) );
224 size += MAXCUTS;
225 }
226
227 ncutscreated++;
228 }
229 }
230 }
231
232 if( states[0] > states[1] && states[1] > states[2] )
233 {
234 for( l = 0; l < 3; ++l )
235 {
236 violation[ncutscreated] = sign[l][0]
237 * SCIPvarGetLPSol(getEdgevar(edgevars, states[0], states[1], 0));
238 violation[ncutscreated] += sign[l][1]
239 * SCIPvarGetLPSol(getEdgevar(edgevars, states[0], states[2], 0));
240 violation[ncutscreated] += sign[l][2]
241 * SCIPvarGetLPSol(getEdgevar(edgevars, states[1], states[2], 0)) - 1;
242
243 if( violation[ncutscreated] > 0 )
244 {
245 (void)SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "edgecut_%d_%d_%d", states[0], states[1], states[2]);
246 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &(cuts[ncutscreated]), sepa, cutname,
247 -SCIPinfinity(scip), 1.0, FALSE, FALSE, TRUE) );
248 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
249 getEdgevar(edgevars, states[0], states[1], 0), sign[l][0]) );
250 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
251 getEdgevar(edgevars, states[0], states[2], 0), sign[l][1]) );
252 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
253 getEdgevar(edgevars, states[1], states[2], 0), sign[l][2]) );
254
255 if( ncutscreated >= size - 1 )
256 {
257 SCIP_CALL( SCIPreallocBufferArray(scip, &violation, (int) (size + MAXCUTS)) );
258 SCIP_CALL( SCIPreallocBufferArray(scip, &cuts, (int) (size + MAXCUTS)) );
259 size += MAXCUTS;
260 }
261
262 ncutscreated++;
263 }
264 }
265 }
266 }
267 }
268 }
269 }
270
271 if( SCIPcycGetNCluster(scip) == 3 )
272 {
273 for( states[0] = 0; states[0] < nstates; ++states[0] )
274 {
275 succs1 = SCIPdigraphGetSuccessors(edgegraph, states[0]);
276 nsuccs1 = SCIPdigraphGetNSuccessors(edgegraph, states[0]);
277
278 for( j = 0; j < nsuccs1 && ncutscreated < MAXCUTSCREATED; ++j )
279 {
280 states[1] = succs1[j];
281 succs2 = SCIPdigraphGetSuccessors(edgegraph, states[1]);
282 nsuccs2 = SCIPdigraphGetNSuccessors(edgegraph, states[1]);
283
284 for( k = 0; k < nsuccs2 && ncutscreated < MAXCUTSCREATED; ++k )
285 {
286 states[2] = succs2[k];
287
288 if( !edgesExist(edgevars, states, 3) )
289 continue;
290
291 violation[ncutscreated] = SCIPvarGetLPSol(getEdgevar(edgevars, states[0], states[1], 1));
292 violation[ncutscreated] += SCIPvarGetLPSol(getEdgevar(edgevars, states[1], states[2], 1));
293 violation[ncutscreated] -= SCIPvarGetLPSol(getEdgevar(edgevars, states[2], states[0], 1)) - 1;
294
295 if( violation[ncutscreated] > 0 )
296 {
297 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "edgecut_%d_%d_%d", states[0], states[1], states[2]);
298 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &(cuts[ncutscreated]), sepa, cutname,
299 -SCIPinfinity(scip), 1.0, FALSE, FALSE, TRUE) );
300
301 SCIP_CALL( SCIPcacheRowExtensions(scip, cuts[ncutscreated]) );
302
303 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
304 getEdgevar(edgevars, states[0], states[1], 1), 1.0) );
305 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
306 getEdgevar(edgevars, states[1], states[2], 1), 1.0) );
307 SCIP_CALL( SCIPaddVarToRow(scip, cuts[ncutscreated],
308 getEdgevar(edgevars, states[2], states[0], 1), -1.0) );
309
310 SCIP_CALL( SCIPflushRowExtensions(scip, cuts[ncutscreated]) );
311
312 if( ncutscreated >= size - 1 )
313 {
314 SCIP_CALL( SCIPreallocBufferArray(scip, &violation, (int) (size + MAXCUTS)) );
315 SCIP_CALL( SCIPreallocBufferArray(scip, &cuts, (int) (size + MAXCUTS)) );
316 size += MAXCUTS;
317 }
318
319 ncutscreated++;
320 }
321 }
322 }
323 }
324 }
325
326 if( ncutscreated > 0 )
327 {
328 /* apply the cuts with the highest violation or use cut-selection */
329 if( usecutselection )
330 {
331 SCIP_CALL( SCIPgetRealParam(scip, "cycleclustering/goodscorefac", &goodscorefac) );
332 SCIP_CALL( SCIPgetRealParam(scip, "cycleclustering/badscorefac", &badscorefac) );
333 SCIP_CALL( SCIPgetRealParam(scip, "cycleclustering/goodmaxparall", &goodmaxparall) );
334 SCIP_CALL( SCIPgetRealParam(scip, "cycleclustering/maxparall", &maxparall) );
335 SCIP_CALL( SCIPgetRealParam(scip, "cycleclustering/dircutoffdist", &dircutoffdist) );
336 SCIP_CALL( SCIPgetRealParam(scip, "cycleclustering/efficacyweight", &efficacyweight) );
337 SCIP_CALL( SCIPgetRealParam(scip, "cycleclustering/objparalweight", &objparalweight) );
338 SCIP_CALL( SCIPgetRealParam(scip, "cycleclustering/intsuppweight", &intsuppweight) );
339
340 SCIP_CALL( SCIPselectCutsHybrid(scip, cuts, NULL, NULL, goodscorefac, badscorefac,
341 goodmaxparall, maxparall, dircutoffdist, efficacyweight, objparalweight, intsuppweight,
342 ncutscreated, 0, MAXCUTS, &ncutsapplied) );
343 }
344 else
345 {
346 SCIPsortDownRealPtr(violation, ((void **) cuts), ncutscreated);
347 ncutsapplied = MIN(ncutscreated, MAXCUTS);
348 }
349
350 for( j = 0; j < ncutsapplied; ++j )
351 {
352 SCIP_CALL( SCIPaddPoolCut(scip, cuts[j]) );
354 }
355 }
356
357 /* free memory */
358 for( j = 0; j < ncutscreated; ++j )
359 {
360 SCIP_CALL( SCIPreleaseRow(scip, &(cuts[j])) );
361 }
363 SCIPfreeBufferArray(scip, &violation);
364 for( j = 0; j < 3; ++j )
365 {
366 SCIPfreeMemoryArray(scip, &sign[j]);
367 }
369
370 return SCIP_OKAY;
371}
372
373/** creates the Edge separator and includes it in SCIP */
375 SCIP* scip /**< SCIP data structure */
376 )
377{
378 SCIP_SEPA* sepa;
379
380 /* include separator */
383 sepaExeclpEdge, NULL,
384 NULL) );
385
386 assert(sepa != NULL);
387
388 /* set non fundamental callbacks via setter functions */
389 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyEdge) );
390
391 return SCIP_OKAY;
392}
hybrid cut selector
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#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 SCIPselectCutsHybrid(SCIP *scip, SCIP_ROW **cuts, SCIP_ROW **forcedcuts, SCIP_RANDNUMGEN *randnumgen, SCIP_Real goodscorefac, SCIP_Real badscorefac, SCIP_Real goodmaxparall, SCIP_Real maxparall, SCIP_Real dircutoffdistweight, SCIP_Real efficacyweight, SCIP_Real objparalweight, SCIP_Real intsupportweight, int ncuts, int nforcedcuts, int maxselectedcuts, int *nselectedcuts)
int SCIPdigraphGetNSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition misc.c:7881
int * SCIPdigraphGetSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition misc.c:7896
SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
Definition scip_param.c:250
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition scip_param.c:307
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition scip_cut.c:336
#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 SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPallocClearMemoryArray(scip, ptr, num)
Definition scip_mem.h:66
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPfreeMemoryArray(scip, ptr)
Definition scip_mem.h:80
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1429
SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
Definition scip_sepa.c:115
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition sepa.c:746
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition sepa.c:893
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:157
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
Definition var.c:24696
void SCIPsortDownRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
return SCIP_OKAY
assert(minobj< SCIPgetCutoffbound(scip))
SCIP_Bool edgesExist(SCIP_VAR ****edgevars, int *states, int nstates)
SCIP_VAR **** SCIPcycGetEdgevars(SCIP *scip)
int SCIPcycGetNBins(SCIP *scip)
SCIP_VAR * getEdgevar(SCIP_VAR ****edgevars, int state1, int state2, EDGETYPE edgetype)
int SCIPcycGetNCluster(SCIP *scip)
SCIP_DIGRAPH * SCIPcycGetEdgeGraph(SCIP *scip)
problem data for cycle clustering problem
#define SEPA_PRIORITY
#define SEPA_DELAY
#define SEPA_DESC
#define SEPA_USESSUBSCIP
#define SEPA_MAXBOUNDDIST
#define SEPA_FREQ
#define SEPA_NAME
SCIP_RETCODE SCIPincludeSepaEdge(SCIP *scip)
Definition sepa_edge.c:374
#define MAXCUTSCREATED
Definition sepa_edge.c:45
#define MAXROUNDS
Definition sepa_edge.c:46
#define MAXCUTS
Definition sepa_edge.c:44
edge-separator. Separates triangle-inequalities in cycle clustering problem
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
struct SCIP_Digraph SCIP_DIGRAPH
Definition type_misc.h:145
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
#define SCIP_DECL_SEPAEXECLP(x)
Definition type_sepa.h:136
struct SCIP_Sepa SCIP_SEPA
Definition type_sepa.h:51
#define SCIP_DECL_SEPACOPY(x)
Definition type_sepa.h:61
struct SCIP_Var SCIP_VAR
Definition type_var.h:166