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 event_globalbnd.c 26 * @ingroup DEFPLUGINS_EVENT 27 * @brief eventhandler for storing all global bound changes 28 * @author Leona Gottwald 29 * 30 * the bound changes are stored so that they can be shared with other threads 31 * in a concurrent solve. 32 */ 33 34 /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 35 36 #include "blockmemshell/memory.h" 37 #include "scip/boundstore.h" 38 #include "scip/concurrent.h" 39 #include "scip/event_globalbnd.h" 40 #include "scip/pub_event.h" 41 #include "scip/pub_lp.h" 42 #include "scip/pub_message.h" 43 #include "scip/pub_var.h" 44 #include "scip/scip_concurrent.h" 45 #include "scip/scip_copy.h" 46 #include "scip/scip_event.h" 47 #include "scip/scip_mem.h" 48 #include "scip/scip_message.h" 49 #include "scip/scip_prob.h" 50 #include "scip/syncstore.h" 51 #include <string.h> 52 53 #define EVENTHDLR_NAME "globalbnd" 54 #define EVENTHDLR_DESC "event handler for globalbnd event" 55 56 57 /* 58 * Data structures 59 */ 60 61 /** event handler data */ 62 struct SCIP_EventhdlrData 63 { 64 int filterpos; 65 SCIP_Bool storebounds; 66 SCIP_BOUNDSTORE* boundstore; 67 }; 68 69 /* 70 * Local methods 71 */ 72 73 /* 74 * Callback methods of event handler 75 */ 76 77 /** destructor of event handler to free user data (called when SCIP is exiting) */ 78 static 79 SCIP_DECL_EVENTFREE(eventFreeGlobalbnd) 80 { /*lint --e{715}*/ 81 SCIP_EVENTHDLRDATA* eventhdlrdata; 82 83 assert(scip != NULL); 84 assert(eventhdlr != NULL); 85 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 86 87 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr); 88 assert(eventhdlrdata != NULL); 89 90 SCIPfreeMemory(scip, &eventhdlrdata); 91 SCIPeventhdlrSetData(eventhdlr, NULL); 92 93 return SCIP_OKAY; 94 } 95 96 /** initialization method of event handler (called after problem was transformed) */ 97 static 98 SCIP_DECL_EVENTINIT(eventInitGlobalbnd) 99 { /*lint --e{715}*/ 100 SCIP_EVENTHDLRDATA* eventhdlrdata; 101 102 assert(scip != NULL); 103 assert(eventhdlr != NULL); 104 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 105 106 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr); 107 assert(eventhdlrdata != NULL); 108 109 if( eventhdlrdata->filterpos < 0 && SCIPgetSubscipDepth(scip) == 0 && SCIPsyncstoreIsInitialized(SCIPgetSyncstore(scip)) ) 110 { 111 int i; 112 int nvars; 113 SCIP_VAR** vars; 114 SCIPdebugMsg(scip, "catching events in " EVENTHDLR_NAME " eventhdlr\n"); 115 /* notify SCIP that this event handler wants to react on global bound change events */ 116 nvars = SCIPgetNVars(scip); 117 vars = SCIPgetVars(scip); 118 eventhdlrdata->storebounds = TRUE; 119 SCIP_CALL( SCIPboundstoreCreate(scip, &eventhdlrdata->boundstore, SCIPgetNOrigVars(scip)) ); 120 121 SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_VARADDED, eventhdlr, NULL, &eventhdlrdata->filterpos) ); 122 for( i = 0; i < nvars ; ++i ) 123 { 124 SCIP_CALL( SCIPcatchVarEvent(scip, vars[i], SCIP_EVENTTYPE_GBDCHANGED, eventhdlr, NULL, NULL) ); 125 } 126 } 127 128 return SCIP_OKAY; 129 } 130 131 /** deinitialization method of event handler (called before transformed problem is freed) */ 132 static 133 SCIP_DECL_EVENTEXIT(eventExitGlobalbnd) 134 { /*lint --e{715}*/ 135 SCIP_EVENTHDLRDATA* eventhdlrdata; 136 137 assert(scip != NULL); 138 assert(eventhdlr != NULL); 139 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 140 141 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr); 142 assert(eventhdlrdata != NULL); 143 144 /* notify SCIP that your event handler wants to drop the event type var added */ 145 if( eventhdlrdata->filterpos >= 0 ) 146 { 147 SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_VARADDED, eventhdlr, NULL, eventhdlrdata->filterpos) ); 148 eventhdlrdata->filterpos = -1; 149 SCIPboundstoreFree(scip, &eventhdlrdata->boundstore); 150 } 151 152 return SCIP_OKAY; 153 } 154 155 /** execution method of event handler */ 156 static 157 SCIP_DECL_EVENTEXEC(eventExecGlobalbnd) 158 { /*lint --e{715}*/ 159 SCIP_EVENTHDLRDATA* eventhdlrdata; 160 SCIP_VAR* var; 161 SCIP_Real newbound; 162 SCIP_BOUNDTYPE boundtype; 163 SCIP_Real constant; 164 SCIP_Real scalar; 165 SCIPdebugMsg(scip, "exec method of eventhdlr " EVENTHDLR_NAME "\n"); 166 assert(eventhdlr != NULL); 167 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 168 assert(event != NULL); 169 assert(scip != NULL); 170 171 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr); 172 assert(eventhdlrdata != NULL); 173 174 var = SCIPeventGetVar(event); 175 switch( SCIPeventGetType(event) ) 176 { 177 case SCIP_EVENTTYPE_VARADDED: 178 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, eventhdlr, NULL, NULL) ); 179 return SCIP_OKAY; 180 case SCIP_EVENTTYPE_GLBCHANGED: 181 boundtype = SCIP_BOUNDTYPE_LOWER; 182 break; 183 case SCIP_EVENTTYPE_GUBCHANGED: 184 boundtype = SCIP_BOUNDTYPE_UPPER; 185 break; 186 default: 187 SCIPABORT(); 188 return SCIP_ERROR; /*lint !e527*/ 189 } 190 191 if( !eventhdlrdata->storebounds ) 192 return SCIP_OKAY; 193 194 newbound = SCIPeventGetNewbound(event); 195 constant = 0.0; 196 scalar = 1.0; 197 SCIP_CALL( SCIPvarGetOrigvarSum(&var, &scalar, &constant) ); 198 if( var != NULL ) 199 { 200 int varidx; 201 202 varidx = SCIPgetConcurrentVaridx(scip, var); 203 204 boundtype = scalar < 0.0 ? SCIPboundtypeOpposite(boundtype) : boundtype; 205 newbound = (newbound - constant) / scalar; 206 207 SCIP_CALL( SCIPboundstoreAdd(scip, eventhdlrdata->boundstore, varidx, newbound, boundtype) ); 208 } 209 return SCIP_OKAY; 210 } 211 212 /** creates event handler for globalbnd event */ 213 SCIP_RETCODE SCIPincludeEventHdlrGlobalbnd( 214 SCIP* scip /**< SCIP data structure */ 215 ) 216 { 217 SCIP_EVENTHDLRDATA* eventhdlrdata; 218 SCIP_EVENTHDLR* eventhdlr; 219 220 /* create globalbnd event handler data */ 221 eventhdlrdata = NULL; 222 SCIP_CALL( SCIPallocMemory(scip, &eventhdlrdata) ); 223 eventhdlrdata->filterpos = -1; 224 eventhdlr = NULL; 225 226 /* include event handler into SCIP */ 227 228 /* use SCIPincludeEventhdlrBasic() plus setter functions if you want to set callbacks one-by-one and your code should 229 * compile independent of new callbacks being added in future SCIP versions 230 */ 231 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, 232 eventExecGlobalbnd, eventhdlrdata) ); 233 assert(eventhdlr != NULL); 234 235 /* set non fundamental callbacks via setter functions */ 236 SCIP_CALL( SCIPsetEventhdlrFree(scip, eventhdlr, eventFreeGlobalbnd) ); 237 SCIP_CALL( SCIPsetEventhdlrInit(scip, eventhdlr, eventInitGlobalbnd) ); 238 SCIP_CALL( SCIPsetEventhdlrExit(scip, eventhdlr, eventExitGlobalbnd) ); 239 240 return SCIP_OKAY; 241 } 242 243 244 /** gets the global bound changes stored in the eventhandler */ 245 SCIP_BOUNDSTORE* SCIPeventGlobalbndGetBoundChanges( 246 SCIP_EVENTHDLR* eventhdlr /**< the globalbound eventhandler */ 247 ) 248 { 249 SCIP_EVENTHDLRDATA* eventhdlrdata; 250 assert(eventhdlr != NULL); 251 assert(strcmp(EVENTHDLR_NAME, SCIPeventhdlrGetName(eventhdlr)) == 0); 252 253 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr); 254 assert(eventhdlrdata != NULL); 255 256 return eventhdlrdata->boundstore; 257 } 258 259 /** enables storing of bound changes */ 260 void SCIPeventGlobalbndEnableBoundStorage( 261 SCIP_EVENTHDLR* eventhdlr /**< the globalbound eventhandler */ 262 ) 263 { 264 SCIP_EVENTHDLRDATA* eventhdlrdata; 265 266 assert(eventhdlr != NULL); 267 assert(strcmp(EVENTHDLR_NAME, SCIPeventhdlrGetName(eventhdlr)) == 0); 268 269 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr); 270 assert(eventhdlrdata != NULL); 271 272 eventhdlrdata->storebounds = TRUE; 273 } 274 275 /** disables storing of bound changes */ 276 void SCIPeventGlobalbndDisableBoundStorage( 277 SCIP_EVENTHDLR* eventhdlr /**< the globalbound eventhandler */ 278 ) 279 { 280 SCIP_EVENTHDLRDATA* eventhdlrdata; 281 282 assert(eventhdlr != NULL); 283 assert(strcmp(EVENTHDLR_NAME, SCIPeventhdlrGetName(eventhdlr)) == 0); 284 285 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr); 286 assert(eventhdlrdata != NULL); 287 288 eventhdlrdata->storebounds = FALSE; 289 } 290 291 /** clears all bound changes stored in the eventhandler */ 292 void SCIPeventGlobalbndClearBoundChanges( 293 SCIP_EVENTHDLR* eventhdlr /**< the globalbound eventhandler */ 294 ) 295 { 296 SCIP_EVENTHDLRDATA* eventhdlrdata; 297 298 assert(eventhdlr != NULL); 299 assert(strcmp(EVENTHDLR_NAME, SCIPeventhdlrGetName(eventhdlr)) == 0); 300 301 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr); 302 assert(eventhdlrdata != NULL); 303 304 SCIPboundstoreClear(eventhdlrdata->boundstore); 305 } 306