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   scip_sepa.c
17  * @ingroup OTHER_CFILES
18  * @brief  public methods for separator plugins
19  * @author Tobias Achterberg
20  * @author Timo Berthold
21  * @author Gerald Gamrath
22  * @author Leona Gottwald
23  * @author Stefan Heinz
24  * @author Gregor Hendel
25  * @author Thorsten Koch
26  * @author Alexander Martin
27  * @author Marc Pfetsch
28  * @author Michael Winkler
29  * @author Kati Wolter
30  *
31  * @todo check all SCIP_STAGE_* switches, and include the new stages TRANSFORMED and INITSOLVE
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #include "scip/debug.h"
37 #include "scip/pub_message.h"
38 #include "scip/scip_sepa.h"
39 #include "scip/sepa.h"
40 #include "scip/set.h"
41 #include "scip/struct_mem.h"
42 #include "scip/struct_scip.h"
43 #include "scip/struct_set.h"
44 #include "scip/tree.h"
45 
46 /** creates a separator and includes it in SCIP.
47  *
48  *  @note method has all separator callbacks as arguments and is thus changed every time a new
49  *        callback is added
50  *        in future releases; consider using SCIPincludeSepaBasic() and setter functions
51  *        if you seek for a method which is less likely to change in future releases
52  */
SCIPincludeSepa(SCIP * scip,const char * name,const char * desc,int priority,int freq,SCIP_Real maxbounddist,SCIP_Bool usessubscip,SCIP_Bool delay,SCIP_DECL_SEPACOPY ((* sepacopy)),SCIP_DECL_SEPAFREE ((* sepafree)),SCIP_DECL_SEPAINIT ((* sepainit)),SCIP_DECL_SEPAEXIT ((* sepaexit)),SCIP_DECL_SEPAINITSOL ((* sepainitsol)),SCIP_DECL_SEPAEXITSOL ((* sepaexitsol)),SCIP_DECL_SEPAEXECLP ((* sepaexeclp)),SCIP_DECL_SEPAEXECSOL ((* sepaexecsol)),SCIP_SEPADATA * sepadata)53 SCIP_RETCODE SCIPincludeSepa(
54    SCIP*                 scip,               /**< SCIP data structure */
55    const char*           name,               /**< name of separator */
56    const char*           desc,               /**< description of separator */
57    int                   priority,           /**< priority of separator (>= 0: before, < 0: after constraint handlers) */
58    int                   freq,               /**< frequency for calling separator */
59    SCIP_Real             maxbounddist,       /**< maximal relative distance from current node's dual bound to primal bound compared
60                                               *   to best node's dual bound for applying separation */
61    SCIP_Bool             usessubscip,        /**< does the separator use a secondary SCIP instance? */
62    SCIP_Bool             delay,              /**< should separator be delayed, if other separators found cuts? */
63    SCIP_DECL_SEPACOPY    ((*sepacopy)),      /**< copy method of separator or NULL if you don't want to copy your plugin into sub-SCIPs */
64    SCIP_DECL_SEPAFREE    ((*sepafree)),      /**< destructor of separator */
65    SCIP_DECL_SEPAINIT    ((*sepainit)),      /**< initialize separator */
66    SCIP_DECL_SEPAEXIT    ((*sepaexit)),      /**< deinitialize separator */
67    SCIP_DECL_SEPAINITSOL ((*sepainitsol)),   /**< solving process initialization method of separator */
68    SCIP_DECL_SEPAEXITSOL ((*sepaexitsol)),   /**< solving process deinitialization method of separator */
69    SCIP_DECL_SEPAEXECLP  ((*sepaexeclp)),    /**< LP solution separation method of separator */
70    SCIP_DECL_SEPAEXECSOL ((*sepaexecsol)),   /**< arbitrary primal solution separation method of separator */
71    SCIP_SEPADATA*        sepadata            /**< separator data */
72    )
73 {
74    SCIP_SEPA* sepa;
75 
76    SCIP_CALL( SCIPcheckStage(scip, "SCIPincludeSepa", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
77 
78    /* check whether separator is already present */
79    if( SCIPfindSepa(scip, name) != NULL )
80    {
81       SCIPerrorMessage("separator <%s> already included.\n", name);
82       return SCIP_INVALIDDATA;
83    }
84 
85    SCIP_CALL( SCIPsepaCreate(&sepa, scip->set, scip->messagehdlr, scip->mem->setmem,
86          name, desc, priority, freq, maxbounddist, usessubscip, delay,
87          sepacopy, sepafree, sepainit, sepaexit, sepainitsol, sepaexitsol, sepaexeclp, sepaexecsol, sepadata) );
88    SCIP_CALL( SCIPsetIncludeSepa(scip->set, sepa) );
89 
90    return SCIP_OKAY;
91 }
92 
93 /** creates a separator and includes it in SCIP with its most fundamental callbacks. All non-fundamental
94  *  (or optional) callbacks as, e.g., init and exit callbacks, will be set to NULL.
95  *  Optional callbacks can be set via specific setter functions, see SCIPsetSepaInit(), SCIPsetSepaFree(),
96  *  SCIPsetSepaInitsol(), SCIPsetSepaExitsol(), SCIPsetSepaCopy(), SCIPsetExit().
97  *
98  *  @note if you want to set all callbacks with a single method call, consider using SCIPincludeSepa() instead
99  */
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)100 SCIP_RETCODE SCIPincludeSepaBasic(
101    SCIP*                 scip,               /**< SCIP data structure */
102    SCIP_SEPA**           sepa,               /**< reference to a separator, or NULL */
103    const char*           name,               /**< name of separator */
104    const char*           desc,               /**< description of separator */
105    int                   priority,           /**< priority of separator (>= 0: before, < 0: after constraint handlers) */
106    int                   freq,               /**< frequency for calling separator */
107    SCIP_Real             maxbounddist,       /**< maximal relative distance from current node's dual bound to primal bound compared
108                                               *   to best node's dual bound for applying separation */
109    SCIP_Bool             usessubscip,        /**< does the separator use a secondary SCIP instance? */
110    SCIP_Bool             delay,              /**< should separator be delayed, if other separators found cuts? */
111    SCIP_DECL_SEPAEXECLP  ((*sepaexeclp)),    /**< LP solution separation method of separator */
112    SCIP_DECL_SEPAEXECSOL ((*sepaexecsol)),   /**< arbitrary primal solution separation method of separator */
113    SCIP_SEPADATA*        sepadata            /**< separator data */
114    )
115 {
116    SCIP_SEPA* sepaptr;
117 
118    SCIP_CALL( SCIPcheckStage(scip, "SCIPincludeSepaBasic", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
119 
120    /* check whether separator is already present */
121    if( SCIPfindSepa(scip, name) != NULL )
122    {
123       SCIPerrorMessage("separator <%s> already included.\n", name);
124       return SCIP_INVALIDDATA;
125    }
126 
127    SCIP_CALL( SCIPsepaCreate(&sepaptr, scip->set, scip->messagehdlr, scip->mem->setmem,
128          name, desc, priority, freq, maxbounddist, usessubscip, delay,
129          NULL, NULL, NULL, NULL, NULL, NULL, sepaexeclp, sepaexecsol, sepadata) );
130 
131    assert(sepaptr != NULL);
132 
133    SCIP_CALL( SCIPsetIncludeSepa(scip->set, sepaptr) );
134 
135    if( sepa != NULL)
136       *sepa = sepaptr;
137 
138    return SCIP_OKAY;
139 }
140 
141 /** sets copy method of separator */
SCIPsetSepaCopy(SCIP * scip,SCIP_SEPA * sepa,SCIP_DECL_SEPACOPY ((* sepacopy)))142 SCIP_RETCODE SCIPsetSepaCopy(
143    SCIP*                 scip,               /**< SCIP data structure */
144    SCIP_SEPA*            sepa,               /**< separator */
145    SCIP_DECL_SEPACOPY    ((*sepacopy))       /**< copy method of separator or NULL if you don't want to copy your plugin into sub-SCIPs */
146    )
147 {
148    SCIP_CALL( SCIPcheckStage(scip, "SCIPsetSepaCopy", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
149 
150    assert(sepa != NULL);
151 
152    SCIPsepaSetCopy(sepa, sepacopy);
153 
154    return SCIP_OKAY;
155 }
156 
157 /** sets destructor method of separator */
SCIPsetSepaFree(SCIP * scip,SCIP_SEPA * sepa,SCIP_DECL_SEPAFREE ((* sepafree)))158 SCIP_RETCODE SCIPsetSepaFree(
159    SCIP*                 scip,               /**< SCIP data structure */
160    SCIP_SEPA*            sepa,               /**< separator */
161    SCIP_DECL_SEPAFREE    ((*sepafree))       /**< destructor of separator */
162    )
163 {
164    SCIP_CALL( SCIPcheckStage(scip, "SCIPsetSepaFree", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
165 
166    assert(sepa != NULL);
167 
168    SCIPsepaSetFree(sepa, sepafree);
169 
170    return SCIP_OKAY;
171 }
172 
173 /** sets initialization method of separator */
SCIPsetSepaInit(SCIP * scip,SCIP_SEPA * sepa,SCIP_DECL_SEPAINIT ((* sepainit)))174 SCIP_RETCODE SCIPsetSepaInit(
175    SCIP*                 scip,               /**< SCIP data structure */
176    SCIP_SEPA*            sepa,               /**< separator */
177    SCIP_DECL_SEPAINIT    ((*sepainit))       /**< initialize separator */
178    )
179 {
180    SCIP_CALL( SCIPcheckStage(scip, "SCIPsetSepaInit", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
181 
182    assert(sepa != NULL);
183 
184    SCIPsepaSetInit(sepa, sepainit);
185 
186    return SCIP_OKAY;
187 }
188 
189 /** sets deinitialization method of separator */
SCIPsetSepaExit(SCIP * scip,SCIP_SEPA * sepa,SCIP_DECL_SEPAEXIT ((* sepaexit)))190 SCIP_RETCODE SCIPsetSepaExit(
191    SCIP*                 scip,               /**< SCIP data structure */
192    SCIP_SEPA*            sepa,               /**< separator */
193    SCIP_DECL_SEPAEXIT    ((*sepaexit))       /**< deinitialize separator */
194    )
195 {
196    SCIP_CALL( SCIPcheckStage(scip, "SCIPsetSepaExit", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
197 
198    assert(sepa != NULL);
199 
200    SCIPsepaSetExit(sepa, sepaexit);
201 
202    return SCIP_OKAY;
203 }
204 
205 /** sets solving process initialization method of separator */
SCIPsetSepaInitsol(SCIP * scip,SCIP_SEPA * sepa,SCIP_DECL_SEPAINITSOL ((* sepainitsol)))206 SCIP_RETCODE SCIPsetSepaInitsol(
207    SCIP*                 scip,               /**< SCIP data structure */
208    SCIP_SEPA*            sepa,               /**< separator */
209    SCIP_DECL_SEPAINITSOL ((*sepainitsol))    /**< solving process initialization method of separator */
210    )
211 {
212    SCIP_CALL( SCIPcheckStage(scip, "SCIPsetSepaInitsol", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
213 
214    assert(sepa != NULL);
215 
216     SCIPsepaSetInitsol(sepa, sepainitsol);
217 
218    return SCIP_OKAY;
219 }
220 
221 /** sets solving process deinitialization method of separator */
SCIPsetSepaExitsol(SCIP * scip,SCIP_SEPA * sepa,SCIP_DECL_SEPAEXITSOL ((* sepaexitsol)))222 SCIP_RETCODE SCIPsetSepaExitsol(
223    SCIP*                 scip,               /**< SCIP data structure */
224    SCIP_SEPA*            sepa,               /**< separator */
225    SCIP_DECL_SEPAEXITSOL ((*sepaexitsol))    /**< solving process deinitialization method of separator */
226    )
227 {
228    SCIP_CALL( SCIPcheckStage(scip, "SCIPsetSepaExitsol", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
229 
230    assert(sepa != NULL);
231 
232    SCIPsepaSetExitsol(sepa, sepaexitsol);
233 
234    return SCIP_OKAY;
235 }
236 
237 /** returns the separator of the given name, or NULL if not existing */
SCIPfindSepa(SCIP * scip,const char * name)238 SCIP_SEPA* SCIPfindSepa(
239    SCIP*                 scip,               /**< SCIP data structure */
240    const char*           name                /**< name of separator */
241    )
242 {
243    assert(scip != NULL);
244    assert(scip->set != NULL);
245    assert(name != NULL);
246 
247    return SCIPsetFindSepa(scip->set, name);
248 }
249 
250 /** returns the array of currently available separators */
SCIPgetSepas(SCIP * scip)251 SCIP_SEPA** SCIPgetSepas(
252    SCIP*                 scip                /**< SCIP data structure */
253    )
254 {
255    assert(scip != NULL);
256    assert(scip->set != NULL);
257 
258    SCIPsetSortSepas(scip->set);
259 
260    return scip->set->sepas;
261 }
262 
263 /** returns the number of currently available separators */
SCIPgetNSepas(SCIP * scip)264 int SCIPgetNSepas(
265    SCIP*                 scip                /**< SCIP data structure */
266    )
267 {
268    assert(scip != NULL);
269    assert(scip->set != NULL);
270 
271    return scip->set->nsepas;
272 }
273 
274 /** sets the priority of a separator */
SCIPsetSepaPriority(SCIP * scip,SCIP_SEPA * sepa,int priority)275 SCIP_RETCODE SCIPsetSepaPriority(
276    SCIP*                 scip,               /**< SCIP data structure */
277    SCIP_SEPA*            sepa,               /**< separator */
278    int                   priority            /**< new priority of the separator */
279    )
280 {
281    assert(scip != NULL);
282    assert(scip->set != NULL);
283 
284    SCIPsepaSetPriority(sepa, scip->set, priority);
285 
286    return SCIP_OKAY;
287 }
288 
289 #undef SCIPgetSepaMinEfficacy
290 
291 /** gets value of minimal efficacy for a cut to enter the LP
292  *
293  *  @pre This method can be called if @p scip is in one of the following stages:
294  *       - \ref SCIP_STAGE_SOLVING
295  *
296  *  @return value of "separating/minefficacyroot" if at root node, otherwise value of "separating/minefficacy"
297  */
SCIPgetSepaMinEfficacy(SCIP * scip)298 SCIP_Real SCIPgetSepaMinEfficacy(
299    SCIP*                 scip                /**< SCIP data structure */
300    )
301 {
302    assert(scip != NULL);
303    assert(scip->tree != NULL);
304    assert(scip->set != NULL);
305 
306    SCIP_CALL_ABORT( SCIPcheckStage(scip, "SCIPgetSepaMinEfficacy", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE) );
307 
308    if( SCIPtreeGetCurrentDepth(scip->tree) != 0 )
309       return scip->set->sepa_minefficacyroot;
310    return scip->set->sepa_minefficacy;
311 }
312