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_pbm.c 26 * @ingroup DEFPLUGINS_READER 27 * @brief file writer for portable bitmap file format (PBM), open with common graphic viewer programs (e.g. xview) 28 * @author Alexandra Kraft 29 * 30 */ 31 32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 33 34 #include "blockmemshell/memory.h" 35 #include "scip/cons_knapsack.h" 36 #include "scip/cons_linear.h" 37 #include "scip/cons_logicor.h" 38 #include "scip/cons_setppc.h" 39 #include "scip/cons_varbound.h" 40 #include "scip/pub_cons.h" 41 #include "scip/pub_message.h" 42 #include "scip/pub_reader.h" 43 #include "scip/pub_var.h" 44 #include "scip/reader_pbm.h" 45 #include "scip/scip_cons.h" 46 #include "scip/scip_mem.h" 47 #include "scip/scip_message.h" 48 #include "scip/scip_param.h" 49 #include "scip/scip_reader.h" 50 #include "scip/scip_var.h" 51 #include <string.h> 52 53 #define READER_NAME "pbmreader" 54 #define READER_DESC "file writer for portable bitmap file format (PBM), open with common graphic viewer programs (e.g. xview)" 55 #define READER_EXTENSION "pbm" 56 57 /* 58 * Data structures 59 */ 60 #define PBM_MAX_LINELEN 71 /**< the maximum length of any line is 70 + '\\0' = 71*/ 61 #define DEFAULT_PBM_BINARY TRUE /**< binary is the default format for PBM */ 62 #define DEFAULT_PBM_MAXROWS 1000 /**< allowed maximum of pixel-rows int the picture */ 63 #define DEFAULT_PBM_MAXCOLS 1000 /**< allowed maximum of pixel-columns in the picture */ 64 65 /** LP reading data */ 66 struct SCIP_ReaderData 67 { 68 SCIP_Bool binary; /**< binary is the default format for PBM */ 69 int maxrows; /**< allowed maximum of pixel-rows int the picture */ 70 int maxcols; /**< allowed maximum of pixel-columns in the picture */ 71 }; 72 73 /* 74 * Local methods (for writing) 75 */ 76 77 /** transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant */ 78 static 79 SCIP_RETCODE getActiveVariables( 80 SCIP* scip, /**< SCIP data structure */ 81 SCIP_VAR** vars, /**< vars array to get active variables for */ 82 SCIP_Real* scalars, /**< scalars a_1, ..., a_n in sum a_1*x_1 + ... + a_n*x_n + c */ 83 int* nvars, /**< pointer to number of variables and values in vars and vals array */ 84 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */ 85 SCIP_Bool transformed /**< transformed constraint? */ 86 ) 87 { 88 int requiredsize; 89 int v; 90 91 assert(scip != NULL); 92 assert(vars != NULL); 93 assert(scalars != NULL); 94 assert(nvars != NULL); 95 assert(constant != NULL); 96 97 if( transformed ) 98 { 99 SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, *nvars, constant, &requiredsize, TRUE) ); 100 101 if( requiredsize > *nvars ) 102 { 103 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) ); 104 SCIP_CALL( SCIPreallocBufferArray(scip, &scalars, requiredsize) ); 105 106 SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, scalars, nvars, requiredsize, constant, &requiredsize, TRUE) ); 107 assert(requiredsize <= *nvars); 108 } 109 } 110 else 111 { 112 for( v = 0; v < *nvars; ++v ) 113 { 114 SCIP_CALL( SCIPvarGetOrigvarSum(&vars[v], &scalars[v], constant) ); 115 } 116 } 117 118 return SCIP_OKAY; 119 } 120 121 /** transforms given variables to the corresponding active variables */ 122 static 123 SCIP_RETCODE getActiveVariables2( 124 SCIP* scip, /**< SCIP data structure */ 125 SCIP_VAR** vars, /**< vars array to get active variables for */ 126 int* nvars, /**< pointer to number of variables and values in vars and vals array */ 127 SCIP_Bool transformed /**< transformed constraint? */ 128 ) 129 { 130 int requiredsize; 131 int v; 132 133 assert(scip != NULL); 134 assert(vars != NULL); 135 assert(nvars != NULL); 136 137 if( transformed ) 138 { 139 SCIP_CALL( SCIPgetActiveVars(scip, vars, nvars, *nvars, &requiredsize) ); 140 141 if( requiredsize > *nvars ) 142 { 143 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) ); 144 145 SCIP_CALL( SCIPgetActiveVars(scip, vars, nvars, requiredsize, &requiredsize) ); 146 assert(requiredsize <= *nvars); 147 } 148 } 149 else 150 { 151 SCIP_Real scalar; 152 SCIP_Real constant; 153 for( v = 0; v < *nvars; ++v ) 154 { 155 scalar = 1.0; 156 constant = 0.0; 157 SCIP_CALL( SCIPvarGetOrigvarSum(&vars[v], &scalar, &constant) ); 158 } 159 } 160 161 return SCIP_OKAY; 162 } 163 164 /** clears the given line buffer */ 165 static 166 void clearLine( 167 char* linebuffer, /**< line */ 168 int* linecnt /**< number of characters in line */ 169 ) 170 { 171 assert(linebuffer != NULL); 172 assert(linecnt != NULL); 173 174 (*linecnt) = 0; 175 linebuffer[0] = '\0'; 176 } 177 178 179 /** appends a bit to buffer and prints it to the give file stream if we've gather a whole byte */ 180 static 181 void flushBits( 182 SCIP* scip, /**< SCIP data structure */ 183 FILE* file, /**< output file (or NULL for standard output) */ 184 unsigned char* bitcnt, /**< counts bits until whole byte is gathered */ 185 unsigned char* bitbuffer /**< bit buffer */ 186 ) 187 { 188 assert(scip != NULL); 189 190 if( *bitcnt == 0 ) 191 return; 192 193 assert(bitbuffer != NULL); 194 assert(*bitcnt > 0 && *bitcnt <= 8); 195 196 (*bitbuffer) <<= (8 - *bitcnt); /*lint !e701 !e734*/ 197 198 fputc(*bitbuffer, file); 199 200 *bitcnt = 0; 201 *bitbuffer = 0; 202 } 203 204 205 /** appends a bit to buffer and prints it to the given file stream if we've gathered a whole byte */ 206 static 207 void appendBit( 208 SCIP* scip, /**< SCIP data structure */ 209 FILE* file, /**< output file (or NULL for standard output) */ 210 unsigned char bit, /**< bit to append */ 211 unsigned char* bitcnt, /**< counts bits until whole byte is gathered */ 212 unsigned char* bitbuffer /**< bit buffer */ 213 ) 214 { 215 assert(scip != NULL); 216 assert(*bitcnt < 8); 217 assert(bitbuffer != NULL); 218 219 (*bitbuffer) = ((*bitbuffer)<<1)|(bit&1); /*lint !e734*/ 220 *bitcnt += 1; 221 222 if( *bitcnt == 8 ) 223 flushBits(scip, file, bitcnt, bitbuffer); 224 } 225 226 /** calculates the size of the quadratic matrix, which will correspond to one pixel in the picture */ 227 static 228 int getSubmatrixSize( 229 SCIP_READERDATA* readerdata, /**< information for reader */ 230 int nvars, /**< number of variables */ 231 int nconss /**< number of constraints */ 232 ) 233 { 234 int sizev; 235 int sizeh; 236 int res; 237 238 assert(readerdata->maxrows != 0 && readerdata->maxcols != 0); 239 240 if( readerdata->maxrows > nconss ) 241 readerdata->maxrows = nconss; 242 243 if( readerdata->maxcols > nvars ) 244 readerdata->maxcols = nvars; 245 246 sizev = (nconss + readerdata->maxrows - 1) / readerdata->maxrows; 247 sizeh = (nvars + readerdata->maxcols - 1) / readerdata->maxcols; 248 249 /* both defined with -1 */ 250 if( readerdata->maxrows == -1 && readerdata->maxcols == -1 ) 251 res = 1; 252 253 /* only width is defined */ 254 else if( readerdata->maxrows == -1 && readerdata->maxcols > 0 ) 255 res = sizeh; 256 257 /* only height is defined */ 258 else if( readerdata->maxrows > 0 && readerdata->maxcols == -1 ) 259 res = sizev; 260 261 /* both are defined, use smaller scaling factor */ 262 else if( sizev > sizeh ) 263 res = sizev; 264 else 265 res = sizeh; 266 267 readerdata->maxrows = (nconss + res - 1) / res; 268 readerdata->maxcols = (nvars + res - 1) / res; 269 270 return res; 271 } 272 273 274 /** print row in PBM format to file stream */ 275 static 276 void printRow( 277 SCIP* scip, /**< SCIP data structure */ 278 SCIP_READERDATA* readerdata, /**< information for reader */ 279 SCIP_VAR** vars, /**< array of constraint variables */ 280 int conscnt, /**< current constraint */ 281 int nvars, /**< number of constraint variables */ 282 int submatrixsize, /**< size of the submatrices */ 283 int* scaledimage /**< array of ints that count variables in every submatrix */ 284 ) 285 { 286 int v; 287 int i; 288 const int y = conscnt / submatrixsize; 289 int x; 290 291 assert(scip != NULL); 292 assert(nvars > 0); 293 assert(readerdata != NULL); 294 295 for( i = 0; i < nvars; ++i ) 296 { 297 assert(vars != NULL); /* for lint */ 298 299 v = SCIPvarGetProbindex(vars[i]); 300 if( v != -1 ) 301 { 302 x = v / submatrixsize; 303 ++(scaledimage[y * readerdata->maxcols + x]); 304 } 305 } 306 307 return; 308 } 309 310 /** prints given linear constraint information in PBM format to file stream */ 311 static 312 SCIP_RETCODE printLinearCons( 313 SCIP* scip, /**< SCIP data structure */ 314 SCIP_READERDATA* readerdata, /**< information for reader */ 315 SCIP_VAR** vars, /**< array of variables */ 316 SCIP_Real* vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */ 317 int nvars, /**< current constraint */ 318 int conscnt, /**< counts variables in the constraint */ 319 SCIP_Bool transformed, /**< transformed constraint? */ 320 int submatrixsize, /**< size of the submatrices */ 321 int* scaledimage /**< array of ints that count variables in every submatrix */ 322 ) 323 { 324 SCIP_VAR** activevars; 325 SCIP_Real* activevals; 326 SCIP_Real activeconstant = 0.0; 327 int nactivevars; 328 int v; 329 330 assert(scip != NULL); 331 assert(vars != NULL); 332 assert(nvars > 0); 333 assert(conscnt >= 0); 334 assert(readerdata != NULL); 335 336 /* duplicate variable and value array */ 337 nactivevars = nvars; 338 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars ) ); 339 if( vals != NULL ) 340 { 341 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars ) ); 342 } 343 else 344 { 345 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) ); 346 347 for( v = 0; v < nactivevars; ++v ) 348 activevals[v] = 1.0; 349 } 350 351 /* retransform given variables to active variables */ 352 SCIP_CALL( getActiveVariables(scip, activevars, activevals, &nactivevars, &activeconstant, transformed) ); 353 354 /* print constraint */ 355 printRow(scip, readerdata, activevars, conscnt, nactivevars, submatrixsize, scaledimage); 356 357 /* free buffer arrays */ 358 SCIPfreeBufferArray(scip, &activevars); 359 SCIPfreeBufferArray(scip, &activevals); 360 361 return SCIP_OKAY; 362 } 363 364 /* draws the scaled image */ 365 static 366 void drawScaledImage( 367 SCIP* scip, /**< SCIP data structure */ 368 FILE* file, /**< output file, or NULL if standard output should be used */ 369 SCIP_READERDATA* readerdata, /**< information for reader */ 370 int* scaledimage /**< array of ints that count variables in every submatrix */ 371 ) 372 { 373 int y; 374 int x; 375 unsigned char bitcnt = 0; 376 unsigned char bitbuffer = '\0'; 377 378 assert(scip != NULL); 379 assert(readerdata != NULL); 380 381 for( y = 0; y < readerdata->maxrows; y++ ) 382 { 383 for( x = 0; x < readerdata->maxcols; x++ ) 384 { 385 unsigned char v = 0; 386 if( scaledimage[y*readerdata->maxcols+x] >= 1 ) 387 { 388 v = 1; 389 } 390 appendBit(scip, file, v, &bitcnt, &bitbuffer); 391 } 392 flushBits(scip, file, &bitcnt, &bitbuffer); 393 } 394 } 395 396 397 /* 398 * Callback methods of reader 399 */ 400 401 /** copy method for reader plugins (called when SCIP copies plugins) */ 402 static 403 SCIP_DECL_READERCOPY(readerCopyPbm) 404 { /*lint --e{715}*/ 405 assert(scip != NULL); 406 assert(reader != NULL); 407 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); 408 409 /* call inclusion method of reader */ 410 SCIP_CALL( SCIPincludeReaderPbm(scip) ); 411 412 return SCIP_OKAY; 413 } 414 415 /** destructor of reader to free user data (called when SCIP is exiting) */ 416 static 417 SCIP_DECL_READERFREE(readerFreePbm) 418 { 419 SCIP_READERDATA* readerdata; 420 421 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); 422 423 readerdata = SCIPreaderGetData(reader); 424 assert(readerdata != NULL); 425 426 SCIPfreeBlockMemory(scip, &readerdata); 427 428 return SCIP_OKAY; 429 } 430 431 /** problem reading method of reader */ 432 #define readerReadPbm NULL 433 434 /** problem writing method of reader */ 435 static 436 SCIP_DECL_READERWRITE(readerWritePbm) 437 { /*lint --e{715}*/ 438 SCIP_READERDATA* readerdata; 439 440 assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); 441 442 readerdata = SCIPreaderGetData(reader); 443 assert(readerdata != NULL); 444 445 SCIP_CALL( SCIPwritePbm(scip, file, name, readerdata, transformed, nvars, conss, nconss, result) ); 446 447 return SCIP_OKAY; 448 } 449 450 /* 451 * reader specific interface methods 452 */ 453 454 /** includes the pbm file reader in SCIP */ 455 SCIP_RETCODE SCIPincludeReaderPbm( 456 SCIP* scip /**< SCIP data structure */ 457 ) 458 { 459 SCIP_READERDATA* readerdata; 460 461 /* create pbm reader data */ 462 SCIP_CALL( SCIPallocBlockMemory(scip, &readerdata) ); 463 464 /* include pbm reader */ 465 SCIP_CALL( SCIPincludeReader(scip, READER_NAME, READER_DESC, READER_EXTENSION, 466 readerCopyPbm, readerFreePbm, readerReadPbm, readerWritePbm, readerdata) ); 467 468 /* add pbm reader parameters */ 469 SCIP_CALL( SCIPaddBoolParam(scip, 470 "reading/pbmreader/binary", "should the output format be binary(P4) (otherwise plain(P1) format)", 471 &readerdata->binary, FALSE, DEFAULT_PBM_BINARY, NULL, NULL) ); 472 SCIP_CALL( SCIPaddIntParam(scip, 473 "reading/pbmreader/maxrows", "maximum number of rows in the scaled picture (-1 for no limit)", 474 &readerdata->maxrows, FALSE, DEFAULT_PBM_MAXROWS, -1, INT_MAX, NULL, NULL) ); 475 SCIP_CALL( SCIPaddIntParam(scip, 476 "reading/pbmreader/maxcols", "maximum number of columns in the scaled picture (-1 for no limit)", 477 &readerdata->maxcols, FALSE, DEFAULT_PBM_MAXCOLS, -1, INT_MAX, NULL, NULL) ); 478 479 return SCIP_OKAY; 480 } 481 482 /* writes picture of matrix structure to file */ 483 SCIP_RETCODE SCIPwritePbm( 484 SCIP* scip, /**< SCIP data structure */ 485 FILE* file, /**< output file, or NULL if standard output should be used */ 486 const char* name, /**< problem name */ 487 SCIP_READERDATA* readerdata, /**< information for reader */ 488 SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */ 489 int nvars, /**< number of active variables in the problem */ 490 SCIP_CONS** conss, /**< array with constraints of the problem */ 491 int nconss, /**< number of constraints in the problem */ 492 SCIP_RESULT* result /**< pointer to store the result of the file writing call */ 493 ) 494 { 495 SCIP_CONSHDLR* conshdlr; 496 SCIP_CONS* cons; 497 SCIP_VAR** consvars; 498 SCIP_Real* consvals; 499 SCIP_READERDATA readerdata_copy; 500 char linebuffer[PBM_MAX_LINELEN]; 501 const char* conshdlrname; 502 int* scaledimage; 503 int submatrixsize; 504 int nconsvars; 505 int linecnt; 506 int c; 507 int v; 508 509 assert(scip != NULL); 510 assert(readerdata != NULL); 511 assert(conss != NULL); 512 513 readerdata_copy = *readerdata; 514 submatrixsize = getSubmatrixSize(&readerdata_copy, nvars, nconss); 515 readerdata = &readerdata_copy; 516 517 SCIP_CALL( SCIPallocBufferArray(scip, &scaledimage, readerdata_copy.maxrows * readerdata_copy.maxcols) ); 518 assert(scaledimage != NULL); 519 BMSclearMemoryArray(scaledimage, readerdata->maxrows * readerdata->maxcols); 520 521 /* print statistics as comment to file */ 522 if( readerdata->binary ) 523 SCIPinfoMessage(scip, file, "P4\n"); 524 else 525 SCIPinfoMessage(scip, file, "P1\n"); 526 527 SCIPinfoMessage(scip, file, "# %s\n", name); 528 SCIPinfoMessage(scip, file, "%d %d\n", readerdata->maxcols, readerdata->maxrows); 529 530 clearLine(linebuffer, &linecnt); 531 532 for( c = 0; c < nconss; ++c ) 533 { 534 cons = conss[c]; 535 assert(cons != NULL); 536 537 /* in case the transformed is written only constraint are posted which are enabled in the current node */ 538 assert(!transformed || SCIPconsIsEnabled(cons)); 539 540 conshdlr = SCIPconsGetHdlr(cons); 541 assert(conshdlr != NULL); 542 543 conshdlrname = SCIPconshdlrGetName(conshdlr); 544 assert(transformed == SCIPconsIsTransformed(cons)); 545 546 if( strcmp(conshdlrname, "linear") == 0 ) 547 { 548 consvars = SCIPgetVarsLinear(scip, cons); 549 nconsvars = SCIPgetNVarsLinear(scip, cons); 550 assert(consvars != NULL || nconsvars == 0); 551 552 if( nconsvars > 0 ) 553 { 554 SCIP_CALL( printLinearCons(scip, readerdata, consvars, SCIPgetValsLinear(scip, cons), 555 nconsvars, c, transformed, submatrixsize, scaledimage) ); 556 } 557 } 558 else if( strcmp(conshdlrname, "setppc") == 0 ) 559 { 560 consvars = SCIPgetVarsSetppc(scip, cons); 561 nconsvars = SCIPgetNVarsSetppc(scip, cons); 562 assert(consvars != NULL || nconsvars == 0); 563 564 if( nconsvars > 0 ) 565 { 566 SCIP_CALL( printLinearCons(scip, readerdata, consvars, NULL, 567 nconsvars, c, transformed, submatrixsize, scaledimage) ); 568 } 569 } 570 else if( strcmp(conshdlrname, "logicor") == 0 ) 571 { 572 consvars = SCIPgetVarsLogicor(scip, cons); 573 nconsvars = SCIPgetNVarsLogicor(scip, cons); 574 assert(consvars != NULL || nconsvars == 0); 575 576 if( nconsvars > 0 ) 577 { 578 SCIP_CALL( printLinearCons(scip, readerdata, consvars, NULL, 579 nconsvars, c, transformed, submatrixsize, scaledimage) ); 580 } 581 } 582 else if( strcmp(conshdlrname, "knapsack") == 0 ) 583 { 584 SCIP_Longint* weights; 585 586 consvars = SCIPgetVarsKnapsack(scip, cons); 587 nconsvars = SCIPgetNVarsKnapsack(scip, cons); 588 assert(consvars != NULL || nconsvars == 0); 589 590 /* copy Longint array to SCIP_Real array */ 591 weights = SCIPgetWeightsKnapsack(scip, cons); 592 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) ); 593 for( v = 0; v < nconsvars; ++v ) 594 consvals[v] = weights[v]; 595 596 if( nconsvars > 0 ) 597 { 598 SCIP_CALL( printLinearCons(scip, readerdata, consvars, consvals, nconsvars, c, transformed, 599 submatrixsize, scaledimage) ); 600 } 601 602 SCIPfreeBufferArray(scip, &consvals); 603 } 604 else if( strcmp(conshdlrname, "varbound") == 0 ) 605 { 606 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) ); 607 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) ); 608 609 consvars[0] = SCIPgetVarVarbound(scip, cons); 610 consvars[1] = SCIPgetVbdvarVarbound(scip, cons); 611 612 consvals[0] = 1.0; 613 consvals[1] = SCIPgetVbdcoefVarbound(scip, cons); 614 615 SCIP_CALL( printLinearCons(scip, readerdata, consvars, consvals, 2, c, transformed, 616 submatrixsize, scaledimage) ); 617 618 SCIPfreeBufferArray(scip, &consvars); 619 SCIPfreeBufferArray(scip, &consvals); 620 } 621 else 622 { 623 SCIP_Bool success; 624 625 consvars = NULL; 626 SCIP_CALL( SCIPgetConsNVars(scip, cons, &nconsvars, &success) ); 627 628 if( success ) 629 { 630 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nconsvars) ); 631 632 SCIP_CALL( SCIPgetConsVars(scip, cons, consvars, nconsvars, &success) ); 633 } 634 635 if( success ) 636 { 637 /* retransform given variables to active variables */ 638 SCIP_CALL( getActiveVariables2(scip, consvars, &nconsvars, transformed) ); 639 640 printRow(scip, readerdata, consvars, c, nconsvars, submatrixsize, scaledimage); 641 } 642 else 643 { 644 SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname ); 645 SCIPinfoMessage(scip, file, "\\ "); 646 SCIP_CALL( SCIPprintCons(scip, cons, file) ); 647 } 648 649 SCIPfreeBufferArrayNull(scip, &consvars); 650 } 651 } 652 653 drawScaledImage(scip, file, readerdata, scaledimage); 654 655 SCIPfreeBufferArray(scip, &scaledimage); 656 657 *result = SCIP_SUCCESS; 658 659 return SCIP_OKAY; /*lint !e438*/ 660 } 661