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.c 26 * @ingroup OTHER_CFILES 27 * @brief interface for input file readers 28 * @author Tobias Achterberg 29 */ 30 31 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 32 33 #include <assert.h> 34 #include <string.h> 35 #if defined(_WIN32) || defined(_WIN64) 36 #else 37 #include <strings.h> /*lint --e{766}*/ 38 #endif 39 #include <math.h> 40 41 #include "scip/def.h" 42 #include "blockmemshell/memory.h" 43 #include "scip/set.h" 44 #include "scip/clock.h" 45 #include "scip/pub_misc.h" 46 #include "scip/reader.h" 47 #include "scip/prob.h" 48 #include "scip/pub_var.h" 49 #include "scip/var.h" 50 #include "scip/pub_cons.h" 51 #include "scip/cons.h" 52 #include "scip/pub_message.h" 53 54 #include "scip/struct_reader.h" 55 56 57 /** copies the given reader to a new scip */ 58 SCIP_RETCODE SCIPreaderCopyInclude( 59 SCIP_READER* reader, /**< reader */ 60 SCIP_SET* set /**< SCIP_SET of SCIP to copy to */ 61 ) 62 { 63 assert(reader != NULL); 64 assert(set != NULL); 65 assert(set->scip != NULL); 66 67 if( reader->readercopy != NULL ) 68 { 69 SCIPsetDebugMsg(set, "including reader %s in subscip %p\n", SCIPreaderGetName(reader), (void*)set->scip); 70 SCIP_CALL( reader->readercopy(set->scip, reader) ); 71 } 72 return SCIP_OKAY; 73 } 74 75 /** internal method to create a reader */ 76 static 77 SCIP_RETCODE doReaderCreate( 78 SCIP_READER** reader, /**< pointer to store reader */ 79 const char* name, /**< name of reader */ 80 const char* desc, /**< description of reader */ 81 const char* extension, /**< file extension that reader processes */ 82 SCIP_DECL_READERCOPY ((*readercopy)), /**< copy method of reader or NULL if you don't want to copy your plugin into sub-SCIPs */ 83 SCIP_DECL_READERFREE ((*readerfree)), /**< destructor of reader */ 84 SCIP_DECL_READERREAD ((*readerread)), /**< read method */ 85 SCIP_DECL_READERWRITE ((*readerwrite)), /**< write method */ 86 SCIP_READERDATA* readerdata /**< reader data */ 87 ) 88 { 89 assert(reader != NULL); 90 assert(name != NULL); 91 assert(desc != NULL); 92 assert(extension != NULL); 93 94 SCIP_ALLOC( BMSallocMemory(reader) ); 95 BMSclearMemory(*reader); 96 97 SCIP_ALLOC( BMSduplicateMemoryArray(&(*reader)->name, name, strlen(name)+1) ); 98 SCIP_ALLOC( BMSduplicateMemoryArray(&(*reader)->desc, desc, strlen(desc)+1) ); 99 SCIP_ALLOC( BMSduplicateMemoryArray(&(*reader)->extension, extension, strlen(extension)+1) ); 100 (*reader)->readercopy = readercopy; 101 (*reader)->readerfree = readerfree; 102 (*reader)->readerread = readerread; 103 (*reader)->readerwrite = readerwrite; 104 (*reader)->readerdata = readerdata; 105 106 /* create reading clock */ 107 SCIP_CALL( SCIPclockCreate(&(*reader)->readingtime, SCIP_CLOCKTYPE_DEFAULT) ); 108 109 return SCIP_OKAY; 110 } 111 112 /** creates a reader */ 113 SCIP_RETCODE SCIPreaderCreate( 114 SCIP_READER** reader, /**< pointer to store reader */ 115 SCIP_SET* set, /**< global SCIP settings */ 116 const char* name, /**< name of reader */ 117 const char* desc, /**< description of reader */ 118 const char* extension, /**< file extension that reader processes */ 119 SCIP_DECL_READERCOPY ((*readercopy)), /**< copy method of reader or NULL if you don't want to copy your plugin into sub-SCIPs */ 120 SCIP_DECL_READERFREE ((*readerfree)), /**< destructor of reader */ 121 SCIP_DECL_READERREAD ((*readerread)), /**< read method */ 122 SCIP_DECL_READERWRITE ((*readerwrite)), /**< write method */ 123 SCIP_READERDATA* readerdata /**< reader data */ 124 ) 125 { 126 assert(reader != NULL); 127 assert(set != NULL); 128 assert(name != NULL); 129 assert(desc != NULL); 130 assert(extension != NULL); 131 132 SCIP_CALL_FINALLY( doReaderCreate(reader, name, desc, extension, readercopy, readerfree, readerread, readerwrite, 133 readerdata), (void) SCIPreaderFree(reader, set) ); 134 135 return SCIP_OKAY; 136 } 137 138 /** frees memory of reader */ 139 SCIP_RETCODE SCIPreaderFree( 140 SCIP_READER** reader, /**< pointer to reader data structure */ 141 SCIP_SET* set /**< global SCIP settings */ 142 ) 143 { 144 assert(reader != NULL); 145 assert(set != NULL); 146 147 if( *reader == NULL ) 148 return SCIP_OKAY; 149 150 /* call destructor of reader */ 151 if( (*reader)->readerfree != NULL ) 152 { 153 SCIP_CALL( (*reader)->readerfree(set->scip, *reader) ); 154 } 155 156 BMSfreeMemoryArrayNull(&(*reader)->name); 157 BMSfreeMemoryArrayNull(&(*reader)->desc); 158 BMSfreeMemoryArrayNull(&(*reader)->extension); 159 160 /* free clock */ 161 SCIPclockFree(&(*reader)->readingtime); 162 163 BMSfreeMemory(reader); 164 165 return SCIP_OKAY; 166 } 167 168 /** returns TRUE, if reader is responsible for files with the given extension */ 169 static 170 SCIP_Bool readerIsApplicable( 171 SCIP_READER* reader, /**< reader */ 172 const char* extension /**< extension of the input file name */ 173 ) 174 { 175 assert(reader != NULL); 176 assert(reader->extension != NULL); 177 178 return (extension != NULL && strcasecmp(reader->extension, extension) == 0) 179 || (extension == NULL && *(reader->extension) == '\0'); 180 } 181 182 /** reads problem data from file with given reader or returns SCIP_DIDNOTRUN */ 183 SCIP_RETCODE SCIPreaderRead( 184 SCIP_READER* reader, /**< reader */ 185 SCIP_SET* set, /**< global SCIP settings */ 186 const char* filename, /**< name of the input file */ 187 const char* extension, /**< extension of the input file name */ 188 SCIP_RESULT* result /**< pointer to store the result of the callback method */ 189 ) 190 { 191 SCIP_RETCODE retcode; 192 193 assert(reader != NULL); 194 assert(set != NULL); 195 assert(filename != NULL); 196 assert(result != NULL); 197 198 /* check, if reader is applicable on the given file */ 199 if( readerIsApplicable(reader, extension) && reader->readerread != NULL ) 200 { 201 SCIP_CLOCK* readingtime; 202 203 /**@note we need temporary clock to measure the reading time correctly since in case of creating a new problem 204 * within the reader all clocks are reset (including the reader clocks); this resetting is necessary for 205 * example for those case we people solve several problems using the (same) interactive shell 206 */ 207 208 assert(!SCIPclockIsRunning(reader->readingtime)); 209 210 /* create a temporary clock for measuring the reading time */ 211 SCIP_CALL( SCIPclockCreate(&readingtime, SCIP_CLOCKTYPE_DEFAULT) ); 212 213 /* start timing */ 214 SCIPclockStart(readingtime, set); 215 216 /* call reader to read problem */ 217 retcode = reader->readerread(set->scip, reader, filename, result); 218 219 /* stop timing */ 220 SCIPclockStop(readingtime, set); 221 222 /* add time to reader reading clock */ 223 SCIPclockSetTime(reader->readingtime, SCIPclockGetTime(reader->readingtime) + SCIPclockGetTime(readingtime)); 224 225 /* free the temporary clock */ 226 SCIPclockFree(&readingtime); 227 } 228 else 229 { 230 *result = SCIP_DIDNOTRUN; 231 retcode = SCIP_OKAY; 232 } 233 234 /* check for reader errors */ 235 if( retcode == SCIP_NOFILE || retcode == SCIP_READERROR ) 236 return retcode; 237 238 /* check if the result code is valid in case no reader error occurred */ 239 assert( *result == SCIP_DIDNOTRUN || *result == SCIP_SUCCESS ); 240 241 SCIP_CALL( retcode ); 242 243 return SCIP_OKAY; 244 } 245 246 247 /* reset the variable name to the given one */ 248 static 249 void resetVarname( 250 SCIP_VAR* var, /**< variable */ 251 SCIP_SET* set, /**< global SCIP settings */ 252 const char* name /**< variable name */ 253 ) 254 { 255 const char * oldname; 256 257 assert( var != NULL ); 258 assert( name != NULL ); 259 260 /* get pointer to temporary generic name and free the memory */ 261 oldname = SCIPvarGetName(var); 262 SCIPsetFreeBufferArray(set, &oldname); 263 264 /* reset name */ 265 SCIPvarSetNamePointer(var, name); 266 } 267 268 269 /** writes problem data to file with given reader or returns SCIP_DIDNOTRUN */ 270 SCIP_RETCODE SCIPreaderWrite( 271 SCIP_READER* reader, /**< reader */ 272 SCIP_PROB* prob, /**< problem data */ 273 SCIP_SET* set, /**< global SCIP settings */ 274 FILE* file, /**< output file (or NULL for standard output) */ 275 const char* extension, /**< file format */ 276 SCIP_Bool genericnames, /**< using generic variable and constraint names? */ 277 SCIP_RESULT* result /**< pointer to store the result of the callback method */ 278 ) 279 { 280 SCIP_RETCODE retcode; 281 282 assert(reader != NULL); 283 assert(set != NULL); 284 assert(set->buffer != NULL); 285 assert(extension != NULL); 286 assert(result != NULL); 287 288 /* check, if reader is applicable on the given file */ 289 if( readerIsApplicable(reader, extension) && reader->readerwrite != NULL ) 290 { 291 const char* consname; 292 const char** varnames = NULL; 293 const char** fixedvarnames = NULL; 294 const char** consnames = NULL; 295 SCIP_VAR** vars; 296 SCIP_VAR** fixedvars; 297 SCIP_CONS** conss; 298 SCIP_CONS* cons; 299 SCIP_Real objscale; 300 char* name; 301 int nfixedvars; 302 int nconss; 303 int nvars; 304 int i; 305 306 vars = prob->vars; 307 nvars = prob->nvars; 308 fixedvars = prob->fixedvars; 309 nfixedvars = prob->nfixedvars; 310 311 /* case of the transformed problem, we want to write currently valid problem */ 312 if( prob->transformed ) 313 { 314 SCIP_CONSHDLR** conshdlrs; 315 int nconshdlrs; 316 317 conshdlrs = set->conshdlrs; 318 nconshdlrs = set->nconshdlrs; 319 320 /* collect number of constraints which have to be enforced; these are the constraints which currency (locally) 321 * enabled; these also includes the local constraints 322 */ 323 nconss = 0; 324 for( i = 0; i < nconshdlrs; ++i ) 325 { 326 /* check if all constraints of the constraint handler should be written */ 327 if( set->write_allconss ) 328 nconss += SCIPconshdlrGetNConss(conshdlrs[i]); 329 else 330 nconss += SCIPconshdlrGetNEnfoConss(conshdlrs[i]); 331 } 332 333 SCIPsetDebugMsg(set, "Writing %d constraints.\n", nconss); 334 335 SCIP_CALL( SCIPsetAllocBufferArray(set, &conss, nconss) ); 336 337 /* copy the constraints */ 338 nconss = 0; 339 for( i = 0; i < nconshdlrs; ++i ) 340 { 341 SCIP_CONS** conshdlrconss; 342 int nconshdlrconss; 343 int c; 344 345 /* check if all constraints of the constraint handler should be written */ 346 if( set->write_allconss ) 347 { 348 conshdlrconss = SCIPconshdlrGetConss(conshdlrs[i]); 349 nconshdlrconss = SCIPconshdlrGetNConss(conshdlrs[i]); 350 } 351 else 352 { 353 conshdlrconss = SCIPconshdlrGetEnfoConss(conshdlrs[i]); 354 nconshdlrconss = SCIPconshdlrGetNEnfoConss(conshdlrs[i]); 355 } 356 357 SCIPsetDebugMsg(set, "Conshdlr <%s> has %d constraints to write from all in all %d constraints.\n", SCIPconshdlrGetName(conshdlrs[i]), nconshdlrconss, SCIPconshdlrGetNConss(conshdlrs[i])); 358 359 for( c = 0; c < nconshdlrconss; ++c ) 360 { 361 conss[nconss] = conshdlrconss[c]; 362 nconss++; 363 } 364 } 365 } 366 else 367 { 368 conss = prob->conss; 369 nconss = prob->nconss; 370 } 371 372 if( genericnames ) 373 { 374 SCIP_VAR* var; 375 int size; 376 377 /* save variable and constraint names and replace these names by generic names */ 378 379 /* allocate memory for saving the original variable and constraint names */ 380 SCIP_CALL( SCIPsetAllocBufferArray(set, &varnames, nvars) ); 381 SCIP_CALL( SCIPsetAllocBufferArray(set, &fixedvarnames, nfixedvars) ); 382 SCIP_CALL( SCIPsetAllocBufferArray(set, &consnames, nconss) ); 383 384 /* compute length of the generic variable names: 385 * - nvars + 1 to avoid log of zero 386 * - +3 (zero at end + 'x' + 1 because we round down) 387 * Example: 10 -> need 4 chars ("x10\0") 388 */ 389 size = (int) log10(nvars+1.0) + 3; 390 391 for( i = 0; i < nvars; ++i ) 392 { 393 var = vars[i]; 394 varnames[i] = SCIPvarGetName(var); 395 396 SCIP_CALL( SCIPsetAllocBufferArray(set, &name, size) ); 397 (void) SCIPsnprintf(name, size, "x%d", i + set->write_genoffset); 398 SCIPvarSetNamePointer(var, name); 399 } 400 401 /* compute length of the generic variable names */ 402 size = (int) log10(nfixedvars+1.0) + 3; 403 404 for( i = 0; i < nfixedvars; ++i ) 405 { 406 var = fixedvars[i]; 407 fixedvarnames[i] = SCIPvarGetName(var); 408 409 SCIP_CALL( SCIPsetAllocBufferArray(set, &name, size) ); 410 (void) SCIPsnprintf(name, size, "y%d", i); 411 SCIPvarSetNamePointer(var, name); 412 } 413 414 /* compute length of the generic constraint names */ 415 size = (int) log10(nconss+1.0) + 3; 416 417 for( i = 0; i < nconss; ++i ) 418 { 419 cons = conss[i]; 420 consnames[i] = SCIPconsGetName(cons); 421 422 SCIP_CALL( SCIPsetAllocBufferArray(set, &name, size) ); 423 (void) SCIPsnprintf(name, size, "c%d", i); 424 SCIPconsSetNamePointer(cons, name); 425 } 426 } 427 428 /* adapt objective scale for transformed problem (for the original no change is necessary) */ 429 objscale = prob->objscale; 430 if( prob->transformed && prob->objsense == SCIP_OBJSENSE_MAXIMIZE ) 431 objscale *= -1.0; 432 433 /* call reader to write problem */ 434 retcode = reader->readerwrite(set->scip, reader, file, prob->name, prob->probdata, prob->transformed, 435 prob->objsense, objscale, prob->objoffset, 436 vars, nvars, prob->nbinvars, prob->nintvars, prob->nimplvars, prob->ncontvars, 437 fixedvars, nfixedvars, prob->startnvars, 438 conss, nconss, prob->maxnconss, prob->startnconss, genericnames, result); 439 440 /* reset variable and constraint names to original names */ 441 if( genericnames ) 442 { 443 assert(varnames != NULL); 444 assert(fixedvarnames != NULL); 445 assert(consnames != NULL); 446 for( i = nconss - 1; i >= 0; --i ) 447 { 448 cons = conss[i]; 449 450 /* get pointer to temporary generic name and free the memory */ 451 consname = SCIPconsGetName(cons); 452 SCIPsetFreeBufferArray(set, &consname); 453 454 /* reset name */ 455 SCIPconsSetNamePointer(cons, consnames[i]); 456 } 457 458 for( i = nfixedvars - 1; i >= 0; --i ) 459 resetVarname(fixedvars[i], set, fixedvarnames[i]); 460 461 for( i = nvars - 1; i >= 0; --i ) 462 resetVarname(vars[i], set, varnames[i]); 463 464 /* free memory */ 465 SCIPsetFreeBufferArray(set, &consnames); 466 SCIPsetFreeBufferArray(set, &fixedvarnames); 467 SCIPsetFreeBufferArray(set, &varnames); 468 } 469 470 if( prob->transformed ) 471 { 472 /* free memory */ 473 SCIPsetFreeBufferArray(set, &conss); 474 } 475 } 476 else 477 { 478 *result = SCIP_DIDNOTRUN; 479 retcode = SCIP_OKAY; 480 } 481 482 /* check for reader errors */ 483 if( retcode == SCIP_WRITEERROR ) 484 return retcode; 485 486 SCIP_CALL( retcode ); 487 488 return SCIP_OKAY; 489 } 490 491 /** gets user data of reader */ 492 SCIP_READERDATA* SCIPreaderGetData( 493 SCIP_READER* reader /**< reader */ 494 ) 495 { 496 assert(reader != NULL); 497 498 return reader->readerdata; 499 } 500 501 /** sets user data of reader; user has to free old data in advance! */ 502 void SCIPreaderSetData( 503 SCIP_READER* reader, /**< reader */ 504 SCIP_READERDATA* readerdata /**< new reader user data */ 505 ) 506 { 507 assert(reader != NULL); 508 509 reader->readerdata = readerdata; 510 } 511 512 /** sets copy method of reader */ 513 void SCIPreaderSetCopy( 514 SCIP_READER* reader, /**< reader */ 515 SCIP_DECL_READERCOPY ((*readercopy)) /**< copy method of reader or NULL if you don't want to copy your plugin into sub-SCIPs */ 516 ) 517 { 518 assert(reader != NULL); 519 520 reader->readercopy = readercopy; 521 } 522 523 /** sets destructor of reader */ 524 void SCIPreaderSetFree( 525 SCIP_READER* reader, /**< reader */ 526 SCIP_DECL_READERFREE ((*readerfree)) /**< destructor of reader */ 527 ) 528 { 529 assert(reader != NULL); 530 531 reader->readerfree = readerfree; 532 } 533 534 /** sets read method of reader */ 535 void SCIPreaderSetRead( 536 SCIP_READER* reader, /**< reader */ 537 SCIP_DECL_READERREAD ((*readerread)) /**< read method */ 538 ) 539 { 540 assert(reader != NULL); 541 542 reader->readerread = readerread; 543 } 544 545 /** sets write method of reader */ 546 void SCIPreaderSetWrite( 547 SCIP_READER* reader, /**< reader */ 548 SCIP_DECL_READERWRITE ((*readerwrite)) /**< write method */ 549 ) 550 { 551 assert(reader != NULL); 552 553 reader->readerwrite = readerwrite; 554 } 555 556 /** gets name of reader */ 557 const char* SCIPreaderGetName( 558 SCIP_READER* reader /**< reader */ 559 ) 560 { 561 assert(reader != NULL); 562 563 return reader->name; 564 } 565 566 /** gets description of reader */ 567 const char* SCIPreaderGetDesc( 568 SCIP_READER* reader /**< reader */ 569 ) 570 { 571 assert(reader != NULL); 572 573 return reader->desc; 574 } 575 576 /** gets file extension of reader */ 577 const char* SCIPreaderGetExtension( 578 SCIP_READER* reader /**< reader */ 579 ) 580 { 581 assert(reader != NULL); 582 583 return reader->extension; 584 } 585 586 /** return whether the reader can read files */ 587 SCIP_Bool SCIPreaderCanRead( 588 SCIP_READER* reader /**< reader */ 589 ) 590 { 591 assert(reader != NULL); 592 593 return (reader->readerread != NULL); 594 } 595 596 /** return whether the reader can write files */ 597 SCIP_Bool SCIPreaderCanWrite( 598 SCIP_READER* reader /**< reader */ 599 ) 600 { 601 assert(reader != NULL); 602 603 return (reader->readerwrite != NULL); 604 } 605 606 /** gets time in seconds used in this reader for reading */ 607 SCIP_Real SCIPreaderGetReadingTime( 608 SCIP_READER* reader /**< reader */ 609 ) 610 { 611 assert(reader != NULL); 612 613 return SCIPclockGetTime(reader->readingtime); 614 } 615 616 /** enables or disables all clocks of \p reader, depending on the value of the flag */ 617 void SCIPreaderEnableOrDisableClocks( 618 SCIP_READER* reader, /**< the reader for which all clocks should be enabled or disabled */ 619 SCIP_Bool enable /**< should the clocks be enabled? */ 620 ) 621 { 622 assert(reader != NULL); 623 624 SCIPclockEnableOrDisable(reader->readingtime, enable); 625 } 626 627 /** resets reading time of reader */ 628 SCIP_RETCODE SCIPreaderResetReadingTime( 629 SCIP_READER* reader /**< reader */ 630 ) 631 { 632 assert(reader != NULL); 633 634 /* reset reading time/clock */ 635 SCIPclockReset(reader->readingtime); 636 637 return SCIP_OKAY; 638 } 639 640