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 reader_osil.c 26 * @ingroup DEFPLUGINS_READER 27 * @brief OS instance language (OSiL) format file reader 28 * @author Stefan Vigerske 29 * @author Ingmar Vierhaus 30 * @author Benjamin Mueller 31 */ 32 33 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 34 35 #define _USE_MATH_DEFINES /* to get M_PI and M_E on Windows */ /*lint !750 */ 36 #include "blockmemshell/memory.h" 37 #include "scip/cons_bounddisjunction.h" 38 #include "scip/cons_nonlinear.h" 39 #include "scip/cons_linear.h" 40 #include "scip/cons_sos1.h" 41 #include "scip/cons_sos2.h" 42 #include "scip/expr_abs.h" 43 #include "scip/expr_erf.h" 44 #include "scip/expr_exp.h" 45 #include "scip/expr_log.h" 46 #include "scip/expr_pow.h" 47 #include "scip/expr_product.h" 48 #include "scip/expr_sum.h" 49 #include "scip/expr_trig.h" 50 #include "scip/expr_value.h" 51 #include "scip/expr_var.h" 52 #include "scip/pub_cons.h" 53 #include "scip/pub_message.h" 54 #include "scip/pub_misc.h" 55 #include "scip/pub_nlp.h" 56 #include "scip/pub_var.h" 57 #include "scip/reader_osil.h" 58 #include "scip/scip_cons.h" 59 #include "scip/scip_mem.h" 60 #include "scip/scip_numerics.h" 61 #include "scip/scip_param.h" 62 #include "scip/scip_prob.h" 63 #include "scip/scip_reader.h" 64 #include "scip/scip_var.h" 65 #include <stdlib.h> 66 #include <string.h> 67 #include "xml/xml.h" 68 69 #define READER_NAME "osilreader" 70 #define READER_DESC "file reader for OS instance language (OSiL) format" 71 #define READER_EXTENSION "osil" 72 73 /* 74 * Local methods 75 */ 76 77 /** create variables with bounds and type according to xml data */ 78 static 79 SCIP_RETCODE readVariables( 80 SCIP* scip, /**< SCIP data structure */ 81 const XML_NODE* datanode, /**< XML root node for instance data */ 82 SCIP_VAR*** vars, /**< buffer to store pointer to variable array */ 83 int* nvars, /**< buffer to store number of variables */ 84 SCIP_Bool initialconss, /**< should model constraints be marked as initial? */ 85 SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */ 86 SCIP_Bool dynamiccols, /**< should columns be added and removed dynamically to the LP? */ 87 SCIP_Bool dynamicrows, /**< should rows be added and removed dynamically to the LP? */ 88 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 89 ) 90 { 91 const XML_NODE* variables; 92 const XML_NODE* varnode; 93 const char* attrval; 94 int varssize; 95 96 assert(scip != NULL); 97 assert(datanode != NULL); 98 assert(vars != NULL); 99 assert(nvars != NULL); 100 assert(doingfine != NULL); 101 102 *vars = NULL; 103 *nvars = 0; 104 105 variables = xmlFindNodeMaxdepth(datanode, "variables", 0, 1); 106 107 if( variables == NULL ) 108 { 109 /* no variables: strange but ok so far */ 110 return SCIP_OKAY; 111 } 112 113 /* get number of variables */ 114 attrval = xmlGetAttrval(variables, "numberOfVariables"); 115 if( attrval == NULL ) 116 { 117 SCIPerrorMessage("Attribute \"numberOfVariables\" not found in <variables> node.\n"); 118 *doingfine = FALSE; 119 return SCIP_OKAY; 120 } 121 122 varssize = (int)strtol(attrval, (char**)&attrval, 10); 123 if( *attrval != '\0' || varssize < 0 ) 124 { 125 SCIPerrorMessage("Invalid value '%s' for \"numberOfVariables\" attribute.\n", xmlGetAttrval(variables, "numberOfVariables")); 126 *doingfine = FALSE; 127 return SCIP_OKAY; 128 } 129 assert(varssize >= 0); 130 131 SCIP_CALL( SCIPallocBufferArray(scip, vars, varssize) ); 132 133 /* parse variable nodes, create SCIP vars and add to problem 134 * create bounddisjunction constraints for semicontinuous/semiinteger variables 135 */ 136 for( varnode = xmlFirstChild(variables); varnode != NULL; varnode = xmlNextSibl(varnode) ) 137 { 138 const char* varname; 139 SCIP_VARTYPE vartype; 140 SCIP_Real varlb; 141 SCIP_Real varub; 142 SCIP_Real semibound; 143 144 if( varssize == *nvars ) 145 { 146 SCIPerrorMessage("Expected %d variables, got at least %d many.\n", varssize, *nvars+1); 147 *doingfine = FALSE; 148 return SCIP_OKAY; 149 } 150 151 /* find variable name */ 152 varname = xmlGetAttrval(varnode, "name"); 153 154 /* check for mult attribute */ 155 attrval = xmlGetAttrval(varnode, "mult"); 156 if( attrval != NULL && strcmp(attrval, "1") != 0 ) 157 { 158 SCIPerrorMessage("Variable attribute 'mult' not supported (while parsing variable <%s>)\n", varname); 159 *doingfine = FALSE; 160 return SCIP_OKAY; 161 } 162 163 /* find variable lower bound (default is 0.0 !) */ 164 attrval = xmlGetAttrval(varnode, "lb"); 165 if( attrval == NULL ) 166 varlb = 0.0; 167 else if( strcmp(attrval, "-INF") == 0 ) 168 varlb = -SCIPinfinity(scip); 169 else if( strcmp(attrval, "INF") == 0 ) 170 varlb = SCIPinfinity(scip); 171 else 172 { 173 varlb = strtod(attrval, (char**)&attrval); 174 if( *attrval != '\0' ) 175 { 176 SCIPerrorMessage("Error parsing variable lower bound '%s' for variable <%s>\n", attrval, varname); 177 *doingfine = FALSE; 178 return SCIP_OKAY; 179 } 180 } 181 182 /* find variable upper bound (default is infinity) */ 183 attrval = xmlGetAttrval(varnode, "ub"); 184 if( attrval == NULL ) 185 varub = SCIPinfinity(scip); 186 else if( strcmp(attrval, "-INF") == 0 ) 187 varub = -SCIPinfinity(scip); 188 else if( strcmp(attrval, "INF") == 0 ) 189 varub = SCIPinfinity(scip); 190 else 191 { 192 varub = strtod(attrval, (char**)&attrval); 193 if( *attrval != '\0' ) 194 { 195 SCIPerrorMessage("Error parsing variable upper bound '%s' for variable <%s>\n", attrval, varname); 196 *doingfine = FALSE; 197 return SCIP_OKAY; 198 } 199 } 200 201 semibound = SCIP_INVALID; 202 203 /* find variable type (default is continuous) 204 * adjust variable lower bound for semicontinuous variables 205 */ 206 attrval = xmlGetAttrval(varnode, "type"); 207 if( attrval == NULL ) 208 vartype = SCIP_VARTYPE_CONTINUOUS; 209 else switch( *attrval ) 210 { 211 case 'C': 212 vartype = SCIP_VARTYPE_CONTINUOUS; 213 break; 214 case 'B': 215 vartype = SCIP_VARTYPE_BINARY; 216 if( varub > 1.0 ) 217 varub = 1.0; 218 break; 219 case 'I': 220 vartype = SCIP_VARTYPE_INTEGER; 221 break; 222 case 'D': 223 vartype = SCIP_VARTYPE_CONTINUOUS; 224 if( varlb > 0.0 ) 225 semibound = varlb; 226 varlb = 0.0; 227 break; 228 case 'J': 229 vartype = SCIP_VARTYPE_INTEGER; 230 if( varlb > 0.0 ) 231 semibound = varlb; 232 varlb = 0.0; 233 break; 234 default: 235 SCIPerrorMessage("Unsupported variable type '%s' for variable <%s>\n", attrval, varname); 236 *doingfine = FALSE; 237 return SCIP_OKAY; 238 } 239 240 if( vartype != SCIP_VARTYPE_CONTINUOUS ) 241 { 242 varlb = SCIPceil(scip, varlb); 243 varub = SCIPfloor(scip, varub); 244 } 245 246 /* create SCIP variable */ 247 SCIP_CALL( SCIPcreateVar(scip, &(*vars)[*nvars], varname, varlb, varub, 0.0, vartype, !dynamiccols, dynamiccols, NULL, NULL, NULL, NULL, NULL) ); 248 assert((*vars)[*nvars] != NULL); 249 250 /* add variable to problem */ 251 SCIP_CALL( SCIPaddVar(scip, (*vars)[*nvars]) ); 252 253 /* if variable is actually semicontinuous or semiintegral, create bounddisjunction constraint (var <= 0.0 || var >= semibound) */ 254 if( semibound != SCIP_INVALID ) /*lint !e777*/ 255 { 256 SCIP_CONS* cons; 257 SCIP_VAR* consvars[2]; 258 SCIP_BOUNDTYPE boundtypes[2]; 259 SCIP_Real bounds[2]; 260 char name[SCIP_MAXSTRLEN]; 261 262 consvars[0] = (*vars)[*nvars]; 263 consvars[1] = (*vars)[*nvars]; 264 265 boundtypes[0] = SCIP_BOUNDTYPE_UPPER; 266 boundtypes[1] = SCIP_BOUNDTYPE_LOWER; 267 268 bounds[0] = 0.0; 269 bounds[1] = semibound; 270 271 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_semibound", SCIPvarGetName((*vars)[*nvars])); 272 273 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, consvars, boundtypes, bounds, 274 initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); 275 SCIP_CALL( SCIPaddCons(scip, cons) ); 276 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 277 } 278 279 ++*nvars; 280 } 281 if( *nvars < varssize ) 282 { 283 SCIPerrorMessage("Expected %d variables, but got only %d many.\n", varssize, *nvars); 284 *doingfine = FALSE; 285 return SCIP_OKAY; 286 } 287 288 return SCIP_OKAY; 289 } 290 291 /** setup linear coefficients and constant of objective and objective sense */ 292 static 293 SCIP_RETCODE readObjective( 294 SCIP* scip, /**< SCIP data structure */ 295 const XML_NODE* datanode, /**< XML root node for instance data */ 296 SCIP_VAR** vars, /**< variables in order of OSiL indices */ 297 int nvars, /**< number of variables */ 298 SCIP_Bool dynamiccols, /**< should columns be added and removed dynamically to the LP? */ 299 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 300 ) 301 { 302 const XML_NODE* objective; 303 const XML_NODE* coefnode; 304 const char* attrval; 305 306 assert(scip != NULL); 307 assert(datanode != NULL); 308 assert(vars != NULL || nvars == 0); 309 assert(doingfine != NULL); 310 311 /* check for first objective */ 312 objective = xmlFindNodeMaxdepth(datanode, "obj", 0, 2); 313 314 /* if no objective, then nothing to do here */ 315 if( objective == NULL ) 316 return SCIP_OKAY; 317 318 /* check for mult attribute */ 319 attrval = xmlGetAttrval(objective, "mult"); 320 if( attrval != NULL && strcmp(attrval, "1") != 0 ) 321 { 322 SCIPerrorMessage("Objective attribute 'mult' not supported.\n"); 323 *doingfine = FALSE; 324 return SCIP_OKAY; 325 } 326 327 /* objective sense */ 328 attrval = xmlGetAttrval(objective, "maxOrMin"); 329 if( attrval == NULL ) 330 { 331 SCIPerrorMessage("Objective sense missing.\n"); 332 *doingfine = FALSE; 333 return SCIP_OKAY; 334 } 335 else if( strcmp(attrval, "min") == 0 ) 336 { 337 SCIP_CALL( SCIPsetObjsense(scip, SCIP_OBJSENSE_MINIMIZE) ); 338 } 339 else if( strcmp(attrval, "max") == 0 ) 340 { 341 SCIP_CALL( SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE) ); 342 } 343 else 344 { 345 SCIPerrorMessage("Cannot parse objective sense '%s'.\n", attrval); 346 *doingfine = FALSE; 347 return SCIP_OKAY; 348 } 349 350 /* objective coefficients */ 351 for( coefnode = xmlFirstChild(objective); coefnode != NULL; coefnode = xmlNextSibl(coefnode) ) 352 { 353 SCIP_Real val; 354 int idx; 355 356 /* get variable index */ 357 attrval = xmlGetAttrval(coefnode, "idx"); 358 if( attrval == NULL ) 359 { 360 SCIPerrorMessage("Missing \"idx\" attribute in objective coefficient.\n"); 361 *doingfine = FALSE; 362 return SCIP_OKAY; 363 } 364 idx = (int)strtol(attrval, (char**)&attrval, 10); 365 if( *attrval != '\0' ) 366 { 367 SCIPerrorMessage("Error parsing variable index '%s' of objective coefficient.\n", xmlGetAttrval(coefnode, "idx")); 368 *doingfine = FALSE; 369 return SCIP_OKAY; 370 } 371 372 if( idx < 0 || idx >= nvars ) 373 { 374 SCIPerrorMessage("Invalid variable index '%d' of objective coefficient.\n", idx); 375 *doingfine = FALSE; 376 return SCIP_OKAY; 377 } 378 379 /* get coefficient value */ 380 if( xmlFirstChild(coefnode) == NULL || xmlGetData(xmlFirstChild(coefnode)) == NULL ) 381 { 382 SCIPerrorMessage("No objective coefficient stored for %d'th variable (<%s>).\n", idx, SCIPvarGetName(vars[idx])); /*lint !e613*/ 383 *doingfine = FALSE; 384 return SCIP_OKAY; 385 } 386 387 attrval = xmlGetData(xmlFirstChild(coefnode)); 388 val = strtod(attrval, (char**)&attrval); 389 if( *attrval != '\0' ) 390 { 391 SCIPerrorMessage("Error parsing objective coefficient value '%s' for %d'th variable (<%s>).\n", xmlGetData(xmlFirstChild(coefnode)), idx, SCIPvarGetName(vars[idx])); /*lint !e613*/ 392 *doingfine = FALSE; 393 return SCIP_OKAY; 394 } 395 396 /* change objective coefficient of SCIP variable */ 397 SCIP_CALL( SCIPchgVarObj(scip, vars[idx], val) ); /*lint !e613*/ 398 } 399 400 /* objective constant: model as fixed variable, if nonzero */ 401 attrval = xmlGetAttrval(objective, "constant"); 402 if( attrval != NULL ) 403 { 404 SCIP_Real objconst; 405 406 objconst = strtod(attrval, (char**)&attrval); 407 if( *attrval != '\0' ) 408 { 409 SCIPerrorMessage("Error parsing objective constant '%s'\n", xmlGetAttrval(objective, "constant")); 410 *doingfine = FALSE; 411 return SCIP_OKAY; 412 } 413 414 if( objconst != 0.0 ) 415 { 416 SCIP_VAR* objconstvar; 417 418 SCIP_CALL( SCIPcreateVar(scip, &objconstvar, "objconstvar", objconst, objconst, 1.0, SCIP_VARTYPE_CONTINUOUS, !dynamiccols, dynamiccols, NULL, NULL, NULL, NULL, NULL) ); 419 SCIP_CALL( SCIPaddVar(scip, objconstvar) ); 420 SCIP_CALL( SCIPreleaseVar(scip, &objconstvar) ); 421 } 422 } 423 424 if( xmlNextSibl(objective) != NULL ) 425 { 426 SCIPerrorMessage("Multiple objectives not supported by SCIP.\n"); 427 *doingfine = FALSE; 428 return SCIP_OKAY; 429 } 430 431 return SCIP_OKAY; 432 } 433 434 /** helper method to get the total number of constraints */ 435 static 436 SCIP_RETCODE readNConstraints( 437 SCIP* scip, /**< SCIP data structure */ 438 const XML_NODE* datanode, /**< XML root node for instance data */ 439 int* nconss, /**< pointer to store the total number of constraints */ 440 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 441 ) 442 { 443 const XML_NODE* constraints; 444 const char* attrval; 445 446 assert(scip != NULL); 447 assert(datanode != NULL); 448 assert(nconss != NULL); 449 assert(doingfine != NULL); 450 451 *nconss = 0; 452 453 constraints = xmlFindNodeMaxdepth(datanode, "constraints", 0, 1); 454 455 /* if no constraints, then nothing to do here */ 456 if( constraints == NULL ) 457 return SCIP_OKAY; 458 459 /* read number of constraints */ 460 attrval = xmlGetAttrval(constraints, "numberOfConstraints"); 461 if( attrval == NULL ) 462 { 463 SCIPerrorMessage("Attribute \"numberOfConstraints\" not found in <constraints> node.\n"); 464 *doingfine = FALSE; 465 return SCIP_OKAY; 466 } 467 468 *nconss = (int)strtol(attrval, (char**)&attrval, 10); 469 if( *attrval != '\0' || *nconss < 0 ) 470 { 471 SCIPerrorMessage("Invalid value '%s' for \"numberOfConstraints\" attribute.\n", xmlGetAttrval(constraints, "numberOfConstraints")); 472 *doingfine = FALSE; 473 return SCIP_OKAY; 474 } 475 assert(*nconss >= 0); 476 477 return SCIP_OKAY; 478 } 479 480 /** helper method to create and add a constraint (or a nonlinear objective constraint) */ 481 static 482 SCIP_RETCODE createConstraint( 483 SCIP* scip, /**< SCIP data structure */ 484 SCIP_VAR** linvars, /**< array containing the linear variables (might be NULL) */ 485 SCIP_Real* lincoefs, /**< array containing the coefficients of the linear variables (might be NULL) */ 486 int nlinvars, /**< the total number of linear variables */ 487 SCIP_VAR** quadvars1, /**< array containing the first variables of the quadratic terms (might be NULL) */ 488 SCIP_VAR** quadvars2, /**< array containing the second variables of the quadratic terms (might be NULL) */ 489 SCIP_Real* quadcoefs, /**< array containing the coefficients of the quadratic terms (might be NULL) */ 490 int nquadterms, /**< the total number of quadratic terms */ 491 SCIP_EXPR* nlexpr, /**< the nonlinear part (might be NULL) */ 492 SCIP_Real lhs, /**< left-hand side */ 493 SCIP_Real rhs, /**< right-hand side */ 494 const char* name, /**< name of the constraint */ 495 SCIP_Bool objcons, /**< whether to add an objective constraints */ 496 SCIP_Bool initialconss, /**< should model constraints be marked as initial? */ 497 SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */ 498 SCIP_Bool dynamicrows /**< should rows be added and removed dynamically to the LP? */ 499 ) 500 { 501 SCIP_CONS* cons; 502 SCIP_VAR* objvar = NULL; 503 504 assert(nlinvars >= 0); 505 assert(nquadterms >= 0); 506 507 /* create objective variable, if requested */ 508 if( objcons ) 509 { 510 SCIP_CALL( SCIPcreateVar(scip, &objvar, "nlobjvar", -SCIPinfinity(scip), SCIPinfinity(scip), 1.0, 511 SCIP_VARTYPE_CONTINUOUS, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); 512 SCIP_CALL( SCIPaddVar(scip, objvar) ); 513 } 514 515 /* linear constraint (can be empty) */ 516 if( nquadterms == 0 && nlexpr == NULL ) 517 { 518 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 519 nlinvars, linvars, lincoefs, lhs, rhs, initialconss, 520 TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); 521 522 /* add objective variable, if requested */ 523 if( objcons ) 524 { 525 assert(objvar != NULL); 526 SCIP_CALL( SCIPaddCoefLinear(scip, cons, objvar, -1.0) ); 527 } 528 } 529 /* nonlinear constraint */ 530 else 531 { 532 SCIP_EXPR* expr = NULL; 533 SCIP_EXPR* varexpr = NULL; 534 535 /* create variable expression for objvar */ 536 if( objcons ) 537 { 538 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, objvar, NULL, NULL) ); 539 } 540 541 /* check whether there is a quadratic part */ 542 if( nlinvars > 0 || nquadterms > 0 ) 543 { 544 /* create quadratic expression; note that this is always a sum */ 545 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, 546 nquadterms, quadvars1, quadvars2, quadcoefs, NULL, NULL) ); 547 assert(SCIPisExprSum(scip, expr)); 548 549 /* add nonlinear expression as a child to expr */ 550 if( nlexpr != NULL ) 551 { 552 SCIP_CALL( SCIPappendExprSumExpr(scip, expr, nlexpr, 1.0) ); 553 } 554 555 /* add expression that represents the objective variable as a child to expr */ 556 if( varexpr != NULL ) 557 { 558 SCIP_CALL( SCIPappendExprSumExpr(scip, expr, varexpr, -1.0) ); 559 } 560 561 /* create nonlinear constraint */ 562 SCIP_CALL( SCIPcreateConsNonlinear(scip, &cons, name, expr, lhs, rhs, 563 initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows) ); 564 565 /* release created expression */ 566 SCIP_CALL( SCIPreleaseExpr(scip, &expr) ); 567 } 568 569 /* there is no quadratic part but we might need to take care of the objective variable */ 570 else 571 { 572 assert(nlexpr != NULL); 573 574 if( objcons ) 575 { 576 SCIP_EXPR* sumexpr; 577 SCIP_EXPR* children[2] = {nlexpr, varexpr}; 578 SCIP_Real coefs[2] = {1.0, -1.0}; 579 580 assert(varexpr != NULL); 581 582 /* create sum expression */ 583 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, children, coefs, 0.0, NULL, NULL) ); 584 585 /* create nonlinear constraint */ 586 SCIP_CALL( SCIPcreateConsNonlinear(scip, &cons, name, sumexpr, lhs, rhs, 587 initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows) ); 588 589 /* release sum expression */ 590 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) ); 591 } 592 else 593 { 594 /* create nonlinear constraint */ 595 SCIP_CALL( SCIPcreateConsNonlinear(scip, &cons, name, nlexpr, lhs, rhs, 596 initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows) ); 597 } 598 } 599 600 /* release variable expression */ 601 if( objcons ) 602 { 603 assert(varexpr != NULL); 604 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) ); 605 } 606 } 607 608 /* add and release constraint */ 609 SCIP_CALL( SCIPaddCons(scip, cons) ); 610 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 611 612 /* release objective variable */ 613 if( objcons ) 614 { 615 assert(objvar != NULL); 616 SCIP_CALL( SCIPreleaseVar(scip, &objvar) ); 617 } 618 619 return SCIP_OKAY; 620 } 621 622 623 /** reads constraint-specific information; creates and adds linear and nonlinear constraints based on the 624 * information that have been collected by @ref readLinearCoefs, @ref readQuadraticCoefs, and @ref readNonlinearExprs 625 */ 626 static 627 SCIP_RETCODE readConstraints( 628 SCIP* scip, /**< SCIP data structure */ 629 const XML_NODE* datanode, /**< XML root node for instance data */ 630 int nconss, /**< total number of constraints */ 631 SCIP_VAR*** linvars, /**< array containing for each constraint the linear variables */ 632 SCIP_Real** lincoefs, /**< array containing for each constraint the coefficients of the linear variables */ 633 int* nlinvars, /**< array containing for each constraint the total number of linear variables */ 634 SCIP_VAR*** quadvars1, /**< array containing for each constraint the first variables of the quadratic terms */ 635 SCIP_VAR*** quadvars2, /**< array containing for each constraint the second variables of the quadratic terms */ 636 SCIP_Real** quadcoefs, /**< array containing for each constraint the coefficients of the quadratic terms */ 637 int* nquadterms, /**< array containing for each constraint the total number of quadratic terms */ 638 SCIP_EXPR** nlexprs, /**< array containing for each constraint the nonlinear part */ 639 SCIP_Bool initialconss, /**< should model constraints be marked as initial? */ 640 SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */ 641 SCIP_Bool dynamicrows, /**< should rows be added and removed dynamically to the LP? */ 642 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 643 ) 644 { 645 const XML_NODE* constraints; 646 const XML_NODE* consnode; 647 const char* attrval; 648 char name[SCIP_MAXSTRLEN]; 649 int c = 0; 650 651 assert(scip != NULL); 652 assert(datanode != NULL); 653 assert(doingfine != NULL); 654 assert(linvars != NULL); 655 assert(lincoefs != NULL); 656 assert(nlinvars != NULL); 657 assert(quadvars1 != NULL); 658 assert(quadvars2 != NULL); 659 assert(quadcoefs != NULL); 660 assert(nquadterms != NULL); 661 assert(nlexprs != NULL); 662 663 constraints = xmlFindNodeMaxdepth(datanode, "constraints", 0, 1); 664 665 /* if no constraints, then nothing to do here */ 666 if( constraints == NULL ) 667 return SCIP_OKAY; 668 669 /* read constraint names, lhs, rhs, constant */ 670 for( consnode = xmlFirstChild(constraints); consnode != NULL; consnode = xmlNextSibl(consnode) ) 671 { 672 const char* consname; 673 SCIP_Real conslhs; 674 SCIP_Real consrhs; 675 676 if( c == nconss ) 677 { 678 SCIPerrorMessage("Expected %d constraints, but got at least %d many.\n", nconss, c+1); 679 *doingfine = FALSE; 680 return SCIP_OKAY; 681 } 682 683 /* find constraint name */ 684 consname = xmlGetAttrval(consnode, "name"); 685 if( consname == NULL ) 686 { 687 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cons%d", c); 688 consname = name; 689 } 690 691 /* check for mult attribute */ 692 attrval = xmlGetAttrval(consnode, "mult"); 693 if( attrval != NULL && strcmp(attrval, "1") != 0 ) 694 { 695 SCIPerrorMessage("Constraint attribute 'mult' not supported (while parsing constraint <%s>).\n", consname); 696 *doingfine = FALSE; 697 return SCIP_OKAY; 698 } 699 700 /* find constraint lower bound (=lhs) (default is -infinity) */ 701 attrval = xmlGetAttrval(consnode, "lb"); 702 if( attrval == NULL ) 703 conslhs = -SCIPinfinity(scip); 704 else if( strcmp(attrval, "-INF") == 0 ) 705 conslhs = -SCIPinfinity(scip); 706 else if( strcmp(attrval, "INF") == 0 ) 707 conslhs = SCIPinfinity(scip); 708 else 709 { 710 conslhs = strtod(attrval, (char**)&attrval); 711 if( *attrval != '\0' ) 712 { 713 SCIPerrorMessage("Error parsing constraint lower bound '%s' for constraint <%s>.\n", attrval, consname); 714 *doingfine = FALSE; 715 return SCIP_OKAY; 716 } 717 } 718 719 /* find constraint upper bound (=rhs) (default is +infinity) */ 720 attrval = xmlGetAttrval(consnode, "ub"); 721 if( attrval == NULL ) 722 consrhs = SCIPinfinity(scip); 723 else if( strcmp(attrval, "-INF") == 0 ) 724 consrhs = -SCIPinfinity(scip); 725 else if( strcmp(attrval, "INF") == 0 ) 726 consrhs = SCIPinfinity(scip); 727 else 728 { 729 consrhs = strtod(attrval, (char**)&attrval); 730 if( *attrval != '\0' ) 731 { 732 SCIPerrorMessage("Error parsing constraint upper bound '%s' for constraint <%s>.\n", attrval, consname); 733 *doingfine = FALSE; 734 return SCIP_OKAY; 735 } 736 } 737 738 /* find constraint constant (default is 0.0) and substract from lhs/rhs */ 739 attrval = xmlGetAttrval(consnode, "constant"); 740 if( attrval != NULL ) 741 { 742 SCIP_Real consconstant; 743 744 consconstant = strtod(attrval, (char**)&attrval); 745 if( *attrval != '\0' ) 746 { 747 SCIPerrorMessage("Error parsing constraint constant '%s' for constraint <%s>.\n", attrval, consname); 748 *doingfine = FALSE; 749 return SCIP_OKAY; 750 } 751 if( conslhs > -SCIPinfinity(scip) ) 752 conslhs -= consconstant; 753 if( consrhs < SCIPinfinity(scip) ) 754 consrhs -= consconstant; 755 } 756 757 /* create, add, and release constraint */ 758 SCIP_CALL( createConstraint(scip, linvars[c], lincoefs[c], nlinvars[c], 759 quadvars1[c], quadvars2[c], quadcoefs[c], nquadterms[c], nlexprs[c], 760 conslhs, consrhs, consname, FALSE, initialconss, dynamicconss, dynamicrows) ); 761 762 ++c; 763 } 764 765 if( c != nconss ) 766 { 767 SCIPerrorMessage("Got %d constraints, but expected %d many.\n", c, nconss); 768 *doingfine = FALSE; 769 return SCIP_OKAY; 770 } 771 772 return SCIP_OKAY; 773 } 774 775 /** reads mult and incr attributes of an OSiL node 776 * 777 * if mult attribute is not present, then returns mult=1 778 * if incr attribute is not present, then returns incrint=0 and incrreal=0 779 */ 780 static 781 void readMultIncr( 782 const XML_NODE* node, /**< XML node to read attributes from */ 783 int* mult, /**< buffer to store mult */ 784 int* incrint, /**< buffer to store incr as int, or NULL if no int expected */ 785 SCIP_Real* incrreal, /**< buffer to store incr as real, or NULL if no real expected */ 786 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 787 ) 788 { 789 const char* attrval; 790 791 assert(node != NULL); 792 assert(mult != NULL); 793 assert(doingfine != NULL); 794 795 *mult = 1; 796 if( incrint != NULL ) 797 *incrint = 0; 798 if( incrreal != NULL ) 799 *incrreal = 0.0; 800 801 attrval = xmlGetAttrval(node, "mult"); 802 if( attrval == NULL ) 803 return; 804 805 /* read "mult" attribute */ 806 *mult = (int)strtol(attrval, (char**)&attrval, 10); 807 if( *attrval != '\0' || *mult < 1 ) 808 { 809 SCIPerrorMessage("Invalid value '%s' in \"mult\" attribute of node.\n", xmlGetAttrval(node, "mult")); 810 *doingfine = FALSE; 811 return; 812 } 813 814 if( *mult == 1 ) 815 return; 816 817 /* read "incr" attribute */ 818 attrval = xmlGetAttrval(node, "incr"); 819 if( attrval == NULL ) 820 return; 821 822 if( incrint != NULL ) 823 { 824 *incrint = (int)strtol(attrval, (char**)&attrval, 10); 825 if( *attrval != '\0' ) 826 { 827 SCIPerrorMessage("Invalid value '%s' in \"incr\" attribute of node.\n", xmlGetAttrval(node, "incr")); 828 *doingfine = FALSE; 829 return; 830 } 831 } 832 833 if( incrreal != NULL ) 834 { 835 *incrreal = strtod(attrval, (char**)&attrval); 836 if( *attrval != '\0' || !SCIPisFinite(*incrreal) ) 837 { 838 SCIPerrorMessage("Invalid value '%s' in \"incr\" attribute of node.\n", xmlGetAttrval(node, "incr")); 839 *doingfine = FALSE; 840 return; 841 } 842 } 843 } 844 845 /** parse linear coefficients of constraints */ 846 static 847 SCIP_RETCODE readLinearCoefs( 848 SCIP* scip, /**< SCIP data structure */ 849 const XML_NODE* datanode, /**< XML root node for instance data */ 850 SCIP_VAR** vars, /**< variables in order of OSiL indices */ 851 int nvars, /**< number of variables */ 852 int nconss, /**< number of constraints */ 853 SCIP_VAR*** linvars, /**< array to store for each constraint the linear variables */ 854 SCIP_Real** lincoefs, /**< array to store for each constraint the coefficients of the linear variables */ 855 int* nlinvars, /**< array to store for each constraint the total number of linear variables */ 856 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 857 ) 858 { 859 const XML_NODE* lincoef; 860 const XML_NODE* startnode; 861 const XML_NODE* idxnode; 862 const XML_NODE* valnode; 863 const XML_NODE* elnode; 864 const char* attrval; 865 SCIP_Bool rowmajor; 866 int* start; 867 int* idx; 868 SCIP_Real* val; 869 int nnz; 870 int count; 871 int mult; 872 int incrint; 873 SCIP_Real incrreal; 874 875 assert(scip != NULL); 876 assert(datanode != NULL); 877 assert(vars != NULL || nvars == 0); 878 assert(doingfine != NULL); 879 880 lincoef = xmlFindNodeMaxdepth(datanode, "linearConstraintCoefficients", 0, 1); 881 882 if( lincoef == NULL ) 883 return SCIP_OKAY; 884 885 /* get number of linear constraint coefficients */ 886 attrval = xmlGetAttrval(lincoef, "numberOfValues"); 887 if( attrval == NULL ) 888 { 889 SCIPerrorMessage("Attribute \"numberOfValues\" not found for <linearConstraintCoefficients> node.\n"); 890 *doingfine = FALSE; 891 return SCIP_OKAY; 892 } 893 894 nnz = (int)strtol(attrval, (char**)&attrval, 10); 895 if( *attrval != '\0' || nnz < 0 ) 896 { 897 SCIPerrorMessage("Invalid value '%s' for \"numberOfValues\" attribute in <linearConstraintCoefficients> node.\n", xmlGetAttrval(lincoef, "numberOfValues")); 898 *doingfine = FALSE; 899 return SCIP_OKAY; 900 } 901 assert(nnz >= 0); 902 903 /* check for start, rowIdx, colIdx, and value nodes */ 904 startnode = xmlFindNodeMaxdepth(lincoef, "start", 0, 1); 905 if( startnode == NULL ) 906 { 907 SCIPerrorMessage("Node <start> not found inside <linearConstraintCoefficients> node.\n"); 908 *doingfine = FALSE; 909 return SCIP_OKAY; 910 } 911 912 idxnode = xmlFindNodeMaxdepth(lincoef, "rowIdx", 0, 1); 913 if( idxnode != NULL ) 914 { 915 if( xmlFindNodeMaxdepth(lincoef, "colIdx", 0, 1) != NULL ) 916 { 917 SCIPerrorMessage("Both <rowIdx> and <colIdx> found under <linearConstraintCoefficients> node.\n"); 918 *doingfine = FALSE; 919 return SCIP_OKAY; 920 } 921 rowmajor = FALSE; 922 } 923 else 924 { 925 idxnode = xmlFindNodeMaxdepth(lincoef, "colIdx", 0, 1); 926 if( idxnode == NULL ) 927 { 928 SCIPerrorMessage("Both <rowIdx> and <colIdx> not found under <linearConstraintCoefficients> node.\n"); 929 *doingfine = FALSE; 930 return SCIP_OKAY; 931 } 932 rowmajor = TRUE; 933 } 934 935 valnode = xmlFindNodeMaxdepth(lincoef, "value", 0, 1); 936 if( valnode == NULL ) 937 { 938 SCIPerrorMessage("<value> node not found under <linearConstraintCoefficients> node.\n"); 939 *doingfine = FALSE; 940 return SCIP_OKAY; 941 } 942 943 start = NULL; 944 idx = NULL; 945 val = NULL; 946 947 /* read row or column start indices */ 948 SCIP_CALL( SCIPallocBufferArray(scip, &start, (rowmajor ? nconss : nvars) + 1) ); 949 950 count = 0; 951 for( elnode = xmlFirstChild(startnode); elnode != NULL; elnode = xmlNextSibl(elnode), ++count ) 952 { 953 /* check for <el> node and read it's data */ 954 if( strcmp(xmlGetName(elnode), "el") != 0 ) 955 { 956 SCIPerrorMessage("Expected <el> node under <start> node in <linearConstraintCoefficients>, but got '%s'.\n", xmlGetName(elnode)); 957 *doingfine = FALSE; 958 goto CLEANUP; 959 } 960 if( count >= (rowmajor ? nconss : nvars) + 1 ) 961 { 962 SCIPerrorMessage("Too many elements under <start> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", (rowmajor ? nconss : nvars) + 1, count + 1); 963 *doingfine = FALSE; 964 goto CLEANUP; 965 } 966 if( xmlFirstChild(elnode) == NULL || xmlGetData(xmlFirstChild(elnode)) == NULL ) 967 { 968 SCIPerrorMessage("No data in <el> node in <linearConstraintCoefficients>.\n"); 969 *doingfine = FALSE; 970 goto CLEANUP; 971 } 972 973 start[count] = (int)strtol(xmlGetData(xmlFirstChild(elnode)), (char**)&attrval, 10); 974 975 if( *attrval != '\0' || start[count] < 0 || (start[count] > nnz) ) 976 { 977 SCIPerrorMessage("Invalid value '%s' in <el> node under <start> node in <linearConstraintCoefficients>.\n", xmlGetData(elnode)); 978 *doingfine = FALSE; 979 goto CLEANUP; 980 } 981 982 /* add additional start-indices according to mult and incr attributes */ 983 readMultIncr(elnode, &mult, &incrint, NULL, doingfine); 984 if( !*doingfine ) 985 goto CLEANUP; 986 987 for( --mult; mult > 0; --mult ) 988 { 989 ++count; 990 if( count >= (rowmajor ? nconss : nvars) + 1 ) 991 { 992 SCIPerrorMessage("Too many elements under <start> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", (rowmajor ? nconss : nvars) + 1, count + 1); 993 *doingfine = FALSE; 994 goto CLEANUP; 995 } 996 start[count] = start[count-1] + incrint; 997 } 998 } 999 if( count != (rowmajor ? nconss : nvars) + 1 ) 1000 { 1001 SCIPerrorMessage("Got only %d <start> entries in <linearConstraintCoefficients>, but expected %d many.\n", count, (rowmajor ? nconss : nvars) + 1); 1002 *doingfine = FALSE; 1003 goto CLEANUP; 1004 } 1005 1006 /* read row or column indices */ 1007 SCIP_CALL( SCIPallocBufferArray(scip, &idx, nnz) ); 1008 1009 count = 0; 1010 for( elnode = xmlFirstChild(idxnode); elnode != NULL; elnode = xmlNextSibl(elnode), ++count ) 1011 { 1012 /* check for <el> node and read it's data */ 1013 if( strcmp(xmlGetName(elnode), "el") != 0 ) 1014 { 1015 SCIPerrorMessage("Expected <el> node under <%s> node in <linearConstraintCoefficients>, but got '%s'.\n", rowmajor ? "colIdx" : "rowIdx", xmlGetName(elnode)); 1016 *doingfine = FALSE; 1017 goto CLEANUP; 1018 } 1019 if( count >= nnz ) 1020 { 1021 SCIPerrorMessage("Too many elements under <%s> node in <linearConstraintCoefficients>, expected %d many, but got at least %d.\n", rowmajor ? "colIdx" : "rowIdx", nnz, count + 1); 1022 *doingfine = FALSE; 1023 goto CLEANUP; 1024 } 1025 if( xmlFirstChild(elnode) == NULL || xmlGetData(xmlFirstChild(elnode)) == NULL ) 1026 { 1027 SCIPerrorMessage("No data in <el> node under <%s> node in <linearConstraintCoefficients>.\n", rowmajor ? "colIdx" : "rowIdx"); 1028 *doingfine = FALSE; 1029 goto CLEANUP; 1030 } 1031 1032 idx[count] = (int)strtol(xmlGetData(xmlFirstChild(elnode)), (char**)&attrval, 10); 1033 1034 if( *attrval != '\0' || idx[count] < 0 || (idx[count] >= (rowmajor ? nvars : nconss)) ) 1035 { 1036 SCIPerrorMessage("Invalid value '%s' in <el> node under <%s> node in <linearConstraintCoefficients>.\n", xmlGetData(elnode), rowmajor ? "colIdx" : "rowIdx"); 1037 *doingfine = FALSE; 1038 goto CLEANUP; 1039 } 1040 1041 /* add additional indices according to mult and incr attributes */ 1042 readMultIncr(elnode, &mult, &incrint, NULL, doingfine); 1043 if( !*doingfine ) 1044 goto CLEANUP; 1045 1046 for( --mult; mult > 0; --mult ) 1047 { 1048 ++count; 1049 if( count >= nnz ) 1050 { 1051 SCIPerrorMessage("Too many elements under <%s> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", rowmajor ? "colIdx" : "rowIdx", nnz, count + 1); 1052 *doingfine = FALSE; 1053 goto CLEANUP; 1054 } 1055 idx[count] = idx[count-1] + incrint; 1056 } 1057 } 1058 if( count != nnz ) 1059 { 1060 SCIPerrorMessage("Got only %d entries in <%s> node in <linearConstraintCoefficients>, expected %d many.\n", count, rowmajor ? "colIdx" : "rowIdx", nnz); 1061 *doingfine = FALSE; 1062 goto CLEANUP; 1063 } 1064 1065 /* read coefficient values */ 1066 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnz) ); 1067 1068 count = 0; 1069 for( elnode = xmlFirstChild(valnode); elnode != NULL; elnode = xmlNextSibl(elnode), ++count ) 1070 { 1071 /* check for <el> node and read it's data */ 1072 if( strcmp(xmlGetName(elnode), "el") != 0 ) 1073 { 1074 SCIPerrorMessage("Expected <el> node under <value> node in <linearConstraintCoefficients>, but got '%s'.\n", xmlGetName(elnode)); 1075 *doingfine = FALSE; 1076 goto CLEANUP; 1077 } 1078 if( count >= nnz ) 1079 { 1080 SCIPerrorMessage("Too many elements under <value> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", nnz, count + 1); 1081 *doingfine = FALSE; 1082 goto CLEANUP; 1083 } 1084 if( xmlFirstChild(elnode) == NULL || xmlGetData(xmlFirstChild(elnode)) == NULL ) 1085 { 1086 SCIPerrorMessage("No data in <el> node under <value> node in <linearConstraintCoefficients>.\n"); 1087 *doingfine = FALSE; 1088 goto CLEANUP; 1089 } 1090 1091 val[count] = strtod(xmlGetData(xmlFirstChild(elnode)), (char**)&attrval); 1092 1093 if( *attrval != '\0' || !SCIPisFinite(val[count]) ) 1094 { 1095 SCIPerrorMessage("Invalid value '%s' in <el> node under <value> node in <linearConstraintCoefficients>.\n", xmlGetData(elnode)); 1096 *doingfine = FALSE; 1097 goto CLEANUP; 1098 } 1099 1100 /* add additional values according to mult and incr attributes */ 1101 readMultIncr(elnode, &mult, NULL, &incrreal, doingfine); 1102 if( !*doingfine ) 1103 goto CLEANUP; 1104 1105 for( --mult; mult > 0; --mult ) 1106 { 1107 ++count; 1108 if( count >= nnz ) 1109 { 1110 SCIPerrorMessage("Too many elements under <value> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", nnz, count + 1); 1111 *doingfine = FALSE; 1112 goto CLEANUP; 1113 } 1114 val[count] = val[count-1] + incrreal; 1115 } 1116 } 1117 if( count != nnz ) 1118 { 1119 SCIPerrorMessage("Got only %d entries under <value> node in <linearConstraintCoefficients>, expected %d many.\n", count, nnz); 1120 *doingfine = FALSE; 1121 goto CLEANUP; 1122 } 1123 1124 /* add coefficients to linear constraints */ 1125 if( rowmajor ) 1126 { 1127 int row; 1128 int pos; 1129 for( row = 0; row < nconss; ++row ) 1130 { 1131 int nterms; 1132 1133 /* these asserts were checked above */ 1134 assert(start[row] >= 0); 1135 assert(start[row+1] >= 0); 1136 assert(start[row] <= nnz); 1137 assert(start[row+1] <= nnz); 1138 1139 assert(linvars[row] == NULL); 1140 assert(lincoefs[row] == NULL); 1141 assert(nlinvars[row] == 0); 1142 1143 nterms = start[row+1] - start[row]; 1144 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &linvars[row], nterms) ); 1145 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lincoefs[row], nterms) ); 1146 1147 for( pos = start[row]; pos < start[row+1]; ++pos ) 1148 { 1149 /* these asserts were checked above */ 1150 assert(pos >= 0); 1151 assert(pos < nnz); 1152 assert(idx[pos] >= 0); 1153 assert(idx[pos] < nvars); 1154 1155 linvars[row][nlinvars[row]] = vars[idx[pos]]; 1156 lincoefs[row][nlinvars[row]] = val[pos]; 1157 ++(nlinvars[row]); 1158 } 1159 assert(nlinvars[row] == nterms); 1160 } 1161 } 1162 else 1163 { 1164 int col; 1165 int pos; 1166 int k; 1167 1168 /* allocate memory for the coefficients in iteration k=0; in k=1 fill in the data */ 1169 for( k = 0; k < 2; ++k ) 1170 { 1171 for( col = 0; col < nvars; ++col ) 1172 { 1173 /* these asserts were checked above */ 1174 assert(start[col] >= 0); 1175 assert(start[col+1] >= 0); 1176 assert(start[col] <= nnz); 1177 assert(start[col+1] <= nnz); 1178 for( pos = start[col]; pos < start[col+1]; ++pos ) 1179 { 1180 int considx = idx[pos]; 1181 1182 /* these asserts were checked above */ 1183 assert(pos >= 0); 1184 assert(pos < nnz); 1185 assert(considx >= 0); 1186 assert(considx < nconss); 1187 1188 if( k == 0 ) 1189 { 1190 ++(nlinvars[considx]); 1191 } 1192 else 1193 { 1194 linvars[considx][nlinvars[considx]] = vars[col]; 1195 lincoefs[considx][nlinvars[considx]] = val[pos]; 1196 ++(nlinvars[considx]); 1197 } 1198 } 1199 } 1200 1201 /* allocate memory to store the linear coefficients for each constraint after the first iteration */ 1202 if( k == 0 ) 1203 { 1204 int c; 1205 1206 for( c = 0; c < nconss; ++c ) 1207 { 1208 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &linvars[c], nlinvars[c]) ); 1209 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &lincoefs[c], nlinvars[c]) ); 1210 1211 /* reset nlinvars[c] so it can be used for iteration k=1 */ 1212 nlinvars[c] = 0; 1213 } 1214 } 1215 } 1216 } 1217 1218 CLEANUP: 1219 SCIPfreeBufferArrayNull(scip, &val); 1220 SCIPfreeBufferArrayNull(scip, &idx); 1221 SCIPfreeBufferArrayNull(scip, &start); 1222 1223 return SCIP_OKAY; 1224 } 1225 1226 /** read quadratic coefficients of constraints and objective */ 1227 static 1228 SCIP_RETCODE readQuadraticCoefs( 1229 SCIP* scip, /**< SCIP data structure */ 1230 const XML_NODE* datanode, /**< XML root node for instance data */ 1231 SCIP_VAR** vars, /**< variables in order of OSiL indices */ 1232 int nvars, /**< number of variables */ 1233 int nconss, /**< number of constraints */ 1234 SCIP_VAR*** quadvars1, /**< array to store for each constraint the first variables of the quadratic terms */ 1235 SCIP_VAR*** quadvars2, /**< array to store for each constraint the second variables of the quadratic terms */ 1236 SCIP_Real** quadcoefs, /**< array to store for each constraint the coefficients of the quadratic terms */ 1237 int* nquadterms, /**< array to store for each constraint the total number of quadratic terms */ 1238 int* termssize, /**< pointer to store the size of quadvars1, quadvars2, and quadcoefs */ 1239 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 1240 ) 1241 { 1242 const XML_NODE* quadcoef; 1243 const XML_NODE* qterm; 1244 const char* attrval; 1245 SCIP_Real coef; 1246 int nqterms; 1247 int count; 1248 int considx; 1249 int varidx1; 1250 int varidx2; 1251 1252 assert(scip != NULL); 1253 assert(datanode != NULL); 1254 assert(quadvars1 != NULL); 1255 assert(quadvars2 != NULL); 1256 assert(quadcoefs != NULL); 1257 assert(nquadterms != NULL); 1258 assert(doingfine != NULL); 1259 1260 quadcoef = xmlFindNodeMaxdepth(datanode, "quadraticCoefficients", 0, 1); 1261 1262 if( quadcoef == NULL ) 1263 return SCIP_OKAY; 1264 1265 /* read number of quadratic terms */ 1266 attrval = xmlGetAttrval(quadcoef, "numberOfQuadraticTerms"); 1267 if( attrval == NULL ) 1268 { 1269 SCIPerrorMessage("Attribute \"numberOfQuadraticTerms\" not found for <quadraticCoefficients> node.\n"); 1270 *doingfine = FALSE; 1271 return SCIP_OKAY; 1272 } 1273 1274 nqterms = (int)strtol(attrval, (char**)&attrval, 10); 1275 if( *attrval != '\0' || nqterms < 0 ) 1276 { 1277 SCIPerrorMessage("Invalid value '%s' for \"numberOfQuadraticTerms\" attribute of <quadraticCoefficients> node.\n", xmlGetAttrval(quadcoef, "numberOfQuadraticTerms")); 1278 *doingfine = FALSE; 1279 return SCIP_OKAY; 1280 } 1281 assert(nqterms >= 0); 1282 1283 if( nqterms == 0 ) 1284 return SCIP_OKAY; 1285 1286 assert(vars != NULL); 1287 1288 count = 0; 1289 for( qterm = xmlFirstChild(quadcoef); qterm != NULL; qterm = xmlNextSibl(qterm), ++count ) 1290 { 1291 /* check for qterm node */ 1292 if( strcmp(xmlGetName(qterm), "qTerm") != 0 ) 1293 { 1294 SCIPerrorMessage("Expected <qTerm> node under <quadraticCoefficients> node, but got <%s>\n", xmlGetName(qterm)); 1295 *doingfine = FALSE; 1296 return SCIP_OKAY; 1297 } 1298 if( count >= nqterms ) 1299 { 1300 SCIPerrorMessage("Too many quadratic terms under <quadraticCoefficients> node, expected %d many, but got at least %d.\n", nqterms, count + 1); 1301 *doingfine = FALSE; 1302 return SCIP_OKAY; 1303 } 1304 1305 /* get constraint index, or -1 for objective */ 1306 attrval = xmlGetAttrval(qterm, "idx"); 1307 if( attrval == NULL ) 1308 { 1309 SCIPerrorMessage("Missing \"idx\" attribute in %d'th <qTerm> node under <quadraticCoefficients> node.\n", count); 1310 *doingfine = FALSE; 1311 return SCIP_OKAY; 1312 } 1313 1314 considx = (int)strtol(attrval, (char**)&attrval, 10); 1315 if( *attrval != '\0' || considx < -1 || considx >= nconss ) 1316 { 1317 SCIPerrorMessage("Invalid value '%s' in \"idx\" attribute of %d'th <qTerm> node under <quadraticCoefficients> node.\n", xmlGetAttrval(qterm, "idx"), count); 1318 *doingfine = FALSE; 1319 return SCIP_OKAY; 1320 } 1321 1322 /* get index of first variable */ 1323 attrval = xmlGetAttrval(qterm, "idxOne"); 1324 if( attrval == NULL ) 1325 { 1326 SCIPerrorMessage("Missing \"idxOne\" attribute in %d'th <qTerm> node under <quadraticCoefficients> node.\n", count); 1327 *doingfine = FALSE; 1328 return SCIP_OKAY; 1329 } 1330 1331 varidx1 = (int)strtol(attrval, (char**)&attrval, 10); 1332 if( *attrval != '\0' || varidx1 < 0 || varidx1 >= nvars ) 1333 { 1334 SCIPerrorMessage("Invalid value '%s' in \"idxOne\" attribute of %d'th <qTerm> node under <quadraticCoefficients> node.\n", xmlGetAttrval(qterm, "idxOne"), count); 1335 *doingfine = FALSE; 1336 return SCIP_OKAY; 1337 } 1338 1339 /* get index of second variable */ 1340 attrval = xmlGetAttrval(qterm, "idxTwo"); 1341 if( attrval == NULL ) 1342 { 1343 SCIPerrorMessage("Missing \"idxTwo\" attribute in %d'th <qTerm> node under <quadraticCoefficients> node.\n", count); 1344 *doingfine = FALSE; 1345 return SCIP_OKAY; 1346 } 1347 1348 varidx2 = (int)strtol(attrval, (char**)&attrval, 10); 1349 if( *attrval != '\0' || varidx2 < 0 || varidx2 >= nvars ) 1350 { 1351 SCIPerrorMessage("Invalid value '%s' in \"idxTwo\" attribute of %d'th <qTerm> node under <quadraticCoefficients> node.\n", xmlGetAttrval(qterm, "idxTwo"), count); 1352 *doingfine = FALSE; 1353 return SCIP_OKAY; 1354 } 1355 1356 /* get (optional) coefficient of quadratic term */ 1357 attrval = xmlGetAttrval(qterm, "coef"); 1358 if( attrval != NULL ) 1359 { 1360 coef = strtod(attrval, (char**)&attrval); 1361 if( *attrval != '\0' || (coef != coef) ) /*lint !e777*/ 1362 { 1363 SCIPerrorMessage("Invalid value '%s' in \"coef\" attribute of %d'th <qTerm> node under <quadraticCoefficients> node.\n", xmlGetAttrval(qterm, "coef"), count); 1364 *doingfine = FALSE; 1365 return SCIP_OKAY; 1366 } 1367 } 1368 else 1369 { 1370 /* default is 1.0 according to specification */ 1371 coef = 1.0; 1372 } 1373 1374 /* skip zero coefficients */ 1375 if( coef == 0.0 ) 1376 continue; 1377 1378 /* put objective at end of array */ 1379 if( considx == -1 ) 1380 considx = nconss; 1381 1382 if( nquadterms[considx] + 1 > termssize[considx] ) 1383 { 1384 int newsize; 1385 1386 newsize = SCIPcalcMemGrowSize(scip, nquadterms[considx] + 1); 1387 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvars1[considx], termssize[considx], newsize) ); /*lint !e866*/ 1388 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvars2[considx], termssize[considx], newsize) ); /*lint !e866*/ 1389 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadcoefs[considx], termssize[considx], newsize) ); /*lint !e866*/ 1390 termssize[considx] = newsize; 1391 } 1392 1393 quadvars1[considx][nquadterms[considx]] = vars[varidx1]; 1394 quadvars2[considx][nquadterms[considx]] = vars[varidx2]; 1395 quadcoefs[considx][nquadterms[considx]] = coef; 1396 ++nquadterms[considx]; 1397 } 1398 1399 if( count != nqterms ) 1400 { 1401 SCIPerrorMessage("Got only %d quadratic terms under <quadraticCoefficients> node, but expected %d many.\n", count, nqterms); 1402 *doingfine = FALSE; 1403 } 1404 1405 return SCIP_OKAY; 1406 } 1407 1408 /** transforms OSnL expression tree into SCIP expression */ 1409 static 1410 SCIP_RETCODE readExpression( 1411 SCIP* scip, /**< SCIP data structure */ 1412 SCIP_EXPR** expr, /**< buffer to store pointer to created expression */ 1413 const XML_NODE* node, /**< root node of expression to be read */ 1414 SCIP_VAR** vars, /**< variables in order of OSiL indices */ 1415 int nvars, /**< total number of variables in problem */ 1416 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 1417 ) 1418 { 1419 const char* exprname; 1420 1421 assert(scip != NULL); 1422 assert(expr != NULL); 1423 assert(node != NULL); 1424 assert(vars != NULL); 1425 assert(doingfine != NULL); 1426 1427 exprname = xmlGetName(node); 1428 assert(exprname != NULL); 1429 1430 *expr = NULL; 1431 1432 /* zero argument operands */ 1433 if( strcmp(exprname, "variable") == 0 ) 1434 { 1435 const char* attrval; 1436 SCIP_Real coef; 1437 int idx; 1438 1439 /* read variable index */ 1440 attrval = xmlGetAttrval(node, "idx"); 1441 if( attrval == NULL ) 1442 { 1443 SCIPerrorMessage("Attribute \"idx\" required for <variable> node in nonlinear expression\n"); 1444 *doingfine = FALSE; 1445 return SCIP_OKAY; 1446 } 1447 1448 idx = (int)strtol(attrval, (char**)&attrval, 10); 1449 if( *attrval != '\0' || idx < 0 || idx >= nvars ) 1450 { 1451 SCIPerrorMessage("Invalid value '%s' in \"idx\" attribute of <variable> node in nonlinear expression.\n", xmlGetAttrval(node, "idx")); 1452 *doingfine = FALSE; 1453 return SCIP_OKAY; 1454 } 1455 1456 /* read variable coefficient */ 1457 attrval = xmlGetAttrval(node, "coef"); 1458 if( attrval != NULL ) 1459 { 1460 coef = strtod(attrval, (char**)&attrval); 1461 if( *attrval != '\0' || !SCIPisFinite(coef) ) 1462 { 1463 SCIPerrorMessage("Invalid value '%s' in \"coef\" attribute of <variable> node in nonlinear expression.\n", xmlGetAttrval(node, "coef")); 1464 *doingfine = FALSE; 1465 return SCIP_OKAY; 1466 } 1467 } 1468 else 1469 { 1470 coef = 1.0; 1471 } 1472 1473 /* create variable expression */ 1474 SCIP_CALL( SCIPcreateExprVar(scip, expr, vars[idx], NULL, NULL) ); 1475 1476 /* create a sum if the coefficient != 1 */ 1477 if( coef != 1.0 ) 1478 { 1479 SCIP_EXPR* sumexpr; 1480 1481 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, expr, &coef, 0.0, NULL, NULL) ); 1482 1483 /* release the variable expression and store the sum */ 1484 SCIP_CALL( SCIPreleaseExpr(scip, expr) ); 1485 *expr = sumexpr; 1486 } 1487 1488 return SCIP_OKAY; 1489 } 1490 1491 if( strcmp(exprname, "number") == 0 ) 1492 { 1493 const char* attrval; 1494 SCIP_Real val; 1495 1496 attrval = xmlGetAttrval(node, "type"); 1497 if( attrval != NULL && (strcmp(attrval, "real") != 0) ) 1498 { 1499 SCIPerrorMessage("Type '%s' for <number> node in nonlinear expression not supported.\n", attrval); 1500 *doingfine = FALSE; 1501 return SCIP_OKAY; 1502 } 1503 1504 attrval = xmlGetAttrval(node, "value"); 1505 if( attrval != NULL ) 1506 { 1507 val = strtod(attrval, (char**)&attrval); 1508 if( *attrval != '\0' || !SCIPisFinite(val) ) 1509 { 1510 SCIPerrorMessage("Invalid value '%s' in \"value\" attribute of <number> node in nonlinear expression.\n", xmlGetAttrval(node, "value")); 1511 *doingfine = FALSE; 1512 return SCIP_OKAY; 1513 } 1514 } 1515 else 1516 { 1517 /* according to OSnL.xsd, the value attribute is optional 1518 * I guess the default is the empty string, which should correspond to 0.0 1519 */ 1520 val = 0.0; 1521 } 1522 1523 /* create constant expression */ 1524 SCIP_CALL( SCIPcreateExprValue(scip, expr, val, NULL, NULL) ); 1525 1526 return SCIP_OKAY; 1527 } 1528 1529 if( strcmp(exprname, "PI") == 0 ) 1530 { 1531 /* create constant expression with PI value */ 1532 SCIP_CALL( SCIPcreateExprValue(scip, expr, M_PI, NULL, NULL) ); 1533 1534 return SCIP_OKAY; 1535 } 1536 1537 if( strcmp(exprname, "E") == 0 ) 1538 { 1539 /* create constant expression with PI value */ 1540 SCIP_CALL( SCIPcreateExprValue(scip, expr, M_E, NULL, NULL) ); 1541 1542 return SCIP_OKAY; 1543 } 1544 1545 /* single argument operands */ 1546 if( strcmp(exprname, "negate") == 0 || 1547 strcmp(exprname, "abs") == 0 || 1548 strcmp(exprname, "squareRoot") == 0 || 1549 strcmp(exprname, "sqrt") == 0 || 1550 strcmp(exprname, "square") == 0 || 1551 strcmp(exprname, "exp") == 0 || 1552 strcmp(exprname, "ln") == 0 || 1553 strcmp(exprname, "log10") == 0 || 1554 strcmp(exprname, "sin") == 0 || 1555 strcmp(exprname, "cos") == 0 || 1556 strcmp(exprname, "erf") == 0 1557 ) 1558 { 1559 SCIP_EXPR* arg; 1560 1561 /* check number of children */ 1562 if( xmlFirstChild(node) == NULL || xmlNextSibl(xmlFirstChild(node)) != NULL ) 1563 { 1564 SCIPerrorMessage("Expected exactly one child in <%s> node in nonlinear expression\n", exprname); 1565 *doingfine = FALSE; 1566 return SCIP_OKAY; 1567 } 1568 1569 /* read child expression */ 1570 SCIP_CALL( readExpression(scip, &arg, xmlFirstChild(node), vars, nvars, doingfine) ); 1571 1572 if( !*doingfine ) 1573 return SCIP_OKAY; 1574 assert(arg != NULL); 1575 1576 /* create SCIP expression according to expression name */ 1577 if( strcmp(exprname, "negate") == 0 ) 1578 { 1579 SCIP_Real minusone; 1580 1581 minusone = -1.0; 1582 1583 SCIP_CALL( SCIPcreateExprSum(scip, expr, 1, &arg, &minusone, 0.0, NULL, NULL) ); 1584 } 1585 else if( strcmp(exprname, "abs") == 0 ) 1586 { 1587 SCIP_CALL( SCIPcreateExprAbs(scip, expr, arg, NULL, NULL) ); 1588 } 1589 else if( strcmp(exprname, "squareRoot") == 0 || strcmp(exprname, "sqrt") == 0 ) 1590 { 1591 SCIP_CALL( SCIPcreateExprPow(scip, expr, arg, 0.5, NULL, NULL) ); 1592 } 1593 else if( strcmp(exprname, "square") == 0 ) 1594 { 1595 SCIP_CALL( SCIPcreateExprPow(scip, expr, arg, 2.0, NULL, NULL) ); 1596 } 1597 else if( strcmp(exprname, "exp") == 0 ) 1598 { 1599 SCIP_CALL( SCIPcreateExprExp(scip, expr, arg, NULL, NULL) ); 1600 } 1601 else if( strcmp(exprname, "ln") == 0 ) 1602 { 1603 SCIP_CALL( SCIPcreateExprLog(scip, expr, arg, NULL, NULL) ); 1604 } 1605 else if( strcmp(exprname, "log10") == 0 ) 1606 { 1607 SCIP_EXPR* logexpr; 1608 SCIP_Real coef = 1.0/log(10.0); 1609 1610 SCIP_CALL( SCIPcreateExprLog(scip, &logexpr, arg, NULL, NULL) ); 1611 SCIP_CALL( SCIPcreateExprSum(scip, expr, 1, &logexpr, &coef, 0.0, NULL, NULL) ); 1612 SCIP_CALL( SCIPreleaseExpr(scip, &logexpr) ); 1613 } 1614 else if( strcmp(exprname, "sin") == 0 ) 1615 { 1616 SCIP_CALL( SCIPcreateExprSin(scip, expr, arg, NULL, NULL) ); 1617 } 1618 else if( strcmp(exprname, "cos") == 0 ) 1619 { 1620 SCIP_CALL( SCIPcreateExprCos(scip, expr, arg, NULL, NULL) ); 1621 } 1622 else if( strcmp(exprname, "erf") == 0 ) 1623 { 1624 SCIPwarningMessage(scip, "Danger! You're entering a construction area. Implementation of support for 'erf' is incomplete.\n"); 1625 SCIP_CALL( SCIPcreateExprErf(scip, expr, arg, NULL, NULL) ); 1626 } 1627 1628 /* release argument expression */ 1629 SCIP_CALL( SCIPreleaseExpr(scip, &arg) ); 1630 1631 return SCIP_OKAY; 1632 } 1633 1634 /* two argument operands */ 1635 if( strcmp(exprname, "plus") == 0 || 1636 strcmp(exprname, "minus") == 0 || 1637 strcmp(exprname, "times") == 0 || 1638 strcmp(exprname, "divide") == 0 || 1639 strcmp(exprname, "power") == 0 || 1640 strcmp(exprname, "signpower") == 0 || 1641 strcmp(exprname, "log") == 0 1642 ) 1643 { 1644 SCIP_EXPR* args[2] = {NULL, NULL}; 1645 1646 /* check number of children */ 1647 if( xmlFirstChild(node) == NULL || 1648 xmlNextSibl(xmlFirstChild(node)) == NULL || 1649 xmlNextSibl(xmlNextSibl(xmlFirstChild(node))) != NULL ) 1650 { 1651 SCIPerrorMessage("Expected exactly two children in <%s> node in nonlinear expression.\n", exprname); 1652 *doingfine = FALSE; 1653 return SCIP_OKAY; 1654 } 1655 1656 /* read first child expression */ 1657 SCIP_CALL( readExpression(scip, &args[0], xmlFirstChild(node), vars, nvars, doingfine) ); 1658 if( !*doingfine ) 1659 goto TERMINATE_TWO_ARGS; 1660 assert(args[0] != NULL); 1661 1662 /* read second child expression */ 1663 SCIP_CALL( readExpression(scip, &args[1], xmlNextSibl(xmlFirstChild(node)), vars, nvars, doingfine) ); 1664 if( !*doingfine ) 1665 goto TERMINATE_TWO_ARGS; 1666 assert(args[1] != NULL); 1667 1668 if( strcmp(exprname, "plus") == 0 ) 1669 { 1670 SCIP_CALL( SCIPcreateExprSum(scip, expr, 2, args, NULL, 0.0, NULL, NULL) ); 1671 } 1672 else if( strcmp(exprname, "minus") == 0 ) 1673 { 1674 SCIP_Real coefs[2] = {1.0, -1.0}; 1675 SCIP_CALL( SCIPcreateExprSum(scip, expr, 2, args, coefs, 0.0, NULL, NULL) ); 1676 } 1677 else if( strcmp(exprname, "times") == 0 ) 1678 { 1679 SCIP_CALL( SCIPcreateExprProduct(scip, expr, 2, args, 1.0, NULL, NULL) ); 1680 } 1681 else if( strcmp(exprname, "divide") == 0 ) 1682 { 1683 SCIP_EXPR* tmp[2]; 1684 SCIP_EXPR* powexpr; 1685 1686 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, args[1], -1.0, NULL, NULL) ); 1687 tmp[0] = args[0]; 1688 tmp[1] = powexpr; 1689 SCIP_CALL( SCIPcreateExprProduct(scip, expr, 2, tmp, 1.0, NULL, NULL) ); 1690 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) ); 1691 } 1692 else if( strcmp(exprname, "power") == 0 ) 1693 { 1694 /* case 1: expr^number */ 1695 if( SCIPisExprValue(scip, args[1]) ) 1696 { 1697 SCIP_CALL( SCIPcreateExprPow(scip, expr, args[0], SCIPgetValueExprValue(args[1]), NULL, NULL) ); 1698 } 1699 /* case 2: number^expr = exp(arg2 * ln(number)) */ 1700 else if( SCIPisExprValue(scip, args[0]) ) 1701 { 1702 SCIP_Real value = SCIPgetValueExprValue(args[0]); 1703 1704 if( value <= 0.0 ) 1705 { 1706 SCIPerrorMessage("Negative base in <power> node with nonconstant exponent not allowed in nonlinear expression.\n"); 1707 *doingfine = FALSE; 1708 goto TERMINATE_TWO_ARGS; 1709 } 1710 else 1711 { 1712 SCIP_EXPR* sumexpr; 1713 SCIP_Real coef = log(value); 1714 1715 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &args[1], &coef, 0.0, NULL, NULL) ); 1716 SCIP_CALL( SCIPcreateExprExp(scip, expr, sumexpr, NULL, NULL) ); 1717 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) ); 1718 } 1719 } 1720 /* case 3: arg1^arg2 is exp(arg2 * ln(arg1)) */ 1721 else 1722 { 1723 SCIP_EXPR* logexpr; 1724 SCIP_EXPR* prodexpr; 1725 SCIP_EXPR* tmp[2]; 1726 1727 SCIP_CALL( SCIPcreateExprLog(scip, &logexpr, args[0], NULL, NULL) ); 1728 tmp[0] = args[1]; 1729 tmp[1] = logexpr; 1730 SCIP_CALL( SCIPcreateExprProduct(scip, &prodexpr, 2, tmp, 1.0, NULL, NULL) ); 1731 SCIP_CALL( SCIPcreateExprExp(scip, expr, prodexpr, NULL, NULL) ); 1732 SCIP_CALL( SCIPreleaseExpr(scip, &prodexpr) ); 1733 SCIP_CALL( SCIPreleaseExpr(scip, &logexpr) ); 1734 } 1735 } 1736 else if( strcmp(exprname, "signpower") == 0 ) 1737 { 1738 /* signpower(expr,number) with number > 1 is the only one we can handle */ 1739 if( !SCIPisExprValue(scip, args[1]) ) 1740 { 1741 SCIPerrorMessage("Signpower only supported for constant exponents.\n"); 1742 *doingfine = FALSE; 1743 goto TERMINATE_TWO_ARGS; 1744 } 1745 if( SCIPgetValueExprValue(args[1]) <= 1.0 ) 1746 { 1747 SCIPerrorMessage("Signpower only supported for exponents > 1, but got %g.\n", 1748 SCIPgetValueExprValue(args[1])); 1749 *doingfine = FALSE; 1750 goto TERMINATE_TWO_ARGS; 1751 } 1752 1753 SCIP_CALL( SCIPcreateExprSignpower(scip, expr, args[0], SCIPgetValueExprValue(args[1]), NULL, NULL) ); 1754 } 1755 /* logarithm of arg2 w.r.t. base arg1 = ln(arg2) / ln(arg1) */ 1756 else if( strcmp(exprname, "log") == 0 ) 1757 { 1758 SCIP_EXPR* logexpr0; 1759 SCIP_EXPR* logexpr1; 1760 SCIP_EXPR* powexpr; 1761 SCIP_EXPR* tmp[2]; 1762 1763 /* logarithm of arg2 w.r.t. base arg1 = ln(arg2) / ln(arg1) = ln(arg2) * pow(ln(arg1),-1) */ 1764 SCIP_CALL( SCIPcreateExprLog(scip, &logexpr0, args[0], NULL, NULL) ); 1765 SCIP_CALL( SCIPcreateExprLog(scip, &logexpr1, args[1], NULL, NULL) ); 1766 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, logexpr0, -1.0, NULL, NULL) ); 1767 tmp[0] = logexpr1; 1768 tmp[1] = powexpr; 1769 SCIP_CALL( SCIPcreateExprProduct(scip, expr, 2, tmp, 1.0, NULL, NULL) ); 1770 1771 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) ); 1772 SCIP_CALL( SCIPreleaseExpr(scip, &logexpr1) ); 1773 SCIP_CALL( SCIPreleaseExpr(scip, &logexpr0) ); 1774 } 1775 else if( strcmp(exprname, "min") == 0 ) 1776 { 1777 SCIPerrorMessage("min expressions are not supported\n"); 1778 *doingfine = FALSE; 1779 goto TERMINATE_TWO_ARGS; 1780 } 1781 else /* if( strcmp(exprname, "max") == 0 ) */ 1782 { 1783 assert(strcmp(exprname, "max") == 0); 1784 1785 SCIPerrorMessage("max expressions are not supported\n"); 1786 *doingfine = FALSE; 1787 goto TERMINATE_TWO_ARGS; 1788 } 1789 1790 TERMINATE_TWO_ARGS: 1791 1792 /* release first and second argument expression */ 1793 if( args[0] != NULL ) 1794 { 1795 SCIP_CALL( SCIPreleaseExpr(scip, &args[0]) ); 1796 } 1797 if( args[1] != NULL ) 1798 { 1799 SCIP_CALL( SCIPreleaseExpr(scip, &args[1]) ); 1800 } 1801 1802 return SCIP_OKAY; 1803 } 1804 1805 /* arbitrary argument operands */ 1806 if( strcmp(exprname, "sum") == 0 || strcmp(exprname, "product") == 0 ) 1807 { 1808 const XML_NODE* argnode; 1809 SCIP_EXPR** args; 1810 int nargs; 1811 int argssize; 1812 int i; 1813 1814 /* a sum or product w.r.t. 0 arguments is constant */ 1815 if( xmlFirstChild(node) == NULL ) 1816 { 1817 SCIP_CALL( SCIPcreateExprValue(scip, expr, (strcmp(exprname, "sum") == 0) ? 0.0 : 1.0, NULL, NULL) ); 1818 1819 return SCIP_OKAY; 1820 } 1821 1822 /* read all child expressions */ 1823 argssize = 5; 1824 SCIP_CALL( SCIPallocBufferArray(scip, &args, argssize) ); 1825 1826 nargs = 0; 1827 for( argnode = xmlFirstChild(node); argnode != NULL; argnode = xmlNextSibl(argnode), ++nargs ) 1828 { 1829 if( nargs >= argssize ) 1830 { 1831 argssize = SCIPcalcMemGrowSize(scip, nargs + 1); 1832 SCIP_CALL( SCIPreallocBufferArray(scip, &args, argssize) ); 1833 } 1834 assert(nargs < argssize); 1835 1836 SCIP_CALL( readExpression(scip, &args[nargs], argnode, vars, nvars, doingfine) ); 1837 if( !*doingfine ) 1838 { 1839 assert(args[nargs] == NULL); 1840 break; 1841 } 1842 } 1843 1844 if( *doingfine ) 1845 { 1846 switch( nargs ) 1847 { 1848 case 0: 1849 { 1850 SCIP_CALL( SCIPcreateExprValue(scip, expr, (strcmp(exprname, "sum") == 0) ? 0.0 : 1.0, NULL, NULL) ); 1851 break; 1852 } 1853 case 1: 1854 { 1855 *expr = args[0]; 1856 /* capture expression here because args[0] will be released at the end */ 1857 SCIPcaptureExpr(*expr); 1858 break; 1859 } 1860 1861 default: 1862 { 1863 /* create sum or product expression */ 1864 if( strcmp(exprname, "sum") == 0 ) 1865 { 1866 SCIP_CALL( SCIPcreateExprSum(scip, expr, nargs, args, NULL, 0.0, NULL, NULL) ); 1867 } 1868 else 1869 { 1870 SCIP_CALL( SCIPcreateExprProduct(scip, expr, nargs, args, 1.0, NULL, NULL) ); 1871 } 1872 1873 break; 1874 } 1875 } 1876 } 1877 1878 /* release argument expressions */ 1879 for( i = 0; i < nargs; ++i ) 1880 { 1881 assert(args[i] != NULL); 1882 SCIP_CALL( SCIPreleaseExpr(scip, &args[i]) ); 1883 } 1884 1885 SCIPfreeBufferArray(scip, &args); 1886 1887 return SCIP_OKAY; 1888 } 1889 1890 if( strcmp(exprname, "min") == 0 || strcmp(exprname, "max") == 0 ) 1891 { 1892 SCIPerrorMessage("min or max expressions are not supported\n"); 1893 *doingfine = FALSE; 1894 return SCIP_OKAY; 1895 } 1896 1897 if( strcmp(exprname, "quadratic") == 0 ) 1898 { 1899 const char* attrval; 1900 const XML_NODE* qterm; 1901 SCIP_VAR** quadvars1; 1902 SCIP_VAR** quadvars2; 1903 SCIP_Real* quadcoefs; 1904 int nquadelems; 1905 int quadelemssize; 1906 int idx; 1907 1908 quadelemssize = 5; 1909 SCIP_CALL( SCIPallocBufferArray(scip, &quadvars1, quadelemssize) ); 1910 SCIP_CALL( SCIPallocBufferArray(scip, &quadvars2, quadelemssize) ); 1911 SCIP_CALL( SCIPallocBufferArray(scip, &quadcoefs, quadelemssize) ); 1912 nquadelems = 0; 1913 1914 /* read quadratic terms */ 1915 for( qterm = xmlFirstChild(node); qterm != NULL; qterm = xmlNextSibl(qterm), ++nquadelems ) 1916 { 1917 /* check for qpTerm node */ 1918 if( strcmp(xmlGetName(qterm), "qpTerm") != 0 ) 1919 { 1920 SCIPerrorMessage("Unexpected <%s> node under <quadratic> node in nonlinear expression, expected <qpTerm>.\n", xmlGetName(qterm)); 1921 *doingfine = FALSE; 1922 return SCIP_OKAY; 1923 } 1924 1925 if( nquadelems >= quadelemssize ) 1926 { 1927 quadelemssize = SCIPcalcMemGrowSize(scip, nquadelems + 1); 1928 SCIP_CALL( SCIPreallocBufferArray(scip, &quadvars1, quadelemssize) ); 1929 SCIP_CALL( SCIPreallocBufferArray(scip, &quadvars2, quadelemssize) ); 1930 SCIP_CALL( SCIPreallocBufferArray(scip, &quadcoefs, quadelemssize) ); 1931 } 1932 assert(quadelemssize > nquadelems); 1933 1934 /* get index of first variable */ 1935 attrval = xmlGetAttrval(qterm, "idxOne"); 1936 if( attrval == NULL ) 1937 { 1938 SCIPerrorMessage("Missing \"idxOne\" attribute in %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", nquadelems); 1939 *doingfine = FALSE; 1940 return SCIP_OKAY; 1941 } 1942 1943 idx = (int)strtol(attrval, (char**)&attrval, 10); 1944 if( *attrval != '\0' || idx < 0 || idx >= nvars ) 1945 { 1946 SCIPerrorMessage("Invalid value '%s' for \"idxOne\" attribute of %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", xmlGetAttrval(qterm, "idxOne"), nquadelems); 1947 *doingfine = FALSE; 1948 return SCIP_OKAY; 1949 } 1950 quadvars1[nquadelems] = vars[idx]; 1951 1952 /* get index of second variable */ 1953 attrval = xmlGetAttrval(qterm, "idxTwo"); 1954 if( attrval == NULL ) 1955 { 1956 SCIPerrorMessage("Missing \"idxTwo\" attribute in %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", nquadelems); 1957 *doingfine = FALSE; 1958 return SCIP_OKAY; 1959 } 1960 1961 idx = (int)strtol(attrval, (char**)&attrval, 10); 1962 if( *attrval != '\0' || idx < 0 || idx >= nvars ) 1963 { 1964 SCIPerrorMessage("Invalid value '%s' for \"idxTwo\" attribute of %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", xmlGetAttrval(qterm, "idxTwo"), nquadelems); 1965 *doingfine = FALSE; 1966 return SCIP_OKAY; 1967 } 1968 quadvars2[nquadelems] = vars[idx]; 1969 1970 /* get coefficient */ 1971 attrval = xmlGetAttrval(qterm, "coef"); 1972 if( attrval != NULL ) 1973 { 1974 quadcoefs[nquadelems] = strtod(attrval, (char**)&attrval); 1975 if( *attrval != '\0' || !SCIPisFinite(quadcoefs[nquadelems]) ) /*lint !e777*/ 1976 { 1977 SCIPerrorMessage("Invalid value '%s' for \"coef\" attribute of %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", xmlGetAttrval(qterm, "coef"), nquadelems); 1978 *doingfine = FALSE; 1979 return SCIP_OKAY; 1980 } 1981 } 1982 else 1983 { 1984 quadcoefs[nquadelems] = 1.0; 1985 } 1986 } 1987 1988 /* create quadratic expression */ 1989 SCIP_CALL( SCIPcreateExprQuadratic(scip, expr, 0, NULL, NULL, nquadelems, quadvars1, quadvars2, quadcoefs, NULL, NULL) ); 1990 } 1991 1992 SCIPerrorMessage("Expression operand <%s> in nonlinear expression not supported by SCIP so far.\n", exprname); 1993 *doingfine = FALSE; 1994 1995 return SCIP_OKAY; 1996 } 1997 1998 1999 /** read nonlinear expressions of constraints and objective */ 2000 static 2001 SCIP_RETCODE readNonlinearExprs( 2002 SCIP* scip, /**< SCIP data structure */ 2003 const XML_NODE* datanode, /**< XML root node for instance data */ 2004 SCIP_VAR** vars, /**< variables in order of OSiL indices */ 2005 int nvars, /**< number of variables */ 2006 int nconss, /**< number of constraints */ 2007 SCIP_EXPR** exprs, /**< array to store for each constraint a nonlinear expression */ 2008 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 2009 ) 2010 { 2011 const XML_NODE* nlexprs; 2012 const XML_NODE* nlexpr; 2013 const char* attrval; 2014 int nnlexprs; 2015 int count; 2016 int considx; 2017 2018 assert(scip != NULL); 2019 assert(datanode != NULL); 2020 assert(vars != NULL || nvars == 0); 2021 assert(exprs != NULL); 2022 assert(doingfine != NULL); 2023 2024 nlexprs = xmlFindNodeMaxdepth(datanode, "nonlinearExpressions", 0, 1); 2025 2026 if( nlexprs == NULL ) 2027 return SCIP_OKAY; 2028 2029 /* get number of nonlinear expressions */ 2030 attrval = xmlGetAttrval(nlexprs, "numberOfNonlinearExpressions"); 2031 if( attrval == NULL ) 2032 { 2033 SCIPerrorMessage("Attribute \"numberOfNonlinearExpressions\" in <nonlinearExpressions> node not found.\n"); 2034 *doingfine = FALSE; 2035 return SCIP_OKAY; 2036 } 2037 2038 nnlexprs = (int)strtol(attrval, (char**)&attrval, 10); 2039 if( *attrval != '\0' || nnlexprs < 0 ) 2040 { 2041 SCIPerrorMessage("Invalid value '%s' for \"numberOfNonlinearExpressions\" attribute in <nonlinearExpressions>.\n", xmlGetAttrval(nlexprs, "numberOfNonlinearExpressions")); 2042 *doingfine = FALSE; 2043 return SCIP_OKAY; 2044 } 2045 assert(nnlexprs >= 0); 2046 2047 /* read nonlinear expressions and store in constraints */ 2048 count = 0; 2049 for( nlexpr = xmlFirstChild(nlexprs); nlexpr != NULL; nlexpr = xmlNextSibl(nlexpr), ++count ) 2050 { 2051 if( strcmp(xmlGetName(nlexpr), "nl") != 0 ) 2052 { 2053 SCIPerrorMessage("Expected <nl> node under <nonlinearExpressions> node, but got '%s'.\n", xmlGetName(nlexpr)); 2054 *doingfine = FALSE; 2055 break; 2056 } 2057 if( count >= nnlexprs ) 2058 { 2059 SCIPerrorMessage("Too many nonlinear expressions under <nonlinearExpressions> node, expected %d many, but got at least %d.\n", nnlexprs, count + 1); 2060 *doingfine = FALSE; 2061 break; 2062 } 2063 2064 /* treat empty expression as 0.0 and continue */ 2065 if( xmlFirstChild(nlexprs) == NULL ) 2066 continue; 2067 2068 /* get constraint index, or -1 for objective */ 2069 attrval = xmlGetAttrval(nlexpr, "idx"); 2070 if( attrval == NULL ) 2071 { 2072 SCIPerrorMessage("Missing \"idx\" attribute in %d'th <nl> node under <nonlinearExpressions> node.\n", count); 2073 *doingfine = FALSE; 2074 break; 2075 } 2076 2077 considx = (int)strtol(attrval, (char**)&attrval, 10); 2078 if( *attrval != '\0' || considx < -1 || considx >= nconss ) 2079 { 2080 SCIPerrorMessage("Invalid value '%s' in \"idx\" attribute of %d'th <nl> node under <nonlinearExpressions> node.\n", xmlGetAttrval(nlexpr, "idx"), count); 2081 *doingfine = FALSE; 2082 break; 2083 } 2084 2085 /* turn OSiL expression into SCIP expression and assign indices to variables; store a nonlinear objective at position nconss */ 2086 SCIP_CALL( readExpression(scip, considx == -1 ? &exprs[nconss] : &exprs[considx], 2087 xmlFirstChild(nlexpr), vars, nvars, doingfine) ); 2088 if( !*doingfine ) 2089 return SCIP_OKAY; 2090 } 2091 2092 return SCIP_OKAY; 2093 } 2094 2095 2096 /** read sos1 and sos2 constraints 2097 * 2098 * sos constraints are expected to be given as a node of \<instanceData\> in the following way: 2099 * @code 2100 * <specialOrderedSets numberOfSpecialOrderedSets="1"> 2101 * <sos numberOfVar="2" order="2"> 2102 * <var idx="1"></var> 2103 * <var idx="2"></var> 2104 * </sos> 2105 * </specialOrderedSets> 2106 * @endcode 2107 * Weights are determined by the order in which the variables are given 2108 * 2109 */ 2110 static 2111 SCIP_RETCODE readSOScons( 2112 SCIP* scip, /**< SCIP data structure */ 2113 const XML_NODE* datanode, /**< XML root node for instance data */ 2114 SCIP_VAR** vars, /**< variables in order of OSiL indices */ 2115 int nvars, /**< number of variables */ 2116 SCIP_Bool initialconss, /**< should model constraints be marked as initial? */ 2117 SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */ 2118 SCIP_Bool dynamicrows, /**< should rows be added and removed dynamically to the LP? */ 2119 SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */ 2120 ) 2121 { 2122 const XML_NODE* soscons; 2123 const XML_NODE* sosvar; 2124 const char* attrval; 2125 int nsoscons; 2126 int nsosvars; 2127 int sosorder; 2128 int type; 2129 int count; 2130 int varcount; 2131 int idx; 2132 SCIP_Bool initial; 2133 SCIP_Bool separate; 2134 SCIP_Bool enforce; 2135 SCIP_Bool check; 2136 SCIP_Bool propagate; 2137 SCIP_Bool local; 2138 SCIP_Bool dynamic; 2139 SCIP_Bool removable; 2140 char name[SCIP_MAXSTRLEN]; 2141 2142 /* standard settings for SOS constraints: */ 2143 initial = initialconss; 2144 separate = TRUE; 2145 enforce = TRUE; 2146 check = TRUE; 2147 propagate = TRUE; 2148 local = FALSE; 2149 dynamic = dynamicconss; 2150 removable = dynamicrows; 2151 2152 soscons= xmlFindNodeMaxdepth(datanode, "specialOrderedSets", 0, 1); 2153 2154 if( soscons== NULL ) 2155 return SCIP_OKAY; 2156 2157 /* get number of sos constraints */ 2158 attrval = xmlGetAttrval(soscons, "numberOfSOS"); 2159 if( attrval == NULL ) 2160 { 2161 SCIPerrorMessage("Attribute \"numberOfSOS in <specialOrderedSets> node not found.\n"); 2162 *doingfine = FALSE; 2163 return SCIP_OKAY; 2164 } 2165 2166 nsoscons = (int)strtol(attrval, (char**)&attrval, 10); 2167 if( *attrval != '\0' || nsoscons < 0 ) 2168 { 2169 SCIPerrorMessage("Invalid value '%s' for \"numberOfSOS\" attribute in <specialOrderedSets>.\n", xmlGetAttrval(soscons, "numberOfSOS")); 2170 *doingfine = FALSE; 2171 return SCIP_OKAY; 2172 } 2173 assert(nsoscons >= 0); 2174 2175 /* read sos constraints and create corresponding constraint */ 2176 count = 0; 2177 for( soscons = xmlFirstChild(soscons); soscons != NULL; soscons = xmlNextSibl(soscons), ++count ) 2178 { 2179 SCIP_CONS* cons; 2180 2181 /* Make sure we get a sos node and not more then announced*/ 2182 if( strcmp(xmlGetName(soscons), "sos") != 0 ) 2183 { 2184 SCIPerrorMessage("Expected <sos> node under <specialOrderedSet> node, but got '%s'.\n", xmlGetName(soscons)); 2185 *doingfine = FALSE; 2186 break; 2187 } 2188 2189 if( count >= nsoscons) 2190 { 2191 SCIPerrorMessage("Too many sos under <specialOrderedSets> node, expected %d many, but got at least %d.\n", nsoscons, count + 1); 2192 *doingfine = FALSE; 2193 break; 2194 } 2195 2196 /* get number of variables in this sos constraint */ 2197 attrval = xmlGetAttrval(soscons, "numberOfVar"); 2198 if( attrval == NULL ) 2199 { 2200 SCIPerrorMessage("Attribute \"numberOfVar in <sos> node not found.\n"); 2201 *doingfine = FALSE; 2202 return SCIP_OKAY; 2203 } 2204 2205 nsosvars = (int)strtol(attrval, (char**)&attrval, 10); 2206 if( *attrval != '\0' || nsosvars < 0 ) 2207 { 2208 SCIPerrorMessage("Invalid value '%s' for \"numberOfVar\" attribute in <sos>.\n", xmlGetAttrval(soscons, "numberOfVar")); 2209 *doingfine = FALSE; 2210 return SCIP_OKAY; 2211 } 2212 assert(nsosvars >= 0); 2213 2214 /* get order of this sos constraint */ 2215 attrval = xmlGetAttrval(soscons, "type"); 2216 if( attrval == NULL ) 2217 { 2218 SCIPerrorMessage("Attribute \"order\" in <sos> node not found.\n"); 2219 *doingfine = FALSE; 2220 return SCIP_OKAY; 2221 } 2222 2223 sosorder = (int)strtol(attrval, (char**)&attrval, 10); 2224 if( *attrval != '\0' || sosorder < 0 || sosorder > 2 ) 2225 { 2226 SCIPerrorMessage("Invalid/unsupported value '%s' for \"order\" attribute in <sos>.\n", xmlGetAttrval(soscons, "order")); 2227 *doingfine = FALSE; 2228 return SCIP_OKAY; 2229 } 2230 assert(sosorder == 1 || sosorder == 2); 2231 type = sosorder; 2232 2233 /* set artificial name for sos constraint*/ 2234 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "SOS%d_%d", type, count); 2235 2236 /* Create sos constraint */ 2237 switch( type ) 2238 { 2239 case 1: 2240 SCIP_CALL( SCIPcreateConsSOS1(scip, &cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate, 2241 local, dynamic, removable, FALSE) ); 2242 break; 2243 case 2: 2244 SCIP_CALL( SCIPcreateConsSOS2(scip, &cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate, 2245 local, dynamic, removable, FALSE) ); 2246 break; 2247 default: 2248 SCIPerrorMessage("unknown SOS type: <%d>\n", type); /* should not happen */ 2249 SCIPABORT(); 2250 return SCIP_INVALIDDATA; /*lint !e527*/ 2251 } 2252 2253 varcount = 0; 2254 for( sosvar = xmlFirstChild(soscons); sosvar!= NULL; sosvar = xmlNextSibl(sosvar), ++varcount ) 2255 { 2256 /* get variable id*/ 2257 attrval = xmlGetAttrval(sosvar, "idx"); 2258 if( attrval == NULL ) 2259 { 2260 SCIPerrorMessage("Attribute \"idx\" in <var> node below <specialOrderedSets> node not found.\n"); 2261 *doingfine = FALSE; 2262 return SCIP_OKAY; 2263 } 2264 2265 idx = (int)strtol(attrval, (char**)&attrval, 10); 2266 if( *attrval != '\0' || idx < 0 || idx > nvars - 1 ) 2267 { 2268 SCIPerrorMessage("Invalid value '%s' for \"idx\" attribute in <var>.\n", xmlGetAttrval(sosvar, "idx")); 2269 *doingfine = FALSE; 2270 return SCIP_OKAY; 2271 } 2272 assert(idx >= 0); 2273 2274 /* we now know that we have a variable/weight pair -> add variable*/ 2275 switch( type ) 2276 { 2277 case 1: 2278 SCIP_CALL( SCIPaddVarSOS1(scip, cons, vars[idx], (SCIP_Real) (nsosvars - varcount)) ); 2279 break; 2280 case 2: 2281 SCIP_CALL( SCIPaddVarSOS2(scip, cons, vars[idx], (SCIP_Real) (nsosvars - varcount)) ); 2282 break; 2283 /* coverity[dead_error_begin] */ 2284 default: 2285 SCIPerrorMessage("unknown SOS type: <%d>\n", type); /* should not happen */ 2286 SCIPABORT(); 2287 return SCIP_INVALIDDATA; /*lint !e527*/ 2288 } 2289 } /* Close loop over variables in sos constraint */ 2290 2291 /* add the SOS constraint */ 2292 SCIP_CALL( SCIPaddCons(scip, cons) ); 2293 SCIP_CALL( SCIPreleaseCons(scip, &cons) ); 2294 } 2295 2296 return SCIP_OKAY; 2297 } 2298 2299 /* 2300 * Callback methods of reader 2301 */ 2302 2303 2304 /** copy method for reader plugins (called when SCIP copies plugins) */ 2305 static 2306 SCIP_DECL_READERCOPY(readerCopyOsil) 2307 { /*lint --e{715}*/ 2308 assert(scip != NULL); 2309 2310 SCIP_CALL( SCIPincludeReaderOsil(scip) ); 2311 2312 return SCIP_OKAY; 2313 } 2314 2315 /** problem reading method of reader */ 2316 static 2317 SCIP_DECL_READERREAD(readerReadOsil) 2318 { /*lint --e{715}*/ 2319 const XML_NODE* header; 2320 const XML_NODE* data; 2321 XML_NODE* start; 2322 SCIP_VAR** vars; 2323 const char* name; 2324 SCIP_RETCODE retcode; 2325 SCIP_Bool doingfine; 2326 SCIP_Bool initialconss; 2327 SCIP_Bool dynamicconss; 2328 SCIP_Bool dynamiccols; 2329 SCIP_Bool dynamicrows; 2330 int nconss; 2331 int nvars; 2332 int c; 2333 int i; 2334 2335 /* linear parts */ 2336 SCIP_VAR*** linvars = NULL; 2337 SCIP_Real** lincoefs = NULL; 2338 int* nlinvars = NULL; 2339 2340 /* quadratic parts */ 2341 SCIP_VAR*** quadvars1 = NULL; 2342 SCIP_VAR*** quadvars2 = NULL; 2343 SCIP_Real** quadcoefs = NULL; 2344 int* nquadterms = NULL; 2345 int* termssize = NULL; 2346 2347 /* nonlinear parts */ 2348 SCIP_EXPR** nlexprs = NULL; 2349 2350 assert(scip != NULL); 2351 assert(reader != NULL); 2352 assert(result != NULL); 2353 assert(filename != NULL); 2354 2355 *result = SCIP_DIDNOTRUN; 2356 retcode = SCIP_READERROR; 2357 doingfine = TRUE; 2358 vars = NULL; 2359 nvars = 0; 2360 nconss = -1; 2361 2362 /* read OSiL xml file */ 2363 start = xmlProcess(filename); 2364 2365 if( start == NULL ) 2366 { 2367 SCIPerrorMessage("Some error occurred when parsing the OSiL XML file '%s'.\n", filename); 2368 goto CLEANUP; 2369 } 2370 2371 SCIPdebug( xmlShowNode(start) ); 2372 2373 /* parse header to get problem name */ 2374 name = filename; 2375 header = xmlFindNodeMaxdepth(start, "instanceHeader", 0, 2); 2376 if( header != NULL ) 2377 { 2378 const XML_NODE* namenode; 2379 2380 namenode = xmlFindNodeMaxdepth(header, "name", 0, 2); 2381 2382 if( namenode != NULL && xmlFirstChild(namenode) != NULL ) 2383 name = xmlGetData(xmlFirstChild(namenode)); 2384 else 2385 { 2386 namenode = xmlFindNodeMaxdepth(header, "description", 0, 2); 2387 2388 if( namenode != NULL && xmlFirstChild(namenode) != NULL ) 2389 name = xmlGetData(xmlFirstChild(namenode)); 2390 } 2391 } 2392 2393 /* create SCIP problem */ 2394 SCIP_CALL( SCIPcreateProb(scip, name, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); 2395 2396 /* process instance data */ 2397 data = xmlFindNodeMaxdepth(start, "instanceData", 0, 2); 2398 if( data == NULL ) 2399 { 2400 SCIPerrorMessage("Node <instanceData> not found.\n"); 2401 goto CLEANUP; 2402 } 2403 2404 SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &initialconss) ); 2405 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &dynamicconss) ); 2406 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &dynamiccols) ); 2407 SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &dynamicrows) ); 2408 2409 /* read variables */ 2410 SCIP_CALL_TERMINATE( retcode, readVariables(scip, data, &vars, &nvars, initialconss, dynamicconss, dynamiccols, dynamicrows, &doingfine), CLEANUP ); 2411 if( !doingfine ) 2412 goto CLEANUP; 2413 assert(vars != NULL || nvars == 0); 2414 2415 /* read objective sense, coefficient, and constant */ 2416 SCIP_CALL_TERMINATE( retcode, readObjective(scip, data, vars, nvars, dynamiccols, &doingfine), CLEANUP ); 2417 if( !doingfine ) 2418 goto CLEANUP; 2419 2420 /* read total number of constraints */ 2421 SCIP_CALL_TERMINATE( retcode, readNConstraints(scip, data, &nconss, &doingfine), CLEANUP ); 2422 if( !doingfine ) 2423 goto CLEANUP; 2424 2425 /* allocate memory to store constraint information (use block memory, since the size have to be reallocaed) */ 2426 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &linvars, nconss + 1) ); 2427 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &lincoefs, nconss + 1) ); 2428 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &nlinvars, nconss + 1) ); 2429 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &quadvars1, nconss + 1) ); 2430 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &quadvars2, nconss + 1) ); 2431 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &quadcoefs, nconss + 1) ); 2432 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &nquadterms, nconss + 1) ); 2433 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &nlexprs, nconss + 1) ); 2434 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &termssize, nconss + 1) ); 2435 2436 /* read linear coefficients matrix */ 2437 SCIP_CALL_TERMINATE( retcode, readLinearCoefs(scip, data, vars, nvars, nconss, linvars, lincoefs, nlinvars, &doingfine), CLEANUP ); 2438 if( !doingfine ) 2439 goto CLEANUP; 2440 2441 /* read quadratic coefficients */ 2442 SCIP_CALL_TERMINATE( retcode, readQuadraticCoefs(scip, data, vars, nvars, nconss, quadvars1, quadvars2, quadcoefs, 2443 nquadterms, termssize, &doingfine), CLEANUP ); 2444 if( !doingfine ) 2445 goto CLEANUP; 2446 2447 /* read nonlinear expressions */ 2448 SCIP_CALL_TERMINATE( retcode, readNonlinearExprs(scip, data, vars, nvars, nconss, nlexprs, &doingfine), CLEANUP ); 2449 if( !doingfine ) 2450 goto CLEANUP; 2451 2452 /* read constraint data; generate constraints */ 2453 SCIP_CALL_TERMINATE( retcode, readConstraints(scip, data, nconss, linvars, lincoefs, nlinvars, 2454 quadvars1, quadvars2, quadcoefs, nquadterms, nlexprs, initialconss, dynamicconss, dynamicrows, &doingfine), 2455 CLEANUP ); 2456 if( !doingfine ) 2457 goto CLEANUP; 2458 2459 /* add nonlinear objective constraint */ 2460 if( nlinvars[nconss] > 0 || nquadterms[nconss] > 0 || nlexprs[nconss] != NULL ) 2461 { 2462 SCIP_CALL( createConstraint(scip, linvars[nconss], lincoefs[nconss], nlinvars[nconss], 2463 quadvars1[nconss], quadvars2[nconss], quadcoefs[nconss], nquadterms[nconss], nlexprs[nconss], 2464 SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE ? -SCIPinfinity(scip) : 0.0, 2465 SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE ? SCIPinfinity(scip) : 0.0, 2466 "objcons", TRUE, TRUE, FALSE, FALSE) ); 2467 } 2468 2469 /* read sos2 constraints and add to problem */ 2470 SCIP_CALL_TERMINATE( retcode, readSOScons(scip, data, vars, nvars, initialconss, dynamicconss, dynamicrows, &doingfine), CLEANUP ); 2471 if( !doingfine ) 2472 goto CLEANUP; 2473 2474 *result = SCIP_SUCCESS; 2475 retcode = SCIP_OKAY; 2476 2477 CLEANUP: 2478 /* free xml data */ 2479 if( start != NULL ) 2480 xmlFreeNode(start); 2481 2482 /* free memory for constraint information (position nconss belongs to the nonlinear objective function) */ 2483 for( c = nconss; c >= 0; --c ) 2484 { 2485 /* free nonlinear parts */ 2486 if( nlexprs != NULL && nlexprs[c] != NULL ) 2487 { 2488 SCIP_CALL( SCIPreleaseExpr(scip, &nlexprs[c]) ); 2489 } 2490 2491 /* free quadratic parts */ 2492 SCIPfreeBlockMemoryArrayNull(scip, &quadcoefs[c], termssize[c]); 2493 SCIPfreeBlockMemoryArrayNull(scip, &quadvars2[c], termssize[c]); 2494 SCIPfreeBlockMemoryArrayNull(scip, &quadvars1[c], termssize[c]); 2495 2496 /* free linear parts */ 2497 SCIPfreeBlockMemoryArray(scip, &lincoefs[c], nlinvars[c]); 2498 SCIPfreeBlockMemoryArray(scip, &linvars[c], nlinvars[c]); 2499 } 2500 SCIPfreeBlockMemoryArrayNull(scip, &termssize, nconss + 1); 2501 SCIPfreeBlockMemoryArrayNull(scip, &nlexprs, nconss + 1); 2502 SCIPfreeBlockMemoryArrayNull(scip, &nquadterms, nconss + 1); 2503 SCIPfreeBlockMemoryArrayNull(scip, &quadcoefs, nconss + 1); 2504 SCIPfreeBlockMemoryArrayNull(scip, &quadvars2, nconss + 1); 2505 SCIPfreeBlockMemoryArrayNull(scip, &quadvars1, nconss + 1); 2506 SCIPfreeBlockMemoryArrayNull(scip, &nlinvars, nconss + 1); 2507 SCIPfreeBlockMemoryArrayNull(scip, &lincoefs, nconss + 1); 2508 SCIPfreeBlockMemoryArrayNull(scip, &linvars, nconss + 1); 2509 2510 /* free variables */ 2511 for( i = 0; i < nvars; ++i ) 2512 { 2513 SCIP_CALL( SCIPreleaseVar(scip, &vars[i]) ); /*lint !e613*/ 2514 } 2515 SCIPfreeBufferArrayNull(scip, &vars); 2516 2517 /* return read error retcode if something went wrong */ 2518 if( !doingfine ) 2519 return SCIP_READERROR; 2520 2521 if( retcode == SCIP_PLUGINNOTFOUND ) 2522 retcode = SCIP_READERROR; 2523 2524 SCIP_CALL( retcode ); 2525 2526 return SCIP_OKAY; 2527 } 2528 2529 /* 2530 * reader specific interface methods 2531 */ 2532 2533 /** includes the osil file reader in SCIP */ 2534 SCIP_RETCODE SCIPincludeReaderOsil( 2535 SCIP* scip /**< SCIP data structure */ 2536 ) 2537 { 2538 SCIP_READER* reader; 2539 2540 /* include osil reader */ 2541 SCIP_CALL( SCIPincludeReaderBasic(scip, &reader, READER_NAME, READER_DESC, READER_EXTENSION, NULL) ); 2542 2543 SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyOsil) ); 2544 SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadOsil) ); 2545 2546 return SCIP_OKAY; 2547 } 2548