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