1/* BEGIN LICENSE BLOCK 2 * Version: CMPL 1.1 3 * 4 * The contents of this file are subject to the Cisco-style Mozilla Public 5 * License Version 1.1 (the "License"); you may not use this file except 6 * in compliance with the License. You may obtain a copy of the License 7 * at www.eclipse-clp.org/license. 8 * 9 * Software distributed under the License is distributed on an "AS IS" 10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11 * the License for the specific language governing rights and limitations 12 * under the License. 13 * 14 * The Original Code is The ECLiPSe Constraint Logic Programming System. 15 * The Initial Developer of the Original Code is Cisco Systems, Inc. 16 * Portions created by the Initial Developer are 17 * Copyright (C) 1995-2006 Cisco Systems, Inc. All Rights Reserved. 18 * 19 * Contributor(s): Joachim Schimpf, Kish Shen and Andrew Eremin, IC-Parc 20 * 21 * END LICENSE BLOCK */ 22/* 23 * ECLiPSe / CPLEX interface 24 * 25 * System: ECLiPSe Constraint Logic Programming System 26 * Author/s: Joachim Schimpf, IC-Parc 27 * Kish Shen, IC-Parc 28 * Version: $Id: eplex.c,v 1.16 2014/07/14 01:02:27 jschimpf Exp $ 29 * 30 */ 31 32/*#define LOG_CALLS*/ 33#undef LOG_CALLS 34#ifdef LOG_CALLS 35int log_ctr = 0; 36#endif 37 38#ifndef __STDC__ 39typedef unsigned size_t; 40char *getenv(); 41#else 42#include <stdlib.h> 43#endif 44#include <string.h> 45 46#ifdef HAVE_UNISTD_H 47# include <unistd.h> 48#endif 49 50# include <stdio.h> 51 52#ifdef WIN32 53# include <process.h> 54# define unlink(File) _unlink(File) 55# define getpid() _getpid() 56# define gethostid() 0 57# define putenv(s) _putenv(s) 58# define PATH_SEPARATOR ";" 59#else 60# define PATH_SEPARATOR ":" 61#endif 62 63 64/* Kish 2008-08-13: 65 Cannot define __eprintf() here for PPC Mac OS X -- at least version 10.4 66 we have access to. It is defined in stdc++, and Mac OS X does not allow 67 multiple definitions of symbols during linking (for flat_namespace). 68 versions, 69 70 Kish 2008-07-24: define __eprintf() for all cases -- Cisco lab Solaris 71 has older libraries that does not have __eprintf() defined 72 73 code modified from koders.com's definition of __eprintf(), which uses 74 fiprintf(), which is also undefined for Intel MacOSX. Here eprintf() 75 is redefined to just the abort. This should be OK, as it is used in 76 assert.h, which should only be used when debugging 77 78-- Kish Shen 2007-11-22 79 80 This is an implementation of the __eprintf function which is 81 compatible with the assert.h which is distributed with gcc. 82 83 This function is provided because in some cases libgcc.a will not 84 provide __eprintf. This will happen if inhibit_libc is defined, 85 which is done because at the time that libgcc2.c is compiled, the 86 correct <stdio.h> may not be available. newlib provides its own 87 copy of assert.h, which calls __assert, not __eprintf. However, in 88 some cases you may accidentally wind up compiling with the gcc 89 assert.h. In such a case, this __eprintf will be used if there 90 does not happen to be one in libgcc2.c. */ 91 92#if !(defined(__APPLE__) && defined(__ppc__)) 93 94void 95__eprintf (format, file, line, expression) 96 const char *format; 97 const char *file; 98 unsigned int line; 99 const char *expression; 100{ 101/* (void) fiprintf (stderr, format, file, line, expression);*/ 102 abort (); 103 } 104 105#endif 106 107 108# include <limits.h> 109# include <math.h> 110 111#if defined(LOG_CALLS) 112# define USE_PROBLEM_ARRAY 113#endif 114 115 116/* 117 * Macros to make code more readable 118 */ 119 120/* this extra step is needed to allow Call itself to be transformed */ 121#define Transform_Quoted(Item) Add_Quotes(Item) 122#define Add_Quotes(Item) #Item 123 124/* Call logging macros: 125 Call(Ret, Call) Log and call Call if LOG_CALLS, assign return value to Ret 126 CallN(Call) Log and call Call if LOG_CALLS, return value is lost 127 128Log only macros (these should be accompanied by an actual call to the 129logged call!) 130 131 Log1(Call, A1)...Log6(Call, A1,A2,A3,A4,A5,A6) 132 Log Call if LOG_CALLS. Call should be in printf 133 form, with appropriate % arguments for the arguments 134*/ 135#ifdef LOG_CALLS 136# define Call(Err, C) { \ 137 Fprintf(log_output_, "\n\ 138 "Transform_Quoted(C)";");\ 139 ec_flush(log_output_); \ 140 Err = C;\ 141} 142 143# define CallN(C) { \ 144 Fprintf(log_output_, "\n\ 145 "Transform_Quoted(C)";");\ 146 ec_flush(log_output_); \ 147 C;\ 148} 149 150# define Log0(C) {\ 151 Fprintf(log_output_, "\n\ 152 "Transform_Quoted(C)";");\ 153 ec_flush(log_output_);\ 154} 155 156# define Log1(C,A1) {\ 157 Fprintf(log_output_, "\n\ 158 "Transform_Quoted(C)";",A1);\ 159 ec_flush(log_output_);\ 160} 161 162# define Log2(C,A1,A2) {\ 163 Fprintf(log_output_, "\n\ 164 "Transform_Quoted(C)";",A1,A2);\ 165 ec_flush(log_output_);\ 166} 167 168# define Log3(C,A1,A2,A3) {\ 169 Fprintf(log_output_, "\n\ 170 "Transform_Quoted(C)";",A1,A2,A3);\ 171 ec_flush(log_output_);\ 172} 173 174# define Log4(C,A1,A2,A3,A4) {\ 175 Fprintf(log_output_, "\n\ 176 "Transform_Quoted(C)";",A1,A2,A3,A4); \ 177 ec_flush(log_output_); \ 178} 179 180# define Log5(C,A1,A2,A3,A4,A5) {\ 181 Fprintf(log_output_, "\n\ 182 "Transform_Quoted(C)";",A1,A2,A3,A4,A5); \ 183 ec_flush(log_output_); \ 184} 185 186# define Log6(C,A1,A2,A3,A4,A5,A6) {\ 187 Fprintf(log_output_, "\n\ 188 "Transform_Quoted(C)";",A1,A2,A3,A4,A5,A6); \ 189 ec_flush(log_output_); \ 190} 191 192#else 193# define Call(Err, C) {Err = C;} 194# define CallN(C) C 195# define Log0(C) 196# define Log1(C,A1) 197# define Log2(C,A1,A2) 198# define Log3(C,A1,A2,A3) 199# define Log4(C,A1,A2,A3,A4) 200# define Log5(C,A1,A2,A3,A4,A5) 201# define Log6(C,A1,A2,A3,A4,A5,A6) 202#endif 203 204 205/* 206 * ECLiPSe declarations 207 */ 208 209#include "external.h" 210 211 212#if defined(WIN32) && defined(LOG_CALLS) 213/* must be after include of external.h to avoid redefining log_output_ there 214 Windows workaround for log_output_ not exported in eclipse.def 215*/ 216# define log_output_ ec_stream_id(ec_stream_nr("log_output")) 217#endif 218 219/* should be used only if v,t is a number */ 220#define DoubleVal(v, t) ( IsInteger(t) ? (double) (v).nint : \ 221 IsDouble(t) ? Dbl(v) : coerce_to_double(v,t) ) 222 223#define Check_Constant_Range(x) \ 224 {if ((x) < -CPX_INFBOUND || (x) > CPX_INFBOUND) {Bip_Error(RANGE_ERROR);}} 225 226 227/* 228 * LpDescOnly can be used if we only want to access 229 * fields within lp_desc, not in the external solver 230 * this made a difference in old Xpress, but now there 231 * is a difference only when logging calls 232 */ 233#define LpDescOnly(vlp, tlp, lpd) Get_Typed_Object(vlp, tlp, &lp_handle_tid, lpd) 234 235#ifdef LOG_CALLS 236static int next_matno = 0, current_matno = -1; 237 238# define LpDesc(vlp, tlp, lpd) { \ 239 Get_Typed_Object(vlp, tlp, &lp_handle_tid, (lpd)); \ 240 if ((lpd)->matno != current_matno) \ 241 { \ 242 Fprintf(log_output_, "\n\ 243 lpd = (lp_desc *) lpdmat[%d];", (lpd)->matno); \ 244 ec_flush(log_output_); \ 245 current_matno = (lpd)->matno; \ 246 } \ 247} 248 249#else 250# define LpDesc(vlp, tlp, lpd) LpDescOnly(vlp, tlp, lpd) 251#endif 252 253 254#define IsArray(t) IsString(t) 255#define Check_Array(t) Check_String(t) 256#define IArrayStart(pw) ((int *)BufferStart(pw)) 257#define DArrayStart(pw) ((double *)BufferStart(pw)) 258#define CArrayStart(pw) ((char *)BufferStart(pw)) 259#define Return_Unify_Array(v,t,a) Return_Unify_String(v,t,a) 260#define DArraySize(pbuf) ((BufferSize(pbuf) - 1) / sizeof(double)) 261#define IArraySize(pbuf) ((BufferSize(pbuf) - 1) / sizeof(int)) 262 263static pword * _create_carray(); 264static pword * _create_darray(); 265static pword * _create_iarray(); 266 267 268/* 269 * Solver-independent constants 270 */ 271 272/* argument indices in Prolog-level prob-handle */ 273#define HANDLE_CPH 1 /* C-level handle */ 274#define HANDLE_STAMP 2 /* timestamp for prob-handle */ 275#define HANDLE_M_METH 0 /* Outputs: offsets from meth-field */ 276#define HANDLE_M_AUXMETH 1 277#define HANDLE_M_NODEMETH 2 278#define HANDLE_M_NODEAUXMETH 3 279#define HANDLE_S_SOLS 0 /* Outputs: offsets from sols-field */ 280#define HANDLE_S_PIS 1 281#define HANDLE_S_SLACKS 2 282#define HANDLE_S_DJS 3 283#define HANDLE_S_CBASE 4 284#define HANDLE_S_RBASE 5 285#define HANDLE_S_CPCM 6 286#define HANDLE_S_IISR 7 287#define HANDLE_S_IISC 8 288#define HANDLE_S_IISCS 9 289 290#define COL_STAMP 1 /* timestamp for a column (in attribute) */ 291 292 293#define DESCR_EMPTY 0 /* problem descriptor state */ 294#define DESCR_LOADED 1 295#define DESCR_SOLVED_SOL 2 296#define DESCR_SOLVED_NOSOL 3 297#define DESCR_ABORTED_SOL 4 298#define DESCR_ABORTED_NOSOL 5 299#define DESCR_UNBOUNDED_NOSOL 6 300#define DESCR_UNKNOWN_NOSOL 7 301 302#define CSTR_TYPE_NORM 0 /* correspond to constraint_type_code/2 */ 303#define CSTR_TYPE_PERMCP 1 304#define CSTR_TYPE_CONDCP 2 305 306#define CSTR_STATE_NOTADDED -1 307#define CSTR_STATE_VIOLATED -1 308#define CSTR_STATE_SAT -2 309#define CSTR_STATE_BINDING -3 310#define CSTR_STATE_INVALID -4 311#define CSTR_STATE_INACTIVE -5 312 313#define MIPSTART_NONE 0 314#define MIPSTART_ALL 1 315#define MIPSTART_INT 2 316 317#define CP_ACTIVE 1 /* correspond to cp_cond_code/2 */ 318#define CP_ADDINIT 2 319 320#define NEWROW_INCR 60 /* default sizes for addrow arrays */ 321#define NEWNZ_INCR 510 322#define NEWBD_INCR 510 /* arrays needed for changing bounds */ 323#define NEWCOL_INCR 1022 /* macsz arrays growth increment */ 324#define NEWSOS_INCR 32 325#define CUTPOOL_INCR 10 /* number of cutpools increment */ 326 327#define RoundTo(n,unit) ((n) - ((n) - 1) % (unit) -1 + (unit)) 328#define Max(x,y) ((x)>(y)?(x):(y)) 329 330/* minimum number of words that Type would fit in */ 331#define NumberOfWords(Type) (1+(sizeof(Type)-1)/sizeof(word)) 332 333 334/* 335 * Include solver-specific declarations 336 */ 337#ifdef CPLEX 338#include "eplex_cplex.h" 339#endif 340 341#ifdef GUROBI 342#include "eplex_gurobi.h" 343#endif 344 345#ifdef XPRESS 346#include "eplex_xpress.h" 347#endif 348 349#ifdef COIN /* COIN based solvers */ 350#include "eplex_coin.h" 351#endif 352 353 354/* 355 * Problem handle 356 */ 357 358/* Methods for lp_handle_tid */ 359static void _free_lp_handle(lp_desc *lpd); 360static int _strsz_lp_handle(lp_desc *lpd, int quoted); 361static int _tostr_lp_handle(lp_desc *lpd, char *buf, int quoted); 362 363/* 2*sizeof(void *) for max. size for a printed address */ 364#define STRSZ_LP_HANDLE 2*sizeof(void *)+20 365 366static int 367_strsz_lp_handle(lp_desc *lpd, int quoted) 368{ 369 return STRSZ_LP_HANDLE; 370} 371 372static int 373_tostr_lp_handle(lp_desc *lpd, char *buf, int quoted) 374{ 375 sprintf(buf, "'EPLEX_"Transform_Quoted(SOLVER_SHORT_NAME)"'(16'%" W_MOD "x)", (uword) lpd); 376 return strlen(buf); /* size of actual string */ 377} 378 379t_ext_type lp_handle_tid = { 380 (void (*)(t_ext_ptr)) _free_lp_handle, /* free */ 381 NULL, /* copy */ 382 NULL, /* mark_dids */ 383 (int (*)(t_ext_ptr,int)) _strsz_lp_handle, /* string_size */ 384 (int (*)(t_ext_ptr,char *,int)) _tostr_lp_handle, /* to_string */ 385 NULL, /* equal */ 386 NULL, /* remote_copy */ 387 NULL, /* get */ 388 NULL /* set */ 389}; 390 391 392typedef struct { 393 int oldmar, oldmac, oldsos, oldidc; 394} untrail_data; 395 396typedef struct { 397 int idx; 398 char ctype; 399} untrail_ctype; 400 401typedef struct { 402 double bds[2]; /* bounds: lower, upper */ 403 int idx; /* index of column */ 404} untrail_bound; 405 406typedef struct { 407 int old_ptype; /* old problem type */ 408} untrail_ptype; 409 410 411/* 412 * Global data 413 */ 414 415/* ECLiPSe streams for 4 message types (log,result,warning,error) */ 416static stream_id solver_streams[4]; 417 418/* Atoms used to communicate with the Prolog level */ 419static dident d_le, d_ge, d_eq, d_optimizer, d_yes, d_no; 420 421/* Global solver environment (!=0 when initialised) */ 422static CPXENVptr cpx_env = (CPXENVptr) 0; 423 424 425#ifdef CPLEX 426 427static CPXCHANNELptr cpxresults = (CPXCHANNELptr) 0; 428static CPXCHANNELptr cpxwarning = (CPXCHANNELptr) 0; 429static CPXCHANNELptr cpxerror = (CPXCHANNELptr) 0; 430static CPXCHANNELptr cpxlog = (CPXCHANNELptr) 0; 431 432# if CPLEX >= 8 433static void CPXPUBLIC eclipse_out ARGS((void *nst, const char*msg)); 434# else 435static void CPXPUBLIC eclipse_out ARGS((void *nst, char*msg)); 436# endif 437#endif /* CPLEX */ 438 439 440#ifdef XPRESS 441 442/* Type of XPRESS library */ 443#define XP_OEM_UNKNOWN -1 444#define XP_OEM_NO 0 445#define XP_OEM_YES 1 446static int oem_xpress = XP_OEM_UNKNOWN; 447 448static void XPRS_CC eclipse_out ARGS((XPRSprob prob, void *obj, const char *msg, int len, int msgtype)); 449 450#endif /* XPRESS */ 451 452 453#if 0 454void * 455Malloc(size_t size) 456{ 457 void *p; 458 p = malloc(size); 459 Fprintf(Current_Error, "%8x malloc(%d)\n", p, size); 460 ec_flush(Current_Error); 461 return p; 462} 463 464void * 465Realloc(void *p, size_t size) 466{ 467 Fprintf(Current_Error, "%8x realloc(%d)\n", p, size); 468 ec_flush(Current_Error); 469 return realloc(p, size); 470} 471 472void 473Free(void *p) 474{ 475 Fprintf(Current_Error, "%8x free\n", p); 476 ec_flush(Current_Error); 477 free(p); 478} 479#else 480#if 1 481#define Malloc(size) malloc(size) 482#define Realloc(p, size) realloc(p, size) 483#define Free(p) free(p) 484#else 485/* Eclipse's hp_alloc() can cause problems because of private heap limit */ 486#define Malloc(size) hp_alloc(size) 487#define Realloc(p, size) hp_resize(p, size) 488#define Free(p) hp_free(p) 489#endif 490#endif 491 492/* free *p if it is pointing at something */ 493#define TryFree(p) if (p) { CallN(Free(p)); p = NULL; } 494 495 496static void _grow_cb_arrays(lp_desc *, int); 497static void _grow_numbers_array(lp_desc * lpd, int m); 498 499 500/* 501 * Include solver-specific code 502 */ 503#ifdef CPLEX 504#include "eplex_cplex.c" 505#endif 506 507#ifdef GUROBI 508#include "eplex_gurobi.c" 509#endif 510 511#ifdef XPRESS 512#include "eplex_xpress.c" 513#endif 514 515#ifdef COIN /* COIN based solvers */ 516#include "eplex_coin.c" 517#endif 518 519 520static double 521coerce_to_double(value vval, type tval) 522{ 523 /* tval MUST be a number type */ 524 value buffer; 525 526 tag_desc[TagType(tval)].coerce_to[TDBL](vval, &buffer); 527 return Dbl(buffer); 528} 529 530 531int 532p_cpx_cleanup(value vlp, type tlp) 533{ 534 pword handle; 535 handle.val.all = vlp.all; 536 handle.tag.all = tlp.all; 537 return ec_free_handle(handle, &lp_handle_tid); 538} 539 540static void 541_free_lp_handle(lp_desc *lpd) 542{ 543 int i; 544#ifdef XPRESS 545 char name[128]; 546#endif 547 if (lpd->descr_state != DESCR_EMPTY) 548 { 549#ifdef CPLEX 550 if (lpd->lp) 551 CallN(CPXfreeprob(cpx_env, &lpd->lp)); 552#endif 553#ifdef XPRESS 554 strcpy(name, lpd->probname); 555 strcat(name, ".glb"); 556 unlink(name); 557 if (lpd->lp) CallN(XPRSdestroyprob(lpd->lp)); 558 if (lpd->lpcopy && lpd->lpcopy != lpd->lp) CallN(XPRSdestroyprob(lpd->lpcopy)); 559 Mark_Copy_As_Modified(lpd); 560 TryFree(lpd->qgtype); 561 TryFree(lpd->mgcols); 562 TryFree(lpd->probname); 563#endif /* XPRESS */ 564#ifdef COIN 565 CallN(coin_free_prob(lpd->lp)); 566 /* lpd->lp allocated with new, and freed with delete by coin_free_prob() 567 so no need to free here 568 */ 569 lpd->lp = NULL; 570#endif /* COIN */ 571 572 TryFree(lpd->rhsx); 573 TryFree(lpd->senx); 574 TryFree(lpd->matbeg); 575 TryFree(lpd->matcnt); 576 TryFree(lpd->matind); 577 TryFree(lpd->matval); 578 TryFree(lpd->bdl); 579 TryFree(lpd->bdu); 580 TryFree(lpd->objx); 581 TryFree(lpd->ctype); 582 if (lpd->cb_sz) 583 { 584 CallN(Free(lpd->cb_index)); 585 TryFree(lpd->cb_index2); 586 CallN(Free(lpd->cb_value)); 587 } 588 if (lpd->sossz) 589 { 590 CallN(Free(lpd->sostype)); 591 CallN(Free(lpd->sosbeg)); 592 CallN(Free(lpd->sosind)); 593 CallN(Free(lpd->sosref)); 594 } 595 TryFree(lpd->rngval); 596 TryFree(lpd->cname); 597 TryFree(lpd->cstore); 598 TryFree(lpd->rname); 599 TryFree(lpd->rstore); 600 TryFree(lpd->numbers); 601 TryFree(lpd->zeroes); 602 TryFree(lpd->dzeroes); 603 if (lpd->nr_sz) 604 { 605 CallN(Free(lpd->rmatbeg)); 606 TryFree(lpd->rcompl); 607 TryFree(lpd->rindind); 608 } 609 if (lpd->nnz_sz) 610 { 611 CallN(Free(lpd->rmatind)); 612 CallN(Free(lpd->rmatval)); 613 } 614/* 615 if (lpd->cp_nr_sz) 616 { 617 CallN(Free(lpd->cp_rmatbeg)); 618 CallN(Free(lpd->cp_rhsx)); 619 CallN(Free(lpd->cp_senx)); 620 } 621 if (lpd->cp_nz_sz) 622 { 623 CallN(Free(lpd->cp_rmatind)); 624 CallN(Free(lpd->cp_rmatval)); 625 } 626*/ 627 if (lpd->cp_nr_sz2) 628 { 629 CallN(Free(lpd->cp_rmatbeg2)); 630 CallN(Free(lpd->cp_rhsx2)); 631 CallN(Free(lpd->cp_senx2)); 632 CallN(Free(lpd->cp_active2)); 633 CallN(Free(lpd->cp_initial_add2)); 634 if (lpd->cp_nz_sz2) 635 { 636 CallN(Free(lpd->cp_rmatind2)); 637 CallN(Free(lpd->cp_rmatval2)); 638 } 639 } 640 641 for (i=0; i < lpd->cp_npools2; i++) { TryFree(lpd->cp_pools2[i]); } 642 TryFree(lpd->cp_pools2); 643 TryFree(lpd->cp_pools_max2); 644 TryFree(lpd->cp_pools_sz2); 645 } 646#ifdef CPLEX 647 CPXflushchannel (cpx_env, cpxresults); 648 CPXflushchannel (cpx_env, cpxlog); 649 CPXflushchannel (cpx_env, cpxerror); 650 CPXflushchannel (cpx_env, cpxwarning); 651#else 652 (void) ec_flush(solver_streams[LogType]); 653 (void) ec_flush(solver_streams[ResType]); 654 (void) ec_flush(solver_streams[WrnType]); 655 (void) ec_flush(solver_streams[ErrType]); 656 657#endif 658 CallN(Free(lpd)); 659} 660 661 662 663 664/* 665 * Get a licence if necessary, print message and fail if impossible. 666 * If ok, do some low-level initialization 667 * 668 * As an indication that initialization was successful, 669 * cpx_env is set not non-NULL, even for XPRESS. 670 * All functions that do not use a problem handle must make sure that 671 * the system is initialised by checking whether cpx_env is non-NULL! 672 */ 673 674int 675p_cpx_init(value vlicloc, type tlicloc, 676 value vserialnum, type tserialnum, 677 value vsubdir, type tsubdir) 678{ 679 int i; 680 681 /* Initialise global variables */ 682 for (i=0; i<4; i++) 683 solver_streams[i] = Current_Null; 684 d_le = ec_did("=<", 0); 685 d_ge = ec_did(">=", 0); 686 d_eq = ec_did("=:=", 0); 687 d_optimizer = ec_did(SOLVER_ATOMIC_NAME, 0); 688 d_yes = ec_did("yes", 0); 689 d_no = ec_did("no", 0); 690 691 if (!cpx_env) 692 { 693#ifdef COIN 694 CallN(coin_create_prob(&cpx_env, NULL)); 695#endif 696 697# if defined(CPLEX) 698 char errmsg[512]; 699 int status, dev_status; 700 char *licloc; /* environment string (CPLEX) */ 701 702 Check_Integer(tserialnum); 703 Get_Name(vlicloc, tlicloc, licloc); 704 if (*licloc == '\0') licloc = NULL; 705# if CPLEX >= 7 706 if (licloc) 707 { 708 /* We have a CPLEX runtime key, call CPXRegisterLicense(). 709 * CAUTION: when this call fails, the process may be in a funny 710 * state. With Cplex 7/8, the thread bindings are changed and 711 * the process cannot use virtual timers any longer (bug 243). 712 */ 713 Log1(CPXRegisterLicense(0, %d), (int) vserialnum.nint); 714 if (CPXRegisterLicense(licloc, (int) vserialnum.nint)) 715 { 716 Fprintf(Current_Error, "Invalid CPLEX runtime key.\n"); 717 (void) ec_flush(Current_Error); 718 Fail; 719 } 720 } 721 /* Note CPLEX prints a banner to stderr in CPXopenCPLEX! */ 722 CallN(cpx_env = CPXopenCPLEX(&dev_status)); 723 if (dev_status) 724 { 725 CPXgeterrorstring(cpx_env, dev_status, errmsg); 726 Fprintf(Current_Error, "%s", errmsg); 727 (void) ec_flush(Current_Error); 728 Fail; 729 } 730# if CPLEX >= 8 731 /* no dual reduction as suggested by manual to get firm infeasible 732 conclusion for MIP 733 */ 734 CallN(CPXsetintparam(cpx_env, CPX_PARAM_REDUCE, 1)); 735# endif 736# else 737 int rt_status = 0; 738 CallN(cpx_env = CPXopenCPLEXdevelop(&dev_status)); 739 740 if (dev_status == 32027) /* out of licences */ 741 { 742 CPXgeterrorstring(cpx_env, dev_status, errmsg); 743 Fprintf(Current_Error, "%s", errmsg); 744 (void) ec_flush(Current_Error); 745 Fail; 746 } 747 if (dev_status != 0) /* other problem, try runtime licence */ 748 { 749 char *serialnumstring = getenv("ECLIPSECPLEXSERIALNUM"); 750 int serialnum = serialnumstring ? strtol(serialnumstring, NULL, 0) : vserialnum.nint; 751 if (serialnum) 752 { 753 cpx_env = CPXopenCPLEXruntime(&rt_status, serialnum, licloc); 754 } 755 else 756 { 757 Fprintf(Current_Error, "Couldn't find CPLEX development licence: check setting of CPLEXLICENCE,\nCPLEXLICDIR, CPLEXLICTYPE or set ECLIPSECPLEXSERIALNUM to use a runtime licence.\n", 0); 758 (void) ec_flush(Current_Error); 759 Fail; 760 } 761 } 762 if (dev_status && rt_status) /* no licence could be opened */ 763 { 764 CPXgeterrorstring(cpx_env, dev_status, errmsg); 765 Fprintf(Current_Error, "DEV: %s", errmsg); 766 CPXgeterrorstring(cpx_env, rt_status, errmsg); 767 Fprintf(Current_Error, "RT: %s", errmsg); 768 (void) ec_flush(Current_Error); 769 Fail; 770 } 771# endif /* CPLEX < 7 */ 772 status = CPXgetchannels(cpx_env, &cpxresults, &cpxwarning, &cpxerror, &cpxlog); 773 if (status) 774 { 775 CPXgeterrorstring(cpx_env, status, errmsg); 776 Fprintf(Current_Error, "%s", errmsg); 777 (void) ec_flush(Current_Error); 778 Bip_Error(EC_EXTERNAL_ERROR); 779 } 780 781# endif /* CPLEX */ 782 783# ifdef XPRESS 784 int err; 785 char slicmsg[256], banner[256]; 786 char *licloc, /* licence location (XPRESS) */ 787 *subdir; /* solver/platform/version-specific stuff (XPRESS 15) */ 788 789 Check_Integer(tserialnum); 790 Get_Name(vlicloc, tlicloc, licloc); 791 Get_Name(vsubdir, tsubdir, subdir); 792 if (*licloc == '\0') licloc = NULL; 793 794 /* Embedded OEM licence handling */ 795 if (oem_xpress == XP_OEM_YES) 796 { 797 i = (int) vserialnum.nint; 798 err = XPRSlicense(&i, slicmsg); /* second call */ 799 } 800# ifdef XPRESS_OEM_ICPARC_2002 801 Handle_OEM_ICPARC 802# endif 803# if (XPRESS == 15) 804 {/* Xpress 15 requires the PATH environment variable to be set 805 to where the license manager lmgrd is, as it execs an 806 unqualified lmgrd from within XPRSinit()! 807 */ 808 const char * curpaths; 809 char * newpaths; 810 curpaths = getenv("PATH"); 811 newpaths = Malloc(strlen("PATH=") + strlen(curpaths) 812 + strlen(PATH_SEPARATOR) + strlen(subdir) + 1); 813 strcpy(newpaths, "PATH="); 814 strcat(newpaths, subdir); 815 strcat(newpaths, PATH_SEPARATOR); 816 strcat(newpaths, curpaths); 817 putenv(newpaths); 818 } 819# endif 820 821 err = XPRSinit(licloc); 822 823# if (XPRESS >= 20) 824 if (err != 0 && err != 32 /* Student mode */) 825 { 826 char msg[512]; 827 XPRSgetlicerrmsg(msg, 512); 828 Fprintf(Current_Error, "%s", msg); 829 ec_flush(Current_Error); 830 Fail; 831 } 832 XPRSgetbanner(banner); 833 Fprintf(Current_Output, "%s\n", banner); 834# else 835 { 836 int ndays; 837 /* no banner printed in XPRESS 13, print it now as it may contain 838 extra error information 839 */ 840 XPRSgetbanner(banner); 841 Fprintf(Current_Output, "%s\n", banner); 842 XPRSgetdaysleft(&ndays); 843 /* ndays == 0 if license is not time-limited */ 844 if (ndays > 0) 845 { 846 Fprintf(Current_Output, "This XPRESS license will expire in %d days.\n\n", ndays); 847 } 848 else if (ndays < 0) 849 { 850 Fprintf(Current_Error, "This XPRESS license has expired\n\n"); 851 ec_flush(Current_Error); 852 } 853 ec_flush(Current_Output); 854 } 855 if (err != 0 && err != 32 /* Student mode */) 856 { 857 if (err != 8 || oem_xpress == XP_OEM_YES) /* suppress message for OEM library */ 858 { 859 860 Fprintf(Current_Error, "XPRESS error (probably licencing problem)\n"); 861 (void) ec_flush(Current_Error); 862 } 863 Fail; 864 } 865 if (oem_xpress == XP_OEM_YES) /* print the OEM message */ 866 { 867 Fprintf(Current_Output, slicmsg); 868 (void) ec_newline(Current_Output); 869 } 870# endif 871 872 /* use cpx_env to store the `default problem' */ 873 CallN(XPRScreateprob(&cpx_env)); 874 875# endif /* XPRESS */ 876 877#ifdef GUROBI 878 int status; 879 char *licloc; 880 881 Get_Name(vlicloc, tlicloc, licloc); 882 if (*licloc == '\0') licloc = NULL; 883 if (licloc && !getenv("GRB_LICENSE_FILE")) 884 { 885 char *envstring = Malloc(strlen("GRB_LICENSE_FILE=")+strlen(licloc)+1); 886 strcat(strcpy(envstring,"GRB_LICENSE_FILE="),licloc); 887 /* Bug: this putenv does not seem to affect GRBloadenv below (Windows) */ 888 putenv(envstring); 889 } 890 891 status = GRBloadenv(&cpx_env, NULL); 892 if (status == GRB_ERROR_NO_LICENSE) 893 { 894 Fprintf(Current_Error, "Couldn't find Gurobi licence.\n"); 895 ec_flush(Current_Error); 896 Fail; 897 } 898 else if (status) 899 { 900 /* can't retrieve error messages yet */ 901 Fprintf(Current_Error, "Gurobi error %d\n", status); 902 ec_flush(Current_Error); 903 Bip_Error(EC_EXTERNAL_ERROR); 904 } 905 /* switch off solver's own output */ 906 GRBsetintparam(cpx_env, GRB_INT_PAR_OUTPUTFLAG, 0); 907 908#endif /* GUROBI */ 909 } 910# ifdef LOG_CALLS 911 Fprintf(log_output_, "\nvoid step_%d() {\n", log_ctr++); 912 ec_flush(log_output_); 913# endif 914 Succeed; 915} 916 917 918int 919p_cpx_challenge(value v, type t) 920{ 921# ifdef XPRESS 922# if defined(WIN32) 923 int nvalue; 924 char slicmsg[256]; 925 /* Caution: calling optlicence() twice crashes on some non-oem XPRESSes */ 926 if (oem_xpress != XP_OEM_NO) 927 { 928 if (XPRSlicense(&nvalue, slicmsg) != 8) 929 { 930 oem_xpress = XP_OEM_YES; 931 Return_Unify_Integer(v, t, (long) nvalue); 932 } 933 } 934# endif 935 oem_xpress = XP_OEM_NO; 936# endif 937 Fail; 938} 939 940 941int 942p_cpx_exit() 943{ 944 if (cpx_env) 945 { 946 CPXcloseCPLEX(&cpx_env); 947 cpx_env = 0; 948 } 949 Succeed; 950} 951 952 953int 954p_cpx_prob_init(value vpre, type tpre, 955 value vcpy, type tcpy, 956 value vrow, type trow, 957 value vcol, type tcol, 958 value vnz, type tnz, 959 value vdir, type tdir, 960 value vsense, type tsense, 961 value vhandle, type thandle) 962{ 963 int i; 964 lp_desc *lpd; 965 966 Check_Integer(tpre); 967 Check_Integer(tcpy); 968 Check_Integer(trow); 969 Check_Integer(tcol); 970 Check_Integer(tnz); 971 Check_Structure(thandle); 972 973 CallN(lpd = (lp_desc *) Malloc(sizeof(lp_desc))); 974 /*CallN(_clr_lp_desc(lpd));*/ 975 CallN(memset(lpd, 0, sizeof(lp_desc))); 976 977 978#ifdef USE_PROBLEM_ARRAY 979 Log1(lpdmat[%d] = lpd, next_matno); 980 current_matno = next_matno; 981 lpd->matno = next_matno++; 982#endif 983 984#ifdef XPRESS 985 lpd->copystatus = (vcpy.nint == 1 ? XP_COPYINVALID : XP_COPYOFF); 986 987 {/* need unique name so that file names created by XPRESS are unique 988 dir is a directory path (but may need to be have the directory 989 separator character (/ or \) added 990 */ 991 int dirlen; 992 993#ifdef WIN32 994# define BASE_PROB_NAME \\eclipse 995#else 996# define BASE_PROB_NAME /eclipse 997#endif 998 Check_String(tdir); 999 dirlen = strlen(StringStart(vdir)); 1000 1001 lpd->probname = (char *) Malloc((50+dirlen) * sizeof(char)); 1002 sprintf(lpd->probname, "%s"Transform_Quoted(BASE_PROB_NAME)"%u-%u", 1003 StringStart(vdir), gethostid(), getpid()); 1004 if (strlen(lpd->probname) > XP_PROBNAME_MAX) 1005 { 1006 Fprintf(Current_Error, "Eplex error: the problem name for Xpress is too long.\n" 1007 "Change tmp_dir to a directory with shorter path length.\n"); 1008 ec_flush(Current_Error); 1009 Bip_Error(RANGE_ERROR); 1010 } 1011 } 1012#endif 1013 lpd->prob_type = PROBLEM_LP; 1014 lpd->presolve = vpre.nint; 1015 lpd->sense = vsense.nint; 1016 lpd->mac = vcol.nint; 1017 lpd->macsz = vcol.nint; 1018 lpd->macadded = 0; 1019 lpd->nidc = 0; 1020 lpd->marsz = vrow.nint; /* max number of rows */ 1021 lpd->mar = vrow.nint; 1022 lpd->matnz = vnz.nint; /* number of nonzero coefficients */ 1023 1024 /* if vcol/vrow/vnz is 0, malloc arrays of at least size 1. This avoid 1025 calling malloc with size 0, and does create an array (Xpress crashes 1026 if NULL is given in place of an array address in some cases) 1027 This increment should only be done after assigning their original 1028 values to the lpd fields! 1029 1030 */ 1031 if (vcol.nint == 0) vcol.nint++; 1032 if (vrow.nint == 0) vrow.nint++; 1033 if (vnz.nint == 0) vnz.nint++; 1034 lpd->rhsx = (double *) Malloc(vrow.nint * sizeof(double)); 1035 lpd->senx = (char *) Malloc(vrow.nint * sizeof(char)); 1036 1037 /* one extra element for matbeg, because some representations of the 1038 matrix (e.g. COIN) needs the `matbeg' for vcol+1 to be specified, 1039 so that the end of the last column can be determined without matcnt 1040 */ 1041 lpd->matbeg = (int *) Malloc((1+vcol.nint) * sizeof(int)); 1042 lpd->matcnt = (int *) Malloc(vcol.nint * sizeof(int)); 1043 lpd->matind = (int *) Malloc(vnz.nint * sizeof(int)); 1044 lpd->matval = (double *) Malloc(vnz.nint * sizeof(double)); 1045 1046 lpd->bdl = (double *) Malloc(vcol.nint * sizeof(double)); 1047 lpd->bdu = (double *) Malloc(vcol.nint * sizeof(double)); 1048 lpd->dirtybdflag = 0; 1049 lpd->objx = (double *) Malloc(vcol.nint * sizeof(double)); 1050 lpd->ctype = (char *) Malloc(vcol.nint * sizeof(char)); 1051 for (i = 0; i < vcol.nint; i++) 1052 { 1053 lpd->bdl[i] = -CPX_INFBOUND; 1054 lpd->bdu[i] = CPX_INFBOUND; 1055 lpd->objx[i] = 0.0; 1056 lpd->ctype[i] = 'C'; 1057 } 1058 1059 /* the cutpools fields in lpd should all be zero/NULL at this point, so 1060 they do not need to be initialised 1061 */ 1062 1063 lpd->descr_state = DESCR_LOADED; 1064 1065 lpd->mipstart_dirty = 0; 1066 1067 {/* Return the cplex descriptor in argument HANDLE_CPH of the handle structure. */ 1068 vhandle.ptr[HANDLE_CPH] = ec_handle(&lp_handle_tid, lpd); 1069 Make_Stamp(vhandle.ptr+HANDLE_STAMP); /* needed for other trail undos */ 1070 } 1071 Succeed; 1072} 1073 1074 1075int 1076p_cpx_get_prob_param(value vlp, type tlp, value vp, type tp, value vval, type tval) 1077{ 1078 lp_desc *lpd; 1079 int i; 1080 Check_Integer(tp); 1081 LpDesc(vlp, tlp, lpd); 1082 switch(vp.nint) 1083 { 1084 case 0: i = lpd->mar; break; 1085 case 1: i = lpd->mac; break; 1086 case 3: i = lpd->sense; break; 1087 case 4: i = lpd->prob_type; break; 1088 case 5: i = lpd->optimum_ctr; break; 1089 case 6: i = lpd->infeas_ctr; break; 1090 case 7: i = lpd->abort_ctr; break; 1091 case 8: i = lpd->sol_itcnt; break; 1092 case 9: i = lpd->sol_nodnum; break; 1093 case 10: i = lpd->descr_state; break; 1094 case 11: i = lpd->sol_state; break; 1095 case 12: CPXupdatemodel(lpd->lp); 1096 i = CPXgetnumnz(cpx_env, lpd->lp); break; 1097 case 13: CPXupdatemodel(lpd->lp); 1098 i = IsMIPProb(lpd->prob_type) ? 1099 CPXgetnumint(cpx_env, lpd->lp) + CPXgetnumbin(cpx_env, lpd->lp) : 0; 1100 break; 1101 case 14: CPXupdatemodel(lpd->lp); 1102 i = IsQPProb(lpd->prob_type) ? CPXgetnumqpnz(cpx_env, lpd->lp) : 0; 1103 break; 1104 case 15: i = lpd->start_mac; break; 1105/* case 16: i = lpd->cp_nr; break;*/ 1106 case 17: i = lpd->cp_nr2; break; 1107 case 18: i = lpd->cp_nact2; break; 1108 default: 1109 Bip_Error(RANGE_ERROR); 1110 } 1111 Return_Unify_Integer(vval, tval, i); 1112} 1113 1114 1115int 1116p_cpx_get_param(value vlp, type tlp, value vp, type tp, value vval, type tval) 1117{ 1118 double dres; 1119 int i, ires; 1120 char sres[STRBUFFERSIZE]; 1121 lp_desc *lpd; 1122 1123#ifndef COIN 1124 if (!cpx_env) 1125 { 1126 Bip_Error(EC_LICENSE_ERROR); 1127 } 1128#endif 1129 /* lpd is NULL for global/default param */ 1130 if (IsHandle(tlp)) { 1131 LpDesc(vlp, tlp, lpd); 1132 if (!lpd->lp) lpd = NULL; 1133 } else lpd = NULL; 1134 1135 if (IsAtom(tp)) 1136 { 1137 for(i=0; i<NUMPARAMS+NUMALIASES; ++i) /* lookup the parameter name */ 1138 { 1139 if (strcmp(params[i].name, DidName(vp.did)) == 0) 1140 break; 1141 } 1142 if (i==NUMPARAMS+NUMALIASES) 1143 { 1144 Bip_Error(RANGE_ERROR); 1145 } 1146 if (params[i].type == 0 && 1147 Get_Int_Param(cpx_env, lpd, params[i].num, &ires) 1148 == 0) 1149 { 1150 Return_Unify_Integer(vval, tval, ires); 1151 } 1152 if (params[i].type == 1 && 1153 Get_Dbl_Param(cpx_env, lpd, params[i].num, &dres) 1154 == 0) 1155 { 1156 Return_Unify_Float(vval, tval, dres); 1157 } 1158#ifdef SOLVER_HAS_STR_PARAMS 1159 if (params[i].type == 2 && 1160 Get_Str_Param(cpx_env, lpd, params[i].num, sres) 1161 == 0) 1162 { 1163 value val; 1164 Check_Output_String(tval); 1165 Cstring_To_Prolog(sres, val); 1166 Return_Unify_String(vval, tval, val.ptr); 1167 } 1168#endif 1169#ifdef COIN 1170 if (params[i].type == 3 && 1171 coin_get_solver_intparam((lpd==NULL ? cpx_env : lpd->lp), 1172 params[i].num, &ires) 1173 == 0) 1174 { 1175 Return_Unify_Integer(vval, tval, ires); 1176 } 1177 if (params[i].type == 4 && 1178 coin_get_solver_dblparam((lpd==NULL ? cpx_env : lpd->lp), 1179 params[i].num, &dres) 1180 == 0) 1181 { 1182 Return_Unify_Float(vval, tval, dres); 1183 } 1184 if (params[i].type == 6 && 1185 coin_get_eplex_intparam((lpd==NULL ? cpx_env : lpd->lp), 1186 params[i].num, &ires) 1187 == 0) 1188 { 1189 Return_Unify_Integer(vval, tval, ires); 1190 } 1191 if (params[i].type == 8 && 1192 coin_get_eplex_strparam((lpd==NULL ? cpx_env : lpd->lp), 1193 params[i].num, sres) 1194 == 0) 1195 { 1196 value val; 1197 Check_Output_String(tval); 1198 Cstring_To_Prolog(sres, val); 1199 Return_Unify_String(vval, tval, val.ptr); 1200 } 1201#endif 1202 1203 Bip_Error(TYPE_ERROR); /* occurs only if params[i].type is wrong */ 1204 } 1205 Check_Integer(tp); 1206 switch (vp.nint) 1207 { 1208 case -1: /* get optimizer code */ 1209 Return_Unify_Atom(vval, tval, d_optimizer); 1210 1211 case -2: /* get optimizer version */ 1212#ifdef COIN 1213 { 1214 char * ver = Malloc(32*sizeof(char)); 1215 pword pw; 1216 1217 coin_get_solver_info(ver); 1218 Make_String(&pw, ver); 1219 Free(ver); 1220 1221 Return_Unify_Pw(vval, tval, pw.val, pw.tag); 1222 } 1223#else 1224 Return_Unify_Integer(vval, tval, SOLVER_VERSION_INT); 1225#endif 1226 1227 case -3: /* has_qp */ 1228#ifdef HAS_QUADRATIC 1229 Return_Unify_Atom(vval, tval, d_yes); 1230#else 1231 Return_Unify_Atom(vval, tval, d_no); 1232#endif 1233 1234 case -4: /* has_miqp */ 1235#ifdef HAS_MIQP 1236 Return_Unify_Atom(vval, tval, d_yes); 1237#else 1238 Return_Unify_Atom(vval, tval, d_no); 1239#endif 1240 1241 case -5: /* has_indicator_constraints */ 1242#ifdef HAS_INDICATOR_CONSTRAINTS 1243 Return_Unify_Atom(vval, tval, d_yes); 1244#else 1245 Return_Unify_Atom(vval, tval, d_no); 1246#endif 1247 1248 default: 1249 Bip_Error(RANGE_ERROR); 1250 } 1251} 1252 1253 1254int 1255p_cpx_set_param(value vlp, type tlp, value vp, type tp, value vval, type tval) 1256/* fails if parameter unknown */ 1257{ 1258 int i; 1259 int err = 1; 1260 lp_desc *lpd; 1261 1262 Check_Atom(tp); 1263#ifndef COIN 1264 if (!cpx_env) 1265 { 1266 Bip_Error(EC_LICENSE_ERROR); 1267 } 1268#endif 1269 /* lpd is NULL for global/default param */ 1270 if (IsHandle(tlp)) { 1271 LpDesc(vlp, tlp, lpd); 1272 if (!lpd->lp) lpd = NULL; 1273 } else lpd = NULL; 1274 1275#ifndef SOLVER_HAS_LOCAL_PARAMETERS 1276 if (lpd != NULL) 1277 { 1278 Fprintf(Current_Error, "Eplex error: per solver instance parameters are not supported for this solver. Use global parameters instead.\n"); 1279 Bip_Error(UNIMPLEMENTED); 1280 } 1281#endif 1282 for(i=0; i<NUMPARAMS+NUMALIASES; ++i) /* lookup the parameter name */ 1283 { 1284 if (strcmp(params[i].name, DidName(vp.did)) == 0) 1285 break; 1286 } 1287 if (i==NUMPARAMS+NUMALIASES) 1288 { 1289 Fail; 1290 } 1291 if (params[i].type == 0 && IsInteger(tval)) 1292 { 1293 /* Log4 because Set_Int_Param expands into 4 arg for Xpress */ 1294 Log4(Set_Int_Param(cpx_env, lpd, %d, %d), params[i].num, vval.nint, 1295 params[i].num, vval.nint); 1296 err = Set_Int_Param(cpx_env, lpd, params[i].num, vval.nint); 1297 } 1298 else if (params[i].type == 1 && IsDouble(tval)) 1299 { 1300 Log4(Set_Dbl_Param(cpx_env, lpd, %d, %f), params[i].num, Dbl(vval), 1301 params[i].num, Dbl(vval)); 1302 err = Set_Dbl_Param(cpx_env, lpd, params[i].num, Dbl(vval)); 1303 } 1304#ifdef SOLVER_HAS_STR_PARAMS 1305 else if (params[i].type == 2 && (IsAtom(tval) || IsString(tval))) 1306 { 1307 char *s = IsAtom(tval)? DidName(vval.did): StringStart(vval); 1308 1309 if (strlen(s) >= STRBUFFERSIZE) Bip_Error(RANGE_ERROR);/*too large*/ 1310 Call(err, Set_Str_Param(cpx_env, lpd, params[i].num, s)); 1311 } 1312#endif 1313#if defined(XPRESS) && defined(WIN32) 1314 else if (params[i].type == 3 && (IsAtom(tval) || IsString(tval))) 1315 { 1316 char *s = IsAtom(tval)? DidName(vval.did): StringStart(vval); 1317 err = XPRSsetlogfile(lpd->lp, s); 1318 } 1319#endif 1320#ifdef COIN 1321 /* Solver dependent parameters */ 1322 else if (params[i].type == 3 && IsInteger(tval)) 1323 { 1324 err = coin_set_solver_intparam((lpd == NULL ? cpx_env : lpd->lp), params[i].num, vval.nint); 1325 } 1326 else if (params[i].type == 4 && IsDouble(tval)) 1327 { 1328 err = coin_set_solver_dblparam((lpd == NULL ? cpx_env : lpd->lp), params[i].num, Dbl(vval)); 1329 } 1330 else if (params[i].type == 6 && IsInteger(tval)) 1331 { 1332 err = coin_set_eplex_intparam((lpd == NULL ? cpx_env : lpd->lp), params[i].num, vval.nint); 1333 } 1334 /* no double params defined yet 1335 else if (params[i].type == 7 && IsDouble(tval)) 1336 { 1337 err = coin_set_eplex_dblparam((lpd == NULL ? cpx_env : lpd->lp), params[i].num, Dbl(vval)); 1338 } 1339 */ 1340 else if (params[i].type == 8 && (IsAtom(tval) || IsString(tval))) 1341 { 1342 char *s = IsAtom(tval)? DidName(vval.did): StringStart(vval); 1343 err = coin_set_eplex_strparam((lpd == NULL ? cpx_env : lpd->lp), params[i].num, s); 1344 } 1345#endif 1346 if (err) { 1347 Bip_Error(TYPE_ERROR); 1348 } 1349 Succeed; 1350} 1351 1352 1353/*----------------------------------------------------------------------* 1354 * Message and error output 1355 *----------------------------------------------------------------------*/ 1356 1357#ifdef CPLEX 1358 1359static void CPXPUBLIC 1360# if CPLEX >= 8 1361eclipse_out(void * nst, const char * msg) 1362# else 1363eclipse_out(void * nst, char * msg) 1364# endif 1365{ 1366 (void) ec_outf((stream_id) nst, msg, strlen(msg)); 1367 (void) ec_flush((stream_id) nst); 1368} 1369 1370 1371int 1372p_cpx_output_stream(value vc, type tc, value vwhat, type twhat, value vs, type ts) 1373{ 1374 stream_id nst; 1375 CPXCHANNELptr ch; 1376 pword pw; 1377 int err; 1378 1379 if (!cpx_env) 1380 { 1381 Bip_Error(EC_LICENSE_ERROR); 1382 } 1383 pw.val = vs; pw.tag = ts; 1384 err = ec_get_stream(pw, &nst); 1385 if (err) { Bip_Error(err); } 1386 Check_Integer(tc); 1387 switch (vc.nint) { 1388 case 0: ch = cpxresults; break; 1389 case 1: ch = cpxerror; break; 1390 case 2: ch = cpxwarning; break; 1391 case 3: ch = cpxlog; break; 1392 default: Bip_Error(RANGE_ERROR); 1393 } 1394 Check_Integer(twhat); 1395 if (vwhat.nint == 0) 1396 { 1397 CPXdelfuncdest(cpx_env, ch, (void *) nst, eclipse_out); 1398 } else { 1399 /* raise error only if adding a stream */ 1400 if (CPXaddfuncdest(cpx_env, ch, (void *) nst, eclipse_out)) 1401 { Bip_Error(EC_EXTERNAL_ERROR); } 1402 } 1403 Succeed; 1404} 1405 1406#else 1407 1408# ifdef XPRESS 1409static void XPRS_CC 1410eclipse_out(XPRSprob lp, void * obj, const char * msg, int len, int msgtype) 1411{ 1412 if (msgtype >= 1 && msgtype <= 4) 1413 { 1414 /* filter out and not print unwanted messages */ 1415 if (msgtype == 3) 1416 { 1417 /* it seems that there are no other way of filtering out 1418 warning messages than to check the msg string 1419 */ 1420 if (strncmp(msg, "?140 ", 5) == 0) return; /* basis lost */ 1421 if (strncmp(msg, "?359 ", 5) == 0) return; /* illegal int bounds */ 1422 } 1423 /* Fprintf(solver_streams[msgtype-1], "*%d*", msgtype); */ 1424 (void) ec_outf(solver_streams[msgtype-1], (char*) msg, len); 1425 (void) ec_newline(solver_streams[msgtype-1]); 1426 } 1427 /* flushing is done in cleanup */ 1428} 1429 1430# endif 1431# ifdef COIN 1432 1433void 1434eclipse_out(int msgtype, const char* message) 1435{ 1436 1437 (void) ec_outf(solver_streams[msgtype], message, strlen(message)); 1438 (void) ec_newline(solver_streams[msgtype]); 1439 1440} 1441 1442# endif 1443 1444int 1445p_cpx_output_stream(value vc, type tc, value vwhat, type twhat, value vs, type ts) 1446{ 1447 stream_id nst; 1448 stream_id *solver_stream; 1449 pword pw; 1450 int err; 1451 1452# ifdef XPRESS 1453 if (!cpx_env) 1454 { 1455 Bip_Error(EC_LICENSE_ERROR); 1456 } 1457# endif 1458 pw.val = vs; pw.tag = ts; 1459 err = ec_get_stream(pw, &nst); 1460 if (err) { Bip_Error(err); } 1461 Check_Integer(tc); 1462 Check_Integer(twhat); 1463 switch (vc.nint) { 1464 case 0: solver_stream = &solver_streams[ResType]; break; 1465 case 1: solver_stream = &solver_streams[ErrType]; break; 1466 case 2: solver_stream = &solver_streams[WrnType]; break; 1467 case 3: solver_stream = &solver_streams[LogType]; break; 1468 default: Bip_Error(RANGE_ERROR); 1469 } 1470 if (vwhat.nint == 1) 1471 *solver_stream = nst; 1472 else if (*solver_stream == nst) 1473 *solver_stream = Current_Null; 1474 Succeed; 1475} 1476 1477#endif 1478 1479/*----------------------------------------------------------------------* 1480 * Initial setup 1481 *----------------------------------------------------------------------*/ 1482 1483int 1484p_cpx_get_rhs(value vlp, type tlp, value vpool, type tpool, value vi, type ti, 1485 value vsense, type tsense, value vval, type tval) 1486{ 1487 lp_desc *lpd; 1488 Prepare_Requests 1489 double rhs[1]; 1490 char sen[1]; 1491 dident sense; 1492 1493 LpDesc(vlp, tlp, lpd); 1494 switch (vpool.nint) 1495 { 1496 case CSTR_TYPE_NORM: 1497 SetPreSolve(lpd->presolve); 1498 CPXupdatemodel(lpd->lp); /* before CPXget... */ 1499 if (CPXgetrhs(cpx_env, lpd->lp, rhs, (int) vi.nint, (int) vi.nint)) 1500 { Bip_Error(EC_EXTERNAL_ERROR); } 1501 if (CPXgetsense(cpx_env, lpd->lp, sen, (int) vi.nint, (int) vi.nint)) 1502 { Bip_Error(EC_EXTERNAL_ERROR); } 1503 break; 1504/* 1505 case CSTR_TYPE_PERMCP: 1506 sen[0] = lpd->cp_senx[vi.nint]; 1507 rhs[0] = lpd->cp_rhsx[vi.nint]; 1508 break; 1509*/ 1510 case CSTR_TYPE_CONDCP: 1511 sen[0] = lpd->cp_senx2[vi.nint]; 1512 rhs[0] = lpd->cp_rhsx2[vi.nint]; 1513 break; 1514 default: 1515 Bip_Error(RANGE_ERROR); 1516 break; 1517 } 1518 1519 sense = sen[0] == SOLVER_SENSE_LE ? d_le : 1520 sen[0] == SOLVER_SENSE_GE ? d_ge : d_eq; 1521 Request_Unify_Atom(vsense, tsense, sense); 1522 Request_Unify_Float(vval, tval, rhs[0]); 1523 1524 Return_Unify; 1525} 1526 1527int 1528p_cpx_set_rhs_coeff(value vlp, type tlp, value vi, type ti, value vsense, type tsense, value vval, type tval) 1529{ 1530 lp_desc *lpd; 1531 LpDescOnly(vlp, tlp, lpd); 1532 Check_Integer(ti); 1533 Check_Number(tval); 1534 if (vi.nint >= lpd->marsz) { Bip_Error(RANGE_ERROR); } 1535 Check_Atom(tsense); 1536 if (vsense.did == d_le) lpd->senx[vi.nint] = SOLVER_SENSE_LE; 1537 else if (vsense.did == d_ge) lpd->senx[vi.nint] = SOLVER_SENSE_GE; 1538 else if (vsense.did == d_eq) lpd->senx[vi.nint] = SOLVER_SENSE_EQ; 1539 else { Bip_Error(RANGE_ERROR); } 1540 lpd->rhsx[vi.nint] = DoubleVal(vval, tval); 1541 Check_Constant_Range(lpd->rhsx[vi.nint]); 1542 Succeed; 1543} 1544 1545int 1546p_cpx_set_obj_coeff(value vlp, type tlp, value vj, type tj, value vval, type tval) 1547{ 1548 lp_desc *lpd; 1549 int j; 1550 1551 LpDescOnly(vlp, tlp, lpd); 1552 Check_Integer(tj); 1553 Check_Number(tval); 1554 j = vj.nint; 1555 1556 if (j >= lpd->mac) { Bip_Error(RANGE_ERROR); } 1557 if (j >= lpd->macadded) j -= lpd->macadded; /* added col */ 1558 1559 lpd->objx[j] = DoubleVal(vval, tval); 1560 Check_Constant_Range(lpd->objx[j]); 1561 Succeed; 1562} 1563 1564#if 0 1565int 1566p_cpx_get_obj_coeff(value vlp, type tlp, value vj, type tj, value vval, type tval) 1567{ 1568 lp_desc *lpd; 1569 LpDescOnly(vlp, tlp, lpd); 1570 Check_Integer(tj); 1571 if (vj.nint >= lpd->mac) { Bip_Error(RANGE_ERROR); } 1572 Return_Unify_Float(vval, tval, lpd->objx[vj.nint]); 1573} 1574#endif 1575 1576int 1577p_cpx_set_qobj_coeff(value vlp, type tlp, value vi, type ti, value vj, type tj, value vval, type tval) 1578{ 1579 lp_desc *lpd; 1580 double coef; 1581 int i; 1582 LpDescOnly(vlp, tlp, lpd); 1583 Check_Integer(ti); 1584 Check_Integer(tj); 1585 Check_Number(tval); 1586 if (IsInteger(tval)) { 1587 coef = (double) vval.nint; 1588 } else { 1589 Check_Float(tval); 1590 coef = DoubleVal(vval, tval); 1591 Check_Constant_Range(coef); 1592 } 1593 if (vj.nint >= lpd->mac || vi.nint >= lpd->mac) { Bip_Error(RANGE_ERROR); } 1594 1595 if (lpd->cb_cnt == 0) /* first quadratic coefficient */ 1596 { 1597 /* change the problem type to quadratic if linear */ 1598 switch (lpd->prob_type) 1599 { 1600 case PROBLEM_LP: 1601 lpd->prob_type = PROBLEM_QP; 1602 break; 1603 case PROBLEM_MIP: 1604 lpd->prob_type = PROBLEM_MIQP; 1605 break; 1606 case PROBLEM_QP: 1607 case PROBLEM_MIQP: 1608 /* nothing to be done if already quadratic */ 1609 break; 1610 default: 1611 Fprintf(Current_Error, 1612 "Eplex error: quadratic objective coefficients cannot be added to problem type %d\n.", 1613 lpd->prob_type); 1614 Bip_Error(RANGE_ERROR); 1615 } 1616 } 1617 if (lpd->cb_cnt >= lpd->cb_sz) /* grow arrays if necessary */ 1618 _grow_cb_arrays(lpd, 1); 1619 i = lpd->cb_cnt++; 1620 lpd->cb_index[i] = vi.nint; 1621 lpd->cb_index2[i] = vj.nint; 1622 lpd->cb_value[i] = vi.nint==vj.nint ? 2*coef : coef; 1623 Succeed; 1624} 1625 1626 1627int 1628p_cpx_load_varname(value vlp, type tlp, value vj, type tj, value vname, type tname) 1629{ 1630 lp_desc *lpd; 1631 1632 1633#ifdef XPRESS 1634 int maxlen = 128; 1635 size_t namelen; 1636 char buffer[128]; 1637#endif 1638 1639 Check_Integer(tj); 1640 Check_String(tname); 1641 LpDesc(vlp, tlp, lpd); 1642 if (vj.nint >= lpd->mac) { Bip_Error(RANGE_ERROR); } 1643 1644#ifdef XPRESS 1645 /* need to use temp. buffer in XPRESS as string is length limited */ 1646 namelen = strlen(StringStart(vname)); 1647 if (maxlen >= (int) namelen) { 1648 /* just in case the call fails, assign some maxlen in that case */ 1649 if (XPRSgetintcontrol(lpd->lp, XPRS_MPSNAMELENGTH, &maxlen) != 0) maxlen = 8; 1650 strcpy(buffer, StringStart(vname)); 1651 } else { 1652 strncpy(buffer, StringStart(vname), (size_t) maxlen); 1653 buffer[maxlen] = '\0'; 1654 } 1655 Log5({ 1656 char buffer[%d]; 1657 strncpy(buffer, "%s", %d); 1658 XPRSaddnames(lpd->lp, 2, buffer, %d, %d); 1659 }, maxlen, buffer, maxlen, vj.nint, vj.nint); 1660 XPRSaddnames(lpd->lp, 2, buffer, vj.nint, vj.nint); 1661 1662#else 1663 /* this assumes that vname.str will be copied upto first \0 */ 1664 /* we use CPXchgname() as this is in version 4 */ 1665 Log2(CPXchgname(cpx_env, lpd->lp, 'c', %d, %s), vj.nint, StringStart(vname)); 1666 CPXchgname(cpx_env, lpd->lp, 'c', vj.nint, StringStart(vname)); 1667#endif 1668 Succeed; 1669} 1670 1671 1672/*----------------------------------------------------------------------* 1673 * Changing rhs 1674 * cplex_change_rhs(++CPH, ++Size, ++RowIdxs, ++RhsCoeffs) 1675 * Changes the rhs coefficients. RowIdxs and RhsCoeffs are lists of length 1676 * Size. There is no provision for backtracking: the changes should be 1677 * undone with another call to cplex_change_rhs 1678 */ 1679int 1680p_cpx_change_rhs(value vlp, type tlp, value vsize, type tsize, 1681 value vidxs, type tidxs, value vvals, type tvals) 1682{ 1683 lp_desc *lpd; 1684 int i, err; 1685 1686 LpDesc(vlp, tlp, lpd); 1687 Check_Integer(tsize); 1688 1689 if (vsize.nint > 0) 1690 { 1691 double *rhs = (double *) Malloc(vsize.nint * sizeof(double)); 1692 int *idxs = (int *) Malloc(vsize.nint * sizeof(int)); 1693 1694 for (i=0; i<vsize.nint; ++i) 1695 { 1696 if (IsList(tidxs) && IsList(tvals)) 1697 { 1698 pword *ihead = vidxs.ptr; 1699 pword *itail = ihead + 1; 1700 pword *vhead = vvals.ptr; 1701 pword *vtail = vhead + 1; 1702 1703 Dereference_(ihead); 1704 Dereference_(vhead); 1705 if (!IsInteger(ihead->tag) || !IsNumber(vhead->tag)) 1706 { 1707 Free(idxs); 1708 Free(rhs); 1709 Bip_Error(TYPE_ERROR); 1710 } 1711 idxs[i] = ihead->val.nint; 1712 rhs[i] = DoubleVal(vhead->val, vhead->tag); 1713 /* check that the row index and rhs value are in range... */ 1714 if (idxs[i] < 0 || idxs[i] >= lpd->mar || 1715 rhs[i] < -CPX_INFBOUND || rhs[i] > CPX_INFBOUND) 1716 { 1717 Free(idxs); 1718 Free(rhs); 1719 Bip_Error(RANGE_ERROR); 1720 } 1721 1722 Dereference_(itail); 1723 Dereference_(vtail); 1724 tidxs = itail->tag; 1725 vidxs = itail->val; 1726 tvals = vtail->tag; 1727 vvals = vtail->val; 1728 } 1729 else 1730 { 1731 Free(idxs); 1732 Free(rhs); 1733 Bip_Error(TYPE_ERROR); 1734 } 1735 } 1736 1737 Call(err, CPXchgrhs(cpx_env, lpd->lp, vsize.nint, idxs, rhs)); 1738 1739 Free(idxs); 1740 Free(rhs); 1741 if (err) { Bip_Error(EC_EXTERNAL_ERROR); } 1742 } 1743 1744 Succeed; 1745} 1746 1747/*----------------------------------------------------------------------* 1748 * Changing column bounds 1749 * cplex_change_cols_bounds(++CPH, ++Size, ++Idxs, ++Los, ++His) 1750 * Changes the lower and upper bounds of columns. Idxs, Los, His are 1751 * lists of length Size. There is no provision for backtracking: the 1752 * changes should be undone with another call to cplex_change_cols_bounds 1753 * 1754 */ 1755int 1756p_cpx_change_cols_bounds(value vlp, type tlp, value vsize, type tsize, 1757 value vidxs, type tidxs, value vlos, type tlos, value vhis, type this) 1758{ 1759 lp_desc *lpd; 1760 int i, err, size; 1761 1762 LpDesc(vlp, tlp, lpd); 1763 Check_Integer(tsize); 1764 1765 size = vsize.nint*2; 1766 if (size > 0) 1767 { 1768 double *bds = (double *) Malloc(size * sizeof(double)); 1769 int *idxs = (int *) Malloc(size * sizeof(double)); 1770 char *types = (char *) Malloc(size * sizeof(char)); 1771 1772 for (i=0; i<size; ) 1773 { 1774 if (IsList(tidxs) && IsList(tlos) && IsList(this)) 1775 { 1776 pword *ihead = vidxs.ptr; 1777 pword *itail = ihead + 1; 1778 pword *lohead = vlos.ptr; 1779 pword *lotail = lohead + 1; 1780 pword *uphead = vhis.ptr; 1781 pword *uptail = uphead + 1; 1782 1783 Dereference_(ihead); 1784 Dereference_(lohead); 1785 Dereference_(uphead); 1786 if (!IsInteger(ihead->tag) || !IsNumber(lohead->tag) || 1787 !IsNumber(uphead->tag)) 1788 { 1789 Free(bds); 1790 Free(idxs); 1791 Free(types); 1792 Bip_Error(TYPE_ERROR); 1793 } 1794 idxs[i] = ihead->val.nint; 1795 if (idxs[i] < 0 || idxs[i] >= lpd->mac) 1796 { 1797 Free(bds); 1798 Free(idxs); 1799 Free(types); 1800 Bip_Error(RANGE_ERROR); 1801 } 1802 bds[i] = DoubleVal(lohead->val, lohead->tag); 1803 if (bds[i] <= -CPX_INFBOUND) bds[i] = -CPX_INFBOUND; 1804 types[i++] = 'L'; 1805 1806 idxs[i] = ihead->val.nint; 1807 bds[i] = DoubleVal(uphead->val, uphead->tag); 1808 if (bds[i] >= CPX_INFBOUND) bds[i] = CPX_INFBOUND; 1809 if (bds[i] < bds[i-1]) 1810 { 1811 Free(bds); 1812 Free(idxs); 1813 Free(types); 1814 Fail; 1815 } 1816 types[i++] = 'U'; 1817 1818 Dereference_(itail); 1819 Dereference_(lotail); 1820 Dereference_(uptail); 1821 tidxs = itail->tag; 1822 vidxs = itail->val; 1823 tlos = lotail->tag; 1824 vlos = lotail->val; 1825 this = uptail->tag; 1826 vhis = uptail->val; 1827 } else 1828 { 1829 Free(bds); 1830 Free(idxs); 1831 Free(types); 1832 Bip_Error(TYPE_ERROR); 1833 } 1834 } 1835 1836 Call(err, CPXchgbds(cpx_env, lpd->lp, size, idxs, types, bds)); 1837 Free(bds); 1838 Free(idxs); 1839 Free(types); 1840 1841 if (err) { Bip_Error(EC_EXTERNAL_ERROR); } 1842 } 1843 1844 Succeed; 1845} 1846 1847int 1848p_cpx_lo_hi(value vlo, type tlo, value vhi, type thi) 1849{ 1850 Prepare_Requests; 1851 Request_Unify_Float(vlo, tlo, -CPX_INFBOUND); 1852 Request_Unify_Float(vhi, thi, CPX_INFBOUND); 1853 Return_Unify; 1854} 1855 1856/*----------------------------------------------------------------------* 1857 * Changing problem type 1858 */ 1859 1860static void _cpx_reset_probtype ARGS((pword*,word*,int,int)); 1861 1862static void 1863_cpx_reset_probtype(pword * pw, word * pdata, int size, int flags) 1864{ 1865 int err; 1866 lp_desc *lpd = ExternalData(pw[HANDLE_CPH].val.ptr); 1867 1868 if (!lpd) 1869 return; /* stale handle */ 1870 1871 if (lpd->descr_state != DESCR_EMPTY) 1872 { 1873#ifdef CPLEX 1874 switch (((untrail_ptype*) pdata)->old_ptype) 1875 { 1876 case PROBLEM_LP: 1877 Call(err, CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_LP)); 1878 break; 1879 case PROBLEM_QP: 1880 Call(err, CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_QP)); 1881 break; 1882 default: 1883 Fprintf(Current_Error, "Eplex problem: Trying to reset an Eplex problem to a unsupported type: %i.\n", 1884 ((untrail_ptype*) pdata)->old_ptype); 1885 ec_flush(Current_Error); 1886 return; 1887 1888 } 1889#endif 1890 lpd->prob_type = ((untrail_ptype*) pdata)->old_ptype; 1891#ifdef SOLVE_MIP_COPY 1892 if (lpd->copystatus != XP_COPYOFF && lpd->lp != lpd->lpcopy) 1893 { 1894 CallN(XPRSdestroyprob(lpd->lpcopy)); 1895 CallN(lpd->lpcopy = lpd->lp); 1896 Mark_Copy_As_Modified(lpd); 1897 } 1898#endif 1899 } 1900} 1901 1902int 1903p_cpx_change_lp_to_mip(value vhandle, type thandle) 1904{ 1905 lp_desc *lpd; 1906 int err; 1907 untrail_ptype pdata; 1908 1909 LpDesc(vhandle.ptr[HANDLE_CPH].val, vhandle.ptr[HANDLE_CPH].tag, lpd); 1910 pdata.old_ptype = lpd->prob_type; 1911 1912 /* all columns are assumed to be type 'C' by changing to MIP. Any 1913 integer columns will be set explicitly later 1914 */ 1915 switch (pdata.old_ptype) 1916 { 1917 case PROBLEM_LP: 1918 lpd->prob_type = PROBLEM_MIP; 1919 Call(err, CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_MILP)); 1920 break; 1921 case PROBLEM_QP: 1922#ifdef HAS_MIQP 1923 lpd->prob_type = PROBLEM_MIQP; 1924 Call(err, CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_MIQP)); 1925#else 1926 Fprintf(Current_Error, "Eplex error: this solver does not support solving of quadratic MIP problems.\n"); 1927 ec_flush(Current_Error); 1928 Bip_Error(UNIMPLEMENTED); 1929#endif 1930 break; 1931 case PROBLEM_MIQP: 1932 case PROBLEM_MIP: 1933 return PSUCCEED; 1934 default: 1935 Fprintf(Current_Error, "Eplex error: trying to change problem to mixed integer from an unexpected state.\n"); 1936 ec_flush(Current_Error); 1937 Bip_Error(RANGE_ERROR); 1938 break; 1939 } 1940 1941 if (err) { Bip_Error(EC_EXTERNAL_ERROR); } 1942 1943#ifdef SOLVE_MIP_COPY 1944 if (lpd->copystatus != XP_COPYOFF) 1945 { 1946 Call(err, XPRScreateprob(&lpd->lpcopy)); 1947 if (err) { Bip_Error(EC_EXTERNAL_ERROR); } 1948 Mark_Copy_As_Modified(lpd); 1949 } 1950#endif 1951 ec_trail_undo(_cpx_reset_probtype, vhandle.ptr, NULL, (word*)&pdata, NumberOfWords(untrail_ptype), TRAILED_WORD32); 1952 return PSUCCEED; 1953} 1954 1955/* cplex_set_problem_type(CPH, ProbType, SetSolverType) 1956 1957 changes the problem type to ProbType. Used to set and reset the problem 1958 type during probing, when the problem type might be changed temporarily. 1959 SetSolverType applies to external solvers which has its own problem type 1960 (currently CPLEX): it specifies if the external solver's problem type 1961 should be set as well (1 = yes, 0 = no). CPLEX's problem type cannot 1962 always be changed when setting a problem type before a probe, e.g. 1963 CPXPROB_FIXEDMILP/MIQP can only be set if there is already a MILP/MIQP 1964 solution. Therefore, in these cases, the solver's problem type is only 1965 changed during the solving of the problem in p_cpx_optimise(). 1966*/ 1967int 1968p_cpx_set_problem_type(value vlp, type tlp, value vtype, type ttype, 1969 value vsetsolver, type tsetsolver) 1970{ 1971 lp_desc *lpd; 1972 LpDescOnly(vlp, tlp, lpd); 1973 1974 Check_Integer(ttype); 1975 Check_Integer(tsetsolver); 1976#ifdef CPLEX 1977 if (vsetsolver.nint == 1) 1978 { 1979 int err; 1980 switch (vtype.nint) 1981 { 1982 case PROBLEM_LP: 1983 Call(err,CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_LP)); 1984 break; 1985 case PROBLEM_MIP: 1986# ifndef HAS_RELAXEDLP 1987 if (CPXgetprobtype(cpx_env, lpd->lp) == CPXPROB_LP && 1988 lpd->ctype != NULL) 1989 { 1990 /* this assumes that we have copied the ctype information 1991 of original MIP problem to lpd->ctype 1992 */ 1993 Call(err, CPXcopyctype(cpx_env, lpd->lp, lpd->ctype)); 1994 TryFree(lpd->ctype); 1995 } 1996 else 1997# endif 1998 { 1999 Call(err,CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_MILP)); 2000 } 2001 break; 2002 case PROBLEM_QP: 2003 Call(err,CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_QP)); 2004 break; 2005# ifdef HAS_MIQP 2006 case PROBLEM_MIQP: 2007 if (CPXgetprobtype(cpx_env, lpd->lp) == CPXPROB_QP && 2008 lpd->ctype != NULL) 2009 { 2010 /* this assumes that we have copied the ctype information 2011 of original MIQP problem to lpd->ctype 2012 */ 2013 Call(err, CPXcopyctype(cpx_env, lpd->lp, lpd->ctype)); 2014 TryFree(lpd->ctype); 2015 } 2016 else 2017 { 2018 Call(err,CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_MILP)); 2019 } 2020 break; 2021 case PROBLEM_FIXEDQ: 2022 Call(err, CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_FIXEDMIQP)); 2023 break; 2024# endif 2025 case PROBLEM_FIXEDL: 2026 Call(err,CPXchgprobtype(cpx_env, lpd->lp, CPXPROB_FIXEDMILP)); 2027 break; 2028 default: 2029 Bip_Error(RANGE_ERROR); 2030 } 2031 if (err) Bip_Error(EC_EXTERNAL_ERROR); 2032 } 2033#endif 2034 2035 lpd->prob_type = vtype.nint; 2036 Succeed; 2037} 2038 2039/*----------------------------------------------------------------------* 2040 * Changing column type 2041 */ 2042 2043#define Get_Col_Bounds(j, lo0,hi0) { \ 2044 if (CPXgetlb(cpx_env, lpd->lp, &lo0, j, j)) \ 2045 { Bip_Error(EC_EXTERNAL_ERROR); } \ 2046 if (CPXgetub(cpx_env, lpd->lp, &hi0, j, j)) \ 2047 { Bip_Error(EC_EXTERNAL_ERROR); } \ 2048} 2049 2050#define Change_Col_Bound(j, Which, oldlo, oldhi, newbd, Stamp, changed) {\ 2051 untrail_bound udata; \ 2052 udata.bds[0] = oldlo; \ 2053 udata.bds[1] = oldhi; \ 2054 udata.idx = j; \ 2055 \ 2056 Log3( \ 2057 {\n\ 2058 int myj = %d;\n\ 2059 double bd = %.15e;\n\ 2060 CPXchgbds(cpx_env, lpd->lp, 1, &myj, "%s", &bd);\n\ 2061 }, j, newbd, Which \ 2062 ); \ 2063 \ 2064 CPXchgbds(cpx_env, lpd->lp, 1, &j, Which, &newbd); \ 2065 changed = 1; \ 2066 ec_trail_undo(_cpx_restore_bounds, vhandle.ptr, \ 2067 Stamp, (word *) &udata, \ 2068 NumberOfWords(untrail_bound), TRAILED_WORD32); \ 2069} 2070 2071 2072static void _cpx_restore_bounds ARGS((pword*,word*,int,int)); 2073 2074static void _cpx_reset_col_type ARGS((pword*,word*,int,int)); 2075 2076int 2077p_cpx_change_col_type(value vhandle, type thandle, 2078 value vj, type tj, 2079 value vtype, type ttype) 2080{ 2081 int idx[1], res; 2082 char ctype[1]; 2083 untrail_ctype udata; 2084 lp_desc *lpd; 2085#if defined(HAS_NARROW_INT_RANGE) || defined(HAS_INTLB_BUG) 2086 double lo0, hi0; 2087#endif 2088 2089 Check_Structure(thandle); 2090 LpDesc(vhandle.ptr[HANDLE_CPH].val, vhandle.ptr[HANDLE_CPH].tag, lpd); 2091 Check_Integer(tj); 2092 2093 if (vj.nint >= lpd->mac || vj.nint < 0) { Bip_Error(RANGE_ERROR); } 2094 2095 SetPreSolve(lpd->presolve); 2096 Mark_Copy_As_Modified(lpd); 2097 idx[0] = vj.nint; 2098 CPXupdatemodel(lpd->lp); /* before CPXget... */ 2099 res = CPXgetctype(cpx_env, lpd->lp, ctype, vj.nint, vj.nint); 2100 2101 if (res != 0) { Bip_Error(EC_EXTERNAL_ERROR); } 2102 2103 if ((char) vtype.nint != ctype[0]) { 2104 /* only need to change if new column type different */ 2105 udata.idx = vj.nint; 2106 udata.ctype = ctype[0]; 2107 2108 /* if change is from B->I, just ignore it (user could have posted 2109 extra integer constraints) 2110 */ 2111 if (!((char) vtype.nint == 'I' && (char) ctype[0] == 'B')) 2112 { 2113 ctype[0] = (char) vtype.nint; 2114#if defined(HAS_NARROW_INT_RANGE) || defined(HAS_INTLB_BUG) 2115 {/* Xpress 14 likes its integers to have smaller bounds */ 2116 Get_Col_Bounds(idx[0], lo0, hi0); 2117# ifdef HAS_NARROW_INT_RANGE 2118 /* no timestamp on these column bound changes: they will always 2119 be untrailed. This is because the type changes may be 2120 applied to multiple merged columns, and we need to 2121 ensure that the bound change is always undone 2122 */ 2123 if (lo0 < -XPRS_MAXINT) 2124 { 2125 double intbound = -XPRS_MAXINT; 2126 int changed; /* dummy here for the macro */ 2127 Change_Col_Bound(idx[0], "L", lo0, hi0, 2128 intbound, NULL, changed); 2129 lo0 = intbound; /* for HAS_INTLB_BUG below */ 2130 } 2131 if (hi0 > XPRS_MAXINT) 2132 { 2133 double intbound = XPRS_MAXINT; 2134 int changed; /* dummy here for the macro */ 2135 Change_Col_Bound(idx[0], "U", lo0, hi0, 2136 intbound, NULL, changed); 2137 } 2138# endif 2139 } 2140#endif 2141 res = CPXchgctype(cpx_env, lpd->lp, 1, idx, ctype); 2142 Log2( 2143 {int idx[1]; 2144 char ctype[1]; 2145 idx[0] = %d; 2146 ctype[0] = '%c'; 2147 CPXchgctype(cpx_env,lpd->lp,1, idx, ctype); 2148 }, idx[0], ctype[0]); 2149#ifdef HAS_INTLB_BUG 2150 /* After changing a column type to integer, the lower bound is 2151 lost (set to 0) if it was negative (Xpress 13-15) 2152 Reported to Dash 2004-10-19 2153 */ 2154 { 2155 char btype[1]; 2156 double lo1[1]; 2157 2158 btype[0] = 'L'; 2159 lo1[0] = lo0; 2160 2161 XPRSchgbounds(lpd->lp, 1, idx, btype, lo1); 2162 } 2163 Log2({\n\ 2164 int myj = %d;\n\ 2165 double bd = %.15e;\n\ 2166 XPRSchgbounds(lpd->lp, 1, &myj, "L", &bd);\n\ 2167 }, idx[0], lo0); 2168#endif 2169 2170 if (res != 0) { Bip_Error(EC_EXTERNAL_ERROR); } 2171 ec_trail_undo(_cpx_reset_col_type, vhandle.ptr, NULL, (word*)&udata, NumberOfWords(untrail_ctype), TRAILED_WORD32); 2172 } 2173 } 2174 Succeed; 2175} 2176 2177 2178static void _cpx_reset_col_type(pword * phandle, word * udata, int size, int flags) 2179 2180{ 2181 int idx[1]; 2182 char octype[1]; 2183 2184 lp_desc *lpd = ExternalData(phandle[HANDLE_CPH].val.ptr); 2185 2186 if (!lpd) 2187 return; /* stale handle */ 2188 2189 idx[0] = ((untrail_ctype*) udata)->idx; 2190 octype[0] = ((untrail_ctype*) udata)->ctype; 2191 2192#if 0 2193 Fprintf(Current_Error, "Resetting col %d to %c, in gc:%d\n", 2194 idx[0], octype[0], ec_.m.vm_flags & NO_EXIT); 2195 ec_flush(Current_Error); 2196#endif 2197 2198 if (lpd->descr_state != DESCR_EMPTY) 2199 { 2200 Log2( 2201 {int idx[1];\n\ 2202 char octype[1];\n\ 2203 idx[0] = %d;\n\ 2204 octype[0] = '%c';\n\ 2205 CPXchgctype(cpx_env,lpd->lp,1, idx, octype);\n\ 2206 }, idx[0], octype[0]); 2207 2208 if (CPXchgctype(cpx_env, lpd->lp, 1, idx, octype)) 2209 { 2210 Fprintf(Current_Error, "Error in Changing column %d to type %c\n", 2211 idx[0], octype[0]); 2212 ec_flush(Current_Error); 2213 return; 2214 } 2215 Mark_Copy_As_Modified(lpd); 2216 } 2217} 2218 2219 2220/*----------------------------------------------------------------------* 2221 * Adding constraints 2222 *----------------------------------------------------------------------*/ 2223/* 2224 * We first collect the new row/col data in (growable) arrays using 2225 * p_cpx_set_matbeg(), p_cpx_set_matval() and p_cpx_set_obj_coeff() [cols] 2226 * p_cpx_new_row() and p_cpx_add_coeff() [rows]. 2227 * Then, the information is transferred to the solver (and trailed) 2228 * by calling p_cpx_flush_new_rowcols(). 2229 * On failure, the constraints get removed by _cpx_del_rowcols(). 2230 * 2231 * added by AE 25/10/02 2232 * this is for adding rows whose index in the external 2233 * solver we want to know for sure - when we get duals 2234 * in colgen we really have to know we are getting the right 2235 * ones associated with the sp cost function vars 2236 * this requires all variables to have their index already in the attribute 2237 */ 2238 2239#define New_Row(nrs, nr_sz, senx, rhsx, rmatbeg, nnz, sense, vrhs, trhs, ExtraAlloc) {\ 2240 if (nrs+1 >= nr_sz) /* allocate/grow arrays */\ 2241 {\ 2242 CallN(nr_sz += NEWROW_INCR);\ 2243 CallN(senx = (char *) Realloc(senx, nr_sz*sizeof(char)));\ 2244 CallN(rhsx = (double *) Realloc(rhsx, nr_sz*sizeof(double)));\ 2245 CallN(rmatbeg = (int *) Realloc(rmatbeg, nr_sz*sizeof(int)));\ 2246 ExtraAlloc; \ 2247 }\ 2248 senx[nrs] = (char) sense;\ 2249 rhsx[nrs] = DoubleVal(vrhs, trhs);\ 2250 Check_Constant_Range(rhsx[nrs]);\ 2251 rmatbeg[nrs] = nnz;\ 2252 ++nrs;\ 2253} 2254 2255int 2256p_cpx_new_row(value vlp, type tlp, value vsense, type tsense, 2257 value vrhs, type trhs, value vgtype, type tgtype, 2258 value vidx, type tidx) 2259{ 2260 lp_desc *lpd; 2261 int idx, sense; 2262 2263 LpDescOnly(vlp, tlp, lpd); 2264 Check_Number(trhs); 2265 Check_Integer(tgtype); 2266 Check_Atom(tsense); 2267 if (vsense.did == d_le) sense = SOLVER_SENSE_LE; 2268 else if (vsense.did == d_ge) sense = SOLVER_SENSE_GE; 2269 else if (vsense.did == d_eq) sense = SOLVER_SENSE_EQ; 2270 else { Bip_Error(RANGE_ERROR); } 2271 2272 switch (vgtype.nint) 2273 { 2274 case CSTR_TYPE_NORM: 2275 idx = lpd->mar+lpd->nr; 2276 New_Row(lpd->nr, lpd->nr_sz, lpd->senx, lpd->rhsx, lpd->rmatbeg, 2277 lpd->nnz, sense, vrhs, trhs, {}); 2278 break; 2279/* 2280 case CSTR_TYPE_PERMCP: 2281 idx = lpd->cp_nr; 2282 New_Row(lpd->cp_nr, lpd->cp_nr_sz, lpd->cp_senx, lpd->cp_rhsx, 2283 lpd->cp_rmatbeg, lpd->cp_nnz, sense, vrhs, trhs, {}); 2284 break; 2285*/ 2286 case CSTR_TYPE_CONDCP: 2287 idx = lpd->cp_nr2; 2288 New_Row(lpd->cp_nr2, lpd->cp_nr_sz2, lpd->cp_senx2, lpd->cp_rhsx2, 2289 lpd->cp_rmatbeg2, lpd->cp_nnz2, sense, vrhs, trhs, 2290 {CallN(lpd->cp_active2 = (char *) Realloc(lpd->cp_active2, lpd->cp_nr_sz2*sizeof(char))); 2291 CallN(lpd->cp_initial_add2 = (char *) Realloc(lpd->cp_initial_add2, lpd->cp_nr_sz2*sizeof(char))); 2292 }); 2293 break; 2294 default: 2295 Bip_Error(RANGE_ERROR); 2296 break; 2297 } 2298 Return_Unify_Integer(vidx, tidx, idx); 2299} 2300 2301 2302int 2303p_cpx_new_row_idc(value vlp, type tlp, value vsense, type tsense, 2304 value vrhs, type trhs, value vcompl, type tcompl, 2305 value vindind, type tindind) 2306{ 2307 int sense; 2308 lp_desc *lpd; 2309 2310 LpDescOnly(vlp, tlp, lpd); 2311 Check_Number(trhs); 2312 Check_Integer(tcompl); 2313 Check_Integer(tindind); 2314 Check_Atom(tsense); 2315 if (vsense.did == d_le) sense = SOLVER_SENSE_LE; 2316 else if (vsense.did == d_ge) sense = SOLVER_SENSE_GE; 2317 else if (vsense.did == d_eq) sense = SOLVER_SENSE_EQ; 2318 else { Bip_Error(RANGE_ERROR); } 2319 2320 if (lpd->nr+1 >= lpd->nr_sz) /* allocate/grow arrays */ 2321 { 2322 CallN(lpd->nr_sz += NEWROW_INCR); 2323 CallN(lpd->senx = (char *) Realloc(lpd->senx, lpd->nr_sz*sizeof(char))); 2324 CallN(lpd->rhsx = (double *) Realloc(lpd->rhsx, lpd->nr_sz*sizeof(double))); 2325 CallN(lpd->rmatbeg = (int *) Realloc(lpd->rmatbeg, lpd->nr_sz*sizeof(int))); 2326 CallN(lpd->rcompl = (char *) Realloc(lpd->rcompl, lpd->nr_sz*sizeof(char))); 2327 CallN(lpd->rindind = (int *) Realloc(lpd->rindind, lpd->nr_sz*sizeof(int))); 2328 } else if (!lpd->rcompl) { 2329 /* Only used for IDC, may not be allocated yet */ 2330 CallN(lpd->rcompl = (char *) Malloc(lpd->nr_sz*sizeof(char))); 2331 CallN(lpd->rindind = (int *) Malloc(lpd->nr_sz*sizeof(int))); 2332 } 2333 lpd->senx[lpd->nr] = (char) sense; 2334 lpd->rhsx[lpd->nr] = DoubleVal(vrhs, trhs); 2335 Check_Constant_Range(lpd->rhsx[lpd->nr]); 2336 lpd->rmatbeg[lpd->nr] = lpd->nnz; 2337 lpd->rcompl[lpd->nr] = vcompl.nint; /* complement flag */ 2338 lpd->rindind[lpd->nr] = vindind.nint; /* indicator variable index */ 2339 ++lpd->nr; 2340 2341 Succeed; 2342} 2343 2344 2345 2346#define Add_Row_Coeff(nnz_sz, nnzs, rmatind, rmatval, idxj, val, tag) {\ 2347 if (nnzs >= nnz_sz) /* allocate/grow arrays */\ 2348 {\ 2349 CallN(nnz_sz += NEWNZ_INCR);\ 2350 CallN(rmatind = (int *) Realloc(rmatind, nnz_sz*sizeof(int)));\ 2351 CallN(rmatval = (double *) Realloc(rmatval, nnz_sz*sizeof(double)));\ 2352 }\ 2353 if (idxj >= lpd->mac) { Bip_Error(RANGE_ERROR); }\ 2354 rmatind[nnzs] = idxj;\ 2355 rmatval[nnzs] = DoubleVal(val, tag);\ 2356 Check_Constant_Range(rmatval[nnzs]);\ 2357 ++nnzs;\ 2358} 2359 2360int 2361p_cpx_add_coeff(value vlp, type tlp, value vj, type tj, value v, type t, value vpool, type tpool) 2362{ 2363 lp_desc *lpd; 2364 2365 LpDescOnly(vlp, tlp, lpd); 2366 Check_Integer(tj); 2367 Check_Number(t); 2368 Check_Integer(tpool); 2369 2370 switch (vpool.nint) 2371 { 2372 case CSTR_TYPE_NORM: 2373 Add_Row_Coeff(lpd->nnz_sz, lpd->nnz, lpd->rmatind, lpd->rmatval, vj.nint, v, t); 2374 break; 2375/* 2376 case CSTR_TYPE_PERMCP: 2377 Add_Row_Coeff(lpd->cp_nz_sz, lpd->cp_nnz, lpd->cp_rmatind, lpd->cp_rmatval, vj.nint, v, t); 2378 break; 2379*/ 2380 case CSTR_TYPE_CONDCP: 2381 Add_Row_Coeff(lpd->cp_nz_sz2, lpd->cp_nnz2, lpd->cp_rmatind2, lpd->cp_rmatval2, vj.nint, v, t); 2382 break; 2383 default: 2384 Bip_Error(RANGE_ERROR); 2385 break; 2386 } 2387 Succeed; 2388} 2389 2390static void 2391_grow_numbers_array(lp_desc * lpd, int m) /* make sure array contains 0..m-1 */ 2392{ 2393 if (m > lpd->numsz) /* grow auxiliary array if necessary */ 2394 { 2395 int i = lpd->numsz; 2396 m = Max(m, i+NEWCOL_INCR); 2397 lpd->numsz = m; 2398# ifdef LOG_CALLS 2399 if (i == 0) 2400 Fprintf(log_output_, "\n\ 2401 lpd->numbers = (int *) malloc(%d*sizeof(int));\n\ 2402 lpd->zeroes = (int *) malloc(%d*sizeof(int));\n\ 2403 lpd->dzeroes = (double *) malloc(%d*sizeof(double));", m, m, m); 2404 else 2405 Fprintf(log_output_, "\n\ 2406 lpd->numbers = (int *) realloc(lpd->numbers, %d*sizeof(int));\n\ 2407 lpd->zeroes = (int *) realloc(lpd->zeroes, %d*sizeof(int));\n\ 2408 lpd->dzeroes = (int *) realloc(lpd->dzeroes, %d*sizeof(double));", m, m, m); 2409 Fprintf(log_output_, "\n\ 2410 { int i; for (i=%d; i<%d; i++)\n\ 2411 { lpd->numbers[i] = i; lpd->zeroes[i] = 0; lpd->dzeroes[i] = 0.0; } }", i, m); 2412# endif 2413 if (i == 0) { 2414 lpd->numbers = (int *) Malloc(m*sizeof(int)); 2415 lpd->zeroes = (int *) Malloc(m*sizeof(int)); 2416 lpd->dzeroes = (double *) Malloc(m*sizeof(double)); 2417 } else { 2418 lpd->numbers = (int *) Realloc(lpd->numbers, m*sizeof(int)); 2419 lpd->zeroes = (int *) Realloc(lpd->zeroes, m*sizeof(int)); 2420 lpd->dzeroes = (double *) Realloc(lpd->dzeroes, m*sizeof(double)); 2421 } 2422 for (; i < m; i++) { 2423 lpd->numbers[i] = i; 2424 lpd->zeroes[i] = 0; 2425 lpd->dzeroes[i] = 0.0; 2426 } 2427 } 2428} 2429 2430 2431static void _cpx_restore_bounds(pword * phandle, word * udata, int size, int undo_context) 2432{ 2433 lp_desc *lpd = ExternalData(phandle[HANDLE_CPH].val.ptr); 2434 2435 if (!lpd) 2436 return; /* stale handle */ 2437 2438 if (lpd->descr_state != DESCR_EMPTY) 2439 { 2440 /* lp has not been cleaned up */ 2441 2442 int idx[2]; 2443 int res; 2444 untrail_bound adata; /* needed to ensure proper alignment */ 2445 2446 memcpy(&adata, udata, sizeof(untrail_bound)); 2447 2448 idx[0] = adata.idx; 2449 idx[1] = adata.idx; 2450 2451 Log4( 2452 { 2453 int idx[2]; 2454 double bds[2]; 2455 idx[0] = %d; 2456 idx[1] = %d; 2457 bds[0] = %.15e; 2458 bds[1] = %.15e; 2459 CPXchgbds(cpx_env, lpd->lp, 2, idx, "LU", bds); 2460 }, idx[0], idx[1], adata.bds[0], adata.bds[1] 2461 ); 2462 2463 res = CPXchgbds(cpx_env, lpd->lp, 2, idx, "LU", adata.bds); 2464 if (res != 0) 2465 { 2466 Fprintf(Current_Error, "Eplex external solver error while trying to restore bounds.to column %d\n", idx[0]); 2467 ec_flush(Current_Error); 2468 2469 } 2470 } 2471} 2472 2473 2474static void 2475reset_sos(lp_desc * lpd, int oldsos) 2476{ 2477 if (lpd->nsos_added > oldsos) 2478 { 2479 if (cpx_delsos(lpd, oldsos, lpd->nsos_added)) 2480 { 2481 Fprintf(Current_Error, "Error in deleting SOSs %d..%d\n", 2482 oldsos, lpd->nsos_added); 2483 ec_flush(Current_Error); 2484 } 2485 lpd->nsos = lpd->nsos_added = oldsos; 2486 } 2487} 2488 2489 2490static void 2491reset_idc(lp_desc * lpd, int oldidc) 2492{ 2493#ifdef HAS_INDICATOR_CONSTRAINTS 2494 if (lpd->nidc > oldidc) 2495 { 2496 if (CPXdelindconstrs(cpx_env, lpd->lp, oldidc, lpd->nidc-1)) 2497 { 2498 Fprintf(Current_Error, "Error in deleting indicator constraints %d..%d\n", 2499 oldidc, lpd->nidc-1); 2500 ec_flush(Current_Error); 2501 } 2502 lpd->nidc = oldidc; 2503 } 2504#endif 2505} 2506 2507 2508static void 2509reset_rowcols(lp_desc * lpd, int oldmar, int oldmac) 2510{ 2511#ifdef CPLEX 2512 if (lpd->mar > oldmar) 2513 { 2514 Log2(CPXdelrows(cpx_env, lpd->lp, %d, %d), oldmar, lpd->mar-1); 2515 if (CPXdelrows(cpx_env, lpd->lp, oldmar, lpd->mar-1)) 2516 { 2517 Fprintf(Current_Error, "Error in CPXdelrows(%d..%d)\n", 2518 oldmar, lpd->mar-1); 2519 ec_flush(Current_Error); 2520 } 2521 lpd->mar = oldmar; 2522 } 2523 if (lpd->macadded > oldmac) 2524 { 2525 Log2(CPXdelcols(cpx_env, lpd->lp, %d, %d), oldmac, lpd->macadded-1); 2526 if (CPXdelcols(cpx_env, lpd->lp, oldmac, lpd->macadded-1)) 2527 { 2528 Fprintf(Current_Error, "Error in CPXdelcols(%d..%d)\n", 2529 oldmac, lpd->macadded-1); 2530 ec_flush(Current_Error); 2531 } 2532 lpd->macadded = oldmac; 2533 } 2534#else 2535 int ndr = lpd->mar - oldmar; 2536 int ndc = lpd->macadded - oldmac; 2537 int m = Max(lpd->mar,lpd->macadded); 2538 2539 _grow_numbers_array(lpd, m); /* if necessary */ 2540 2541 if (ndr > 0) 2542 { 2543 Log2(XPRSdelrows(lpd->lp,%d, &lpd->numbers[%d]), ndr,oldmar); 2544 if (XPRSdelrows(lpd->lp, ndr, &lpd->numbers[oldmar])) 2545 { 2546 Fprintf(Current_Error, "Error in deleting rows %d..%d\n", 2547 oldmar, oldmar+ndr-1); 2548 ec_flush(Current_Error); 2549 } 2550 lpd->mar = oldmar; 2551 } 2552 if (ndc > 0) 2553 { 2554 Log2(XPRSdelcols(lpd->lp,%d, &lpd->numbers[%d]), ndc,oldmac); 2555 if (XPRSdelcols(lpd->lp, ndc, &lpd->numbers[oldmac])) 2556 { 2557 Fprintf(Current_Error, "Error in deleting cols %d..%d\n", 2558 oldmac, oldmac+ndc-1); 2559 ec_flush(Current_Error); 2560 } 2561 lpd->macadded = oldmac; 2562 } 2563#endif 2564 lpd->mac = lpd->macadded; 2565 Mark_Copy_As_Modified(lpd); 2566} 2567 2568 2569static void _cpx_del_rowcols(pword * phandle,word * udata, int size, int flags) 2570{ 2571 lp_desc *lpd = ExternalData(phandle[HANDLE_CPH].val.ptr); 2572 2573 int oldmar = ((untrail_data*) udata)->oldmar, 2574 oldmac = ((untrail_data*) udata)->oldmac, 2575 oldsos = ((untrail_data*) udata)->oldsos, 2576 oldidc = ((untrail_data*) udata)->oldidc; 2577 2578 if (lpd && lpd->descr_state != DESCR_EMPTY) 2579 { 2580#if 0 2581 Fprintf(Current_Error, 2582 "Removing rows %d..%d, cols %d..%d, soss %d..%d, idcs %d..%d, in gc:%d\n", 2583 oldmar, lpd->mar-1, oldmac, lpd->macadded-1, 2584 oldsos, lpd->nsos_added, oldidc, lpd->nidc, 2585 ec_.m.vm_flags & NO_EXIT); 2586 ec_flush(Current_Error); 2587#endif 2588 reset_idc(lpd, oldidc); 2589 reset_sos(lpd, oldsos); 2590 reset_rowcols(lpd, oldmar, oldmac); 2591 } 2592} 2593 2594 2595/* 2596 * flush_new_rowcols(+Handle, +HasObjCoeffs) expects the following input: 2597 * 2598 * lpd->mac new column count (>= macadded, those already added) 2599 * lpd->objx objective coefficients for new vars only (if HasObjCoeffs) 2600 * lpd->matnz number of nonzero coefficients for new vars in old constraints 2601 * lpd->matxxx those nonzero coefficients 2602 * lpd->ctype types for new vars only 2603 * 2604 * lpd->nr number of rows to add 2605 * lpd->senx row senses 2606 * lpd->rhsx row RHSs 2607 * lpd->nnz number of nonzero coefficients to add 2608 * lpd->rmatxxx those nonzero coefficients 2609 * 2610 * We may add only columns or only rows. 2611 */ 2612/* newcolobjs == 1 if non-zero objective coeffs are to be added */ 2613int 2614p_cpx_flush_new_rowcols(value vhandle, type thandle, value vnewcolobjs, type tnewcolobjs) 2615{ 2616 lp_desc *lpd; 2617 int res, coladded, rowadded, nzadded; 2618 2619 Check_Structure(thandle); 2620 LpDesc(vhandle.ptr[HANDLE_CPH].val, vhandle.ptr[HANDLE_CPH].tag, lpd); 2621 Check_Integer(tnewcolobjs); 2622 coladded = lpd->mac - lpd->macadded; 2623 rowadded = lpd->nr; 2624 nzadded = lpd->nnz; 2625 2626 /*** 2627 Fprintf(Current_Error, "Adding rows %d..%d, cols %d..%d\n", 2628 lpd->mar, lpd->mar+rowadded-1, 2629 lpd->mac, lpd->mac+coladded-1); 2630 ec_flush(Current_Error); 2631 ***/ 2632 2633 SetPreSolve(lpd->presolve); 2634 Mark_Copy_As_Modified(lpd); 2635 2636#ifdef LOG_CALLS 2637 { 2638 int i; 2639 Fprintf(log_output_, "\n\ 2640 lpd->nr = %d;", lpd->nr); 2641 Fprintf(log_output_, "\n\ 2642 lpd->matnz = %d;", lpd->matnz); 2643 /* needed by OSI */ 2644 Fprintf(log_output_, "\n\ 2645 lpd->mac = %d;", lpd->mac); 2646 if (vnewcolobjs.nint) 2647 { 2648 for (i=0; i<coladded; ++i) 2649 { 2650 Fprintf(log_output_, "\n\ 2651 lpd->objx[%d] = %.15e;", i, lpd->objx[i]); 2652 } 2653 } 2654 for (i=0; i<coladded; ++i) 2655 { 2656 Fprintf(log_output_, "\n\ 2657 lpd->bdl[%d] = %.15e;\n\ 2658 lpd->bdu[%d] = %.15e;", i, lpd->bdl[i], i, lpd->bdu[i]); 2659 } 2660 for (i=0; i<lpd->matnz; ++i) 2661 { 2662 Fprintf(log_output_, "\n\ 2663 lpd->matind[%d] = %d;\n\ 2664 lpd->matval[%d] = %.15e;", i, lpd->matind[i], i, lpd->matval[i]); 2665 } 2666 if (lpd->matnz > 0) 2667 { 2668 for (i=0; i<coladded; ++i) 2669 { 2670 Fprintf(log_output_, "\n\ 2671 lpd->matbeg[%d] = %d;", i, lpd->matbeg[i]); 2672 } 2673 } 2674 2675 for (i=0; i<lpd->nr; ++i) 2676 { 2677 Fprintf(log_output_, "\n\ 2678 lpd->senx[%d] = '%c';\n\ 2679 lpd->rhsx[%d] = %.15e;\n\ 2680 lpd->rmatbeg[%d] = %d;", 2681 i, lpd->senx[i], i, lpd->rhsx[i], i, lpd->rmatbeg[i]); 2682 } 2683 Fprintf(log_output_, "\n\ 2684 lpd->nnz = %d;", lpd->nnz); 2685 for (i=0; i<lpd->nnz; ++i) 2686 { 2687 Fprintf(log_output_, "\n\ 2688 lpd->rmatind[%d] = %d;\n\ 2689 lpd->rmatval[%d] = %.15e;", 2690 i, lpd->rmatind[i], i, lpd->rmatval[i]); 2691 } 2692 } 2693#endif 2694 2695 if (coladded) 2696 { 2697 _grow_numbers_array(lpd, coladded+1); /* for zeroes[] */ 2698 Log2(CPXaddcols(cpx_env, lpd->lp, %d, lpd->matnz, 2699 %s, (lpd->matnz ? lpd->matbeg : lpd->zeroes), 2700 lpd->matind, lpd->matval, lpd->bdl, lpd->bdu, NULL), 2701 coladded, (vnewcolobjs.nint ? "lpd->objx" : "lpd->dzeroes")); 2702 2703 res = CPXaddcols(cpx_env, lpd->lp, coladded, lpd->matnz, 2704 (vnewcolobjs.nint ? lpd->objx : lpd->dzeroes), 2705 (lpd->matnz ? lpd->matbeg : lpd->zeroes), 2706 lpd->matind, lpd->matval, lpd->bdl, lpd->bdu, NULL); 2707 TryFree(lpd->objx); 2708 TryFree(lpd->matbeg); 2709 TryFree(lpd->matind); 2710 TryFree(lpd->matval); 2711 lpd->matnz = 0; 2712 if (lpd->dirtybdflag & 3) 2713 { 2714 if (lpd->dirtybdflag & 1) TryFree(lpd->bdl); 2715 if (lpd->dirtybdflag & 2) TryFree(lpd->bdu); 2716 lpd->dirtybdflag = 0; 2717 } 2718 2719 if (IsMIPProb(lpd->prob_type) && res == 0) 2720 { 2721 int i, colidx; 2722 if (lpd->qgtype) CallN(Free(lpd->qgtype)); 2723 lpd->qgtype = NULL; 2724 if (lpd->mgcols) CallN(Free(lpd->mgcols)); 2725 lpd->mgcols = Malloc(coladded*sizeof(int)); 2726 Log1(lpd->mgcols = (int *) malloc(%d*sizeof(int)), coladded); 2727 /* we reuse mgcols for the index of the added columns. We set the 2728 type for all columns, as Dash does not specify what types 2729 columns are set to in XPRSaddcols(). 2730 */ 2731 for ((i=0, colidx=lpd->macadded); i < coladded; (i++, colidx++)) 2732 { 2733 lpd->mgcols[i] = colidx; 2734 Log2(lpd->mgcols[%d] = %d, i, colidx); 2735 Log2(lpd->ctype[%d] = %d, i, lpd->ctype[i]); 2736 } 2737 CPXupdatemodel(lpd->lp); /* columns must be added before type can be set */ 2738 Log1(CPXchgctype(cpx_env, lpd->lp, %d, lpd->mgcols, lpd->ctype), 2739 coladded); 2740 res = CPXchgctype(cpx_env, lpd->lp, coladded, 2741 lpd->mgcols, lpd->ctype); 2742 } 2743 2744 if (res != 0) { Bip_Error(EC_EXTERNAL_ERROR); } 2745 } 2746 CPXupdatemodel(lpd->lp); /* columns must be added before rows can be created */ 2747 if (rowadded) 2748 { 2749 Log2(CPXaddrows(cpx_env, lpd->lp, 0, %d, %d, lpd->rhsx, lpd->senx, 2750 lpd->rmatbeg, lpd->rmatind, lpd->rmatval, NULL, NULL), 2751 rowadded, nzadded); 2752 res = CPXaddrows(cpx_env, lpd->lp, 0, rowadded, nzadded, 2753 lpd->rhsx, lpd->senx, lpd->rmatbeg, lpd->rmatind, 2754 lpd->rmatval, NULL, NULL); 2755 if (res != 0) { Bip_Error(EC_EXTERNAL_ERROR); } 2756 } 2757 2758 if (coladded || rowadded) 2759 { 2760 untrail_data udata; 2761 udata.oldmac = lpd->macadded; 2762 udata.oldmar = lpd->mar; 2763 udata.oldsos = lpd->nsos_added; 2764 udata.oldidc = lpd->nidc; 2765 ec_trail_undo(_cpx_del_rowcols, vhandle.ptr, vhandle.ptr+HANDLE_STAMP, (word*) &udata, NumberOfWords(untrail_data), TRAILED_WORD32); 2766 } 2767 2768 lpd->macadded = lpd->mac; /* remember what we added */ 2769 lpd->mar += rowadded; 2770 2771 lpd->nr = lpd->nnz = 0; /* maybe shrink arrays here */ 2772 Succeed; 2773} 2774 2775 2776/* 2777 * Add Indicator Constraints from descriptor arrays to solver 2778 * Input: 2779 * lpd->nr number of indicator rows to add 2780 * lpd->senx row senses 2781 * lpd->rhsx row RHSs 2782 * lpd->nnz number of nonzero coefficients to add 2783 * lpd->rmatxxx those nonzero coefficients 2784 * lpd->rcompl the complement flags 2785 * lpd->rindind the indicator variable indexes 2786 */ 2787 2788int 2789p_cpx_flush_idcs(value vhandle, type thandle) 2790{ 2791#ifdef HAS_INDICATOR_CONSTRAINTS 2792 int i; 2793 lp_desc *lpd; 2794 untrail_data udata; 2795 2796 Check_Structure(thandle); 2797 LpDesc(vhandle.ptr[HANDLE_CPH].val, vhandle.ptr[HANDLE_CPH].tag, lpd); 2798 2799 if (lpd->nr == 0) 2800 Succeed; 2801 2802 /* trail first, in case we abort during adding */ 2803 udata.oldmac = lpd->macadded; 2804 udata.oldmar = lpd->mar; 2805 udata.oldsos = lpd->nsos_added; 2806 udata.oldidc = lpd->nidc; 2807 ec_trail_undo(_cpx_del_rowcols, vhandle.ptr, vhandle.ptr+HANDLE_STAMP, (word*) &udata, NumberOfWords(untrail_data), TRAILED_WORD32); 2808 2809 lpd->rmatbeg[lpd->nr] = lpd->nnz; 2810 for(i=0; lpd->nr>0; --lpd->nr,++i) 2811 { 2812#if 0 2813 int k; 2814 Fprintf(Current_Error, "CPXaddindconstr(%d,%d,%d,%f,%d,...,...)\n", 2815 lpd->rindind[i], lpd->rcompl[i], 2816 lpd->rmatbeg[i+1]-lpd->rmatbeg[i], /* nzcnt */ 2817 lpd->rhsx[i], lpd->senx[i]); 2818 for(k=lpd->rmatbeg[i];k<lpd->rmatbeg[i+1];++k) { 2819 Fprintf(Current_Error, "%d:%f, ", lpd->rmatind[k], lpd->rmatval[k]); 2820 } 2821 (void) ec_newline(Current_Error); 2822 (void) ec_flush(Current_Error); 2823#endif 2824 2825 if (CPXaddindconstr(cpx_env, lpd->lp, lpd->rindind[i], lpd->rcompl[i], 2826 lpd->rmatbeg[i+1]-lpd->rmatbeg[i], /* nzcnt */ 2827 lpd->rhsx[i], lpd->senx[i], 2828 lpd->rmatind+lpd->rmatbeg[i], lpd->rmatval+lpd->rmatbeg[i], 2829 NULL)) 2830 { 2831 Bip_Error(EC_EXTERNAL_ERROR); 2832 } 2833 ++lpd->nidc; 2834 } 2835 /* could free/resize arrays here */ 2836 Succeed; 2837#else 2838 Bip_Error(UNIMPLEMENTED); 2839#endif 2840} 2841 2842 2843/*----------------------------------------------------------------------* 2844 * Updating variable bounds 2845 *----------------------------------------------------------------------*/ 2846 2847/* the *impose* procedures are for columns that have been added to the 2848 external solver already. 2849*/ 2850int 2851p_cpx_impose_col_lwb(value vhandle, type thandle, 2852 value vatt, type tatt, 2853 value vj, type tj, 2854 value vlo, type tlo, 2855 value vchanged, type tchanged) 2856{ 2857 lp_desc *lpd; 2858 double lo0, hi0, newlo; 2859 int j, changed = 0; 2860 Check_Integer(tj); 2861 Check_Float(tlo); 2862 LpDesc(vhandle.ptr[HANDLE_CPH].val, vhandle.ptr[HANDLE_CPH].tag, lpd); 2863 2864 if (lpd->descr_state == DESCR_EMPTY) 2865 { 2866 Fprintf(Current_Error, "Eplex error: empty handle\n"); 2867 (void) ec_flush(Current_Error); 2868 Bip_Error(EC_EXTERNAL_ERROR); 2869 } 2870 2871 j = (int) vj.nint; 2872 if (j >= lpd->macadded) { Bip_Error(RANGE_ERROR); } 2873 if ((newlo = Dbl(vlo)) < -CPX_INFBOUND) newlo = -CPX_INFBOUND; 2874 2875 CPXupdatemodel(lpd->lp); /* make sure bounds are up-to-date */ 2876 Get_Col_Bounds(j, lo0, hi0); 2877 if (newlo > hi0) 2878 { 2879 double ftol; 2880 2881 Get_Feasibility_Tolerance(cpx_env, lpd, &ftol); 2882 if (newlo <= hi0 + ftol) newlo = hi0; 2883 else { Fail; } 2884 } 2885 2886 if (lo0 < newlo) 2887 { 2888 Change_Col_Bound(j, "L", lo0, hi0, newlo, vatt.ptr+COL_STAMP, changed); 2889 } 2890 2891 Return_Unify_Integer(vchanged, tchanged, changed); 2892} 2893 2894int 2895p_cpx_impose_col_upb(value vhandle, type thandle, 2896 value vatt, type tatt, 2897 value vj, type tj, 2898 value vhi, type thi, 2899 value vchanged, type tchanged) 2900{ 2901 lp_desc *lpd; 2902 double lo0, hi0, newhi; 2903 int j, changed = 0; 2904 2905 LpDesc(vhandle.ptr[HANDLE_CPH].val, vhandle.ptr[HANDLE_CPH].tag, lpd); 2906 Check_Integer(tj); 2907 Check_Float(thi); 2908 2909 if (lpd->descr_state == DESCR_EMPTY) 2910 { 2911 Fprintf(Current_Error, "Eplex error: empty handle\n"); 2912 (void) ec_flush(Current_Error); 2913 Bip_Error(EC_EXTERNAL_ERROR); 2914 } 2915 2916 j = (int) vj.nint; 2917 if (j >= lpd->macadded) { Bip_Error(RANGE_ERROR); } 2918 if ((newhi = Dbl(vhi)) > CPX_INFBOUND) newhi = CPX_INFBOUND; 2919 2920 CPXupdatemodel(lpd->lp); /* make sure bounds are up-to-date */ 2921 Get_Col_Bounds(j, lo0, hi0); 2922 if (newhi < lo0) 2923 { 2924 double ftol; 2925 2926 Get_Feasibility_Tolerance(cpx_env, lpd, &ftol); 2927 if (newhi >= lo0 - ftol) newhi = lo0; 2928 else { Fail; } 2929 } 2930 2931 if (hi0 > newhi) 2932 { 2933 Change_Col_Bound(j, "U", lo0, hi0, newhi, vatt.ptr+COL_STAMP, changed); 2934 } 2935 2936 Return_Unify_Integer(vchanged, tchanged, changed); 2937} 2938 2939int 2940p_cpx_impose_col_bounds(value vhandle, type thandle, 2941 value vatt, type tatt, 2942 value vj, type tj, 2943 value vflag, type tflag, 2944 value vlo, type tlo, 2945 value vhi, type thi, 2946 value vchanged, type tchanged) 2947{ 2948 lp_desc *lpd; 2949 double lo0, hi0, newlo, newhi; 2950 int res, j, flag, changed = 0; 2951 char ctype[1]; 2952 2953 Check_Integer(tj); 2954 Check_Integer(tflag); 2955 Check_Float(thi); 2956 Check_Float(tlo); 2957 LpDesc(vhandle.ptr[HANDLE_CPH].val, vhandle.ptr[HANDLE_CPH].tag, lpd); 2958 2959 if (lpd->descr_state == DESCR_EMPTY) 2960 { 2961 Fprintf(Current_Error, "Eplex error: empty handle\n"); 2962 (void) ec_flush(Current_Error); 2963 Bip_Error(EC_EXTERNAL_ERROR); 2964 } 2965 2966 CPXupdatemodel(lpd->lp); /* make sure types and bounds are up-to-date */ 2967 2968 j = (int) vj.nint; 2969 if (j >= lpd->macadded || j < 0) { Bip_Error(RANGE_ERROR); } 2970 if ((newhi = Dbl(vhi)) > CPX_INFBOUND) newhi = CPX_INFBOUND; 2971 if ((newlo = Dbl(vlo)) < -CPX_INFBOUND) newlo = -CPX_INFBOUND; 2972 2973 flag = (int) vflag.nint; 2974 if (flag == 0) { 2975 /* flag == 0 ==> we can widen the bound. Check to make sure that the new 2976 bounds are not too wide, i.e. invalid for the column type 2977 */ 2978 switch (lpd->prob_type) 2979 { 2980 case PROBLEM_MIP: 2981 case PROBLEM_MIQP: 2982 res = CPXgetctype(cpx_env, lpd->lp, ctype, vj.nint, vj.nint); 2983 if (res != 0) { Bip_Error(EC_EXTERNAL_ERROR); } 2984 2985 if (ctype[0] == 'B' && (newhi > 1 || newhi < 0 || newlo > 1 || newlo < 0)) 2986 { Bip_Error(RANGE_ERROR); } 2987#ifdef HAS_NARROW_INT_RANGE 2988 if (ctype[0] == 'I' && (newhi > XPRS_MAXINT || newhi < -XPRS_MAXINT || newlo > XPRS_MAXINT || newlo < -XPRS_MAXINT)) 2989 { Bip_Error(RANGE_ERROR); } 2990#endif 2991 default: 2992 break; 2993 } 2994 } 2995 2996 Get_Col_Bounds(j, lo0, hi0); 2997 if (newhi < newlo) { Fail; } 2998 if (flag && (newhi < lo0)) 2999 { 3000 double ftol; 3001 3002 /* if new bound outside but within tolerance of old bound, ignore change */ 3003 Get_Feasibility_Tolerance(cpx_env, lpd, &ftol); 3004 if (newhi >= lo0 - ftol) 3005 { 3006 newhi = lo0; 3007 if (newlo > newhi) newlo = lo0; /* make sure other bound is consistent! */ 3008 } 3009 else 3010 { 3011 Fail; 3012 } 3013 } 3014 3015 if (flag && (newlo > hi0)) 3016 { 3017 double ftol; 3018 3019 Get_Feasibility_Tolerance(cpx_env, lpd, &ftol); 3020 if (newlo <= hi0 + ftol) 3021 { 3022 newlo = hi0; 3023 if (newhi < newlo) newhi = hi0; 3024 } else 3025 { 3026 Fail; 3027 } 3028 } 3029 3030 if (newhi == newlo) 3031 { 3032 if (newhi != hi0 || newhi != lo0) 3033 Change_Col_Bound(j, "B", lo0, hi0, newlo, vatt.ptr+COL_STAMP, 3034 changed); 3035 } 3036 else 3037 { 3038 if (newhi < hi0 || (!flag && newhi > hi0)) Change_Col_Bound(j, "U", lo0, hi0, newhi, 3039 vatt.ptr+COL_STAMP, changed); 3040 if (newlo > lo0 || (!flag && newlo < lo0)) Change_Col_Bound(j, "L", lo0, hi0, newlo, 3041 vatt.ptr+COL_STAMP, changed); 3042 } 3043 3044 Return_Unify_Integer(vchanged, tchanged, changed); 3045} 3046 3047int 3048p_cpx_get_col_bounds(value vlp, type tlp, 3049 value vj, type tj, 3050 value vlo, type tlo, 3051 value vhi, type thi) 3052{ 3053 Prepare_Requests 3054 lp_desc *lpd; 3055 double lo, hi; 3056 int j; 3057 3058 LpDesc(vlp, tlp, lpd); 3059 Check_Integer(tj); 3060 j = vj.nint; 3061 3062 if (lpd->descr_state == DESCR_EMPTY) 3063 { 3064 Fprintf(Current_Error, "Eplex error: empty handle\n"); 3065 (void) ec_flush(Current_Error); 3066 Bip_Error(EC_EXTERNAL_ERROR); 3067 } 3068 3069 if (lpd->lp == NULL) 3070 {/* solver not created for problem yet, get bounds from arrays */ 3071 Request_Unify_Float(vhi, thi, lpd->bdu[j]); 3072 Request_Unify_Float(vlo, tlo, lpd->bdl[j]); 3073 Return_Unify; 3074 } 3075 else if (j >= lpd->mac || j < 0) 3076 {/* invalid column index */ 3077 Bip_Error(RANGE_ERROR); 3078 } 3079 else if (j >= lpd->macadded) 3080 {/* column not yet added to solver, get bounds from arrays */ 3081 j -= lpd->macadded; /* arrays are for new added columns only */ 3082 Request_Unify_Float(vhi, thi, lpd->bdu[j]); 3083 Request_Unify_Float(vlo, tlo, lpd->bdl[j]); 3084 Return_Unify; 3085 } 3086 else 3087 { 3088 CPXupdatemodel(lpd->lp); /* before CPXget... */ 3089 if (CPXgetub(cpx_env, lpd->lp, &hi, (int) vj.nint, (int) vj.nint)) 3090 { 3091 Bip_Error(EC_EXTERNAL_ERROR); 3092 } 3093 if (CPXgetlb(cpx_env, lpd->lp, &lo, (int) vj.nint, (int) vj.nint)) 3094 { 3095 Bip_Error(EC_EXTERNAL_ERROR); 3096 } 3097 Request_Unify_Float(vhi, thi, hi); 3098 Request_Unify_Float(vlo, tlo, lo); 3099 Return_Unify; 3100 } 3101} 3102 3103 3104/* 3105 * cplex_set_new_cols(CPH, AddedCols, NewObjCoeffs, NewLos, NewHis, NonZeros) 3106 * 3107 * Sets the following fields: 3108 * lpd->mac +AddedCold 3109 * lpd->matnz +NonZeros 3110 * lpd->matxxx get resized for AddedCols and NonZeros 3111 * lpd->ctype resized to AddedCols only and initialised to 'C' 3112 * lpd->bdl/bdu resized to AddedCols or maczs?? and filled 3113 * lpd->objx resized to AddedCols, if NewObjCoeffs given 3114 */ 3115 3116int 3117p_cpx_set_new_cols(value vlp, type tlp, value vadded, type tadded, value vobjs, type tobjs, value vlos, type tlos, value vhis, type this, value vnzs, type tnzs) 3118{ 3119 /* the column `buffer arrays' are needed by CPLEX and Xpress's interface 3120 to pass information for the columns. Except for ctype 3121 and possibly bdl, bdu, we simpy pass 3122 default values to the solver on setup/adding columns 3123 */ 3124 lp_desc *lpd; 3125 int i; 3126 3127 LpDescOnly(vlp, tlp, lpd); 3128 Check_Integer(tadded); 3129 Check_Integer(tnzs); 3130 if (vadded.nint == 0) { Succeed; } /* no added columns, return now! */ 3131 3132 lpd->mac += vadded.nint; 3133 lpd->matnz = vnzs.nint; 3134 TryFree(lpd->matind); 3135 TryFree(lpd->matval); 3136 if (vnzs.nint > 0) 3137 { 3138 lpd->matind = (int *) Malloc((size_t) vnzs.nint*sizeof(int)); 3139 lpd->matval = (double *) Malloc((size_t) vnzs.nint*sizeof(double)); 3140 Log1(lpd->matind = (int *) malloc((size_t) %d*sizeof(int)), vnzs.nint); 3141 Log1(lpd->matval = (double *) Malloc((size_t) %d*sizeof(double)), vnzs.nint); 3142 } 3143 TryFree(lpd->ctype); 3144 TryFree(lpd->matbeg); 3145 TryFree(lpd->matcnt); 3146 lpd->ctype = (char *) Malloc((size_t) vadded.nint*sizeof(char)); 3147 /* +1 for matbeg required by COIN */ 3148 lpd->matbeg = (int *) Malloc((size_t) (vadded.nint+1)*sizeof(int)); 3149 lpd->matcnt = (int *) Malloc((size_t) vadded.nint*sizeof(int)); 3150 Log3({\n\ 3151 lpd->ctype = (char *) Malloc((size_t) %d*sizeof(char));\n\ 3152 lpd->matbeg = (int *) Malloc((size_t) %d*sizeof(int));\n\ 3153 lpd->matcnt = (int *) Malloc((size_t) %d*sizeof(int));\n\ 3154 }, vadded.nint, vadded.nint, vadded.nint); 3155 3156 for (i=0; i<vadded.nint; i++) lpd->ctype[i] = 'C'; 3157 3158 /* treatment of bounds arrays lpd->bdl, lpd->bdu: 3159 3160 if columns with non-default bounds were added immediately previously 3161 the bounds arrays will have been freed in p_cpx_flush_new_rowcols so 3162 any existing bounds arrays contain default values and are length lpd->macsz 3163 3164 1) if vadded.nint > lpd->macsz any existing arrays are too small: 3165 a) if we have non-default bounds to apply we free any existing array 3166 and Malloc a new one of correct size vadded.nint since Realloc may 3167 have to copy the contents of the existing array and free it and we 3168 need to overwrite the entries again anyway 3169 b) if we have default bounds to apply we just expand the existing array 3170 with Realloc and initialize the new positions 3171 2) otherwise any existing arrays are big enough: 3172 a) if we have non-default bounds to apply we overwrite the necessary entries 3173 b) if we have default bounds to apply we have nothing to do 3174 3175 if we have non-default bounds we set the appropriate bit of the lpd->dirtybdflag 3176 so that the arrays can be freed in p_cpx_flush_new_rowcols 3177 */ 3178 if (vadded.nint > lpd->macsz) /* any existing bound arrays are too small */ 3179 { 3180 if (IsList(tlos)) /* non-default lower bounds */ 3181 { 3182 /* since Realloc may copy and free and we need to overwrite entries 3183 anyway it is probably better to free and Malloc */ 3184 TryFree(lpd->bdl); 3185 lpd->bdl = (double *) Malloc((size_t) vadded.nint*sizeof(double)); 3186 Log1(lpd->bdl = (double *) malloc(%d*sizeof(double)), vadded.nint); 3187 if (IsList(this)) /* non-default upper bounds */ 3188 { 3189 /* both bounds arrays are non-default and will be freed 3190 immediately after flushing: no need to increase lpd->macsz since 3191 we will need to Malloc new bounds arrays of correct size next 3192 time around anyway */ 3193 TryFree(lpd->bdu); 3194 lpd->bdu = (double *) Malloc((size_t) vadded.nint*sizeof(double)); 3195 Log1(lpd->bdu = (double *) malloc(%d*sizeof(double)), vadded.nint); 3196 /* fill the bounds arrays with explicit bounds */ 3197 for (i = 0; (IsList(tlos) && IsList(this)); ++i) 3198 { 3199 pword *lhead = vlos.ptr; 3200 pword *ltail = lhead + 1; 3201 pword *hhead = vhis.ptr; 3202 pword *htail = hhead + 1; 3203 double lo, hi; 3204 3205 Dereference_(lhead); 3206 if (IsInteger(lhead->tag)) { 3207 lo = (double) lhead->val.nint; 3208 } else { 3209 Check_Float(lhead->tag); 3210 lo = Dbl(lhead->val); 3211 } 3212 lpd->bdl[i] = (lo < -CPX_INFBOUND ? -CPX_INFBOUND : lo); 3213 Dereference_(hhead); 3214 if (IsInteger(hhead->tag)) { 3215 hi = (double) hhead->val.nint; 3216 } else { 3217 Check_Float(hhead->tag); 3218 hi = Dbl(hhead->val); 3219 } 3220 lpd->bdu[i] = (hi > CPX_INFBOUND ? CPX_INFBOUND : hi); 3221 Dereference_(ltail); 3222 tlos = ltail->tag; 3223 vlos = ltail->val; 3224 Dereference_(htail); 3225 this = htail->tag; 3226 vhis = htail->val; 3227 } 3228 /* check that there are the right number of bds */ 3229 if (i != vadded.nint) { Bip_Error(RANGE_ERROR) } 3230 /* mark both arrays as "dirty" */ 3231 lpd->dirtybdflag |= 3; 3232 } 3233 else /* default upper bounds */ 3234 { 3235 int newcsz; 3236 3237 newcsz = Max(vadded.nint, lpd->macsz+NEWCOL_INCR); 3238 if (lpd->bdu == NULL) /* upper bounds array freed */ 3239 { 3240 lpd->bdu = (double *) Malloc((size_t) newcsz*sizeof(double)); 3241 Log1(lpd->bdu = (double *) malloc(%d*sizeof(double)), newcsz); 3242 3243 for (i=0; i<newcsz; i++) 3244 { 3245 lpd->bdu[i] = CPX_INFBOUND; 3246 } 3247 } 3248 else 3249 { 3250 lpd->bdu = (double *) Realloc(lpd->bdu, (size_t) newcsz*sizeof(double)); 3251 Log1(lpd->bdu = (double *) realloc(%d*sizeof(double)), newcsz); 3252 for (i=lpd->macsz; i<newcsz; i++) 3253 { 3254 lpd->bdu[i] = CPX_INFBOUND; 3255 } 3256 } 3257 lpd->macsz = newcsz; 3258 /* fill the lower bounds array with explicit bounds */ 3259 for (i = 0; (IsList(tlos)); ++i) 3260 { 3261 pword *lhead = vlos.ptr; 3262 pword *ltail = lhead + 1; 3263 double lo; 3264 3265 Dereference_(lhead); 3266 if (IsInteger(lhead->tag)) { 3267 lo = (double) lhead->val.nint; 3268 } else { 3269 Check_Float(lhead->tag); 3270 lo = Dbl(lhead->val); 3271 } 3272 lpd->bdl[i] = (lo < -CPX_INFBOUND ? -CPX_INFBOUND : lo); 3273 Dereference_(ltail); 3274 tlos = ltail->tag; 3275 vlos = ltail->val; 3276 } 3277 /* check that there are the right number of bds */ 3278 if (i != vadded.nint) { Bip_Error(RANGE_ERROR) } 3279 /* mark lower bounds array as "dirty" */ 3280 lpd->dirtybdflag |= 1; 3281 } 3282 } 3283 else if (IsList(this)) /* default lower bounds, non-default upper bounds */ 3284 { 3285 int newcsz; 3286 3287 newcsz = Max(vadded.nint, lpd->macsz+NEWCOL_INCR); 3288 if (lpd->bdl == NULL) /* lower bounds array freed */ 3289 { 3290 lpd->bdl = (double *) Malloc((size_t) newcsz*sizeof(double)); 3291 Log1(lpd->bdl = (double *) malloc(%d*sizeof(double)), newcsz); 3292 for (i=0; i<newcsz; i++) 3293 { 3294 lpd->bdl[i] = -CPX_INFBOUND; 3295 } 3296 } 3297 else 3298 { 3299 lpd->bdl = (double *) Realloc(lpd->bdl, (size_t) newcsz*sizeof(double)); 3300 Log1(lpd->bdl = (double *) realloc(%d*sizeof(double)), newcsz); 3301 for (i=lpd->macsz; i<newcsz; i++) 3302 { 3303 lpd->bdl[i] = -CPX_INFBOUND; 3304 } 3305 } 3306 lpd->macsz = newcsz; 3307 TryFree(lpd->bdu); 3308 lpd->bdu = (double *) Malloc((size_t) vadded.nint*sizeof(double)); 3309 Log1(lpd->bdu = (double *) malloc(%d*sizeof(double)), vadded.nint); 3310 /* fill the upper bounds array with explicit bounds */ 3311 for (i = 0; (IsList(this)); ++i) 3312 { 3313 pword *hhead = vhis.ptr; 3314 pword *htail = hhead + 1; 3315 double hi; 3316 3317 Dereference_(hhead); 3318 if (IsInteger(hhead->tag)) { 3319 hi = (double) hhead->val.nint; 3320 } else { 3321 Check_Float(hhead->tag); 3322 hi = Dbl(hhead->val); 3323 } 3324 lpd->bdu[i] = (hi > CPX_INFBOUND ? CPX_INFBOUND : hi); 3325 Dereference_(htail); 3326 this = htail->tag; 3327 vhis = htail->val; 3328 } 3329 /* check that there are the right number of bds */ 3330 if (i != vadded.nint) { Bip_Error(RANGE_ERROR) } 3331 /* mark upper bounds array as "dirty" */ 3332 lpd->dirtybdflag |= 2; 3333 } 3334 else /* default bounds */ 3335 { 3336 int newcsz; 3337 3338 newcsz = Max(vadded.nint, lpd->macsz+NEWCOL_INCR); 3339 if (lpd->bdl == NULL) /* lower bounds array freed */ 3340 { 3341 lpd->bdl = (double *) Malloc((size_t) newcsz*sizeof(double)); 3342 Log1(lpd->bdl = (double *) malloc(%d*sizeof(double)), newcsz); 3343 for (i=0; i<newcsz; i++) 3344 { 3345 lpd->bdl[i] = -CPX_INFBOUND; 3346 } 3347 } 3348 else 3349 { 3350 lpd->bdl = (double *) Realloc(lpd->bdl, (size_t) newcsz*sizeof(double)); 3351 Log1(lpd->bdl = (double *) realloc(%d*sizeof(double)), newcsz); 3352 for (i=lpd->macsz; i<newcsz; i++) 3353 { 3354 lpd->bdl[i] = -CPX_INFBOUND; 3355 } 3356 } 3357 if (lpd->bdu == NULL) /* upper bounds array freed */ 3358 { 3359 lpd->bdu = (double *) Malloc((size_t) newcsz*sizeof(double)); 3360 Log1(lpd->bdu = (double *) malloc(%d*sizeof(double)), newcsz); 3361 for (i=0; i<newcsz; i++) 3362 { 3363 lpd->bdu[i] = CPX_INFBOUND; 3364 } 3365 } 3366 else 3367 { 3368 lpd->bdu = (double *) Realloc(lpd->bdu, (size_t) newcsz*sizeof(double)); 3369 Log1(lpd->bdu = (double *) malloc(%d*sizeof(double)), newcsz); 3370 for (i=lpd->macsz; i<newcsz; i++) 3371 { 3372 lpd->bdu[i] = CPX_INFBOUND; 3373 } 3374 } 3375 lpd->macsz = newcsz; 3376 } 3377 } 3378 else /* any existing bound arrays are big enough */ 3379 { 3380 if (IsList(tlos)) /* non-default lower bounds */ 3381 { 3382 if (lpd->bdl == NULL) 3383 { 3384 lpd->bdl = (double *) Malloc((size_t) vadded.nint*sizeof(double)); 3385 Log1(lpd->bdl = (double *) malloc(%d*sizeof(double)), vadded.nint); 3386 } 3387 if (IsList(this)) /* non-default upper bounds */ 3388 { 3389 if (lpd->bdu == NULL) 3390 { 3391 lpd->bdu = (double *) Malloc((size_t) vadded.nint*sizeof(double)); 3392 Log1(lpd->bdu = (double *) malloc(%d*sizeof(double)), vadded.nint); 3393 } 3394 /* fill the bounds arrays with explicit bounds */ 3395 for (i = 0; (IsList(tlos) && IsList(this)); ++i) 3396 { 3397 pword *lhead = vlos.ptr; 3398 pword *ltail = lhead + 1; 3399 pword *hhead = vhis.ptr; 3400 pword *htail = hhead + 1; 3401 double lo, hi; 3402 3403 Dereference_(lhead); 3404 if (IsInteger(lhead->tag)) { 3405 lo = (double) lhead->val.nint; 3406 } else { 3407 Check_Float(lhead->tag); 3408 lo = Dbl(lhead->val); 3409 } 3410 lpd->bdl[i] = (lo < -CPX_INFBOUND ? -CPX_INFBOUND : lo); 3411 Dereference_(hhead); 3412 if (IsInteger(hhead->tag)) { 3413 hi = (double) hhead->val.nint; 3414 } else { 3415 Check_Float(hhead->tag); 3416 hi = Dbl(hhead->val); 3417 } 3418 lpd->bdu[i] = (hi > CPX_INFBOUND ? CPX_INFBOUND : hi); 3419 Dereference_(ltail); 3420 tlos = ltail->tag; 3421 vlos = ltail->val; 3422 Dereference_(htail); 3423 this = htail->tag; 3424 vhis = htail->val; 3425 } 3426 /* check that there are the right number of bds */ 3427 if (i != vadded.nint) { Bip_Error(RANGE_ERROR) } 3428 /* mark both arrays as "dirty" */ 3429 lpd->dirtybdflag |= 3; 3430 } 3431 else /* default upper bounds */ 3432 { 3433 if (lpd->bdu == NULL) /* upper bounds array freed */ 3434 { 3435 lpd->bdu = (double *) Malloc((size_t) lpd->macsz*sizeof(double)); 3436 Log1(lpd->bdu = (double *) malloc(%d*sizeof(double)), lpd->macsz); 3437 for (i=0; i<lpd->macsz; i++) 3438 { 3439 lpd->bdu[i] = CPX_INFBOUND; 3440 } 3441 } 3442 /* fill the lower bounds array with explicit bounds */ 3443 for (i = 0; (IsList(tlos)); ++i) 3444 { 3445 pword *lhead = vlos.ptr; 3446 pword *ltail = lhead + 1; 3447 double lo; 3448 3449 Dereference_(lhead); 3450 if (IsInteger(lhead->tag)) { 3451 lo = (double) lhead->val.nint; 3452 } else { 3453 Check_Float(lhead->tag); 3454 lo = Dbl(lhead->val); 3455 } 3456 lpd->bdl[i] = (lo < -CPX_INFBOUND ? -CPX_INFBOUND : lo); 3457 Dereference_(ltail); 3458 tlos = ltail->tag; 3459 vlos = ltail->val; 3460 } 3461 /* check that there are the right number of bds */ 3462 if (i != vadded.nint) { Bip_Error(RANGE_ERROR) } 3463 /* mark lower bounds array as "dirty" */ 3464 lpd->dirtybdflag |= 1; 3465 } 3466 } 3467 else if (IsList(this)) /* default lower bounds, non-default upper bounds */ 3468 { 3469 if (lpd->bdl == NULL) /* lower bounds array freed */ 3470 { 3471 lpd->bdl = (double *) Malloc((size_t) lpd->macsz*sizeof(double)); 3472 Log1(lpd->bdl = (double *) malloc(%d*sizeof(double)), lpd->macsz); 3473 for (i=0; i<lpd->macsz; i++) 3474 { 3475 lpd->bdl[i] = -CPX_INFBOUND; 3476 } 3477 } 3478 /* fill the upper bounds array with explicit bounds */ 3479 for (i = 0; (IsList(this)); ++i) 3480 { 3481 pword *hhead = vhis.ptr; 3482 pword *htail = hhead + 1; 3483 double hi; 3484 3485 Dereference_(hhead); 3486 if (IsInteger(hhead->tag)) { 3487 hi = (double) hhead->val.nint; 3488 } else { 3489 Check_Float(hhead->tag); 3490 hi = Dbl(hhead->val); 3491 } 3492 lpd->bdu[i] = (hi > CPX_INFBOUND ? CPX_INFBOUND : hi); 3493 Dereference_(htail); 3494 this = htail->tag; 3495 vhis = htail->val; 3496 } 3497 /* check that there are the right number of bds */ 3498 if (i != vadded.nint) { Bip_Error(RANGE_ERROR) } 3499 /* mark upper bounds array as "dirty" */ 3500 lpd->dirtybdflag |= 2; 3501 } 3502 else /* default bounds */ 3503 { 3504 if (lpd->bdl == NULL) /* lower bounds array freed */ 3505 { 3506 lpd->bdl = (double *) Malloc((size_t) lpd->macsz*sizeof(double)); 3507 Log1(lpd->bdl = (double *) malloc(%d*sizeof(double)), lpd->macsz); 3508 for (i=0; i<lpd->macsz; i++) 3509 { 3510 lpd->bdl[i] = -CPX_INFBOUND; 3511 } 3512 } 3513 if (lpd->bdu == NULL) /* upper bounds array freed */ 3514 { 3515 lpd->bdu = (double *) Malloc((size_t) lpd->macsz*sizeof(double)); 3516 Log1(lpd->bdu = (double *) malloc(%d*sizeof(double)), lpd->macsz); 3517 for (i=0; i<lpd->macsz; i++) 3518 { 3519 lpd->bdu[i] = CPX_INFBOUND; 3520 } 3521 } 3522 } 3523 } 3524 3525 /* fill the objective coefficients array if specified */ 3526 if (IsList(tobjs)) 3527 { 3528 3529 if (IsList(tobjs)) /* only if there are objective coefficients */ 3530 { 3531 TryFree(lpd->objx); 3532 Log1(lpd->objx = (double *) malloc((size_t) %d*sizeof(double)), vadded.nint); 3533 lpd->objx = (double *) Malloc((size_t) vadded.nint*sizeof(double)); 3534 } 3535 3536 for (i = 0; IsList(tobjs); ++i) 3537 { 3538 pword *head = vobjs.ptr; 3539 pword *tail = head + 1; 3540 double coeff; 3541 3542 Dereference_(head); 3543 if (IsInteger(head->tag)) { 3544 coeff = (double) head->val.nint; 3545 } else { 3546 Check_Float(head->tag); 3547 coeff = Dbl(head->val); 3548 Check_Constant_Range(coeff); 3549 } 3550 lpd->objx[i] = coeff; 3551 Dereference_(tail); 3552 tobjs = tail->tag; 3553 vobjs = tail->val; 3554 } 3555 /* check that there are the right number of objs */ 3556 if (i != vadded.nint) { Bip_Error(RANGE_ERROR) } 3557 } 3558 3559 Succeed; 3560} 3561 3562 3563int 3564p_cpx_init_type(value vlp, type tlp, value vj, type tj, value vtype, type ttype) 3565{ 3566 lp_desc *lpd; 3567 int j; 3568 3569 LpDescOnly(vlp, tlp, lpd); 3570 Check_Integer(tj); 3571 j = vj.nint; 3572 3573 if (j >= lpd->mac) { Bip_Error(RANGE_ERROR); } 3574 if (j >= lpd->macadded) j -= lpd->macadded; /* added col */ 3575 lpd->ctype[j] = (char) vtype.nint; 3576 if (vtype.nint != 'C') 3577 { 3578 switch (lpd->prob_type) 3579 { 3580 case PROBLEM_LP: 3581 lpd->prob_type = PROBLEM_MIP; 3582 break; 3583#ifdef HAS_MIQP 3584 case PROBLEM_QP: 3585 lpd->prob_type = PROBLEM_MIQP; 3586 break; 3587 case PROBLEM_MIQP: 3588#endif 3589 case PROBLEM_MIP: 3590 break; 3591 default: 3592 Fprintf(Current_Error, "Eplex error: this solver does not support solving of quadratic MIP problems.\n"); 3593 ec_flush(Current_Error); 3594 Bip_Error(EC_EXTERNAL_ERROR); 3595 break; 3596 } 3597 3598#ifdef XPRESS 3599 ++lpd->ngents; 3600#endif 3601 } 3602 Succeed; 3603} 3604 3605 3606/* Set bounds for new variables in buffer arrays. 3607 * Used for initial setup and for adding variables. 3608 */ 3609int 3610p_cpx_init_bound(value vlp, type tlp, value vj, type tj, value vwhich, type twhich, value vval, type tval) 3611{ 3612 lp_desc *lpd; 3613 int j; 3614 double bd; 3615 3616 LpDescOnly(vlp, tlp, lpd); 3617 Check_Integer(tj); 3618 Check_Atom(twhich); 3619 Check_Float(tval); 3620 bd = Dbl(vval); 3621 3622 j = vj.nint; 3623 if (j >= lpd->mac) { Bip_Error(RANGE_ERROR); } 3624 if (j >= lpd->macadded) j -= lpd->macadded; /* added col */ 3625 3626 if (vwhich.did == d_le) { /* upper bound */ 3627 if (bd < lpd->bdl[j]) { Fail; } 3628 if (bd < lpd->bdu[j]) { lpd->bdu[j] = bd; lpd->dirtybdflag |= 2; } 3629 3630 } else if (vwhich.did == d_ge) { /* lower bound */ 3631 if (bd > lpd->bdu[j]) { Fail; } 3632 if (bd > lpd->bdl[j]) { lpd->bdl[j] = bd; lpd->dirtybdflag |= 1; } 3633 3634 } else if (vwhich.did == d_eq) { /* both bounds */ 3635 if (bd < lpd->bdl[j] || lpd->bdu[j] < bd) { Fail; } 3636 lpd->bdl[j] = lpd->bdu[j] = bd; 3637 lpd->dirtybdflag |= 3; 3638 3639 } else { 3640 Bip_Error(RANGE_ERROR); 3641 } 3642 Succeed; 3643} 3644 3645 3646/*----------------------------------------------------------------------* 3647 * Retrieving variable type and bounds 3648 *----------------------------------------------------------------------*/ 3649 3650 3651int 3652p_cpx_get_col_type(value vlp, type tlp, value vj, type tj, value vtype, type ttype) 3653{ 3654 lp_desc *lpd; 3655 char ctype[1]; 3656 3657 LpDesc(vlp, tlp, lpd); 3658 Check_Integer(tj); 3659 if (vj.nint >= lpd->mac || vj.nint < 0) { Bip_Error(RANGE_ERROR); } 3660 SetPreSolve(lpd->presolve); 3661 if (IsMIPProb(lpd->prob_type)) 3662 { 3663 CPXupdatemodel(lpd->lp); /* before CPXget... */ 3664 if (CPXgetctype(cpx_env, lpd->lp, ctype, (int) vj.nint, (int) vj.nint)) 3665 { 3666 Bip_Error(EC_EXTERNAL_ERROR); 3667 } 3668 } 3669 else 3670 { 3671 ctype[0] = 'C'; 3672 } 3673 Return_Unify_Integer(vtype, ttype, (int) ctype[0]); 3674} 3675 3676/*----------------------------------------------------------------------* 3677 * Updating objective 3678 *----------------------------------------------------------------------*/ 3679 3680static void 3681_grow_cb_arrays(lp_desc * lpd, int with_index2) 3682{ 3683 if (lpd->cb_sz == 0) 3684 { 3685#ifdef LOG_CALLS 3686 Fprintf(log_output_, "\n\ 3687 lpd->cb_sz = %d;\n\ 3688 lpd->cb_index = (int *) malloc(lpd->cb_sz*sizeof(int));\n\ 3689 lpd->cb_value = (double *) malloc(lpd->cb_sz*sizeof(double));", 3690 NEWBD_INCR); 3691 if (with_index2) 3692 Fprintf(log_output_, "\n\ 3693 lpd->cb_index2 = (int *) malloc(lpd->cb_sz*sizeof(int));"); 3694 ec_flush(log_output_); 3695#endif 3696 lpd->cb_sz = NEWBD_INCR; 3697 lpd->cb_index = (int *) Malloc(NEWBD_INCR*sizeof(int)); 3698 if (with_index2) 3699 lpd->cb_index2 = (int *) Malloc(NEWBD_INCR*sizeof(int)); 3700 lpd->cb_value = (double *) Malloc(NEWBD_INCR*sizeof(double)); 3701 } 3702 else 3703 { 3704#ifdef LOG_CALLS 3705 Fprintf(log_output_, "\n\ 3706 lpd->cb_sz += %d;\n\ 3707 lpd->cb_index = (int *) realloc(lpd->cb_index, lpd->cb_sz*sizeof(int));\n\ 3708 lpd->cb_value = (double *) realloc(lpd->cb_value, lpd->cb_sz*sizeof(double));", 3709 NEWBD_INCR); 3710 if (with_index2) 3711 { 3712 Fprintf(log_output_, "\n\ 3713 lpd->cb_index2 = lpd->cb_index2\n\ 3714 ? (int *) realloc(lpd->cb_index2, lpd->cb_sz*sizeof(int))\n\ 3715 : (int *) malloc(lpd->cb_sz*sizeof(int));"); 3716 } 3717 else if (lpd->cb_index2) 3718 { 3719 Fprintf(log_output_, "\n\ 3720 free(lpd->cb_index2);\n\ 3721 lpd->cb_index2 = 0;"); 3722 } 3723 ec_flush(log_output_); 3724#endif 3725 lpd->cb_sz += NEWBD_INCR; 3726 lpd->cb_index = (int *) Realloc(lpd->cb_index, lpd->cb_sz*sizeof(int)); 3727 lpd->cb_value = (double *) Realloc(lpd->cb_value, lpd->cb_sz*sizeof(double)); 3728 if (with_index2) 3729 { 3730 lpd->cb_index2 = lpd->cb_index2 3731 ? (int *) Realloc(lpd->cb_index2, lpd->cb_sz*sizeof(int)) 3732 : (int *) Malloc(lpd->cb_sz*sizeof(int)); 3733 } 3734 else if (lpd->cb_index2) 3735 { 3736 Free(lpd->cb_index2); 3737 lpd->cb_index2 = 0; 3738 } 3739 } 3740} 3741 3742 3743int 3744p_cpx_new_obj_coeff(value vlp, type tlp, value vj, type tj, value vcoeff, type tcoeff) 3745{ 3746 lp_desc *lpd; 3747 double coeff; 3748 int i; 3749 3750 LpDescOnly(vlp, tlp, lpd); 3751 Check_Integer(tj); 3752 if (vj.nint >= lpd->mac) 3753 { Bip_Error(RANGE_ERROR); } 3754 3755 if (IsInteger(tcoeff)) { 3756 coeff = (double) vcoeff.nint; 3757 } else { 3758 Check_Float(tcoeff); 3759 coeff = Dbl(vcoeff); 3760 Check_Constant_Range(coeff); 3761 } 3762 if (lpd->cb_cnt >= lpd->cb_sz) /* grow arrays if necessary */ 3763 { 3764 _grow_cb_arrays(lpd, 0); 3765 } 3766 i = lpd->cb_cnt++; 3767 lpd->cb_index[i] = vj.nint; 3768 lpd->cb_value[i] = coeff; 3769 Succeed; 3770} 3771 3772int 3773p_cpx_flush_obj(value vlp, type tlp) 3774{ 3775 lp_desc *lpd; 3776 LpDesc(vlp, tlp, lpd); 3777 if (lpd->cb_cnt == 0) 3778 { 3779 Succeed; 3780 } 3781 SetPreSolve(lpd->presolve); 3782 Mark_Copy_As_Modified(lpd); 3783#ifdef LOG_CALLS 3784 { 3785 int i; 3786 for (i=0; i<lpd->cb_cnt; ++i) 3787 { 3788 Fprintf(log_output_, "\n\ 3789 lpd->cb_index[%d] = %d;\n\ 3790 lpd->cb_value[%d] = %.15e;", 3791 i, lpd->cb_index[i], i, lpd->cb_value[i]); 3792 } 3793 Log1(CPXchgobj(cpx_env, lpd->lp, %d, lpd->cb_index, lpd->cb_value), lpd->cb_cnt); 3794 } 3795#endif 3796 if (CPXchgobj(cpx_env, lpd->lp, lpd->cb_cnt, lpd->cb_index, lpd->cb_value)) 3797 { 3798 Bip_Error(EC_EXTERNAL_ERROR); 3799 } 3800 lpd->cb_cnt = 0; 3801 Succeed; 3802} 3803 3804int 3805p_cpx_new_qobj_coeff(value vlp, type tlp, 3806 value vi, type ti, 3807 value vj, type tj, 3808 value vcoeff, type tcoeff) 3809{ 3810 lp_desc *lpd; 3811 double coeff; 3812 3813 Check_Integer(ti); 3814 Check_Integer(tj); 3815 LpDesc(vlp, tlp, lpd); 3816 if (vj.nint >= lpd->mac || vi.nint >= lpd->mac) 3817 { Bip_Error(RANGE_ERROR); } 3818 3819 if (IsInteger(tcoeff)) { 3820 coeff = (double) vcoeff.nint; 3821 } else { 3822 Check_Float(tcoeff); 3823 coeff = Dbl(vcoeff); 3824 Check_Constant_Range(coeff); 3825 } 3826 if (vi.nint==vj.nint) 3827 coeff *= 2; 3828 SetPreSolve(lpd->presolve); 3829 Log3(CPXchgqpcoef(cpx_env, lpd->lp, %d,%d,%.15e), vi.nint, vj.nint, coeff); 3830 if (CPXchgqpcoef(cpx_env, lpd->lp, vi.nint, vj.nint, coeff)) 3831 { 3832 Bip_Error(EC_EXTERNAL_ERROR); 3833 } 3834 Succeed; 3835} 3836 3837 3838int 3839p_cpx_change_obj_sense(value vlp, type tlp, value vsense, type tsense) 3840{ 3841 lp_desc *lpd; 3842 3843 Check_Integer(tsense); 3844 LpDesc(vlp, tlp, lpd); 3845 3846 SetPreSolve(lpd->presolve); 3847 lpd->sense = vsense.nint; 3848 CPXchgobjsen(cpx_env, lpd->lp, vsense.nint); 3849#ifdef SOLVE_MIP_COPY 3850 if (lpd->copystatus != XP_COPYOFF) Mark_Copy_As_Modified(lpd); 3851#endif 3852 Succeed; 3853} 3854 3855/*----------------------------------------------------------------------* 3856 * Initial matrix setup 3857 *----------------------------------------------------------------------*/ 3858 3859int 3860p_cpx_set_matbeg(value vlp, type tlp, 3861 value vj, type tj, 3862 value vk, type tk, 3863 value vk1, type tk1) 3864{ 3865 lp_desc *lpd; 3866 int j; 3867 3868 Check_Integer(tk); 3869 Check_Integer(tk1); 3870 Check_Integer(tj); 3871 j = vj.nint; 3872 LpDescOnly(vlp, tlp, lpd); 3873 3874 if (j >= lpd->mac || j < 0) { Bip_Error(RANGE_ERROR); } 3875 if (j >= lpd->macadded) j -= lpd->macadded; /* added col */ 3876 lpd->matbeg[j] = vk.nint; 3877 lpd->matcnt[j] = vk1.nint - vk.nint; 3878 Succeed; 3879} 3880 3881int 3882p_cpx_set_matval(value vlp, type tlp, 3883 value vk, type tk, 3884 value vi, type ti, 3885 value vval, type tval) 3886{ 3887 lp_desc *lpd; 3888 Check_Integer(tk); 3889 Check_Integer(ti); 3890 Check_Number(tval); 3891 LpDescOnly(vlp, tlp, lpd); 3892 3893 if (vk.nint >= lpd->matnz || vk.nint < 0 || 3894 vi.nint >= lpd->mar || vi.nint < SOLVER_MAT_BASE) 3895 { Bip_Error(RANGE_ERROR); } 3896 lpd->matind[vk.nint] = vi.nint; 3897 lpd->matval[vk.nint] = DoubleVal(vval, tval); 3898 Check_Constant_Range(lpd->matval[vk.nint]); 3899 Succeed; 3900} 3901 3902int 3903p_cpx_loadprob(value vlp, type tlp) 3904{ 3905 int err; 3906 lp_desc *lpd; 3907 LpDescOnly(vlp, tlp, lpd); 3908 3909 SetPreSolve(lpd->presolve); 3910 lpd->start_mac = lpd->mac; 3911 3912 if (lpd->nsos) { 3913 if (lpd->prob_type == PROBLEM_QP) 3914 lpd->prob_type = PROBLEM_MIQP; 3915 else 3916 lpd->prob_type = PROBLEM_MIP; 3917 } 3918 3919#ifndef HAS_MIQP 3920 if (lpd->prob_type == PROBLEM_MIQP) 3921 { 3922 Fprintf(Current_Error, "Eplex error: this solver does not support solving of quadratic MIP problems.\n"); 3923 ec_flush(Current_Error); 3924 Bip_Error(UNIMPLEMENTED); 3925 } 3926#endif 3927#ifdef LOG_CALLS 3928 { 3929 int i; 3930# ifndef DUMPMAT 3931# ifdef XPRESS 3932 Fprintf(log_output_, "\n\ 3933 lpd->probname = (char *) malloc(16*sizeof(char));\n\ 3934 strcpy(lpd->probname, \"eclipse\");" 3935 ); 3936# endif 3937# ifdef CPLEX 3938 Log1(lpd->sense = %d, lpd->sense); 3939# endif 3940 Fprintf(log_output_, "\n\ 3941 lpd->sense = %d;\n\ 3942 lpd->macsz = %d;\n\ 3943 lpd->marsz = %d;\n\ 3944 lpd->matnz = %d;\n\ 3945 lpd->mac = %d;\n\ 3946 lpd->mar = %d;\n\ 3947 lpd->rhsx = (double *) malloc(lpd->marsz * sizeof(double));\n\ 3948 lpd->senx = (char *) malloc(lpd->marsz * sizeof(char));\n\ 3949 lpd->matbeg = (int *) malloc((lpd->macsz+1) * sizeof(int));\n\ 3950 lpd->matcnt = (int *) malloc(lpd->macsz * sizeof(int));\n\ 3951 lpd->matind = (int *) malloc(lpd->matnz * sizeof(int));\n\ 3952 lpd->matval = (double *) malloc(lpd->matnz * sizeof(double));\n\ 3953 lpd->bdl = (double *) malloc(lpd->macsz * sizeof(double));\n\ 3954 lpd->bdu = (double *) malloc(lpd->macsz * sizeof(double));\n\ 3955 lpd->objx = (double *) malloc(lpd->macsz * sizeof(double));\n\ 3956 lpd->ctype = (char *) malloc(lpd->macsz * sizeof(char));", 3957 lpd->sense,(lpd->macsz ? lpd->macsz : 1), (lpd->marsz ? lpd->marsz: 1), (lpd->matnz? lpd->matnz : 1), 3958 lpd->mac, lpd->mar); 3959 3960 for (i=0; i<lpd->mac; ++i) 3961 { 3962 Fprintf(log_output_, "\n\tlpd->objx[%d] = %.15e;", i, lpd->objx[i]); 3963 Fprintf(log_output_, "\n\tlpd->bdl[%d] = %.15e;", i, lpd->bdl[i]); 3964 Fprintf(log_output_, "\n\tlpd->bdu[%d] = %.15e;", i, lpd->bdu[i]); 3965 Fprintf(log_output_, "\n\tlpd->matbeg[%d] = %d;", i, lpd->matbeg[i]); 3966 Fprintf(log_output_, "\n\tlpd->matcnt[%d] = %d;", i, lpd->matcnt[i]); 3967 } 3968 for (i=0; i<lpd->mar; ++i) 3969 { 3970 Fprintf(log_output_, "\n\tlpd->rhsx[%d] = %.15e;", i, lpd->rhsx[i]); 3971 Fprintf(log_output_, "\n\tlpd->senx[%d] = '%c';", i, lpd->senx[i]); 3972 } 3973 for (i=0; i<lpd->matnz; ++i) 3974 { 3975 Fprintf(log_output_, "\n\tlpd->matind[%d] = %d;", i, lpd->matind[i]); 3976 Fprintf(log_output_, "\n\tlpd->matval[%d] = %.15e;", i, lpd->matval[i]); 3977 } 3978# else /* DUMPMAT */ 3979 dump_problem(lpd); 3980# endif 3981 } 3982#endif /* LOG_CALLS */ 3983 3984 lpd->lp = NULL; 3985 3986#ifdef GUROBI 3987 if (cpx_loadprob(lpd)) 3988 { 3989 Bip_Error(EC_EXTERNAL_ERROR); 3990 } 3991#endif 3992 3993#ifdef CPLEX 3994 CallN(lpd->lp = CPXcreateprob(cpx_env, &err, "eclipse")); 3995 3996 if (lpd->lp == NULL) 3997 { 3998 if (err == CPXERR_NO_ENVIRONMENT) { 3999 Fprintf(Current_Error, "Unable to create problem in CPLEX: licensing problem?\n"); 4000 ec_flush(Current_Error); 4001 } 4002 Bip_Error(EC_EXTERNAL_ERROR); 4003 } 4004#endif 4005#ifdef COIN 4006 CallN(coin_create_prob(&(lpd->lp), cpx_env)); 4007#endif 4008#if defined(CPLEX) || defined(COIN) 4009 CallN(lpd->lpcopy = lpd->lp); /* no need for a copy in CPLEX */ 4010 Call(err, CPXcopylp(cpx_env, lpd->lp, lpd->mac, lpd->mar, 4011 lpd->sense, lpd->objx, lpd->rhsx, lpd->senx, 4012 lpd->matbeg, lpd->matcnt, lpd->matind, lpd->matval, 4013 lpd->bdl, lpd->bdu, NULL)); 4014 if (err) 4015 { Bip_Error(EC_EXTERNAL_ERROR); } 4016 4017 if (IsMIPProb(lpd->prob_type)) 4018 { 4019# if defined(LOG_CALLS) 4020/* no need to log for XPRESS as ctype array not used directly */ 4021 { int i; 4022 for (i=0; i<lpd->mac; ++i) 4023 { 4024 Fprintf(log_output_, "\n\tlpd->ctype[%d] = '%c';", i, lpd->ctype[i]); 4025 } 4026 } 4027# endif 4028 Call(err, CPXcopyctype(cpx_env, lpd->lp, lpd->ctype)); 4029 if (err) 4030 { Bip_Error(EC_EXTERNAL_ERROR); } 4031 } 4032 4033 if (lpd->nsos) 4034 { 4035#if defined(CPLEX) && CPLEX < 10 4036 if (CPXaddsos(cpx_env, lpd->lp, lpd->nsos, lpd->nsosnz, lpd->sostype, 4037 NULL, lpd->sosbeg, lpd->sosind, lpd->sosref)) 4038#else 4039 if (CPXaddsos(cpx_env, lpd->lp, lpd->nsos, lpd->nsosnz, lpd->sostype, 4040 lpd->sosbeg, lpd->sosind, lpd->sosref, NULL)) 4041#endif 4042 { Bip_Error(EC_EXTERNAL_ERROR); } 4043 lpd->nsos_added = lpd->nsos; 4044 } 4045 if IsQPProb(lpd->prob_type) 4046 { 4047# ifdef HAS_QUADRATIC 4048 int i; 4049# ifdef HAS_MIQP 4050 int ptype = (lpd->prob_type == PROBLEM_QP ? CPXPROB_QP : CPXPROB_MIQP); 4051# else 4052 int ptype = CPXPROB_QP; 4053# endif 4054 if (CPXgetprobtype(cpx_env, lpd->lp) != ptype) 4055 { 4056 Call(err, CPXchgprobtype(cpx_env, lpd->lp, ptype)); 4057 if (err != 0) 4058 { Bip_Error(EC_EXTERNAL_ERROR); } 4059 } 4060# ifdef CPLEX 4061 for (i=0; i<lpd->cb_cnt; ++i) 4062 { 4063 Log3(CPXchgqpcoef(cpx_env, lpd->lp, %d, %d, %f), 4064 lpd->cb_index[i], lpd->cb_index2[i], lpd->cb_value[i]); 4065 4066 if (CPXchgqpcoef(cpx_env, lpd->lp, lpd->cb_index[i], 4067 lpd->cb_index2[i], lpd->cb_value[i])) 4068 { Bip_Error(EC_EXTERNAL_ERROR); } 4069 } 4070 lpd->cb_cnt = 0; 4071# elif defined(COIN) 4072 coin_set_qobj(lpd->lp, lpd->mac, lpd->cb_cnt, lpd->cb_index, lpd->cb_index2, lpd->cb_value); 4073# endif 4074 4075# else /* !HAS_QUADRATIC */ 4076 Fprintf(Current_Error, "Eplex error: Quadratic problems not supported for this solver!\n"); 4077 ec_flush(Current_Error); 4078 Bip_Error(EC_EXTERNAL_ERROR); 4079# endif 4080 } 4081 4082#endif /* CPLEX || COIN */ 4083#ifdef XPRESS 4084 4085 Call(err, XPRScreateprob(&lpd->lp)); 4086 if (lpd->copystatus != XP_COPYOFF) 4087 { 4088 Mark_Copy_As_Modified(lpd); 4089 if (IsMIPProb(lpd->prob_type)) 4090 { 4091 if (err == 0) { Call(err, XPRScreateprob(&lpd->lpcopy)); } 4092 } 4093 else 4094 CallN(lpd->lpcopy = lpd->lp); 4095 } 4096 else 4097 CallN(lpd->lpcopy = lpd->lp); 4098 4099 if (err && (err != 32/*student version*/)) 4100 { 4101 char errmsg[256]; 4102 XPRSgetlasterror(lpd->lp, errmsg); 4103 Fprintf(Current_Error, "Eplex error: %s\n", errmsg); 4104 ec_flush(Current_Error); 4105 Bip_Error(EC_EXTERNAL_ERROR); 4106 } 4107 4108 CallN(XPRScopycontrols(lpd->lp, cpx_env)); 4109 /* Switch presolve off if requested, otherwise leave cpx_env's defaults */ 4110 if (lpd->presolve == 0) 4111 { 4112 CallN(XPRSsetintcontrol(lpd->lp, XPRS_PRESOLVE, 0)); 4113 CallN(XPRSsetintcontrol(lpd->lp, XPRS_MIPPRESOLVE, 0)); 4114 } 4115 4116 /* this call back was done globally before version 13 */ 4117 XPRSsetcbmessage(lpd->lp, eclipse_out, NULL); 4118 4119 /* the problem is now always loaded with XPRSloadglobal() 4120 as suggested by David Nielsen @ Dash 2004-09-28 4121 For a quadratic problem, the quadratic terms are then added 4122 */ 4123 if (lpd->ngents) /* has integers */ 4124 { 4125 int i,j; 4126 /* don't know whether these arrays can be temporary */ 4127 Log1({ 4128 lpd->ngents = %i;\n\ 4129 lpd->nsos = 0;\n\ 4130 lpd->sossz = 0;\n\ 4131 lpd->sostype = NULL;\n\ 4132 lpd->sosbeg = NULL;\n\ 4133 lpd->sosind = NULL;\n\ 4134 lpd->sosref = NULL;\n\ 4135 }, lpd->ngents); 4136 CallN(lpd->qgtype = (char *)Malloc(lpd->ngents*sizeof(char))); 4137 CallN(lpd->mgcols = (int *)Malloc(lpd->ngents*sizeof(int))); 4138 for (i=0,j=0; i < lpd->mac; i++) 4139 { 4140 if (lpd->ctype[i] != 'C') 4141 { 4142 Log4({\n\ 4143 lpd->qgtype[%i] = '%c';\n\ 4144 lpd->mgcols[%i] = %i;\n\ 4145 }, j, lpd->ctype[i], j, i); 4146 4147 lpd->qgtype[j] = lpd->ctype[i]; /* 'B' or 'I' */ 4148 lpd->mgcols[j++] = i; 4149 } 4150 } 4151 /* correct the count, in case there were duplicates 4152 * in the integer list (yes it happened...) */ 4153 lpd->ngents = j; 4154 Log1(lpd->ngents = %i, j); 4155 } 4156 else 4157 { 4158 lpd->qgtype = NULL; 4159 lpd->mgcols = NULL; 4160 } 4161 4162 Call(err, XPRSloadglobal(lpd->lp, lpd->probname, 4163 lpd->mac, lpd->mar, lpd->senx, lpd->rhsx, NULL, lpd->objx, 4164 lpd->matbeg, lpd->matcnt, lpd->matind, lpd->matval, 4165 lpd->bdl, lpd->bdu, 4166 lpd->ngents, lpd->nsos, lpd->qgtype, lpd->mgcols, NULL, 4167 lpd->sostype, lpd->sosbeg, lpd->sosind, lpd->sosref)); 4168 4169 if (err) { Bip_Error(EC_EXTERNAL_ERROR); } 4170 4171 if (lpd->cb_cnt) /* has quadratic objective terms */ 4172 { 4173# ifdef LOG_CALLS 4174 int i; 4175 Fprintf(log_output_, "\n\tlpd->cb_cnt = %d;", lpd->cb_cnt); 4176 for(i=0; i< lpd->cb_cnt; ++i) 4177 { 4178 Fprintf(log_output_, "\n\tlpd->cb_index[%d] = %d;", i, lpd->cb_index[i]); 4179 Fprintf(log_output_, "\n\tlpd->cb_index2[%d] = %d;", i, lpd->cb_index2[i]); 4180 Fprintf(log_output_, "\n\tlpd->cb_value[%d] = %.15e;", i, lpd->cb_value[i]); 4181 } 4182# endif 4183 Call(err, XPRSchgmqobj(lpd->lp, lpd->cb_cnt, 4184 lpd->cb_index, lpd->cb_index2, lpd->cb_value)); 4185 4186 lpd->cb_cnt = 0; 4187 if (err) { Bip_Error(EC_EXTERNAL_ERROR); } 4188 } 4189 4190 4191 4192#endif /* XPRESS */ 4193 4194 /* free our copy of the problem */ 4195 Free(lpd->rhsx); lpd->rhsx = NULL; 4196 Free(lpd->senx); lpd->senx = NULL; 4197 Free(lpd->matbeg); lpd->matbeg = NULL; 4198 Free(lpd->matcnt); lpd->matcnt = NULL; 4199 Free(lpd->matind); lpd->matind = NULL; 4200 Free(lpd->matval); lpd->matval = NULL; 4201 Free(lpd->bdl); lpd->bdl = NULL; 4202 Free(lpd->bdu); lpd->bdu = NULL; 4203 Free(lpd->ctype); lpd->ctype = NULL; 4204 Free(lpd->objx); lpd->objx = NULL; 4205 lpd->matnz = 0; 4206 lpd->macsz = 0; 4207 4208 if (lpd->nsos) 4209 { 4210 lpd->nsos_added = lpd->nsos; 4211 Free(lpd->sosbeg); lpd->sosbeg = NULL; 4212 Free(lpd->sosind); lpd->sosind = NULL; 4213 Free(lpd->sosref); lpd->sosref = NULL; 4214 lpd->nsosnz = 0; 4215 } 4216 4217 lpd->macadded = lpd->mac; 4218 Succeed; 4219} 4220 4221/* add initial cutpool constraints to problem */ 4222static int 4223_setup_initial_cp_constraints(lp_desc * lpd, int add_all, int * unadded_cntp, 4224 int * cp_unadded, int * cp_map2) 4225{ 4226 double * rhs, * rmatval; 4227 int * rmatbeg, * rmatind, i, offset, first = -1, 4228 cp_rcnt2 = 0, rcnt = 0; 4229 char * senx; 4230 4231 4232 rmatbeg = (int *)Malloc((lpd->cp_nr2+1)*sizeof(int)); 4233 4234 for (i=0; i < lpd->cp_nr2; i++) 4235 { 4236 if (lpd->cp_active2[i] == 1) 4237 { 4238 if (lpd->cp_initial_add2[i] == 1 || add_all) 4239 {/* active, added initially (or add all active constraints) */ 4240 if (first == -1) 4241 { 4242 first = i; 4243 offset = lpd->cp_rmatbeg2[first]; 4244 } 4245 /* rmatbeg need to be offset from the start of array */ 4246 rmatbeg[cp_rcnt2] = lpd->cp_rmatbeg2[i] - offset; 4247 cp_map2[i] = cp_rcnt2++; 4248 rcnt++; 4249 continue; 4250 } else 4251 { /* active, but not added initially */ 4252 cp_map2[i] = CSTR_STATE_NOTADDED; /* not added yet */ 4253 cp_unadded[(*unadded_cntp)++] = i; 4254 } 4255 } else 4256 {/* not active */ 4257 cp_map2[i] = CSTR_STATE_INACTIVE; /* not active */ 4258 } 4259 4260 if (rcnt > 0) 4261 {/* there are some rows to add... */ 4262 rhs = &lpd->cp_rhsx2[first]; 4263 rmatind = &lpd->cp_rmatind2[offset]; 4264 rmatval = &lpd->cp_rmatval2[offset]; 4265 senx = &lpd->cp_senx2[first]; 4266 CPXaddrows(cpx_env, lpd->lp, 0, rcnt, 4267 (lpd->cp_rmatbeg2[i] - offset), 4268 rhs, senx, rmatbeg, rmatind, rmatval, NULL, NULL); 4269 rcnt = 0; 4270 first = -1; 4271 } 4272 4273 } 4274 4275 if (rcnt > 0) 4276 {/* there are some rows to add... */ 4277 rhs = &lpd->cp_rhsx2[first]; 4278 rmatind = &lpd->cp_rmatind2[offset]; 4279 rmatval = &lpd->cp_rmatval2[offset]; 4280 senx = &lpd->cp_senx2[first]; 4281 CPXaddrows(cpx_env, lpd->lp, 0, rcnt, 4282 (lpd->cp_nnz2 - offset), 4283 rhs, senx, rmatbeg, rmatind, rmatval, NULL, NULL); 4284 rcnt = 0; 4285 first = -1; 4286 } 4287 4288 lpd->mar += cp_rcnt2; 4289 lpd->cp_nact2 = cp_rcnt2; 4290 if (cp_rcnt2 > 0) { Mark_Copy_As_Modified(lpd); } 4291 Free(rmatbeg); 4292 4293 return 0; 4294} 4295 4296/*----------------------------------------------------------------------* 4297 * Read/write 4298 *----------------------------------------------------------------------*/ 4299 4300int 4301p_cpx_lpwrite(value vfile, type tfile, value vformat, type tformat, 4302 value vlp, type tlp) 4303{ 4304 lp_desc *lpd; 4305 char has_cp = 0, *file, *format; 4306 int oldmar, res; 4307 Get_Name(vformat, tformat, format); 4308 Get_Name(vfile, tfile, file); 4309 LpDesc(vlp, tlp, lpd); 4310 4311 oldmar = lpd->mar; 4312 4313 SetPreSolve(lpd->presolve); 4314 if (lpd->cp_nr2 > 0) 4315 { 4316 int unadded_cnt = 0, * cp_unadded, * cp_map2; 4317 4318 cp_unadded = (int *)Malloc(lpd->cp_nr2*sizeof(int)); 4319 cp_map2 = (int *)Malloc(lpd->cp_nr2*sizeof(int)); 4320 if (_setup_initial_cp_constraints(lpd, 1, &unadded_cnt, cp_unadded, cp_map2) == -1) 4321 { 4322 reset_rowcols(lpd, oldmar, lpd->mac); 4323 Bip_Error(RANGE_ERROR); 4324 } 4325 } 4326 res = cpx_write(lpd, file, format); 4327 reset_rowcols(lpd, oldmar, lpd->mac); 4328 if (res == 0) 4329 { 4330 Succeed; 4331 } else 4332 { 4333 Bip_Error(EC_EXTERNAL_ERROR); 4334 } 4335} 4336 4337 4338int 4339p_cpx_lpread(value vfile, type tfile, 4340 value vformat, type tformat, 4341 value vpresolve, type tpresolve, 4342 value vhandle, type thandle) 4343{ 4344 lp_desc *lpd; 4345 char *file, *format; 4346 int res; 4347#if defined(CPLEX) || defined(XPRESS) 4348 if (!cpx_env) 4349 { 4350 Bip_Error(EC_LICENSE_ERROR); 4351 } 4352#endif 4353 4354 Get_Name(vfile, tfile, file); 4355 Get_Name(vformat, tformat, format); 4356 Check_Structure(thandle); 4357 Check_Integer(tpresolve); 4358 4359 CallN((lpd = (lp_desc *) Malloc(sizeof(lp_desc)))); 4360 /*CallN(_clr_lp_desc(lpd));*/ 4361 CallN(memset(lpd, 0, sizeof(lp_desc))); 4362 /* the logged code needs to be hand-adjusted to put file in scope */ 4363 Log1({char *file = "%s";}, file); 4364 lpd->presolve = vpresolve.nint; 4365 4366#ifdef USE_PROBLEM_ARRAY 4367 Log1(lpdmat[%d] = lpd, next_matno); 4368 current_matno = next_matno; 4369 lpd->matno = next_matno++; 4370#endif 4371 4372 if (cpx_read(lpd, file, format)) 4373 { 4374 Bip_Error(EC_EXTERNAL_ERROR); 4375 } 4376 4377 lpd->start_mac = lpd->macadded = lpd->mac; 4378 lpd->descr_state = DESCR_LOADED; 4379 4380 {/* Return the cplex descriptor in argument HANDLE_CPH of the handle structure. */ 4381 vhandle.ptr[HANDLE_CPH] = ec_handle(&lp_handle_tid, lpd); 4382 Make_Stamp(vhandle.ptr+HANDLE_STAMP); /* needed for other trail undos */ 4383 } 4384 Succeed; 4385} 4386 4387 4388void 4389_create_result_darray(value vhandle, int pos, int size, pword* pw, double** start) 4390{ 4391 pword *argp = &vhandle.ptr[pos]; 4392 4393 Dereference_(argp); 4394 if (IsRef(argp->tag)) 4395 *start = NULL; 4396 else 4397 { 4398 pw->tag.kernel = TSTRG; 4399 pw->val.ptr = _create_darray(size); 4400 *start = DArrayStart(pw->val.ptr); 4401 } 4402} 4403 4404void 4405_create_result_iarray(value vhandle, int pos, int size, pword *pw, int** start) 4406{ 4407 pword *argp = &vhandle.ptr[pos]; 4408 4409 Dereference_(argp); 4410 if (IsRef(argp->tag)) 4411 *start = NULL; 4412 else 4413 { 4414 pw->tag.kernel = TSTRG; 4415 pw->val.ptr = _create_iarray(size); 4416 *start = IArrayStart(pw->val.ptr); 4417 } 4418} 4419 4420/*----------------------------------------------------------------------* 4421 * Accessing Infeasible information 4422 *----------------------------------------------------------------------*/ 4423 4424#ifdef SUPPORT_IIS 4425static int 4426_get_iis(lp_desc * lpd, int * nrowsp, int * ncolsp, int * rowidxs, int * colidxs, char * colstats) 4427{ 4428 int status; 4429 int i; 4430# ifdef CPLEX 4431 int * rowstatbuf, * colstatbuf; 4432 4433 rowstatbuf = Malloc(sizeof(int) * *nrowsp); 4434 colstatbuf = Malloc(sizeof(int) * *ncolsp); 4435 4436# endif 4437 4438 Get_Conflict(lpd->lp, status, rowidxs, rowstatbuf, nrowsp, colidxs, colstatbuf, ncolsp); 4439 4440# ifdef CPLEX 4441 switch (status) 4442 { 4443 case CPX_STAT_CONFLICT_MINIMAL: 4444 for(i=0;i<*ncolsp;i++) 4445 { 4446 switch (colstatbuf[i]) 4447 { 4448# ifdef HAS_GENERAL_CONFLICT_REFINER 4449 case CPX_CONFLICT_MEMBER: 4450 colstats[i] = 'b'; 4451 break; 4452# endif 4453 case CPX_CONFLICT_LB: 4454 colstats[i] = 'l'; 4455 break; 4456 case CPX_CONFLICT_UB: 4457 colstats[i] = 'u'; 4458 break; 4459 default: 4460 colstats[i] = 'x'; 4461 break; 4462 } 4463 } 4464 Free(rowstatbuf); 4465 Free(colstatbuf); 4466 break; 4467 default: 4468 Free(rowstatbuf); 4469 Free(colstatbuf); 4470 return -1; 4471 break; 4472# ifdef HAS_GENERAL_CONFLICT_REFINER 4473 case CPX_STAT_CONFLICT_FEASIBLE: 4474 /* An infeaible problem can return CONFLICT_FEASIBLE, with no conflict set, probably because 4475 problem is near feasible. 4476 */ 4477 *nrowsp = 0; 4478 *ncolsp = 0; 4479 Free(rowstatbuf); 4480 Free(colstatbuf); 4481 return 1; 4482 break; 4483# endif 4484 } 4485# endif 4486# ifdef XPRESS 4487 if (!status) { 4488 for(i=0;i<*ncolsp;i++) colstats[i] = 'x'; 4489 } else { 4490 return -1; 4491 } 4492# endif 4493 4494 return 0; 4495} 4496 4497#endif /* SUPPORT_IIS */ 4498 4499 4500/*----------------------------------------------------------------------* 4501 * Solve 4502 *----------------------------------------------------------------------*/ 4503 4504 4505static int 4506_cstr_state(lp_desc * lpd, int row, char add_cp_cstr, double * sols, double tol) 4507{ 4508 int lastarg, argpos; 4509 double lhs = 0.0, slack; 4510 4511 /* add_cp_cstr == 2 if unbounded result -- simply add all constraints 4512 in this case by returning violated state 4513 */ 4514 if (add_cp_cstr == 2) return CSTR_STATE_VIOLATED; 4515 lastarg = (row < lpd->cp_nr2 - 1 ? lpd->cp_rmatbeg2[row+1] : lpd->cp_nnz2); 4516 for (argpos = lpd->cp_rmatbeg2[row] ; argpos < lastarg ; argpos++) 4517 { 4518 lhs += sols[lpd->cp_rmatind2[argpos]] * lpd->cp_rmatval2[argpos]; 4519 } 4520 /* definition of slack for all row types except ranged rows, which we 4521 don't use 4522 */ 4523 slack = lpd->cp_rhsx2[row] - lhs; 4524 switch (lpd->cp_senx2[row]) 4525 { 4526 case SOLVER_SENSE_LE: 4527 return (slack<-tol ? CSTR_STATE_VIOLATED 4528 : (slack<=tol ? CSTR_STATE_BINDING : CSTR_STATE_SAT)); 4529 break; 4530 case SOLVER_SENSE_GE: 4531 return (slack > tol ? CSTR_STATE_VIOLATED 4532 : (slack >= -tol ? CSTR_STATE_BINDING : CSTR_STATE_SAT)); 4533 break; 4534 case SOLVER_SENSE_EQ: 4535 return (slack <= tol && slack >= -tol ? CSTR_STATE_BINDING 4536 : CSTR_STATE_VIOLATED); 4537 break; 4538 default: 4539 /* constraint type out of range */ 4540 return CSTR_STATE_INVALID; 4541 break; 4542 } 4543} 4544 4545 4546/* cplex_optimise(Handle, SolveMethods, TimeOut, WriteBefore, MipStart, 4547 OutputPos, OptResult, OptStatus, WorstBound, BestBound) 4548 4549 optimises problem in Handle. Handle is needed to access the result 4550 arrays located in Handle by the OutputPos arguments. 4551 OptResult is the resulting status after the optimisation, OptStatus is 4552 the optimiser-dependent status returned by the optimiser. Worst and 4553 Best bounds are the bounds on the optimal solution determined by the 4554 solver. 4555 4556 Any solution state must be extracted from the optimiser in this procedure, 4557 as it modifies the problem by first adding the cutpool constraints before 4558 calling the optimiser and then removing them before exiting. 4559*/ 4560 4561int 4562p_cpx_optimise(value vhandle, type thandle, value vmeths, type tmeths, 4563 value vtimeout, type ttimeout, value vdump, type tdump, 4564 value vmipstart, type tmipstart, 4565 value vout, type tout, value vres, type tres, value vstat, type tstat, 4566 value vworst, type tworst, value vbest, type tbest) 4567{ 4568 lp_desc *lpd; 4569 int res, oldmar; 4570 int solspos, pispos, slackspos, djspos, cbasepos, rbasepos, cpcondmappos; 4571 int iis_rowspos, iis_colspos, iis_colstatspos; 4572 pword * pw, outsols, outpis, outslacks, outdjs, outcbase, outrbase; 4573 /* outdjs: when adding a solver, check to make sure that the reduced 4574 cost is of the same sign as what we defined (and what CPLEX and 4575 XPress uses). Reverse the signs before returning to ECLiPSe if required! 4576 */ 4577 struct lp_meth meth; 4578 struct lp_sol sol; 4579 char has_cp = 0; /* has cutpool constraints added */ 4580 char add_cp_cstr = 0; 4581 char *file = NULL; 4582 char *format = NULL; 4583 double bestbound, worstbound; 4584 int * cp_unadded, last_violated_idx, violated_cnt, unadded_cnt = 0; 4585 int * cp_map2; 4586 pword * old_tg; 4587 4588 /********************************************************************* 4589 * Type Checking and Initialisation * 4590 *********************************************************************/ 4591 4592 Prepare_Requests 4593 4594 Check_Structure(thandle); 4595 Check_Structure(tmeths); 4596 Check_Integer(tout); 4597 Check_Integer(tmipstart); 4598 Check_Number(ttimeout); 4599 4600 LpDesc(vhandle.ptr[HANDLE_CPH].val, vhandle.ptr[HANDLE_CPH].tag, lpd); 4601 4602 if (lpd->descr_state == DESCR_EMPTY) 4603 { 4604 Fprintf(Current_Error, "Eplex optimise: empty handle\n"); 4605 (void) ec_flush(Current_Error); 4606 Bip_Error(EC_EXTERNAL_ERROR); 4607 } 4608 4609 /* m(Method,AuxMeth,NodeMeth,NodeAuxMeth) */ 4610 pw = &vmeths.ptr[1]; 4611 Dereference_(pw); 4612 Check_Integer(pw->tag); 4613 meth.meth = pw->val.nint; 4614 pw = &vmeths.ptr[2]; 4615 Dereference_(pw); 4616 Check_Integer(pw->tag); 4617 meth.auxmeth = pw->val.nint; 4618 pw = &vmeths.ptr[3]; 4619 Dereference_(pw); 4620 Check_Integer(pw->tag); 4621 meth.node_meth = pw->val.nint; 4622 pw = &vmeths.ptr[4]; 4623 Dereference_(pw); 4624 Check_Integer(pw->tag); 4625 meth.node_auxmeth = pw->val.nint; 4626 4627 /* positions for output arrays in the Prolog handle */ 4628 solspos = vout.nint + HANDLE_S_SOLS; 4629 pispos = vout.nint + HANDLE_S_PIS; 4630 slackspos = vout.nint + HANDLE_S_SLACKS; 4631 djspos = vout.nint + HANDLE_S_DJS; 4632 cbasepos = vout.nint + HANDLE_S_CBASE; 4633 rbasepos = vout.nint + HANDLE_S_RBASE; 4634 cpcondmappos = vout.nint + HANDLE_S_CPCM; 4635 iis_rowspos = vout.nint + HANDLE_S_IISR; 4636 iis_colspos = vout.nint + HANDLE_S_IISC; 4637 iis_colstatspos = vout.nint + HANDLE_S_IISCS; 4638 4639 if (IsStructure(tdump)) 4640 { /* write_before_solve(Format,File) */ 4641 pw = &vdump.ptr[1]; 4642 Dereference_(pw); 4643 Get_Name(pw->val, pw->tag, format); 4644 pw = &vdump.ptr[2]; 4645 Dereference_(pw); 4646 Get_Name(pw->val, pw->tag, file); 4647 } 4648 4649 SetPreSolve(lpd->presolve); 4650 4651 oldmar = lpd->mar; 4652 if (lpd->cp_nr2 > 0) 4653 { 4654 4655 pword map; 4656 4657 _create_result_iarray(vhandle, cpcondmappos, lpd->cp_nr2, &map, &cp_map2); 4658 4659 cp_unadded = (int *)Malloc(lpd->cp_nr2*sizeof(int)); 4660 4661 if (_setup_initial_cp_constraints(lpd, 0, &unadded_cnt, cp_unadded, cp_map2) == -1) 4662 { 4663 reset_rowcols(lpd, oldmar, lpd->mac); 4664 Bip_Error(RANGE_ERROR); 4665 } 4666 if (cp_map2) 4667 ec_assign(vhandle.ptr+cpcondmappos, map.val, map.tag); 4668 has_cp = 1; 4669 } 4670 4671 /* initialise the lp_sol structure 4672 */ 4673 pw = &vhandle.ptr[solspos]; 4674 Dereference_(pw); 4675 sol.oldmac = IsArray(pw->tag) ? DArraySize(pw->val.ptr) : 0; 4676 sol.oldsols = IsArray(pw->tag) ? DArrayStart(pw->val.ptr) : NULL; 4677 4678 _create_result_darray(vhandle, solspos, lpd->mac, &outsols, &sol.sols); 4679#ifdef HAS_LIMITED_MIP_RESULTS 4680 if (IsMIPProb(lpd->prob_type)) { 4681 sol.djs = NULL; 4682 sol.cbase = NULL; 4683 } else 4684#endif 4685 {/* djs, basis, pis are available for non-MIP problems only for CPLEX; 4686 for XPRESS, the returned values are for the optimal LP node 4687 */ 4688 _create_result_darray(vhandle, djspos, lpd->mac, &outdjs, &sol.djs); 4689 _create_result_iarray(vhandle, cbasepos, lpd->mac, &outcbase, &sol.cbase); 4690 } 4691 4692 /* allocate the row-wise arrays later as these may need to be expanded 4693 with the addition cutpool constraints 4694 */ 4695 old_tg = TG; 4696 _create_result_darray(vhandle, slackspos, lpd->mar, &outslacks, &sol.slacks); 4697#ifdef HAS_LIMITED_MIP_RESULTS 4698 if (IsMIPProb(lpd->prob_type)) { 4699 sol.pis = NULL; 4700 sol.rbase = NULL; 4701 } else 4702#endif 4703 { 4704 _create_result_iarray(vhandle, rbasepos, lpd->mar, &outrbase, &sol.rbase); 4705 _create_result_darray(vhandle, pispos, lpd->mar, &outpis, &sol.pis); 4706 } 4707 sol.mac = lpd->mac; 4708 4709 Log6({ 4710 sol.sols = (double *) malloc(sizeof(double) * %d);\n\ 4711 sol.pis = (double *) malloc(sizeof(double) * %d);\n\ 4712 sol.slacks = (double *) malloc(sizeof(double) * %d);\n\ 4713 sol.djs = (double *) malloc(sizeof(double) * %d);\n\ 4714 sol.cbase = (int *) malloc(sizeof(int) * %d); 4715 sol.rbase = (int *) malloc(sizeof(int) * %d); 4716 }, lpd->mac, lpd->mar, lpd->mar, lpd->mac, lpd->mac, lpd->mar); 4717 4718 4719 /* configure solver with timeout and solution methods 4720 */ 4721 if (cpx_prepare_solve(lpd, &meth, 4722#ifdef XPRESS 4723 &sol, 4724#endif 4725 DoubleVal(vtimeout,ttimeout))) 4726 { 4727 reset_rowcols(lpd, oldmar, lpd->mac); 4728 Bip_Error(EC_EXTERNAL_ERROR); 4729 } 4730 meth.option_mipstart = vmipstart.nint; 4731 4732 /* if solution values are unavailable, and there are unadded cutpool 4733 constraints, abort with RANGE_ERROR as we can't check for violations 4734 */ 4735 if (unadded_cnt > 0 && sol.sols == NULL) 4736 { 4737 reset_rowcols(lpd, oldmar, lpd->mac); 4738 Bip_Error(RANGE_ERROR); 4739 } 4740 4741 /********************************************************************* 4742 * Solve Problem with the External Solver * 4743 * depending on problem type, call the appropriate routine * 4744 * may solve multiple times with cutpool constraints * 4745 *********************************************************************/ 4746 4747 do 4748 { 4749 int i; 4750 4751 violated_cnt = 0; 4752 if (IsStructure(tdump)) 4753 { 4754 cpx_write(lpd, file, format); /* ignore any errors here */ 4755 } 4756 4757 /* Run the solver 4758 */ 4759 if (cpx_solve(lpd, &meth, &sol, &bestbound, &worstbound)) 4760 { 4761 if (has_cp) reset_rowcols(lpd, oldmar, lpd->mac); 4762 Bip_Error(EC_EXTERNAL_ERROR); 4763 } 4764 4765#ifdef LOG_CALLS 4766 Fprintf(log_output_, "\n}\nvoid step_%d() {\n", log_ctr++); 4767 ec_flush(log_output_); 4768 current_matno = -1; /* no current mat, exited from procedure */ 4769#endif 4770 4771 /********************************************************************* 4772 * Get Result from External Solver * 4773 * Get the result for the optimisation from the external * 4774 * solver if there is one * 4775 *********************************************************************/ 4776 4777 switch (lpd->descr_state) 4778 { 4779 case DESCR_SOLVED_SOL: 4780 case DESCR_ABORTED_SOL: 4781 add_cp_cstr = 1; 4782 if (cpx_get_soln_state(lpd, &sol)) 4783 { 4784 if (has_cp) reset_rowcols(lpd, oldmar, lpd->mac); 4785 Bip_Error(EC_EXTERNAL_ERROR); 4786 } 4787 break; 4788 4789 case DESCR_SOLVED_NOSOL: 4790 add_cp_cstr = 0; 4791 /* no solution; state always fail */ 4792#ifdef SUPPORT_IIS 4793 { 4794 pword *argp = &vhandle.ptr[iis_rowspos]; 4795 4796 Dereference_(argp); 4797 4798 if (!IsRef(argp->tag)) 4799 { 4800 int iis_nrows, iis_ncols; 4801 int err; 4802 pword * old_tg1; 4803 4804 pword iis_rowidxs, iis_colidxs, iis_colstats; 4805 4806 Find_Conflict(err, lpd->lp, iis_nrows, iis_ncols); 4807 if (err) 4808 {/* we can't simply abort here if an error occurs, just create dummy arrays 4809 and do not proceed to try to get the IIS */ 4810 iis_nrows = 0; 4811 iis_ncols = 0; 4812 } 4813 old_tg1 = TG; 4814 iis_rowidxs.val.ptr = _create_iarray(iis_nrows); 4815 iis_rowidxs.tag.kernel = TSTRG; 4816 iis_colidxs.val.ptr = _create_iarray(iis_ncols); 4817 iis_colidxs.tag.kernel = TSTRG; 4818 iis_colstats.val.ptr = _create_carray(iis_ncols); 4819 iis_colstats.tag.kernel = TSTRG; 4820 4821 4822 if (!err && (_get_iis(lpd, &iis_nrows, &iis_ncols, 4823 IArrayStart(iis_rowidxs.val.ptr), IArrayStart(iis_colidxs.val.ptr), 4824 CArrayStart(iis_colstats.val.ptr)) 4825 != 0) 4826 ) 4827 { 4828 /* something went wrong; reallocate iis arrays with 0 size */ 4829 TG = old_tg1; 4830 iis_nrows = 0; 4831 iis_ncols = 0; 4832 iis_rowidxs.val.ptr = _create_iarray(0); 4833 iis_colidxs.val.ptr = _create_iarray(0); 4834 iis_colstats.val.ptr = _create_carray(0); 4835 } 4836 4837 ec_assign(vhandle.ptr+iis_rowspos, iis_rowidxs.val, iis_rowidxs.tag); 4838 ec_assign(vhandle.ptr+iis_colspos, iis_colidxs.val, iis_colidxs.tag); 4839 ec_assign(vhandle.ptr+iis_colstatspos, iis_colstats.val, iis_colstats.tag); 4840 4841 } 4842 } 4843#endif 4844 break; 4845 4846 default: 4847 { 4848#ifdef HAS_POSTSOLVE 4849 int presolve; /* postsolve prob. if it is left in a presolved state */ 4850 4851 if (XPRSgetintattrib(lpd->lp, XPRS_PRESOLVESTATE, &presolve)) 4852 { 4853 if (presolve & 2) /* is in a presolve state */ 4854 CallN(XPRSpostsolve(lpd->lp)); /* post-solve problem if possible */ 4855 } 4856#endif 4857 if (lpd->descr_state == DESCR_UNBOUNDED_NOSOL || 4858 lpd->descr_state == DESCR_UNKNOWN_NOSOL) 4859 {/* no result this time, but add all cutpool constraints 4860 and resolve may give a solution 4861 */ 4862 add_cp_cstr = 2; 4863 } else 4864 {/* no results, and adding more constraints will not improve the 4865 situation */ 4866 add_cp_cstr = 0; 4867 } 4868 }} 4869#ifdef COIN 4870 coin_reset_prob(lpd); 4871#endif 4872 4873 if (add_cp_cstr) 4874 { 4875 int zerobeg = 0, offset, nzcount, j; 4876 double ftol; 4877 4878 Get_Feasibility_Tolerance(cpx_env, lpd, &ftol); 4879 i = 0; 4880 last_violated_idx = -1; 4881 while (i < unadded_cnt) 4882 { 4883 if ((j = cp_unadded[i]) >= 0) 4884 { 4885 switch (cp_map2[j] = _cstr_state(lpd,j,add_cp_cstr,sol.sols,ftol)) 4886 { 4887 case CSTR_STATE_VIOLATED: 4888 violated_cnt++; 4889 offset = lpd->cp_rmatbeg2[j]; 4890 nzcount = ( j < lpd->cp_nr2-1 ? lpd->cp_rmatbeg2[j+1] - offset : lpd->cp_nnz2 - offset); 4891 4892 CPXaddrows(cpx_env, lpd->lp, 0, 1, nzcount, 4893 &(lpd->cp_rhsx2[j]), &(lpd->cp_senx2[j]), 4894 &zerobeg, /* only one row */ 4895 &(lpd->cp_rmatind2[offset]), 4896 &(lpd->cp_rmatval2[offset]), NULL, NULL); 4897 lpd->mar++; 4898 cp_map2[j] = lpd->cp_nact2++; 4899 /* set last_violated_idx if it is not valid */ 4900 if (last_violated_idx < 0) last_violated_idx = i; 4901 break; 4902 case CSTR_STATE_SAT: /* satisfied, but not binding */ 4903 case CSTR_STATE_BINDING: /* satisfied and binding */ 4904 if (last_violated_idx >= 0) 4905 { 4906 cp_unadded[last_violated_idx] = last_violated_idx - i; 4907 last_violated_idx = -1; 4908 } 4909 break; 4910 case CSTR_STATE_INVALID: /* error */ 4911 Bip_Error(RANGE_ERROR); 4912 break; 4913 } 4914 i++; 4915 } else 4916 {/* j < 0 : j is -displacement to unadded cstr */ 4917 i -= j; 4918 } 4919 } 4920 if (last_violated_idx >= 0) cp_unadded[last_violated_idx] = last_violated_idx- i; 4921 if (violated_cnt > 0) 4922 { 4923 Mark_Copy_As_Modified(lpd); 4924 TG = old_tg; /* reallocate row-wise result arrays */ 4925 if (sol.slacks != NULL) 4926 _create_result_darray(vhandle, slackspos, lpd->mar, &outslacks, &sol.slacks); 4927 if (sol.rbase != NULL) 4928 _create_result_iarray(vhandle, rbasepos, lpd->mar, &outrbase, &sol.rbase); 4929 if (sol.pis != NULL) 4930 _create_result_darray(vhandle, pispos, lpd->mar, &outpis, &sol.pis); 4931 } 4932 } /* if (add_cp_cstr) */ 4933 4934 } while (violated_cnt > 0); /* do ... */ 4935 4936 Request_Unify_Integer(vres, tres, lpd->descr_state); 4937 Request_Unify_Integer(vstat, tstat, lpd->sol_state); 4938 4939 /* (-)HUGE_VAL is used for the maximum best/worst bound instead of 4940 (-)CPX_INFBOUND because: 4941 1) The objective value can exceed CPX_INFBOUND 4942 2) We use 1.0Inf at the ECLiPSe level for unbounded objective 4943 value 4944 Note worst and best bounds are unified even for failure case 4945 (for use in any future failure handler) 4946 */ 4947 Request_Unify_Float(vworst, tworst, worstbound); 4948 Request_Unify_Float(vbest, tbest, bestbound); 4949 4950 if (add_cp_cstr == 1) 4951 {/* have results */ 4952 if (sol.sols != NULL) 4953 ec_assign(vhandle.ptr+solspos, outsols.val, outsols.tag); 4954 if (sol.pis != NULL) 4955 ec_assign(vhandle.ptr+pispos, outpis.val, outpis.tag); 4956 if (sol.slacks != NULL) 4957 ec_assign(vhandle.ptr+slackspos, outslacks.val, outslacks.tag); 4958 if (sol.djs != NULL) 4959 ec_assign(vhandle.ptr+djspos, outdjs.val, outdjs.tag); 4960 if (sol.cbase != NULL) 4961 ec_assign(vhandle.ptr+cbasepos, outcbase.val, outcbase.tag); 4962 if (sol.rbase != NULL) 4963 ec_assign(vhandle.ptr+rbasepos, outrbase.val, outrbase.tag); 4964 } 4965 else 4966 { 4967 pword pw; 4968 /* no solution; reset arrays as these states might not fail */ 4969 Make_Nil(&pw); 4970 if (sol.sols != NULL) 4971 ec_assign(vhandle.ptr+solspos, pw.val, pw.tag); 4972 if (sol.pis != NULL) 4973 ec_assign(vhandle.ptr+pispos, pw.val, pw.tag); 4974 if (sol.slacks != NULL) 4975 ec_assign(vhandle.ptr+slackspos, pw.val, pw.tag); 4976 if (sol.djs != NULL) 4977 ec_assign(vhandle.ptr+djspos, pw.val, pw.tag); 4978 if (sol.cbase != NULL) 4979 ec_assign(vhandle.ptr+cbasepos, pw.val, pw.tag); 4980 if (sol.rbase != NULL) 4981 ec_assign(vhandle.ptr+rbasepos, pw.val, pw.tag); 4982 } 4983 4984 if (has_cp) reset_rowcols(lpd, oldmar, lpd->mac); 4985 4986 Return_Unify; 4987} 4988 4989 4990int 4991p_cpx_loadbase(value vlp, type tlp, value vcarr, type tcarr, value vrarr, type trarr) 4992{ 4993 lp_desc *lpd; 4994 int res; 4995 Check_Array(tcarr); 4996 Check_Array(trarr); 4997 LpDesc(vlp, tlp, lpd); 4998 SetPreSolve(lpd->presolve); 4999 if (lpd->mac == IArraySize(vcarr.ptr) && lpd->mar == IArraySize(vrarr.ptr)) { 5000 /* Finx b58: only load basis if current row/col == array sizes */ 5001#ifdef LOG_CALLS 5002 Fprintf(log_output_, "\niloadbasis(...);"); 5003#endif 5004 res = CPXcopybase(cpx_env, lpd->lp, IArrayStart(vcarr.ptr), IArrayStart(vrarr.ptr)); 5005 if (res != 0) { Bip_Error(EC_EXTERNAL_ERROR); } 5006 } 5007 Succeed; 5008} 5009 5010#ifdef COIN 5011int 5012p_cpx_loadorder(value vlp, type tlp, value vn, type tn, value vl, type tl) 5013{ 5014 Succeed; 5015} 5016#else 5017 5018int 5019p_cpx_loadorder(value vlp, type tlp, value vn, type tn, value vl, type tl) 5020{ 5021 lp_desc *lpd; 5022 int *idx, *prio; 5023#ifdef CPLEX 5024 int *bdir; 5025#endif 5026#ifdef XPRESS 5027 char *bdir; 5028#endif 5029 int i, res; 5030 pword *buf = TG; 5031 5032 Check_Integer(tn); 5033 if (vn.nint <= 0) Succeed; /* no need to load anything */ 5034 5035 LpDesc(vlp, tlp, lpd); 5036 Push_Buffer(vn.nint*3*sizeof(int)); 5037 idx = (int*) BufferStart(buf); 5038 prio = (int*) (BufferStart(buf) + vn.nint*sizeof(int)); 5039#ifdef CPLEX 5040 bdir = (int*) (BufferStart(buf) + vn.nint*2*sizeof(int)); 5041#endif 5042#ifdef XPRESS 5043 bdir = (char*) (BufferStart(buf) + vn.nint*2*sizeof(int)); 5044#endif 5045 i = 0; 5046 while (IsList(tl)) 5047 { 5048 pword *car = vl.ptr; 5049 pword *cdr = car + 1; 5050 pword *pw; 5051 5052 Dereference_(car); 5053 Check_Structure(car->tag); 5054 if (DidArity(car->val.ptr->val.did) != 3) 5055 { Bip_Error(RANGE_ERROR); } 5056 5057 pw = car->val.ptr + 1; /* colindex */ 5058 Dereference_(pw); 5059 idx[i] = pw->val.nint; 5060 pw = car->val.ptr + 2; /* priority */ 5061 Dereference_(pw); 5062 prio[i] = pw->val.nint; 5063 pw = car->val.ptr + 3; /* direction */ 5064 Dereference_(pw); 5065#ifdef CPLEX 5066 bdir[i] = pw->val.nint; 5067#endif 5068#ifdef XPRESS 5069 bdir[i] = pw->val.nint == 1 ? 'D' : pw->val.nint == 2 ? 'U' : 'N'; 5070#endif 5071 ++i; 5072 5073 Dereference_(cdr); 5074 tl = cdr->tag; 5075 vl = cdr->val; 5076 } 5077 Check_List(tl); 5078 if (i != vn.nint) 5079 { Bip_Error(RANGE_ERROR); } 5080 5081#ifdef LOG_CALLS 5082 Fprintf(log_output_, "\nloaddir(...);"); ec_flush(log_output_); 5083#endif 5084 SetPreSolve(lpd->presolve); 5085 res = CPXcopyorder(cpx_env, lpd->lp, i, idx, prio, bdir); 5086 TG = buf; /* pop aux arrays */ 5087 if (res != 0) { Bip_Error(EC_EXTERNAL_ERROR); } 5088 Succeed; 5089} 5090 5091#endif 5092 5093 5094/* 5095 * Add SOSs from descriptor arrays to solver 5096 */ 5097 5098int 5099p_cpx_flush_sos(value vhandle, type thandle) 5100{ 5101#ifdef HAS_NO_ADDSOS 5102 Bip_Error(UNIMPLEMENTED); 5103#else 5104 lp_desc *lpd; 5105 untrail_data udata; 5106 5107 Check_Structure(thandle); 5108 LpDesc(vhandle.ptr[HANDLE_CPH].val, vhandle.ptr[HANDLE_CPH].tag, lpd); 5109 5110 if (lpd->nsos <= lpd->nsos_added) 5111 Succeed; 5112 5113#if defined(CPLEX) && CPLEX < 10 5114 if (CPXaddsos(cpx_env, lpd->lp, lpd->nsos, lpd->nsosnz, lpd->sostype, 5115 NULL, lpd->sosbeg, lpd->sosind, lpd->sosref)) 5116#else 5117 if (CPXaddsos(cpx_env, lpd->lp, lpd->nsos, lpd->nsosnz, lpd->sostype, 5118 lpd->sosbeg, lpd->sosind, lpd->sosref, NULL)) 5119#endif 5120 { 5121 Bip_Error(EC_EXTERNAL_ERROR); 5122 } 5123 udata.oldmac = lpd->macadded; 5124 udata.oldmar = lpd->mar; 5125 udata.oldsos = lpd->nsos_added; 5126 udata.oldidc = lpd->nidc; 5127 ec_trail_undo(_cpx_del_rowcols, vhandle.ptr, vhandle.ptr+HANDLE_STAMP, (word*) &udata, NumberOfWords(untrail_data), TRAILED_WORD32); 5128 lpd->nsos_added = lpd->nsos; 5129 /* could free/resize arrays here */ 5130 Succeed; 5131#endif 5132} 5133 5134 5135/* 5136 * Set up SOS arrays in descriptor 5137 */ 5138 5139int 5140p_cpx_add_new_sos(value vlp, type tlp, 5141 value vsostype, type tsostype, /* 1 or 2 */ 5142 value vn, type tn, /* member count */ 5143 value vl, type tl) /* member list */ 5144{ 5145 lp_desc *lpd; 5146 double weight; 5147 int i, nnewsos; 5148 5149 Check_Integer(tsostype); 5150 Check_Integer(tn); 5151 5152 LpDescOnly(vlp, tlp, lpd); 5153 if (vn.nint <= vsostype.nint) 5154 Succeed; /* return immediately if sos set is trivial */ 5155 5156 /* the temporary array index of the new SOS */ 5157 nnewsos = lpd->nsos - lpd->nsos_added; 5158 ++lpd->nsos; 5159 if (nnewsos+1 >= lpd->sossz) 5160 { 5161 /* allocate enough space for the new sos */ 5162 /* CAUTION: in this array must have at least nnewsos+1 elements !!! */ 5163 if (lpd->sossz == 0) 5164 { 5165 lpd->sossz = NEWSOS_INCR; 5166 lpd->sosbeg = (int *) Malloc(NEWSOS_INCR*sizeof(int)); 5167 } 5168 else 5169 { 5170 lpd->sossz += NEWSOS_INCR; 5171 lpd->sosbeg = (int *) Realloc(lpd->sosbeg, lpd->sossz*sizeof(int)); 5172 } 5173 } 5174 lpd->sosbeg[nnewsos] = lpd->nsosnz; 5175 lpd->sosbeg[nnewsos+1] = lpd->nsosnz + vn.nint; 5176 5177 /* allocate enough space for the sos members */ 5178 i = lpd->nsosnz; 5179 lpd->nsosnz += vn.nint; 5180 if (lpd->nsosnz > lpd->sosnzsz) 5181 { 5182 if (lpd->sosnzsz == 0) 5183 { 5184 lpd->sosnzsz = RoundTo(lpd->nsosnz, 512); 5185 lpd->sostype = (sostype_t *) Malloc(lpd->sosnzsz*sizeof(sostype_t)); 5186 lpd->sosind = (int *) Malloc(lpd->sosnzsz*sizeof(int)); 5187 lpd->sosref = (double *) Malloc(lpd->sosnzsz*sizeof(double)); 5188 } 5189 else 5190 { 5191 lpd->sosnzsz = RoundTo(lpd->nsosnz, 512); 5192 lpd->sostype = (sostype_t *) Realloc(lpd->sostype, lpd->sosnzsz*sizeof(sostype_t)); 5193 lpd->sosind = (int *) Realloc(lpd->sosind, lpd->sosnzsz*sizeof(int)); 5194 lpd->sosref = (double *) Realloc(lpd->sosref, lpd->sosnzsz*sizeof(double)); 5195 } 5196 } 5197 5198 for (weight = 1.0; IsList(tl); weight += 1.0, ++i) 5199 { 5200 pword *car = vl.ptr; 5201 pword *cdr = car + 1; 5202 5203 Dereference_(car); 5204 if (!IsInteger(car->tag)) 5205 { Bip_Error(TYPE_ERROR); } 5206 5207 lpd->sostype[i] = vsostype.nint==1 ? SOLVER_SOS_TYPE1 : SOLVER_SOS_TYPE2; 5208 lpd->sosind[i] = (int) car->val.nint; 5209 lpd->sosref[i] = weight; 5210 5211 Dereference_(cdr); 5212 tl = cdr->tag; 5213 vl = cdr->val; 5214 } 5215 Check_List(tl); 5216 if (i != lpd->nsosnz) 5217 { Bip_Error(RANGE_ERROR); } 5218 5219 Succeed; 5220} 5221 5222 5223int 5224p_cpx_get_objval(value vlp, type tlp, value v, type t) 5225{ 5226 lp_desc *lpd; 5227 5228 LpDescOnly(vlp, tlp, lpd); 5229 Return_Unify_Float(v, t, lpd->objval); 5230} 5231 5232 5233#if 0 /* not used */ 5234int 5235p_cpx_get_coef(value vlp, type tlp, 5236 value vi, type ti, 5237 value vj, type tj, 5238 value vc, type tc) 5239{ 5240#ifdef CPLEX 5241 lp_desc *lpd; 5242 double d; 5243 LpDesc(vlp, tlp, lpd); 5244 SetPreSolve(lpd->presolve); 5245 Check_Integer(ti); 5246 Check_Integer(tj); 5247 if (vi.nint >= lpd->mar || vj.nint >= lpd->mac) { Bip_Error(RANGE_ERROR); } 5248 CPXupdatemodel(lpd->lp); /* before CPXget... */ 5249 if (CPXgetcoef(cpx_env, lpd->lp, vi.nint, vj.nint, &d) != 0) 5250 { Bip_Error(EC_EXTERNAL_ERROR); } 5251 Return_Unify_Float(vc, tc, d); 5252#else 5253 Bip_Error(UNIMPLEMENTED); 5254#endif 5255} 5256 5257#endif 5258 5259/* 5260 * Retrieve the matrix coefficients: 5261 * - First call cplex_get_row(+CPH, +CType, +I, -Base) which 5262 * prepares for retrieval of row i of constraint type CType: 5263 * normal constraints: 5264 * retrieves the coefficients of row I into the rmatind/rmatval 5265 * arrays 5266 * cutpool constraints: 5267 * setup lpd->nnz to the non-zero size for row i, and set Base 5268 * to the offset to coefficients for row i in the appropriate 5269 * rmatind/rmatval arrays 5270 * - Then call cplex_get_col_coef(+CPH, +CType, +Base, -J, -C) which returns 5271 * one nonzero column J and the corresponding coefficient C. Successive 5272 * calls return the other nonzero columns in decreasing order. When no 5273 * nonzero column is left, cplex_get_col_coef/3 fails. The row number is 5274 * the one given in the preceding cpx_get_row/2 call. */ 5275 5276int 5277p_cpx_get_row(value vlp, type tlp, value vpool, type tpool, 5278 value vi, type ti, value vbase, type tbase) 5279{ 5280 lp_desc *lpd; 5281 int base; 5282 LpDesc(vlp, tlp, lpd); 5283 5284 Check_Integer(ti); 5285 5286 CPXupdatemodel(lpd->lp); /* before CPXget... */ 5287 switch (vpool.nint) 5288 { 5289 case CSTR_TYPE_NORM: 5290 { 5291 int ncols; 5292 int rmatbeg[2]; 5293#ifdef CPLEX 5294 int surplus; 5295#endif 5296 base = 0; /* read one constraint only */ 5297 ncols = lpd->mac; 5298 if (ncols > lpd->nnz_sz) /* allocate/grow arrays */ 5299 { 5300 if (lpd->nnz_sz == 0) 5301 { 5302 lpd->nnz_sz = ncols; 5303 lpd->rmatind = (int *) Malloc(ncols*sizeof(int)); 5304 lpd->rmatval = (double *) Malloc(ncols*sizeof(double)); 5305 } 5306 else 5307 { 5308 lpd->nnz_sz = ncols; 5309 lpd->rmatind = (int *) Realloc(lpd->rmatind, ncols*sizeof(int)); 5310 lpd->rmatval = (double *) Realloc(lpd->rmatval, ncols*sizeof(double)); 5311 } 5312 } 5313 SetPreSolve(lpd->presolve); 5314 /* note that for COIN, CPXgetrows maps to coin_getrow, which gets 5315 one row only 5316 */ 5317 if ( 5318 CPXgetrows(cpx_env, lpd->lp, &lpd->nnz, rmatbeg, lpd->rmatind, 5319 lpd->rmatval, lpd->nnz_sz, &surplus, vi.nint, vi.nint) 5320 ) 5321 { Bip_Error(EC_EXTERNAL_ERROR); } 5322 break; 5323 } 5324/* 5325 case CSTR_TYPE_PERMCP: 5326 base = lpd->cp_rmatbeg[vi.nint]; 5327 lpd->nnz = (vi.nint == lpd->cp_nr-1 ? lpd->cp_nnz-base : lpd->cp_rmatbeg[vi.nint+1]-base); 5328 break; 5329*/ 5330 case CSTR_TYPE_CONDCP: 5331 base = lpd->cp_rmatbeg2[vi.nint]; 5332 lpd->nnz = (vi.nint == lpd->cp_nr2-1 ? lpd->cp_nnz2-base : lpd->cp_rmatbeg2[vi.nint+1]-base); 5333 5334 break; 5335 default: 5336 Bip_Error(RANGE_ERROR); 5337 break; 5338 } 5339 5340 Return_Unify_Integer(vbase, tbase, base); 5341} 5342 5343 5344/* returns the coeff vc for vj'th argument of the Prolog variable array 5345 NOTE: assumes variable array created from a list in reverse column order 5346*/ 5347int 5348p_cpx_get_col_coef(value vlp, type tlp, value vpool, type tpool, 5349 value vbase, type tbase, 5350 value vj, type tj, value vc, type tc) 5351{ 5352 int i; 5353 lp_desc *lpd; 5354 Prepare_Requests 5355 LpDescOnly(vlp, tlp, lpd); 5356 if (lpd->nnz == 0) 5357 { Fail; } 5358 --lpd->nnz; 5359 i = vbase.nint + lpd->nnz; 5360 switch (vpool.nint) 5361 { 5362/* 5363 case CSTR_TYPE_PERMCP: 5364 Request_Unify_Integer(vj, tj, (lpd->mac+SOLVER_MAT_BASE - lpd->cp_rmatind[i])); 5365 Request_Unify_Float(vc, tc, lpd->cp_rmatval2[i]); 5366 break; 5367*/ 5368 case CSTR_TYPE_CONDCP: 5369 Request_Unify_Integer(vj, tj, (lpd->mac+SOLVER_MAT_BASE - lpd->cp_rmatind2[i])); 5370 Request_Unify_Float(vc, tc, lpd->cp_rmatval2[i]); 5371 break; 5372 case CSTR_TYPE_NORM: 5373 Request_Unify_Integer(vj, tj, (lpd->mac+SOLVER_MAT_BASE - lpd->rmatind[i])); 5374 Request_Unify_Float(vc, tc, lpd->rmatval[i]); 5375 break; 5376 default: 5377 Bip_Error(RANGE_ERROR); 5378 } 5379 Return_Unify; 5380} 5381 5382int 5383p_cpx_get_obj_coef(value vlp, type tlp, value vj, type tj, value vc, type tc) 5384{ 5385 lp_desc *lpd; 5386 double d[1]; 5387 Check_Integer(tj); 5388 LpDesc(vlp, tlp, lpd); 5389 if (vj.nint >= lpd->mac) { Bip_Error(RANGE_ERROR); } 5390 SetPreSolve(lpd->presolve); 5391 CPXupdatemodel(lpd->lp); /* before CPXget... */ 5392 if (CPXgetobj(cpx_env, lpd->lp, d, (int) vj.nint, (int) vj.nint) != 0) 5393 { Bip_Error(EC_EXTERNAL_ERROR); } 5394 Return_Unify_Float(vc, tc, d[0]); 5395} 5396 5397 5398/*----------------------------------------------------------------------* 5399 * Global stack arrays (used for answer vectors) 5400 *----------------------------------------------------------------------*/ 5401 5402 5403int 5404p_create_darray(value vi, type ti, value varr, type tarr) 5405{ 5406 pword *pbuf; 5407 Check_Integer(ti); 5408 pbuf = _create_darray(vi.nint); 5409 Return_Unify_String(varr, tarr, pbuf); 5410} 5411 5412static pword * 5413_create_carray(int i) 5414{ 5415 pword *pbuf = TG; 5416 Push_Buffer(i*sizeof(char) + 1); 5417 return pbuf; 5418} 5419 5420static pword * 5421_create_darray(int i) 5422{ 5423 pword *pbuf = TG; 5424 Push_Buffer(i*sizeof(double) + 1); 5425 return pbuf; 5426} 5427 5428static pword * 5429_create_iarray(int i) 5430{ 5431 pword *pbuf = TG; 5432 Push_Buffer(i*sizeof(int) + 1); 5433 return pbuf; 5434} 5435 5436int 5437p_darray_size(value varr, type tarr, value vi, type ti) 5438{ 5439 Check_Array(tarr); 5440 Return_Unify_Integer(vi, ti, DArraySize(varr.ptr)); 5441} 5442 5443int 5444p_get_darray_element(value varr, type tarr, value vi, type ti, value vel, type tel) 5445{ 5446 double f; 5447 Check_Array(tarr); 5448 Check_Integer(ti); 5449 /* RANGE_ERROR if vi.nint is negative -- as it is a large unsigned */ 5450 if ((unsigned) vi.nint >= DArraySize(varr.ptr)) 5451 { Bip_Error(RANGE_ERROR); } 5452 f = ((double *) BufferStart(varr.ptr))[vi.nint]; 5453 Return_Unify_Float(vel, tel, f); 5454} 5455 5456int 5457p_set_darray_element(value varr, type tarr, value vi, type ti, value vel, type tel) 5458{ 5459 Check_Array(tarr); 5460 Check_Integer(ti); 5461 Check_Float(tel); 5462 Check_Number(tel); 5463 5464 if ((unsigned) vi.nint >= DArraySize(varr.ptr)) 5465 { Bip_Error(RANGE_ERROR); } 5466 if (GB <= varr.ptr && varr.ptr < TG) 5467 { 5468 ((double *) BufferStart(varr.ptr))[vi.nint] = DoubleVal(vel, tel); 5469 Succeed; 5470 } 5471 else /* nondeterministic */ 5472 { 5473 Bip_Error(UNIMPLEMENTED); 5474 } 5475} 5476 5477int 5478p_darray_list(value varr, type tarr, value vmr, type tmr, value vlst, type tlst) 5479{ 5480 pword list; 5481 pword *car; 5482 pword *cdr = &list; 5483 unsigned i; 5484 5485 Check_Array(tarr); 5486 Check_Integer(tmr); 5487 if (vmr.nint > DArraySize(varr.ptr)) Bip_Error(RANGE_ERROR); 5488 for (i = 0; i < vmr.nint; ++i) 5489 { 5490 car = TG; 5491 Push_List_Frame(); 5492 Make_List(cdr, car); 5493 Make_Float(car, ((double *) BufferStart(varr.ptr))[i]); 5494 cdr = car + 1; 5495 } 5496 Make_Nil(cdr); 5497 Return_Unify_Pw(vlst, tlst, list.val, list.tag); 5498} 5499 5500/* returns the base (start) of the solver matrix (0 or 1) */ 5501int 5502p_cpx_matrix_base(value vbase, type tbase) 5503{ 5504 Return_Unify_Integer(vbase, tbase, SOLVER_MAT_BASE); 5505} 5506 5507int 5508p_cpx_matrix_offset(value voff, type toff) 5509{ 5510 Return_Unify_Integer(voff, toff, SOLVER_MAT_OFFSET); 5511} 5512 5513 5514/*----------------------------------------------------------------------* 5515 * CutPools 5516 *----------------------------------------------------------------------*/ 5517 5518/* cutpools implemented using the rowwise representation of a problem 5519 used by CPLEX and Xpress. These are then added to the problem before 5520 optimisation. There two types of cutpools: unconditional and 5521 conditional, each representing by its own data structures in the handle. 5522 Rows in the conditional cutpool have a `name' associated with them, which 5523 group the rows into different virtual pools. These virtual pools correspond 5524 conceptually to the different cutpools in a MP solver 5525*/ 5526 5527int 5528p_cpx_get_cutpool_size(value vlp, type tlp, value vnr, type tnr, value vnnz, type tnnz) 5529{ 5530 lp_desc *lpd; 5531 Prepare_Requests 5532 LpDescOnly(vlp, tlp, lpd); 5533 5534 Request_Unify_Integer(vnr, tnr, lpd->cp_nr2); 5535 Request_Unify_Integer(vnnz, tnnz, lpd->cp_nnz2); 5536 Return_Unify; 5537} 5538 5539int 5540p_cpx_reset_cutpool_size(value vlp, type tlp, 5541 value vnr, type tnr, value vnnz, type tnnz) 5542{ 5543 lp_desc *lpd; 5544 LpDescOnly(vlp, tlp, lpd); 5545 5546 Check_Integer(tnr); 5547 Check_Integer(tnnz); 5548 5549 if (vnr.nint > lpd->cp_nr2 || vnr.nint < 0) {Bip_Error(RANGE_ERROR);} 5550 lpd->cp_nr2 = vnr.nint; 5551 if (vnnz.nint > lpd->cp_nnz2 || vnnz.nint < 0) {Bip_Error(RANGE_ERROR);} 5552 lpd->cp_nnz2 = vnnz.nint; 5553 Succeed; 5554} 5555 5556int 5557p_cpx_set_cpcstr_cond(value vlp, type tlp, value vidx, type tidx, 5558 value vtype, type ttype, value vc, type tc) 5559{ 5560 int i; 5561 lp_desc *lpd; 5562 5563 LpDescOnly(vlp, tlp, lpd); 5564 Check_Integer(tidx); 5565 Check_Integer(ttype); 5566 Check_Integer(tc); 5567 5568 if (vidx.nint < 0 || vidx.nint >= lpd->cp_nr2) { Bip_Error(RANGE_ERROR); } 5569 switch (vtype.nint) 5570 { 5571 case CP_ACTIVE: /* active state */ 5572 if (vc.nint != 0 && vc.nint != 1) { Bip_Error(RANGE_ERROR); } 5573 lpd->cp_active2[vidx.nint] = (char) vc.nint; 5574 break; 5575 case CP_ADDINIT: /* add initially */ 5576 if (vc.nint != 0 && vc.nint != 1) { Bip_Error(RANGE_ERROR); } 5577 lpd->cp_initial_add2[vidx.nint] = (char) vc.nint; 5578 break; 5579 default: 5580 Bip_Error(RANGE_ERROR); 5581 break; 5582 } 5583 5584 Succeed; 5585} 5586 5587int 5588p_cpx_init_cpcstr(value vlp, type tlp, value vidx, type tidx, value vgrp, type tgrp, 5589 value vact, type tact, value vinit_add, type tinit_add) 5590{ 5591 lp_desc *lpd; 5592 LpDescOnly(vlp, tlp, lpd); 5593 5594 Check_Integer(tidx); 5595 Check_Integer(tgrp); 5596 Check_Integer(tact); 5597 Check_Integer(tinit_add); 5598 5599 lpd->cp_initial_add2[vidx.nint] = (char) vinit_add.nint; 5600 lpd->cp_active2[vidx.nint] = (char) vact.nint; 5601 if (lpd->cp_pools_max2[vgrp.nint] >= lpd->cp_pools_sz2[vgrp.nint]) 5602 { 5603 lpd->cp_pools_sz2[vgrp.nint] += NEWROW_INCR; 5604 lpd->cp_pools2[vgrp.nint] = (int *) Realloc(lpd->cp_pools2[vgrp.nint],lpd->cp_pools_sz2[vgrp.nint]*sizeof(int)); 5605 } 5606 lpd->cp_pools2[vgrp.nint][lpd->cp_pools_max2[vgrp.nint]++] = vidx.nint; 5607 5608 return PSUCCEED; 5609} 5610 5611#define Expand_Named_CutPool_Arrays(lpd, n) { \ 5612 int sz = lpd->cp_npools_sz2 += CUTPOOL_INCR; \ 5613 /* expand the arrays */\ 5614 lpd->cp_pools2 = (int **) Realloc(lpd->cp_pools2,sz*sizeof(int *));\ 5615 lpd->cp_pools_max2 = (int *) Realloc(lpd->cp_pools_max2,sz*sizeof(int));\ 5616 lpd->cp_pools_sz2 = (int *) Realloc(lpd->cp_pools_sz2,sz*sizeof(int));\ 5617 lpd->cp_names2 = (char **) Realloc(lpd->cp_names2,sz*sizeof(char *));\ 5618 for (i = n+1; i < sz; i++) \ 5619 { /* initialise the new elements (except n - which will be filled \ 5620 by Create_New_CutPool) */\ 5621 lpd->cp_pools2[i] = NULL;\ 5622 lpd->cp_names2[i] = NULL; \ 5623 lpd->cp_pools_max2[i] = 0;\ 5624 lpd->cp_pools_sz2[i] = 0;\ 5625 }\ 5626} 5627 5628#define Create_New_CutPool(lpd, n, name) { \ 5629 lpd->cp_pools_sz2[n] = NEWROW_INCR; \ 5630 lpd->cp_pools_max2[n] = 0; \ 5631 lpd->cp_pools2[n] = Malloc(NEWROW_INCR*sizeof(int)); \ 5632 lpd->cp_names2[n] = Malloc((strlen(name)+1)*sizeof(char)); \ 5633 strcpy(lpd->cp_names2[n], name); \ 5634} 5635 5636 5637int 5638p_cpx_get_named_cp_index(value vlp, type tlp, value vname, type tname, 5639 value vnew, type tnew, value vidx, type tidx) 5640{ 5641 int i, n; 5642 lp_desc *lpd; 5643 LpDescOnly(vlp, tlp, lpd); 5644 5645 Check_Integer(tnew); 5646 5647 if (lpd->cp_npools_sz2 == 0) 5648 {/* create the default group the first time we use the named groups */ 5649 lpd->cp_npools2 = 1; 5650 Expand_Named_CutPool_Arrays(lpd, 0); 5651 Create_New_CutPool(lpd, 0, "[]"); 5652 } 5653 if (IsNil(tname)) i = 0; /* default group */ 5654 else 5655 {/* user defined named group */ 5656 Check_Atom(tname); 5657 for(i=1; i < lpd->cp_npools2; ++i) 5658 { 5659 if (strcmp(lpd->cp_names2[i], DidName(vname.did)) == 0) break; 5660 } 5661 if (i == lpd->cp_npools2) 5662 {/* name was not found */ 5663 if (vnew.nint == 0) { Fail; } /* don't create new group */ 5664 else if ((n = lpd->cp_npools2++) >= lpd->cp_npools_sz2) 5665 { 5666 Expand_Named_CutPool_Arrays(lpd, n); 5667 } 5668 Create_New_CutPool(lpd, n, DidName(vname.did)); 5669 } 5670 5671 } 5672 5673 Return_Unify_Integer(vidx, tidx, i); 5674} 5675 5676 5677int 5678p_cpx_get_cpcstr_info(value vlp, type tlp, value vidx, type tidx, 5679 value vitype, type titype, value vval, type tval) 5680{ 5681 int i, val; 5682 5683 lp_desc *lpd; 5684 LpDescOnly(vlp, tlp, lpd); 5685 5686 Check_Integer(titype); 5687 Check_Integer(tidx); 5688 5689 if (vidx.nint < 0 || vidx.nint >= lpd->cp_nr2) { Bip_Error(RANGE_ERROR);} 5690 5691 switch (vitype.nint) 5692 { 5693 case CP_ACTIVE: /* active state */ 5694 val = (int) lpd->cp_active2[vidx.nint]; 5695 break; 5696 case CP_ADDINIT: 5697 val = (int) lpd->cp_initial_add2[vidx.nint]; 5698 break; 5699 default: 5700 Bip_Error(RANGE_ERROR); 5701 break; 5702 } 5703 5704 Return_Unify_Integer(vval, tval, val); 5705} 5706 5707int 5708p_cpx_get_named_cpcstr_indices(value vlp, type tlp, value vpidx, type tpidx, 5709 value vilst, type tilst) 5710{ 5711 int i; 5712 pword list; 5713 pword * head, * next = &list; 5714 5715 lp_desc *lpd; 5716 LpDescOnly(vlp, tlp, lpd); 5717 5718 Check_Integer(tpidx); 5719 5720 if (vpidx.nint < 0 || vpidx.nint >= lpd->cp_npools2) Bip_Error(RANGE_ERROR); 5721 for (i=0; i < lpd->cp_pools_max2[vpidx.nint]; i++) 5722 { 5723 head = TG; 5724 Push_List_Frame(); 5725 Make_List(next, head); 5726 Make_Integer(head, lpd->cp_pools2[vpidx.nint][i]); 5727 next = head + 1; 5728 } 5729 Make_Nil(next); 5730 Return_Unify_Pw(vilst, tilst, list.val, list.tag); 5731} 5732 5733 5734/*----------------------------------------------------------------------* 5735 * Extending basis matrices 5736 *----------------------------------------------------------------------*/ 5737 5738 5739int 5740p_create_extended_iarray(value varr, type tarr, value vi, type ti, value vxarr, type txarr) 5741{ 5742 pword *pbuf; 5743 5744 Check_Integer(ti); 5745 Check_Array(tarr); 5746 pbuf = _create_iarray(vi.nint + IArraySize(varr.ptr)); 5747 Return_Unify_String(vxarr, txarr, pbuf); 5748} 5749 5750int 5751p_create_extended_darray(value varr, type tarr, value vi, type ti, value vxarr, type txarr) 5752{ 5753 pword *pbuf; 5754 5755 Check_Integer(ti); 5756 Check_Array(tarr); 5757 pbuf = _create_darray(vi.nint + DArraySize(varr.ptr)); 5758 Return_Unify_String(vxarr, txarr, pbuf); 5759} 5760 5761int 5762p_decode_basis(value varr, type tarr, value vout, type tout) 5763{ 5764 int i,n; 5765 int *v; 5766 pword *pw = TG; 5767 Check_Array(tarr); 5768 v = IArrayStart(varr.ptr); 5769 n = IArraySize(varr.ptr); 5770 Push_Struct_Frame(Did("[]",n)); 5771 for (i = 0; i < n; ++i) 5772 { 5773 Make_Integer(&pw[i+1], v[i]); 5774 } 5775 Return_Unify_Structure(vout, tout, pw); 5776} 5777 5778int 5779p_copy_extended_column_basis(value varr, type tarr, value vlos, type tlos, 5780 value vhis, type this, value vxarr, type txarr) 5781{ 5782 unsigned i; 5783 int *v; 5784 int *vx; 5785 5786 Check_Array(tarr); 5787 Check_Array(txarr); 5788 Check_List(tlos); 5789 Check_List(this); 5790 5791 v = IArrayStart(varr.ptr); 5792 vx = IArrayStart(vxarr.ptr); 5793 5794 /* 5795 * Note that this assumes the basis status array contains 5796 * the status of the problem variables (columns) only 5797 * and not the status of the slack variables (rows). 5798 * We want to add status for the new columns so we must: 5799 * 1) copy the existing variables' status 5800 * 2) add the CPX_COL_FREE_SUPER status for the new columns 5801 */ 5802 for (i = 0; i < IArraySize(varr.ptr); ++i) 5803 { 5804 vx[i] = v[i]; 5805 } 5806 for (i = IArraySize(varr.ptr); i < IArraySize(vxarr.ptr); ++i) 5807 { 5808 if (IsList(tlos) && IsList(this)) 5809 { 5810 double lo, hi; 5811 pword *car = vlos.ptr; 5812 pword *cdr = car + 1; 5813 Dereference_(car); Check_Double(car->tag); 5814 lo = Dbl(car->val); 5815 Dereference_(cdr); tlos = cdr->tag; vlos = cdr->val; 5816 car = vhis.ptr; 5817 cdr = car + 1; 5818 Dereference_(car); Check_Double(car->tag); 5819 hi = Dbl(car->val); 5820 Dereference_(cdr); this = cdr->tag; vhis = cdr->val; 5821 /* The following are the settings determined by experimentation */ 5822 if (hi <= 0.0) 5823 vx[i] = CPX_COL_AT_UPPER; 5824 else if (lo > -CPX_INFBOUND) 5825 vx[i] = CPX_COL_AT_LOWER; 5826 else 5827 vx[i] = CPX_COL_FREE_SUPER; 5828 } 5829 else { Bip_Error(TYPE_ERROR); } 5830 } 5831 Check_Nil(tlos); 5832 Succeed; 5833} 5834 5835int 5836p_copy_extended_arrays(value vbarr, type tbarr, value vsarr, type tsarr, value vdarr, type tdarr, value vxbarr, type txbarr, value vxsarr, type txsarr, value vxdarr, type txdarr) 5837{ 5838 int i; 5839 int *vb; 5840 int *vxb; 5841 double *vs; 5842 double *vxs; 5843 double *vd; 5844 double *vxd; 5845 5846 Check_Array(tbarr); 5847 Check_Array(tsarr); 5848 Check_Array(tdarr); 5849 Check_Array(txbarr); 5850 Check_Array(txsarr); 5851 Check_Array(txdarr); 5852 5853 vb = IArrayStart(vbarr.ptr); 5854 vxb = IArrayStart(vxbarr.ptr); 5855 vs = DArrayStart(vsarr.ptr); 5856 vxs = DArrayStart(vxsarr.ptr); 5857 vd = DArrayStart(vdarr.ptr); 5858 vxd = DArrayStart(vxdarr.ptr); 5859 5860 /* 5861 * Note that this assumes the basis status array contains 5862 * the status of the problem variables (columns) only 5863 * and not the status of the slack variables (rows). 5864 * We want to add status for the new columns so we must: 5865 * 1) copy the existing variables' status, solution value 5866 * 2) add the CPX_COL_FREE_SUPER status, 0.0 solution value 5867 * and 0.0 reduced cost for the new columns 5868 */ 5869 for (i = 0; i < IArraySize(vbarr.ptr); ++i) 5870 { 5871 vxb[i] = vb[i]; 5872 vxs[i] = vs[i]; 5873 vxd[i] = vd[i]; 5874 } 5875 for (i = IArraySize(vbarr.ptr); i < IArraySize(vxbarr.ptr); ++i) 5876 { 5877 vxb[i] = CPX_COL_FREE_SUPER; 5878 vxs[i] = 0.0; 5879 vxd[i] = 0.0; 5880 } 5881 Succeed; 5882} 5883 5884 5885/*----------------------------------------------------------------------* 5886 * Accessing iarrays 5887 *----------------------------------------------------------------------*/ 5888 5889 5890int 5891p_create_iarray(value vi, type ti, value varr, type tarr) 5892{ 5893 pword *pbuf; 5894 Check_Integer(ti); 5895 pbuf = _create_iarray(vi.nint); 5896 Return_Unify_String(varr, tarr, pbuf); 5897} 5898 5899int 5900p_iarray_size(value varr, type tarr, value vi, type ti) 5901{ 5902 Check_Array(tarr); 5903 Return_Unify_Integer(vi, ti, IArraySize(varr.ptr)); 5904} 5905 5906int 5907p_get_iarray_element(value varr, type tarr, value vi, type ti, value vel, type tel) 5908{ 5909 int i; 5910 Check_Array(tarr); 5911 Check_Integer(ti); 5912 if ((unsigned) vi.nint >= IArraySize(varr.ptr)) 5913 { Bip_Error(RANGE_ERROR); } 5914 i = ((int *) BufferStart(varr.ptr))[vi.nint]; 5915 Return_Unify_Integer(vel, tel, i); 5916} 5917 5918int 5919p_set_iarray_element(value varr, type tarr, value vi, type ti, value vel, type tel) 5920{ 5921 Check_Array(tarr); 5922 Check_Integer(ti); 5923 Check_Integer(tel); 5924 if ((unsigned) vi.nint >= IArraySize(varr.ptr)) 5925 { Bip_Error(RANGE_ERROR); } 5926 if (GB <= varr.ptr && varr.ptr < TG) 5927 { 5928 ((int *) BufferStart(varr.ptr))[vi.nint] = vel.nint; 5929 Succeed; 5930 } 5931 else /* nondeterministic */ 5932 { 5933 Bip_Error(UNIMPLEMENTED); 5934 } 5935} 5936 5937int 5938p_iarray_list(value varr, type tarr, value vlst, type tlst) 5939{ 5940 pword list; 5941 pword *car; 5942 pword *cdr = &list; 5943 unsigned i; 5944 5945 Check_Array(tarr); 5946 for (i = 0; i < IArraySize(varr.ptr); ++i) 5947 { 5948 car = TG; 5949 Push_List_Frame(); 5950 Make_List(cdr, car); 5951 Make_Integer(car, ((int *) BufferStart(varr.ptr))[i]); 5952 cdr = car + 1; 5953 } 5954 Make_Nil(cdr); 5955 Return_Unify_Pw(vlst, tlst, list.val, list.tag); 5956} 5957 5958#ifdef DUMPMAT 5959 5960int 5961dump_problem(lp_desc * lpd) 5962{ 5963 int i; 5964 Fprintf(log_output_, "\n\ 5965 lpd->macsz = %d;\n\ 5966 lpd->marsz = %d;\n\ 5967 lpd->matnz = %d;\n\ 5968 lpd->mac = %d;\n\ 5969 lpd->mar = %d;\n\ 5970 lpd->rhsx = a_rhsx;\n\ 5971 lpd->senx = a_senx;\n\ 5972 lpd->matbeg = a_matbeg;\n\ 5973 lpd->matcnt = a_matcnt;\n\ 5974 lpd->matind = a_matind;\n\ 5975 lpd->matval = a_matval;\n\ 5976 lpd->bdl = a_bdl;\n\ 5977 lpd->bdu = a_bdu;\n\ 5978 lpd->objx = a_objx;\n\ 5979 lpd->ctype = a_ctype;", 5980 lpd->macsz, lpd->marsz, lpd->matnz, 5981 lpd->mac, lpd->mar); 5982 5983 Fprintf(log_output_, "\n\ 5984 /*\n\ 5985 * Problem data\n\ 5986 */\n\ 5987 "); 5988 Fprintf(log_output_, "double a_objx[%d] ={\n", lpd->mac); 5989 for (i=0; i<lpd->mac; ++i) 5990 Fprintf(log_output_, "%.15e,\n", lpd->objx[i]); 5991 Fprintf(log_output_, "};\n\n"); 5992 5993 Fprintf(log_output_, "double a_bdl[%d] ={\n", lpd->mac); 5994 for (i=0; i<lpd->mac; ++i) 5995 Fprintf(log_output_, "%.15e,\n", lpd->bdl[i]); 5996 Fprintf(log_output_, "};\n\n"); 5997 5998 Fprintf(log_output_, "double a_bdu[%d] ={\n", lpd->mac); 5999 for (i=0; i<lpd->mac; ++i) 6000 Fprintf(log_output_, "%.15e,\n", lpd->bdu[i]); 6001 Fprintf(log_output_, "};\n\n"); 6002 6003 Fprintf(log_output_, "int a_matbeg[%d] ={\n", lpd->mac); 6004 for (i=0; i<lpd->mac; ++i) 6005 Fprintf(log_output_, "%d,\n", lpd->matbeg[i]); 6006 Fprintf(log_output_, "};\n\n"); 6007 6008 Fprintf(log_output_, "int a_matcnt[%d] ={\n", lpd->mac); 6009 for (i=0; i<lpd->mac; ++i) 6010 Fprintf(log_output_, "%d,\n", lpd->matcnt[i]); 6011 Fprintf(log_output_, "};\n\n"); 6012 6013 Fprintf(log_output_, "char a_ctype[%d] ={\n", lpd->mac); 6014 for (i=0; i<lpd->mac; ++i) 6015 Fprintf(log_output_, "'%c',\n", lpd->ctype[i]); 6016 Fprintf(log_output_, "};\n\n"); 6017 6018 Fprintf(log_output_, "double a_rhsx[%d] ={\n", lpd->mar); 6019 for (i=0; i<lpd->mar; ++i) 6020 Fprintf(log_output_, "%.15e,\n", lpd->rhsx[i]); 6021 Fprintf(log_output_, "};\n\n"); 6022 6023 Fprintf(log_output_, "char a_senx[%d] ={\n", lpd->mar); 6024 for (i=0; i<lpd->mar; ++i) 6025 Fprintf(log_output_, "'%c',\n", lpd->senx[i]); 6026 Fprintf(log_output_, "};\n\n"); 6027 6028 Fprintf(log_output_, "int a_matind[%d] ={\n", lpd->matnz); 6029 for (i=0; i<lpd->matnz; ++i) 6030 Fprintf(log_output_, "%d,\n", lpd->matind[i]); 6031 Fprintf(log_output_, "};\n\n"); 6032 6033 Fprintf(log_output_, "double a_matval[%d] ={\n", lpd->matnz); 6034 for (i=0; i<lpd->matnz; ++i) 6035 Fprintf(log_output_, "%.15e,\n", lpd->matval[i]); 6036 Fprintf(log_output_, "};\n\n"); 6037 6038 Fprintf(log_output_, "\n\ 6039 /*\n\ 6040 * End data\n\ 6041 */\n\ 6042 "); 6043 6044# if 0 6045 Fprintf(log_output_, "\n\ 6046 lpd->cb_sz = %d;\n\ 6047 lpd->cb_index = a_cb_index;\n\ 6048 lpd->cb_index2 = a_cb_index2;\n\ 6049 lpd->cb_value = a_cb_value;\n\ 6050 lpd->cb_cnt = %d;", 6051 lpd->cb_cnt, lpd->cb_cnt); 6052 Fprintf(log_output_, "int a_cb_index[%d] ={\n", lpd->cb_cnt); 6053 for (i=0; i<lpd->cb_cnt; ++i) 6054 Fprintf(log_output_, "%d,\n", lpd->cb_index[i]); 6055 Fprintf(log_output_, "};\n\n"); 6056 6057 Fprintf(log_output_, "int a_cb_index2[%d] ={\n", lpd->cb_cnt); 6058 for (i=0; i<lpd->cb_cnt; ++i) 6059 Fprintf(log_output_, "%d,\n", lpd->cb_index2[i]); 6060 Fprintf(log_output_, "};\n\n"); 6061 6062 Fprintf(log_output_, "double a_cb_value[%d] ={\n", lpd->cb_cnt); 6063 for (i=0; i<lpd->cb_cnt; ++i) 6064 Fprintf(log_output_, "%.15e,\n", lpd->cb_value[i]); 6065 Fprintf(log_output_, "};\n\n"); 6066# endif 6067} 6068#endif 6069