From 4c77b1b9dde7b7fe985945428e9c0623dd6c77fc Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 08:41:08 -0500 Subject: [PATCH 01/26] ci: trying to fix ci --- .github/workflows/ci.yaml | 2 +- ilpy/impl/gurobi_c.h | 328 ++++++++++++++++++---------- ilpy/impl/solvers/GurobiBackend.cpp | 2 +- ilpy/impl/solvers/ScipBackend.cpp | 2 +- pyproject.toml | 1 + setup.py | 5 +- 6 files changed, 218 insertions(+), 122 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1c25002..83860dc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -65,7 +65,7 @@ jobs: channel-priority: true - name: install build deps - run: mamba install scip=9.1.0 gurobi gcovr + run: mamba install scip=9.1.0 gurobi=12.0.0 gcovr - name: add gurobi license shell: bash diff --git a/ilpy/impl/gurobi_c.h b/ilpy/impl/gurobi_c.h index 149c2a6..fcb1ee9 100644 --- a/ilpy/impl/gurobi_c.h +++ b/ilpy/impl/gurobi_c.h @@ -1,4 +1,4 @@ -/* Copyright 2022, Gurobi Optimization, LLC */ +/* Copyright 2024, Gurobi Optimization, LLC */ #ifndef _GUROBI_C_H #define _GUROBI_C_H @@ -40,9 +40,9 @@ typedef struct _GRBenv GRBenv; /* Version numbers */ -#define GRB_VERSION_MAJOR 9 -#define GRB_VERSION_MINOR 5 -#define GRB_VERSION_TECHNICAL 1 +#define GRB_VERSION_MAJOR 12 +#define GRB_VERSION_MINOR 0 +#define GRB_VERSION_TECHNICAL 0 /* Default and max priority for Compute Server jobs */ @@ -57,8 +57,9 @@ typedef struct _GRBenv GRBenv; #define DEFAULT_CS_HANGUP 60 -/* Error codes */ +/* Error codes: adjust MIN/MAX if adding new codes */ +#define GRB_C_MIN_ERROR 10001 #define GRB_ERROR_OUT_OF_MEMORY 10001 #define GRB_ERROR_NULL_ARGUMENT 10002 #define GRB_ERROR_INVALID_ARGUMENT 10003 @@ -91,6 +92,7 @@ typedef struct _GRBenv GRBenv; #define GRB_ERROR_CSWORKER 10030 #define GRB_ERROR_TUNE_MODEL_TYPES 10031 #define GRB_ERROR_SECURITY 10032 +#define GRB_C_MAX_ERROR 10032 /* Constraint senses */ @@ -251,15 +253,24 @@ int __stdcall GRBgetlogcallbackfuncenv(GRBenv *env, int (__stdcall **cbP)(LOGCB_ARGS), void **logdataP); + +int __stdcall + GRBcbproceed(void *cbdata); int __stdcall GRBcbget(void *cbdata, int where, int what, void *resultP); +int __stdcall + GRBcbsetintparam(void *cbdata, const char *paramname, int newvalue); +int __stdcall + GRBcbsetdblparam(void *cbdata, const char *paramname, double newvalue); +int __stdcall + GRBcbsetstrparam(void *cbdata, const char *paramname, const char *newvalue); int __stdcall GRBcbsetparam(void *cbdata, const char *paramname, const char *newvalue); int __stdcall GRBcbsolution(void *cbdata, const double *solution, double *objvalP); int __stdcall GRBcbcut(void *cbdata, int cutlen, const int *cutind, const double *cutval, - char cutsense, double cutrhs); + char cutsense, double cutrhs); int __stdcall GRBcblazy(void *cbdata, int lazylen, const int *lazyind, const double *lazyval, char lazysense, double lazyrhs); @@ -287,11 +298,9 @@ int __stdcall #define GRB_INT_ATTR_MODELSENSE "ModelSense" /* 1=min, -1=max */ #define GRB_DBL_ATTR_OBJCON "ObjCon" /* Objective constant */ #define GRB_INT_ATTR_IS_MIP "IsMIP" /* Is model a MIP? */ -#define GRB_INT_ATTR_IS_QP "IsQP" /* Model has quadratic obj? */ +#define GRB_INT_ATTR_IS_QP "IsQP" /* Is model a QP/MIQP (without Q/NL constraints)? */ #define GRB_INT_ATTR_IS_QCP "IsQCP" /* Model has quadratic constr? */ #define GRB_INT_ATTR_IS_MULTIOBJ "IsMultiObj" /* Model has multiple objectives? */ -#define GRB_STR_ATTR_SERVER "Server" /* Name of Compute Server */ -#define GRB_STR_ATTR_JOBID "JobID" /* Compute Server job ID */ #define GRB_INT_ATTR_LICENSE_EXPIRATION "LicenseExpiration" /* License expiration date */ #define GRB_INT_ATTR_NUMTAGGED "NumTagged" /* number of tagged elements in model */ #define GRB_INT_ATTR_FINGERPRINT "Fingerprint" /* fingerprint computed from the model data and attributes influencing the optimization process */ @@ -343,9 +352,10 @@ int __stdcall /* General function constraint attributes */ #define GRB_INT_ATTR_FUNCPIECES "FuncPieces" /* An option for PWL translation */ -#define GRB_DBL_ATTR_FUNCPIECEERROR "FuncPieceError" /* An option for PWL translation */ +#define GRB_DBL_ATTR_FUNCPIECEERROR "FuncPieceError" /* An option for PWL translation */ #define GRB_DBL_ATTR_FUNCPIECELENGTH "FuncPieceLength" /* An option for PWL translation */ #define GRB_DBL_ATTR_FUNCPIECERATIO "FuncPieceRatio" /* An option for PWL translation */ +#define GRB_INT_ATTR_FUNCNONLINEAR "FuncNonlinear" /* An option for PWL translation */ /* Model statistics */ @@ -391,7 +401,8 @@ int __stdcall #define GRB_DBL_ATTR_X "X" /* Solution value */ #define GRB_DBL_ATTR_XN "Xn" /* Alternate MIP solution, depends on solutionnumber */ -#define GRB_DBL_ATTR_BARX "BarX" /* Best barrier iterate */ +#define GRB_DBL_ATTR_BARX "BarX" /* Best barrier primal iterate */ +#define GRB_DBL_ATTR_BARPI "BarPi" /* Best barrier dual iterate */ #define GRB_DBL_ATTR_RC "RC" /* Reduced costs */ #define GRB_DBL_ATTR_VDUALNORM "VDualNorm" /* Dual norm square */ #define GRB_INT_ATTR_VBASIS "VBasis" /* Variable basis status */ @@ -527,6 +538,12 @@ int __stdcall #define GRB_INT_ATTR_NUMSTART "NumStart" /* number of MIP starts */ +/* Memory consumption statistics */ + +#define GRB_DBL_ATTR_MEMUSED "MemUsed" /* current amount of allocated memory (in GB) in master environment */ +#define GRB_DBL_ATTR_MAXMEMUSED "MaxMemUsed" /* maximum amount of allocated memory (in GB) in master environment */ + + /* Alternate define */ #define GRB_DBL_ATTR_Xn "Xn" @@ -539,17 +556,42 @@ int __stdcall #define GRB_GENCONSTR_AND 3 #define GRB_GENCONSTR_OR 4 #define GRB_GENCONSTR_NORM 5 -#define GRB_GENCONSTR_INDICATOR 6 -#define GRB_GENCONSTR_PWL 7 -#define GRB_GENCONSTR_POLY 8 -#define GRB_GENCONSTR_EXP 9 -#define GRB_GENCONSTR_EXPA 10 -#define GRB_GENCONSTR_LOG 11 -#define GRB_GENCONSTR_LOGA 12 -#define GRB_GENCONSTR_POW 13 -#define GRB_GENCONSTR_SIN 14 -#define GRB_GENCONSTR_COS 15 -#define GRB_GENCONSTR_TAN 16 +#define GRB_GENCONSTR_NL 6 +#define GRB_GENCONSTR_INDICATOR 7 +#define GRB_GENCONSTR_PWL 8 +#define GRB_GENCONSTR_POLY 9 +#define GRB_GENCONSTR_EXP 10 +#define GRB_GENCONSTR_EXPA 11 +#define GRB_GENCONSTR_LOG 12 +#define GRB_GENCONSTR_LOGA 13 +#define GRB_GENCONSTR_POW 14 +#define GRB_GENCONSTR_SIN 15 +#define GRB_GENCONSTR_COS 16 +#define GRB_GENCONSTR_TAN 17 +#define GRB_GENCONSTR_LOGISTIC 18 + +#define NUMGENCONSTYPES 19 + +/* Operation codes for genconstrNL */ + +#define GRB_OPCODE_CONSTANT 0 +#define GRB_OPCODE_VARIABLE 1 +#define GRB_OPCODE_PLUS 2 +#define GRB_OPCODE_MINUS 3 +#define GRB_OPCODE_MULTIPLY 4 +#define GRB_OPCODE_DIVIDE 5 +#define GRB_OPCODE_UMINUS 6 +#define GRB_OPCODE_SQUARE 7 +#define GRB_OPCODE_SQRT 8 +#define GRB_OPCODE_SIN 9 +#define GRB_OPCODE_COS 10 +#define GRB_OPCODE_TAN 11 +#define GRB_OPCODE_POW 12 +#define GRB_OPCODE_EXP 13 +#define GRB_OPCODE_LOG 14 +#define GRB_OPCODE_LOG2 15 +#define GRB_OPCODE_LOG10 16 +#define GRB_OPCODE_LOGISTIC 17 /* CALLBACKS @@ -614,6 +656,8 @@ int __stdcall #define GRB_CB_MSG_STRING 6001 #define GRB_CB_RUNTIME 6002 #define GRB_CB_WORK 6003 +#define GRB_CB_MEMUSED 6004 +#define GRB_CB_MAXMEMUSED 6005 #define GRB_CB_BARRIER_ITRCNT 7001 #define GRB_CB_BARRIER_PRIMOBJ 7002 @@ -625,6 +669,23 @@ int __stdcall #define GRB_CB_MULTIOBJ_OBJCNT 8001 #define GRB_CB_MULTIOBJ_SOLCNT 8002 #define GRB_CB_MULTIOBJ_SOL 8003 +#define GRB_CB_MULTIOBJ_ITRCNT 8004 +#define GRB_CB_MULTIOBJ_OBJBST 8005 /* if single objective is an LP we + * still do not have a "_OBJVAL", the + * user can query the _OBJBST/_OBJBND + * values instead */ +#define GRB_CB_MULTIOBJ_OBJBND 8006 +#define GRB_CB_MULTIOBJ_STATUS 8007 +#define GRB_CB_MULTIOBJ_MIPGAP 8008 +#define GRB_CB_MULTIOBJ_NODCNT 8009 +#define GRB_CB_MULTIOBJ_NODLFT 8010 +#define GRB_CB_MULTIOBJ_RUNTIME 8011 +#define GRB_CB_MULTIOBJ_WORK 8012 +/* TODO maybe we should also support, think about in MIP/LP cases if not applicable +#define GRB_CB_MULTIOBJ_PRIMINF 8012 +#define GRB_CB_MULTIOBJ_DUALINF 8013 +#define GRB_CB_MULTIOBJ_ISPERT 8014 +*/ #define GRB_CB_IIS_CONSTRMIN 9001 #define GRB_CB_IIS_CONSTRMAX 9002 @@ -633,6 +694,8 @@ int __stdcall #define GRB_CB_IIS_BOUNDMAX 9005 #define GRB_CB_IIS_BOUNDGUESS 9006 +/* FeasRelax method parameter values */ + #define GRB_FEASRELAX_LINEAR 0 #define GRB_FEASRELAX_QUADRATIC 1 #define GRB_FEASRELAX_CARDINALITY 2 @@ -671,6 +734,9 @@ int __stdcall int __stdcall GRBgetgenconstrNorm(GRBmodel *model, int genconstr, int *resvarP, int *nvarsP, int *vars, double *whichP); +int __stdcall +GRBgetgenconstrNL(GRBmodel *model, int genconstr, int *resvarP, int *nnodesP, + int *opcode, double *data, int *parent); int __stdcall GRBgetgenconstrIndicator(GRBmodel *model, int genconstr, int *binvarP, int *binvalP, int *nvarsP, int *vars, double *vals, @@ -694,6 +760,9 @@ int __stdcall GRBgetgenconstrExp(GRBmodel *model, int genconstr, int *xvarP, int *yvarP); int __stdcall GRBgetgenconstrLog(GRBmodel *model, int genconstr, int *xvarP, int *yvarP); +int __stdcall + GRBgetgenconstrLogistic(GRBmodel *model, int genconstr, int *xvarP, + int *yvarP); int __stdcall GRBgetgenconstrSin(GRBmodel *model, int genconstr, int *xvarP, int *yvarP); int __stdcall @@ -725,6 +794,8 @@ int __stdcall GRBmodel * __stdcall GRBcopymodel(GRBmodel *model); +int __stdcall + GRBcopymodeltoenv(GRBmodel *model, GRBenv *env, GRBmodel **resultP); int __stdcall GRBfixmodel(GRBmodel *model, GRBmodel **fixedP); int __stdcall @@ -733,6 +804,8 @@ int __stdcall double *feasobjP); int __stdcall GRBsinglescenariomodel(GRBmodel *model, GRBmodel **singlescenarioP); +int __stdcall + GRBconverttofixed(GRBmodel *model); /* Undocumented routines */ @@ -740,8 +813,6 @@ int __stdcall GRBgetcbwhatinfo(void *cbdata, int what, int *typeP, int *sizeP); int __stdcall GRBrelaxmodel(GRBmodel *model, GRBmodel **relaxedP); -int __stdcall - GRBconverttofixed(GRBmodel *model); int __stdcall GRBpresolvemodel(GRBmodel *model, GRBmodel **presolvedP); int __stdcall @@ -764,26 +835,27 @@ int __stdcall #define THREADCREATECB_ARGS void **threadP, void (*start_routine)(void *), void *arg, void *syscbusrdata #define THREADJOINCB_ARGS void *thread, void *syscbusrdata -int __stdcall - GRBloadenvsyscb(GRBenv **envP, const char *logfilename, - void * (__stdcall *malloccb)(MALLOCCB_ARGS), - void * (__stdcall *calloccb)(CALLOCCB_ARGS), - void * (__stdcall *realloccb)(REALLOCCB_ARGS), - void (__stdcall *freecb)(FREECB_ARGS), - int (__stdcall *threadcreatecb)(THREADCREATECB_ARGS), - void (__stdcall *threadjoincb)(THREADJOINCB_ARGS), - void *syscbusrdata); +#define GRBemptyenvadv(envP, malloccb, callocbc, realloccb, freecb, threadcreatecb, threadjoincb, syscbusrdata) GRBemptyenvadvinternal(envP, -1, GRB_VERSION_MAJOR, GRB_VERSION_MINOR, GRB_VERSION_TECHNICAL, malloccb, callocbc, realloccb, freecb, threadcreatecb, threadjoincb, syscbusrdata) +int __stdcall + GRBemptyenvadvnocheck(GRBenv **envP, + void * (__stdcall *malloccb)(MALLOCCB_ARGS), + void * (__stdcall *calloccb)(CALLOCCB_ARGS), + void * (__stdcall *realloccb)(REALLOCCB_ARGS), + void (__stdcall *freecb)(FREECB_ARGS), + int (__stdcall *threadcreatecb)(THREADCREATECB_ARGS), + void (__stdcall *threadjoincb)(THREADJOINCB_ARGS), + void *syscbusrdata); int __stdcall - GRBemptyenvadv(GRBenv **envP, int apitype, int major, int minor, int tech, - void * (__stdcall *malloccb)(MALLOCCB_ARGS), - void * (__stdcall *calloccb)(CALLOCCB_ARGS), - void * (__stdcall *realloccb)(REALLOCCB_ARGS), - void (__stdcall *freecb)(FREECB_ARGS), - int (__stdcall *threadcreatecb)(THREADCREATECB_ARGS), - void (__stdcall *threadjoincb)(THREADJOINCB_ARGS), - void *syscbusrdata); + GRBemptyenvadvinternal(GRBenv **envP, int apitype, int major, int minor, int tech, + void * (__stdcall *malloccb)(MALLOCCB_ARGS), + void * (__stdcall *calloccb)(CALLOCCB_ARGS), + void * (__stdcall *realloccb)(REALLOCCB_ARGS), + void (__stdcall *freecb)(FREECB_ARGS), + int (__stdcall *threadcreatecb)(THREADCREATECB_ARGS), + void (__stdcall *threadjoincb)(THREADJOINCB_ARGS), + void *syscbusrdata); int __stdcall GRBreadmodel(GRBenv *env, const char *filename, GRBmodel **modelP); @@ -885,6 +957,10 @@ int __stdcall int __stdcall GRBaddgenconstrNorm(GRBmodel *model, const char *name, int resvar, int nvars, const int *vars, double which); +int __stdcall +GRBaddgenconstrNL(GRBmodel *model, + const char *name, int resvar, int nnodes, const int *opcode, + const double *data, const int *parent); int __stdcall GRBaddgenconstrIndicator(GRBmodel *model, const char *name, int binvar, int binval, int nvars, const int *vars, @@ -920,6 +996,9 @@ int __stdcall int __stdcall GRBaddgenconstrTan(GRBmodel *model, const char *name, int xvar, int yvar, const char *options); +int __stdcall + GRBaddgenconstrLogistic(GRBmodel *model, const char *name, int xvar, + int yvar, const char *options); int __stdcall GRBaddqconstr(GRBmodel *model, int numlnz, int *lind, double *lval, int numqnz, int *qrow, int *qcol, double *qval, @@ -953,10 +1032,7 @@ int __stdcall GRBupdatemodel(GRBmodel *model); int __stdcall -GRBreset(GRBmodel *model, int clearall); - -int __stdcall - GRBresetmodel(GRBmodel *model); + GRBreset(GRBmodel *model, int clearall); int __stdcall GRBfreemodel(GRBmodel *model); @@ -997,6 +1073,9 @@ int __stdcall int __stdcall GRBcbstoponemultiobj(GRBmodel *model, void *cbdata, int objnum); +int __stdcall + GRBsingularvectors(GRBmodel *model, double *left, double *right); + /* Model status codes */ #define GRB_LOADED 1 @@ -1015,6 +1094,7 @@ int __stdcall #define GRB_INPROGRESS 14 #define GRB_USER_OBJ_LIMIT 15 #define GRB_WORK_LIMIT 16 +#define GRB_MEM_LIMIT 17 /* Basis status info */ @@ -1042,6 +1122,7 @@ int __stdcall #define GRB_DBL_PAR_TIMELIMIT "TimeLimit" #define GRB_DBL_PAR_WORKLIMIT "WorkLimit" #define GRB_DBL_PAR_MEMLIMIT "MemLimit" +#define GRB_DBL_PAR_SOFTMEMLIMIT "SoftMemLimit" #define GRB_DBL_PAR_BESTOBJSTOP "BestObjStop" #define GRB_DBL_PAR_BESTBDSTOP "BestBdStop" @@ -1057,17 +1138,18 @@ int __stdcall /* Simplex */ -#define GRB_INT_PAR_METHOD "Method" -#define GRB_DBL_PAR_PERTURBVALUE "PerturbValue" -#define GRB_DBL_PAR_OBJSCALE "ObjScale" -#define GRB_INT_PAR_SCALEFLAG "ScaleFlag" -#define GRB_INT_PAR_SIMPLEXPRICING "SimplexPricing" -#define GRB_INT_PAR_QUAD "Quad" -#define GRB_INT_PAR_NORMADJUST "NormAdjust" -#define GRB_INT_PAR_SIFTING "Sifting" -#define GRB_INT_PAR_SIFTMETHOD "SiftMethod" -#define GRB_INT_PAR_LPWARMSTART "LPWarmStart" -#define GRB_INT_PAR_NETWORKALG "NetworkAlg" +#define GRB_INT_PAR_METHOD "Method" +#define GRB_INT_PAR_CONCURRENTMETHOD "ConcurrentMethod" +#define GRB_DBL_PAR_PERTURBVALUE "PerturbValue" +#define GRB_DBL_PAR_OBJSCALE "ObjScale" +#define GRB_INT_PAR_SCALEFLAG "ScaleFlag" +#define GRB_INT_PAR_SIMPLEXPRICING "SimplexPricing" +#define GRB_INT_PAR_QUAD "Quad" +#define GRB_INT_PAR_NORMADJUST "NormAdjust" +#define GRB_INT_PAR_SIFTING "Sifting" +#define GRB_INT_PAR_SIFTMETHOD "SiftMethod" +#define GRB_INT_PAR_LPWARMSTART "LPWarmStart" +#define GRB_INT_PAR_NETWORKALG "NetworkAlg" /* Barrier */ @@ -1097,6 +1179,7 @@ int __stdcall #define GRB_INT_PAR_NODEMETHOD "NodeMethod" #define GRB_DBL_PAR_NORELHEURTIME "NoRelHeurTime" #define GRB_DBL_PAR_NORELHEURWORK "NoRelHeurWork" +#define GRB_INT_PAR_OBBT "OBBT" #define GRB_INT_PAR_PUMPPASSES "PumpPasses" #define GRB_INT_PAR_RINS "RINS" #define GRB_STR_PAR_SOLFILES "SolFiles" @@ -1131,6 +1214,8 @@ int __stdcall #define GRB_INT_PAR_BQPCUTS "BQPCuts" #define GRB_INT_PAR_PSDCUTS "PSDCuts" #define GRB_INT_PAR_LIFTPROJECTCUTS "LiftProjectCuts" +#define GRB_INT_PAR_MIXINGCUTS "MixingCuts" +#define GRB_INT_PAR_DUALIMPLIEDCUTS "DualImpliedCuts" #define GRB_INT_PAR_CUTAGGPASSES "CutAggPasses" #define GRB_INT_PAR_CUTPASSES "CutPasses" @@ -1168,8 +1253,11 @@ int __stdcall #define GRB_STR_PAR_WLSACCESSID "WLSAccessID" #define GRB_STR_PAR_WLSSECRET "WLSSecret" #define GRB_INT_PAR_WLSTOKENDURATION "WLSTokenDuration" +#define GRB_DBL_PAR_WLSTOKENREFRESH "WLSTokenRefresh" #define GRB_STR_PAR_WLSTOKEN "WLSToken" #define GRB_INT_PAR_LICENSEID "LicenseID" +#define GRB_STR_PAR_WLSPROXY "WLSProxy" +#define GRB_STR_PAR_WLSCONFIG "WLSConfig" /* Other */ @@ -1208,7 +1296,9 @@ int __stdcall #define GRB_INT_PAR_RECORD "Record" #define GRB_STR_PAR_RESULTFILE "ResultFile" #define GRB_INT_PAR_SEED "Seed" +#define GRB_INT_PAR_SOLUTIONTARGET "SolutionTarget" #define GRB_INT_PAR_THREADS "Threads" +#define GRB_INT_PAR_THREADLIMIT "ThreadLimit" #define GRB_DBL_PAR_TUNETIMELIMIT "TuneTimeLimit" #define GRB_INT_PAR_TUNERESULTS "TuneResults" #define GRB_INT_PAR_TUNECRITERION "TuneCriterion" @@ -1219,6 +1309,7 @@ int __stdcall #define GRB_DBL_PAR_TUNETARGETMIPGAP "TuneTargetMIPGap" #define GRB_DBL_PAR_TUNETARGETTIME "TuneTargetTime" #define GRB_INT_PAR_TUNEMETRIC "TuneMetric" +#define GRB_INT_PAR_TUNEDYNAMICJOBS "TuneDynamicJobs" #define GRB_INT_PAR_UPDATEMODE "UpdateMode" #define GRB_INT_PAR_OBJNUMBER "ObjNumber" #define GRB_INT_PAR_MULTIOBJMETHOD "MultiObjMethod" @@ -1236,27 +1327,30 @@ int __stdcall #define GRB_DBL_PAR_FUNCPIECEERROR "FuncPieceError" #define GRB_DBL_PAR_FUNCPIECERATIO "FuncPieceRatio" #define GRB_DBL_PAR_FUNCMAXVAL "FuncMaxVal" +#define GRB_INT_PAR_FUNCNONLINEAR "FuncNonlinear" #define GRB_STR_PAR_DUMMY "Dummy" - -/* Deprecated */ - #define GRB_STR_PAR_JOBID "JobID" /* Parameter enumerations */ -/* All *CUTS parameters */ +/* Cuts parameter values */ + #define GRB_CUTS_AUTO -1 #define GRB_CUTS_OFF 0 #define GRB_CUTS_CONSERVATIVE 1 #define GRB_CUTS_AGGRESSIVE 2 #define GRB_CUTS_VERYAGGRESSIVE 3 +/* Presolve parameter values */ + #define GRB_PRESOLVE_AUTO -1 #define GRB_PRESOLVE_OFF 0 #define GRB_PRESOLVE_CONSERVATIVE 1 #define GRB_PRESOLVE_AGGRESSIVE 2 +/* Method parameter values */ + #define GRB_METHOD_NONE -1 #define GRB_METHOD_AUTO -1 #define GRB_METHOD_PRIMAL 0 @@ -1264,20 +1358,34 @@ int __stdcall #define GRB_METHOD_BARRIER 2 #define GRB_METHOD_CONCURRENT 3 #define GRB_METHOD_DETERMINISTIC_CONCURRENT 4 -#define GRB_METHOD_DETERMINISTIC_CONCURRENT_SIMPLEX 5 +#define GRB_METHOD_DETERMINISTIC_CONCURRENT_SIMPLEX 5 /* Deprecated since v11 */ + +#define GRB_CONCURRENTMETHOD_AUTO -1 +#define GRB_CONCURRENTMETHOD_BARRIER_PRIMAL_DUAL 0 +#define GRB_CONCURRENTMETHOD_BARRIER_DUAL 1 +#define GRB_CONCURRENTMETHOD_BARRIER_PRIMAL 2 +#define GRB_CONCURRENTMETHOD_PRIMAL_DUAL 3 + +/* BarHomogeneous parameter values */ #define GRB_BARHOMOGENEOUS_AUTO -1 #define GRB_BARHOMOGENEOUS_OFF 0 #define GRB_BARHOMOGENEOUS_ON 1 +/* BarOrder parameter values */ + +#define GRB_BARORDER_AUTOMATIC -1 +#define GRB_BARORDER_AMD 0 +#define GRB_BARORDER_NESTEDDISSECTION 1 + +/* MIPFocus parameter values */ + #define GRB_MIPFOCUS_BALANCED 0 #define GRB_MIPFOCUS_FEASIBILITY 1 #define GRB_MIPFOCUS_OPTIMALITY 2 #define GRB_MIPFOCUS_BESTBOUND 3 -#define GRB_BARORDER_AUTOMATIC -1 -#define GRB_BARORDER_AMD 0 -#define GRB_BARORDER_NESTEDDISSECTION 1 +/* SimplexPricing parameter values */ #define GRB_SIMPLEXPRICING_AUTO -1 #define GRB_SIMPLEXPRICING_PARTIAL 0 @@ -1285,30 +1393,32 @@ int __stdcall #define GRB_SIMPLEXPRICING_DEVEX 2 #define GRB_SIMPLEXPRICING_STEEPEST_QUICK 3 +/* VarBranch parameter values */ + #define GRB_VARBRANCH_AUTO -1 #define GRB_VARBRANCH_PSEUDO_REDUCED 0 #define GRB_VARBRANCH_PSEUDO_SHADOW 1 #define GRB_VARBRANCH_MAX_INFEAS 2 #define GRB_VARBRANCH_STRONG 3 +/* PartitionPlace parameter values */ + #define GRB_PARTITION_EARLY 16 #define GRB_PARTITION_ROOTSTART 8 #define GRB_PARTITION_ROOTEND 4 #define GRB_PARTITION_NODES 2 #define GRB_PARTITION_CLEANUP 1 +/* Callback phase values */ + #define GRB_PHASE_MIP_NOREL 0 #define GRB_PHASE_MIP_SEARCH 1 #define GRB_PHASE_MIP_IMPROVE 2 int __stdcall GRBcheckmodel(GRBmodel *model); -void __stdcall - GRBsetsignal(GRBmodel *model); void __stdcall GRBterminate(GRBmodel *model); -void __stdcall - GRBcbproceed(GRBmodel *model); int __stdcall GRBreplay(const char *filename); int __stdcall @@ -1324,23 +1434,17 @@ void __stdcall void __stdcall GRBclean3(int *lenP, int *ind0, int *ind1, double *val); +int __stdcall + GRBprintquality(GRBmodel *model); + /* Logging */ void __stdcall GRBmsg(GRBenv *env, const char *message); -/* The following four routines are deprecated in Gurobi 2.0. - Use the 'LogFile' parameter to control logging instead. */ - -int __stdcall - GRBgetlogfile(GRBenv *env, FILE **logfileP); - - /* Parameter routines */ -int __stdcall - GRBfixtuneparam(GRBenv *env, const char *paramname); int __stdcall GRBgetintparam(GRBenv *env, const char *paramname, int *valueP); int __stdcall @@ -1379,10 +1483,16 @@ int __stdcall GRBwriteparams(GRBenv *env, const char *filename); int __stdcall GRBreadparams(GRBenv *env, const char *filename); +int __stdcall + GRBreadconcurrentsettings(GRBmodel *model, const char *filename); +int __stdcall + GRBreadmultiobjsettings(GRBmodel *model, const char *filename); +int __stdcall + GRBreadtunebasesettings(GRBenv *env, const char *filename); int __stdcall GRBgetnumparams(GRBenv *env); int __stdcall - GRBgetparamname(GRBenv *env, int i, char **paramnameP); + GRBgetparamname(GRBenv *env, int parnum, char **paramnameP); int __stdcall GRBgetnumattributes(GRBmodel *model); int __stdcall @@ -1390,10 +1500,13 @@ int __stdcall /* Environment routines */ +#define GRBloadenv(envP, logfilename) GRBloadenvinternal(envP, logfilename, GRB_VERSION_MAJOR, GRB_VERSION_MINOR, GRB_VERSION_TECHNICAL) +#define GRBemptyenv(envP) GRBemptyenvinternal(envP, GRB_VERSION_MAJOR, GRB_VERSION_MINOR, GRB_VERSION_TECHNICAL) + int __stdcall - GRBloadenv(GRBenv **envP, const char *logfilename); +GRBloadenvinternal(GRBenv **envP, const char *logfilename, int major, int minor, int tech); int __stdcall - GRBemptyenv(GRBenv **envP); +GRBemptyenvinternal(GRBenv **envP, int major, int minor, int tech); int __stdcall GRBstartenv(GRBenv *env); int __stdcall @@ -1402,33 +1515,9 @@ int __stdcall const char *server, const char *router, const char *password, const char *group, int priority, int idletimeout, - const char *accessid, const char *secretkey, + const char *cloudaccessid, const char *cloudsecretkey, int (__stdcall *cb)(CB_ARGS), void *usrdata, int (__stdcall *logcb)(LOGCB_ARGS), void *logdata); -GRB_DEPRECATED("Replaced by GRBemptyenv() and parameter settings", -int __stdcall - GRBloadclientenv(GRBenv **envP, const char *logfilename, - const char *computeserver, const char *router, - const char *password, const char *group, int CStlsinsecure, - int priority, double timeout)); -int __stdcall - GRBloadclientenvadv(GRBenv **envP, const char *logfilename, - const char *computeserver, const char *router, - const char *password, const char *group, int CStlsinsecure, - int priority, double timeout, int apitype, - int major, int minor, int tech, - int (__stdcall *cb)(CB_ARGS), void *usrdata); -GRB_DEPRECATED("Replaced by GRBemptyenv() and parameter settings", -int __stdcall - GRBloadcloudenv(GRBenv **envP, const char *logfilename, - const char *accessID, const char *secretKey, - const char *pool, int priority)); -int __stdcall - GRBloadcloudenvadv(GRBenv **envP, const char *logfilename, - const char *accessID, const char *secretKey, - const char *pool, int priority, int apitype, int major, - int minor, int tech, - int (__stdcall *cb)(CB_ARGS), void *usrdata); GRBenv *__stdcall GRBgetenv(GRBmodel *model); GRBenv *__stdcall @@ -1461,6 +1550,9 @@ void __stdcall void __stdcall GRBversion(int *majorP, int *minorP, int *technicalP); +void __stdcall + GRBgetdistro(char *str); + char * __stdcall GRBplatform(void); @@ -1470,18 +1562,8 @@ char * __stdcall int __stdcall GRBlisttokens(void); -/* Tuning */ - -void __stdcall - GRBprinttuneparams(void); -int __stdcall - GRBtunemodel(GRBmodel *model); -int __stdcall - GRBtunemodels(GRBenv *env, int nummodels, GRBmodel **models); int __stdcall - GRBgettuneresult(GRBmodel *model, int i); -int __stdcall - GRBgettunelog(GRBmodel *model, int i, char **logP); + GRBgetwlstokenlifespan(GRBenv *env, int *lifespanP); /* Used in Matlab API */ void __stdcall @@ -1544,6 +1626,20 @@ int __stdcall int __stdcall GRBprefetchattr(GRBmodel *model, const char *attrname); +/* Tuning */ + +int __stdcall + GRBtunemodel(GRBmodel *model); +int __stdcall + GRBtunemodels(GRBenv *env, int nummodels, GRBmodel **models); +int __stdcall + GRBgettuneresult(GRBmodel *model, int i); +int __stdcall + GRBgettunelog(GRBmodel *model, int i, char **logP); +int __stdcall + GRBwritetunelog(GRBmodel *model, int result, const char *filename); +void __stdcall + GRBtuneparamsPrint(void); #ifdef __cplusplus } diff --git a/ilpy/impl/solvers/GurobiBackend.cpp b/ilpy/impl/solvers/GurobiBackend.cpp index ce6986e..7917fb9 100644 --- a/ilpy/impl/solvers/GurobiBackend.cpp +++ b/ilpy/impl/solvers/GurobiBackend.cpp @@ -142,7 +142,7 @@ GurobiBackend::setConstraints(const Constraints &constraints) if (numConstrs > 0) { int *constraintIndicies = new int[numConstrs]; - for (unsigned int i = 0; i < numConstrs; i++) + for (int i = 0; i < numConstrs; i++) constraintIndicies[i] = i; GRB_CHECK(GRBdelconstrs(_model, numConstrs, constraintIndicies)); diff --git a/ilpy/impl/solvers/ScipBackend.cpp b/ilpy/impl/solvers/ScipBackend.cpp index 03045e5..8d1f7ad 100644 --- a/ilpy/impl/solvers/ScipBackend.cpp +++ b/ilpy/impl/solvers/ScipBackend.cpp @@ -52,7 +52,7 @@ ScipBackend::initialize( // delete previous variables freeVariables(); - for (int i = 0; i < _numVariables; i++) { + for (unsigned int i = 0; i < _numVariables; i++) { SCIP_VAR* v; std::string name("x"); diff --git a/pyproject.toml b/pyproject.toml index c4d010d..13c0774 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ dev = [ "ruff", "mypy", "pytest", + "ipython", "pytest-cov", "cython", "setuptools==71.1.0", diff --git a/setup.py b/setup.py index 30f414d..31c7ae9 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ libraries = ["libscip"] if os.name == "nt" else ["scip"] include_dirs = ["ilpy/impl"] library_dirs = [] -compile_args = ["-O3", "-DHAVE_SCIP"] +compile_args = ["-O3", "-DHAVE_SCIP", "-Wno-unreachable-code"] if os.name == "nt": compile_args.append("/std:c++17") else: @@ -27,7 +27,7 @@ # look for various gurobi versions, which are annoyingly # suffixed with the version number, and wildcards don't work -for v in range(80, 200): +for v in range(100, 150): GUROBI_LIB = f"libgurobi{v}" if os.name == "nt" else f"gurobi{v}" if (gurolib := util.find_library(GUROBI_LIB)) is not None: print("FOUND GUROBI library: ", gurolib) @@ -37,7 +37,6 @@ else: print("WARNING: GUROBI library not found") - wrapper = Extension( "ilpy.wrapper", sources=["ilpy/wrapper.pyx"], From 1d0b9bda2b847b6f501cf77bd9648cd41dd56011 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 08:55:29 -0500 Subject: [PATCH 02/26] switch compile arg --- pyproject.toml | 15 ++++++++------- setup.py | 5 ++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 13c0774..394fa55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,12 @@ authors = [ { email = "talley.lambert@gmail.com", name = "Talley Lambert" }, ] dynamic = ["version", "readme"] -dependencies = [] +# these are required... but hard to install from pypi +# we list them here for completeness, but it's up to the user to install them :( +dependencies = [ + # "gurobi==12.0.0", + # "scip==9.1.0", +] # extras # https://peps.python.org/pep-0621/#dependencies-optional-dependencies @@ -28,13 +33,9 @@ dev = [ "cython", "setuptools==71.1.0", "numpy", - "gurobipy", # used on CI to confirm equality of results -] -docs = [ - "sphinx", - "sphinx_rtd_theme", - "sphinx-autodoc-typehints", + "gurobipy", # used on CI to confirm equality of results ] +docs = ["sphinx", "sphinx_rtd_theme", "sphinx-autodoc-typehints"] [project.urls] homepage = "https://github.com/funkelab/ilpy" diff --git a/setup.py b/setup.py index 31c7ae9..7e65843 100644 --- a/setup.py +++ b/setup.py @@ -11,11 +11,10 @@ libraries = ["libscip"] if os.name == "nt" else ["scip"] include_dirs = ["ilpy/impl"] library_dirs = [] -compile_args = ["-O3", "-DHAVE_SCIP", "-Wno-unreachable-code"] if os.name == "nt": - compile_args.append("/std:c++17") + compile_args = ["/O2", "/DHAVE_SCIP", "/std:c++17", "/wd4702"] else: - compile_args.append("-std=c++17") + compile_args = ["-O3", "-DHAVE_SCIP", "-std=c++17", "-Wno-unreachable-code"] # include conda environment windows include/lib if it exists # this will be done automatically by conda build, but is useful if someone From e2de0f9717a347db775d2a31201db93657374ec9 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 08:56:22 -0500 Subject: [PATCH 03/26] also with gurobi --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7e65843..01c8d95 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ if (gurolib := util.find_library(GUROBI_LIB)) is not None: print("FOUND GUROBI library: ", gurolib) libraries.append(GUROBI_LIB) - compile_args.append("-DHAVE_GUROBI") + compile_args.append("/DHAVE_GUROBI" if os.name == "nt" else "-DHAVE_GUROBI") break else: print("WARNING: GUROBI library not found") From 67ff753138fdffba0e49c33ee5a67e64a12a2a62 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 08:59:39 -0500 Subject: [PATCH 04/26] change gurobi search pattern --- setup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 01c8d95..8e701ef 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +from itertools import product import os from ctypes import util @@ -26,8 +27,8 @@ # look for various gurobi versions, which are annoyingly # suffixed with the version number, and wildcards don't work -for v in range(100, 150): - GUROBI_LIB = f"libgurobi{v}" if os.name == "nt" else f"gurobi{v}" +for v, prefix in product(range(100, 150, 10), ("lib", "")): + GUROBI_LIB = f"{prefix}gurobi{v}" if (gurolib := util.find_library(GUROBI_LIB)) is not None: print("FOUND GUROBI library: ", gurolib) libraries.append(GUROBI_LIB) From 4fbea3c79a639dbf48424ade30b2352973f2754b Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 09:15:40 -0500 Subject: [PATCH 05/26] try more exhaustive search --- setup.py | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 8e701ef..4d5bc09 100644 --- a/setup.py +++ b/setup.py @@ -27,10 +27,37 @@ # look for various gurobi versions, which are annoyingly # suffixed with the version number, and wildcards don't work + +def find_conda_gurobi() -> tuple[str, str] | tuple[None, None]: + conda_prefix = os.environ.get("CONDA_PREFIX") + if not conda_prefix: + raise RuntimeError( + "No active Conda environment found. Activate an environment before running." + ) + + # Construct the potential library paths + library_paths = [ + os.path.join(conda_prefix, "Library", "bin"), # Windows DLLs + os.path.join(conda_prefix, "lib"), # macOS/Linux + ] + + for lib_path in library_paths: + if os.path.exists(lib_path): + os.environ["PATH"] += os.pathsep + lib_path # Dynamically add to PATH + + # Search for Gurobi in the active Conda environment + for v, prefix in product(range(100, 150, 10), ("lib", "")): + gurobi_lib = f"{prefix}gurobi{v}" + if found := util.find_library(gurobi_lib): + return gurobi_lib, found + + return (None, None) + + for v, prefix in product(range(100, 150, 10), ("lib", "")): - GUROBI_LIB = f"{prefix}gurobi{v}" - if (gurolib := util.find_library(GUROBI_LIB)) is not None: - print("FOUND GUROBI library: ", gurolib) + GUROBI_LIB, lib_path = find_conda_gurobi() + if GUROBI_LIB is not None: + print(f"FOUND GUROBI library {GUROBI_LIB!r}: {lib_path}") libraries.append(GUROBI_LIB) compile_args.append("/DHAVE_GUROBI" if os.name == "nt" else "-DHAVE_GUROBI") break From cbe6a25d65c546e1cbbb7cd898b9f1ae5646f9ff Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 09:24:55 -0500 Subject: [PATCH 06/26] another print --- setup.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/setup.py b/setup.py index 4d5bc09..f3b5d5c 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ -from itertools import product import os from ctypes import util +from itertools import product from Cython.Build import cythonize from setuptools import setup @@ -8,6 +8,10 @@ # enable test coverage tracing if CYTHON_TRACE is set to a non-zero value CYTHON_TRACE = int(os.getenv("CYTHON_TRACE") in ("1", "True")) +if not (CONDA_PREFIX := os.environ.get("CONDA_PREFIX")): + raise RuntimeError( + "No active Conda environment found. Activate an environment before running." + ) libraries = ["libscip"] if os.name == "nt" else ["scip"] include_dirs = ["ilpy/impl"] @@ -20,25 +24,25 @@ # include conda environment windows include/lib if it exists # this will be done automatically by conda build, but is useful if someone # tries to build this directly with pip install in a conda environment -if os.name == "nt" and "CONDA_PREFIX" in os.environ: - include_dirs.append(os.path.join(os.environ["CONDA_PREFIX"], "Library", "include")) - library_dirs.append(os.path.join(os.environ["CONDA_PREFIX"], "Library", "lib")) +if os.name == "nt": + include = os.path.join(CONDA_PREFIX, "Library", "include") + include_dirs.append(include) + library_dirs.append(os.path.join(CONDA_PREFIX, "Library", "lib")) + if not os.path.exists(include): + print( + "WARNING: Conda include directory not found. " + "Ensure you have the Conda environment activated." + ) # look for various gurobi versions, which are annoyingly # suffixed with the version number, and wildcards don't work -def find_conda_gurobi() -> tuple[str, str] | tuple[None, None]: - conda_prefix = os.environ.get("CONDA_PREFIX") - if not conda_prefix: - raise RuntimeError( - "No active Conda environment found. Activate an environment before running." - ) - +def find_conda_gurobi() -> "tuple[str, str] | tuple[None, None]": # Construct the potential library paths library_paths = [ - os.path.join(conda_prefix, "Library", "bin"), # Windows DLLs - os.path.join(conda_prefix, "lib"), # macOS/Linux + os.path.join(str(CONDA_PREFIX), "Library", "bin"), # Windows DLLs + os.path.join(str(CONDA_PREFIX), "lib"), # macOS/Linux ] for lib_path in library_paths: From a0af3989dbf7e6239b9a7d034731d7052f24b627 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 09:27:40 -0500 Subject: [PATCH 07/26] more debug --- setup.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/setup.py b/setup.py index f3b5d5c..c95fac6 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +import glob import os from ctypes import util from itertools import product @@ -6,6 +7,41 @@ from setuptools import setup from setuptools.extension import Extension +print("PATH:", os.environ["PATH"]) +print("CONDA_PREFIX:", os.environ.get("CONDA_PREFIX")) + + +def assert_gurobi_and_scip() -> None: + # Get the Conda environment prefix + conda_prefix = os.environ.get("CONDA_PREFIX") + if not conda_prefix: + raise RuntimeError("CONDA_PREFIX is not set. Ensure Conda is active in CI.") + + # Paths to check + gurobi_dll_path = os.path.join(conda_prefix, "Library", "bin", "gurobi*.dll") + scip_header_path = os.path.join( + conda_prefix, "Library", "include", "scip", "scipdefplugins.h" + ) + + # Verify Gurobi DLL + gurobi_found = any(os.path.exists(path) for path in glob.glob(gurobi_dll_path)) + if not gurobi_found: + raise FileNotFoundError( + f"Gurobi DLL not found in {gurobi_dll_path}. Ensure Gurobi is installed." + ) + + # Verify SCIP header + if not os.path.exists(scip_header_path): + raise FileNotFoundError( + f"SCIP header 'scipdefplugins.h' not found in {scip_header_path}. " + "Ensure SCIP is installed." + ) + + print("All required files are present.") + +if os.name == "nt": + assert_gurobi_and_scip() + # enable test coverage tracing if CYTHON_TRACE is set to a non-zero value CYTHON_TRACE = int(os.getenv("CYTHON_TRACE") in ("1", "True")) if not (CONDA_PREFIX := os.environ.get("CONDA_PREFIX")): From 62a356cf64cf2ad28745ed287833137a6042bf88 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 09:38:39 -0500 Subject: [PATCH 08/26] print output --- setup.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/setup.py b/setup.py index c95fac6..5eb8f9b 100644 --- a/setup.py +++ b/setup.py @@ -11,6 +11,40 @@ print("CONDA_PREFIX:", os.environ.get("CONDA_PREFIX")) +def debug_conda_env() -> None: + conda_prefix = os.environ.get("CONDA_PREFIX") + if not conda_prefix: + raise RuntimeError("No active Conda environment found. Ensure Conda is active.") + print() + # Check Gurobi DLL directory + if os.name == "nt": + bin_dir = os.path.join(conda_prefix, "Library", "bin") + else: + bin_dir = os.path.join(conda_prefix, "lib") + print(f"Inspecting bin directory: {bin_dir}") + if os.path.exists(bin_dir): + for file in glob.glob(os.path.join(bin_dir, "*gurobi*")): + print(f" Found: {file}") + for file in glob.glob(os.path.join(bin_dir, "*scip*")): + print(f" Found: {file}") + else: + print("Gurobi bin directory does not exist!") + + print() + # Check SCIP include directory + if os.name == "nt": + inc_dir = os.path.join(conda_prefix, "Library", "include") + else: + inc_dir = os.path.join(conda_prefix, "include") + print(f"Inspecting include directory: {inc_dir}") + if os.path.exists(inc_dir): + for file in glob.glob(os.path.join(inc_dir, "**/*scip/")): + print(f" Found: {file}") + else: + print("SCIP include directory does not exist!") + print() + + def assert_gurobi_and_scip() -> None: # Get the Conda environment prefix conda_prefix = os.environ.get("CONDA_PREFIX") @@ -39,6 +73,8 @@ def assert_gurobi_and_scip() -> None: print("All required files are present.") + +debug_conda_env() if os.name == "nt": assert_gurobi_and_scip() From 80a8bd65e2aa9d7be7b468882c3d56e87cdffc6e Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 09:42:28 -0500 Subject: [PATCH 09/26] more print --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 5eb8f9b..c868151 100644 --- a/setup.py +++ b/setup.py @@ -33,12 +33,12 @@ def debug_conda_env() -> None: print() # Check SCIP include directory if os.name == "nt": - inc_dir = os.path.join(conda_prefix, "Library", "include") + inc_dir = os.path.join(conda_prefix, "Library", "include", "scip") else: - inc_dir = os.path.join(conda_prefix, "include") + inc_dir = os.path.join(conda_prefix, "include", "scip") print(f"Inspecting include directory: {inc_dir}") if os.path.exists(inc_dir): - for file in glob.glob(os.path.join(inc_dir, "**/*scip/")): + for file in glob.glob(os.path.join(inc_dir, "*")): print(f" Found: {file}") else: print("SCIP include directory does not exist!") From 2e8fb35c9aba05edfa869cd6eaa5b08a3e76bb8a Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 09:48:51 -0500 Subject: [PATCH 10/26] more stupid prints --- setup.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup.py b/setup.py index c868151..4f8db3e 100644 --- a/setup.py +++ b/setup.py @@ -27,6 +27,9 @@ def debug_conda_env() -> None: print(f" Found: {file}") for file in glob.glob(os.path.join(bin_dir, "*scip*")): print(f" Found: {file}") + # print the whole damn directory + for file in glob.glob(os.path.join(bin_dir, "*")): + print(f" Found: {file}") else: print("Gurobi bin directory does not exist!") @@ -42,6 +45,10 @@ def debug_conda_env() -> None: print(f" Found: {file}") else: print("SCIP include directory does not exist!") + # print parent directory + print(f" Parent directory: {os.path.dirname(inc_dir)}") + for file in glob.glob(os.path.join(os.path.dirname(inc_dir), "*")): + print(f" Found: {file}") print() From 64010e28ff673e6831462422220192ee6ef60ea4 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 09:53:56 -0500 Subject: [PATCH 11/26] use conda --- .github/workflows/ci.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 83860dc..9ecf9ea 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -60,12 +60,11 @@ jobs: with: python-version: ${{ matrix.python-version }} miniforge-version: latest - use-mamba: true channels: conda-forge,gurobi,defaults channel-priority: true - name: install build deps - run: mamba install scip=9.1.0 gurobi=12.0.0 gcovr + run: conda install scip=9.1.0 gurobi=12.0.0 gcovr - name: add gurobi license shell: bash From 4734059a53755c751c62e4b58d556e5d246305a2 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 10:01:28 -0500 Subject: [PATCH 12/26] try again --- .github/workflows/ci.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9ecf9ea..2c9ce0f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -60,11 +60,12 @@ jobs: with: python-version: ${{ matrix.python-version }} miniforge-version: latest - channels: conda-forge,gurobi,defaults channel-priority: true - name: install build deps - run: conda install scip=9.1.0 gurobi=12.0.0 gcovr + run: | + conda install -c conda-forge scip=9.1.0 gcovr + conda install -c gurobi gurobi=12.0.0 - name: add gurobi license shell: bash From 67f0672761cb1d724cd4aee1279438f6cf61a9f3 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 10:02:44 -0500 Subject: [PATCH 13/26] update install and conda list --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2c9ce0f..cb4e2be 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -64,8 +64,7 @@ jobs: - name: install build deps run: | - conda install -c conda-forge scip=9.1.0 gcovr - conda install -c gurobi gurobi=12.0.0 + conda install -c conda-forge -c gurobi gurobi=12.0.0 scip=9.1.0 gcovr - name: add gurobi license shell: bash @@ -78,6 +77,7 @@ jobs: - name: install package run: | + conda list python -m pip install -U pip python -m pip install -e .[dev] python setup.py build_ext --inplace # required for C coverage From 5f81cda3c7ffc84935df0768d8e45480c1023d95 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 10:18:14 -0500 Subject: [PATCH 14/26] downgrade gurobi --- .github/workflows/ci.yaml | 2 +- ilpy/impl/gurobi_c.h | 144 +++++++++----------------------------- pyproject.toml | 2 +- setup.py | 16 ++--- 4 files changed, 43 insertions(+), 121 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cb4e2be..428bae8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -64,7 +64,7 @@ jobs: - name: install build deps run: | - conda install -c conda-forge -c gurobi gurobi=12.0.0 scip=9.1.0 gcovr + conda install -c conda-forge -c gurobi gurobi=11.0.3 scip=9.1.0 gcovr - name: add gurobi license shell: bash diff --git a/ilpy/impl/gurobi_c.h b/ilpy/impl/gurobi_c.h index fcb1ee9..ca93f29 100644 --- a/ilpy/impl/gurobi_c.h +++ b/ilpy/impl/gurobi_c.h @@ -40,9 +40,9 @@ typedef struct _GRBenv GRBenv; /* Version numbers */ -#define GRB_VERSION_MAJOR 12 +#define GRB_VERSION_MAJOR 11 #define GRB_VERSION_MINOR 0 -#define GRB_VERSION_TECHNICAL 0 +#define GRB_VERSION_TECHNICAL 3 /* Default and max priority for Compute Server jobs */ @@ -255,15 +255,9 @@ int __stdcall void **logdataP); int __stdcall - GRBcbproceed(void *cbdata); + GRBcbproceed(void *cbdata_in); int __stdcall GRBcbget(void *cbdata, int where, int what, void *resultP); -int __stdcall - GRBcbsetintparam(void *cbdata, const char *paramname, int newvalue); -int __stdcall - GRBcbsetdblparam(void *cbdata, const char *paramname, double newvalue); -int __stdcall - GRBcbsetstrparam(void *cbdata, const char *paramname, const char *newvalue); int __stdcall GRBcbsetparam(void *cbdata, const char *paramname, const char *newvalue); int __stdcall @@ -401,8 +395,7 @@ int __stdcall #define GRB_DBL_ATTR_X "X" /* Solution value */ #define GRB_DBL_ATTR_XN "Xn" /* Alternate MIP solution, depends on solutionnumber */ -#define GRB_DBL_ATTR_BARX "BarX" /* Best barrier primal iterate */ -#define GRB_DBL_ATTR_BARPI "BarPi" /* Best barrier dual iterate */ +#define GRB_DBL_ATTR_BARX "BarX" /* Best barrier iterate */ #define GRB_DBL_ATTR_RC "RC" /* Reduced costs */ #define GRB_DBL_ATTR_VDUALNORM "VDualNorm" /* Dual norm square */ #define GRB_INT_ATTR_VBASIS "VBasis" /* Variable basis status */ @@ -538,12 +531,6 @@ int __stdcall #define GRB_INT_ATTR_NUMSTART "NumStart" /* number of MIP starts */ -/* Memory consumption statistics */ - -#define GRB_DBL_ATTR_MEMUSED "MemUsed" /* current amount of allocated memory (in GB) in master environment */ -#define GRB_DBL_ATTR_MAXMEMUSED "MaxMemUsed" /* maximum amount of allocated memory (in GB) in master environment */ - - /* Alternate define */ #define GRB_DBL_ATTR_Xn "Xn" @@ -556,42 +543,18 @@ int __stdcall #define GRB_GENCONSTR_AND 3 #define GRB_GENCONSTR_OR 4 #define GRB_GENCONSTR_NORM 5 -#define GRB_GENCONSTR_NL 6 -#define GRB_GENCONSTR_INDICATOR 7 -#define GRB_GENCONSTR_PWL 8 -#define GRB_GENCONSTR_POLY 9 -#define GRB_GENCONSTR_EXP 10 -#define GRB_GENCONSTR_EXPA 11 -#define GRB_GENCONSTR_LOG 12 -#define GRB_GENCONSTR_LOGA 13 -#define GRB_GENCONSTR_POW 14 -#define GRB_GENCONSTR_SIN 15 -#define GRB_GENCONSTR_COS 16 -#define GRB_GENCONSTR_TAN 17 -#define GRB_GENCONSTR_LOGISTIC 18 - -#define NUMGENCONSTYPES 19 - -/* Operation codes for genconstrNL */ - -#define GRB_OPCODE_CONSTANT 0 -#define GRB_OPCODE_VARIABLE 1 -#define GRB_OPCODE_PLUS 2 -#define GRB_OPCODE_MINUS 3 -#define GRB_OPCODE_MULTIPLY 4 -#define GRB_OPCODE_DIVIDE 5 -#define GRB_OPCODE_UMINUS 6 -#define GRB_OPCODE_SQUARE 7 -#define GRB_OPCODE_SQRT 8 -#define GRB_OPCODE_SIN 9 -#define GRB_OPCODE_COS 10 -#define GRB_OPCODE_TAN 11 -#define GRB_OPCODE_POW 12 -#define GRB_OPCODE_EXP 13 -#define GRB_OPCODE_LOG 14 -#define GRB_OPCODE_LOG2 15 -#define GRB_OPCODE_LOG10 16 -#define GRB_OPCODE_LOGISTIC 17 +#define GRB_GENCONSTR_INDICATOR 6 +#define GRB_GENCONSTR_PWL 7 +#define GRB_GENCONSTR_POLY 8 +#define GRB_GENCONSTR_EXP 9 +#define GRB_GENCONSTR_EXPA 10 +#define GRB_GENCONSTR_LOG 11 +#define GRB_GENCONSTR_LOGA 12 +#define GRB_GENCONSTR_POW 13 +#define GRB_GENCONSTR_SIN 14 +#define GRB_GENCONSTR_COS 15 +#define GRB_GENCONSTR_TAN 16 +#define GRB_GENCONSTR_LOGISTIC 17 /* CALLBACKS @@ -656,8 +619,6 @@ int __stdcall #define GRB_CB_MSG_STRING 6001 #define GRB_CB_RUNTIME 6002 #define GRB_CB_WORK 6003 -#define GRB_CB_MEMUSED 6004 -#define GRB_CB_MAXMEMUSED 6005 #define GRB_CB_BARRIER_ITRCNT 7001 #define GRB_CB_BARRIER_PRIMOBJ 7002 @@ -669,23 +630,6 @@ int __stdcall #define GRB_CB_MULTIOBJ_OBJCNT 8001 #define GRB_CB_MULTIOBJ_SOLCNT 8002 #define GRB_CB_MULTIOBJ_SOL 8003 -#define GRB_CB_MULTIOBJ_ITRCNT 8004 -#define GRB_CB_MULTIOBJ_OBJBST 8005 /* if single objective is an LP we - * still do not have a "_OBJVAL", the - * user can query the _OBJBST/_OBJBND - * values instead */ -#define GRB_CB_MULTIOBJ_OBJBND 8006 -#define GRB_CB_MULTIOBJ_STATUS 8007 -#define GRB_CB_MULTIOBJ_MIPGAP 8008 -#define GRB_CB_MULTIOBJ_NODCNT 8009 -#define GRB_CB_MULTIOBJ_NODLFT 8010 -#define GRB_CB_MULTIOBJ_RUNTIME 8011 -#define GRB_CB_MULTIOBJ_WORK 8012 -/* TODO maybe we should also support, think about in MIP/LP cases if not applicable -#define GRB_CB_MULTIOBJ_PRIMINF 8012 -#define GRB_CB_MULTIOBJ_DUALINF 8013 -#define GRB_CB_MULTIOBJ_ISPERT 8014 -*/ #define GRB_CB_IIS_CONSTRMIN 9001 #define GRB_CB_IIS_CONSTRMAX 9002 @@ -734,9 +678,6 @@ int __stdcall int __stdcall GRBgetgenconstrNorm(GRBmodel *model, int genconstr, int *resvarP, int *nvarsP, int *vars, double *whichP); -int __stdcall -GRBgetgenconstrNL(GRBmodel *model, int genconstr, int *resvarP, int *nnodesP, - int *opcode, double *data, int *parent); int __stdcall GRBgetgenconstrIndicator(GRBmodel *model, int genconstr, int *binvarP, int *binvalP, int *nvarsP, int *vars, double *vals, @@ -804,8 +745,6 @@ int __stdcall double *feasobjP); int __stdcall GRBsinglescenariomodel(GRBmodel *model, GRBmodel **singlescenarioP); -int __stdcall - GRBconverttofixed(GRBmodel *model); /* Undocumented routines */ @@ -813,6 +752,8 @@ int __stdcall GRBgetcbwhatinfo(void *cbdata, int what, int *typeP, int *sizeP); int __stdcall GRBrelaxmodel(GRBmodel *model, GRBmodel **relaxedP); +int __stdcall + GRBconverttofixed(GRBmodel *model); int __stdcall GRBpresolvemodel(GRBmodel *model, GRBmodel **presolvedP); int __stdcall @@ -835,17 +776,15 @@ int __stdcall #define THREADCREATECB_ARGS void **threadP, void (*start_routine)(void *), void *arg, void *syscbusrdata #define THREADJOINCB_ARGS void *thread, void *syscbusrdata -#define GRBemptyenvadv(envP, malloccb, callocbc, realloccb, freecb, threadcreatecb, threadjoincb, syscbusrdata) GRBemptyenvadvinternal(envP, -1, GRB_VERSION_MAJOR, GRB_VERSION_MINOR, GRB_VERSION_TECHNICAL, malloccb, callocbc, realloccb, freecb, threadcreatecb, threadjoincb, syscbusrdata) - int __stdcall - GRBemptyenvadvnocheck(GRBenv **envP, - void * (__stdcall *malloccb)(MALLOCCB_ARGS), - void * (__stdcall *calloccb)(CALLOCCB_ARGS), - void * (__stdcall *realloccb)(REALLOCCB_ARGS), - void (__stdcall *freecb)(FREECB_ARGS), - int (__stdcall *threadcreatecb)(THREADCREATECB_ARGS), - void (__stdcall *threadjoincb)(THREADJOINCB_ARGS), - void *syscbusrdata); + GRBemptyenvadv(GRBenv **envP, + void * (__stdcall *malloccb)(MALLOCCB_ARGS), + void * (__stdcall *calloccb)(CALLOCCB_ARGS), + void * (__stdcall *realloccb)(REALLOCCB_ARGS), + void (__stdcall *freecb)(FREECB_ARGS), + int (__stdcall *threadcreatecb)(THREADCREATECB_ARGS), + void (__stdcall *threadjoincb)(THREADJOINCB_ARGS), + void *syscbusrdata); int __stdcall GRBemptyenvadvinternal(GRBenv **envP, int apitype, int major, int minor, int tech, @@ -957,10 +896,6 @@ int __stdcall int __stdcall GRBaddgenconstrNorm(GRBmodel *model, const char *name, int resvar, int nvars, const int *vars, double which); -int __stdcall -GRBaddgenconstrNL(GRBmodel *model, - const char *name, int resvar, int nnodes, const int *opcode, - const double *data, const int *parent); int __stdcall GRBaddgenconstrIndicator(GRBmodel *model, const char *name, int binvar, int binval, int nvars, const int *vars, @@ -1032,7 +967,10 @@ int __stdcall GRBupdatemodel(GRBmodel *model); int __stdcall - GRBreset(GRBmodel *model, int clearall); +GRBreset(GRBmodel *model, int clearall); + +int __stdcall + GRBresetmodel(GRBmodel *model); int __stdcall GRBfreemodel(GRBmodel *model); @@ -1215,7 +1153,6 @@ int __stdcall #define GRB_INT_PAR_PSDCUTS "PSDCuts" #define GRB_INT_PAR_LIFTPROJECTCUTS "LiftProjectCuts" #define GRB_INT_PAR_MIXINGCUTS "MixingCuts" -#define GRB_INT_PAR_DUALIMPLIEDCUTS "DualImpliedCuts" #define GRB_INT_PAR_CUTAGGPASSES "CutAggPasses" #define GRB_INT_PAR_CUTPASSES "CutPasses" @@ -1256,8 +1193,6 @@ int __stdcall #define GRB_DBL_PAR_WLSTOKENREFRESH "WLSTokenRefresh" #define GRB_STR_PAR_WLSTOKEN "WLSToken" #define GRB_INT_PAR_LICENSEID "LicenseID" -#define GRB_STR_PAR_WLSPROXY "WLSProxy" -#define GRB_STR_PAR_WLSCONFIG "WLSConfig" /* Other */ @@ -1298,7 +1233,6 @@ int __stdcall #define GRB_INT_PAR_SEED "Seed" #define GRB_INT_PAR_SOLUTIONTARGET "SolutionTarget" #define GRB_INT_PAR_THREADS "Threads" -#define GRB_INT_PAR_THREADLIMIT "ThreadLimit" #define GRB_DBL_PAR_TUNETIMELIMIT "TuneTimeLimit" #define GRB_INT_PAR_TUNERESULTS "TuneResults" #define GRB_INT_PAR_TUNECRITERION "TuneCriterion" @@ -1417,6 +1351,8 @@ int __stdcall int __stdcall GRBcheckmodel(GRBmodel *model); +void __stdcall + GRBsetsignal(GRBmodel *model); void __stdcall GRBterminate(GRBmodel *model); int __stdcall @@ -1434,9 +1370,6 @@ void __stdcall void __stdcall GRBclean3(int *lenP, int *ind0, int *ind1, double *val); -int __stdcall - GRBprintquality(GRBmodel *model); - /* Logging */ void __stdcall @@ -1483,10 +1416,6 @@ int __stdcall GRBwriteparams(GRBenv *env, const char *filename); int __stdcall GRBreadparams(GRBenv *env, const char *filename); -int __stdcall - GRBreadconcurrentsettings(GRBmodel *model, const char *filename); -int __stdcall - GRBreadmultiobjsettings(GRBmodel *model, const char *filename); int __stdcall GRBreadtunebasesettings(GRBenv *env, const char *filename); int __stdcall @@ -1500,13 +1429,10 @@ int __stdcall /* Environment routines */ -#define GRBloadenv(envP, logfilename) GRBloadenvinternal(envP, logfilename, GRB_VERSION_MAJOR, GRB_VERSION_MINOR, GRB_VERSION_TECHNICAL) -#define GRBemptyenv(envP) GRBemptyenvinternal(envP, GRB_VERSION_MAJOR, GRB_VERSION_MINOR, GRB_VERSION_TECHNICAL) - int __stdcall -GRBloadenvinternal(GRBenv **envP, const char *logfilename, int major, int minor, int tech); + GRBloadenv(GRBenv **envP, const char *logfilename); int __stdcall -GRBemptyenvinternal(GRBenv **envP, int major, int minor, int tech); + GRBemptyenv(GRBenv **envP); int __stdcall GRBstartenv(GRBenv *env); int __stdcall @@ -1636,8 +1562,6 @@ int __stdcall GRBgettuneresult(GRBmodel *model, int i); int __stdcall GRBgettunelog(GRBmodel *model, int i, char **logP); -int __stdcall - GRBwritetunelog(GRBmodel *model, int result, const char *filename); void __stdcall GRBtuneparamsPrint(void); diff --git a/pyproject.toml b/pyproject.toml index 394fa55..a6225e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ dynamic = ["version", "readme"] # these are required... but hard to install from pypi # we list them here for completeness, but it's up to the user to install them :( dependencies = [ - # "gurobi==12.0.0", + # "gurobi==11.0.3", # "scip==9.1.0", ] diff --git a/setup.py b/setup.py index 4f8db3e..3f5c75f 100644 --- a/setup.py +++ b/setup.py @@ -129,21 +129,19 @@ def find_conda_gurobi() -> "tuple[str, str] | tuple[None, None]": os.environ["PATH"] += os.pathsep + lib_path # Dynamically add to PATH # Search for Gurobi in the active Conda environment - for v, prefix in product(range(100, 150, 10), ("lib", "")): - gurobi_lib = f"{prefix}gurobi{v}" + for prefix in ("lib", ""): + gurobi_lib = f"{prefix}gurobi110" if found := util.find_library(gurobi_lib): return gurobi_lib, found return (None, None) -for v, prefix in product(range(100, 150, 10), ("lib", "")): - GUROBI_LIB, lib_path = find_conda_gurobi() - if GUROBI_LIB is not None: - print(f"FOUND GUROBI library {GUROBI_LIB!r}: {lib_path}") - libraries.append(GUROBI_LIB) - compile_args.append("/DHAVE_GUROBI" if os.name == "nt" else "-DHAVE_GUROBI") - break +GUROBI_LIB, lib_path = find_conda_gurobi() +if GUROBI_LIB is not None: + print(f"FOUND GUROBI library {GUROBI_LIB!r}: {lib_path}") + libraries.append(GUROBI_LIB) + compile_args.append("/DHAVE_GUROBI" if os.name == "nt" else "-DHAVE_GUROBI") else: print("WARNING: GUROBI library not found") From 2e3a16c164afee5b09d219aa411595d1524f0e30 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 10:31:13 -0500 Subject: [PATCH 15/26] show all gurobi stuff --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 428bae8..045353f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -65,9 +65,9 @@ jobs: - name: install build deps run: | conda install -c conda-forge -c gurobi gurobi=11.0.3 scip=9.1.0 gcovr + find $CONDA_PREFIX -name "*gurobi*" - name: add gurobi license - shell: bash id: write-license env: LICENSE: ${{ secrets.GRB_LICENSE_FILE }} From 6c9bab0560d84a708d1a178a5de2589d40d90c9e Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 10:34:47 -0500 Subject: [PATCH 16/26] simplify setup again --- setup.py | 130 +++++-------------------------------------------------- 1 file changed, 11 insertions(+), 119 deletions(-) diff --git a/setup.py b/setup.py index 3f5c75f..ff4157e 100644 --- a/setup.py +++ b/setup.py @@ -1,96 +1,12 @@ -import glob import os from ctypes import util -from itertools import product from Cython.Build import cythonize from setuptools import setup from setuptools.extension import Extension -print("PATH:", os.environ["PATH"]) -print("CONDA_PREFIX:", os.environ.get("CONDA_PREFIX")) - - -def debug_conda_env() -> None: - conda_prefix = os.environ.get("CONDA_PREFIX") - if not conda_prefix: - raise RuntimeError("No active Conda environment found. Ensure Conda is active.") - print() - # Check Gurobi DLL directory - if os.name == "nt": - bin_dir = os.path.join(conda_prefix, "Library", "bin") - else: - bin_dir = os.path.join(conda_prefix, "lib") - print(f"Inspecting bin directory: {bin_dir}") - if os.path.exists(bin_dir): - for file in glob.glob(os.path.join(bin_dir, "*gurobi*")): - print(f" Found: {file}") - for file in glob.glob(os.path.join(bin_dir, "*scip*")): - print(f" Found: {file}") - # print the whole damn directory - for file in glob.glob(os.path.join(bin_dir, "*")): - print(f" Found: {file}") - else: - print("Gurobi bin directory does not exist!") - - print() - # Check SCIP include directory - if os.name == "nt": - inc_dir = os.path.join(conda_prefix, "Library", "include", "scip") - else: - inc_dir = os.path.join(conda_prefix, "include", "scip") - print(f"Inspecting include directory: {inc_dir}") - if os.path.exists(inc_dir): - for file in glob.glob(os.path.join(inc_dir, "*")): - print(f" Found: {file}") - else: - print("SCIP include directory does not exist!") - # print parent directory - print(f" Parent directory: {os.path.dirname(inc_dir)}") - for file in glob.glob(os.path.join(os.path.dirname(inc_dir), "*")): - print(f" Found: {file}") - print() - - -def assert_gurobi_and_scip() -> None: - # Get the Conda environment prefix - conda_prefix = os.environ.get("CONDA_PREFIX") - if not conda_prefix: - raise RuntimeError("CONDA_PREFIX is not set. Ensure Conda is active in CI.") - - # Paths to check - gurobi_dll_path = os.path.join(conda_prefix, "Library", "bin", "gurobi*.dll") - scip_header_path = os.path.join( - conda_prefix, "Library", "include", "scip", "scipdefplugins.h" - ) - - # Verify Gurobi DLL - gurobi_found = any(os.path.exists(path) for path in glob.glob(gurobi_dll_path)) - if not gurobi_found: - raise FileNotFoundError( - f"Gurobi DLL not found in {gurobi_dll_path}. Ensure Gurobi is installed." - ) - - # Verify SCIP header - if not os.path.exists(scip_header_path): - raise FileNotFoundError( - f"SCIP header 'scipdefplugins.h' not found in {scip_header_path}. " - "Ensure SCIP is installed." - ) - - print("All required files are present.") - - -debug_conda_env() -if os.name == "nt": - assert_gurobi_and_scip() - # enable test coverage tracing if CYTHON_TRACE is set to a non-zero value CYTHON_TRACE = int(os.getenv("CYTHON_TRACE") in ("1", "True")) -if not (CONDA_PREFIX := os.environ.get("CONDA_PREFIX")): - raise RuntimeError( - "No active Conda environment found. Activate an environment before running." - ) libraries = ["libscip"] if os.name == "nt" else ["scip"] include_dirs = ["ilpy/impl"] @@ -103,48 +19,24 @@ def assert_gurobi_and_scip() -> None: # include conda environment windows include/lib if it exists # this will be done automatically by conda build, but is useful if someone # tries to build this directly with pip install in a conda environment -if os.name == "nt": - include = os.path.join(CONDA_PREFIX, "Library", "include") - include_dirs.append(include) - library_dirs.append(os.path.join(CONDA_PREFIX, "Library", "lib")) - if not os.path.exists(include): - print( - "WARNING: Conda include directory not found. " - "Ensure you have the Conda environment activated." - ) +if os.name == "nt" and "CONDA_PREFIX" in os.environ: + include_dirs.append(os.path.join(os.environ["CONDA_PREFIX"], "Library", "include")) + library_dirs.append(os.path.join(os.environ["CONDA_PREFIX"], "Library", "lib")) # look for various gurobi versions, which are annoyingly # suffixed with the version number, and wildcards don't work - -def find_conda_gurobi() -> "tuple[str, str] | tuple[None, None]": - # Construct the potential library paths - library_paths = [ - os.path.join(str(CONDA_PREFIX), "Library", "bin"), # Windows DLLs - os.path.join(str(CONDA_PREFIX), "lib"), # macOS/Linux - ] - - for lib_path in library_paths: - if os.path.exists(lib_path): - os.environ["PATH"] += os.pathsep + lib_path # Dynamically add to PATH - - # Search for Gurobi in the active Conda environment - for prefix in ("lib", ""): - gurobi_lib = f"{prefix}gurobi110" - if found := util.find_library(gurobi_lib): - return gurobi_lib, found - - return (None, None) - - -GUROBI_LIB, lib_path = find_conda_gurobi() -if GUROBI_LIB is not None: - print(f"FOUND GUROBI library {GUROBI_LIB!r}: {lib_path}") - libraries.append(GUROBI_LIB) - compile_args.append("/DHAVE_GUROBI" if os.name == "nt" else "-DHAVE_GUROBI") +for prefix in ("lib", ""): + gurobi_lib = f"{prefix}gurobi110" # only using gurobi 11 at the moment + if found := util.find_library(gurobi_lib): + print("FOUND GUROBI library: ", found) + libraries.append(gurobi_lib) + compile_args.append("/DHAVE_GUROBI" if os.name == 'nt' else "-DHAVE_GUROBI") + break else: print("WARNING: GUROBI library not found") + wrapper = Extension( "ilpy.wrapper", sources=["ilpy/wrapper.pyx"], From d162dd8cd6b5b3183ffc0db83bdc21985759a48e Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 10:43:54 -0500 Subject: [PATCH 17/26] add one more path --- setup.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/setup.py b/setup.py index ff4157e..890d8e0 100644 --- a/setup.py +++ b/setup.py @@ -5,6 +5,15 @@ from setuptools import setup from setuptools.extension import Extension +CONDA_PREFIX = os.environ.get("CONDA_PREFIX") +if not CONDA_PREFIX: + raise ValueError("CONDA_PREFIX not set, did you active a conda environment?") + +# gurobi seems to be putting its libraries in the top of the conda env +os.environ["PATH"] += os.pathsep + CONDA_PREFIX +print("CONDA_PREFIX:", CONDA_PREFIX) +print("PATH:", os.environ["PATH"]) + # enable test coverage tracing if CYTHON_TRACE is set to a non-zero value CYTHON_TRACE = int(os.getenv("CYTHON_TRACE") in ("1", "True")) From 2e52d07dcf17bc422f00ada277f50941ee657808 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 10:46:16 -0500 Subject: [PATCH 18/26] linting --- setup.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 890d8e0..0673497 100644 --- a/setup.py +++ b/setup.py @@ -6,11 +6,12 @@ from setuptools.extension import Extension CONDA_PREFIX = os.environ.get("CONDA_PREFIX") -if not CONDA_PREFIX: - raise ValueError("CONDA_PREFIX not set, did you active a conda environment?") +if CONDA_PREFIX: + os.environ["PATH"] += os.pathsep + CONDA_PREFIX +else: + print("CONDA_PREFIX not set!, did you active a conda environment?") # gurobi seems to be putting its libraries in the top of the conda env -os.environ["PATH"] += os.pathsep + CONDA_PREFIX print("CONDA_PREFIX:", CONDA_PREFIX) print("PATH:", os.environ["PATH"]) @@ -40,7 +41,7 @@ if found := util.find_library(gurobi_lib): print("FOUND GUROBI library: ", found) libraries.append(gurobi_lib) - compile_args.append("/DHAVE_GUROBI" if os.name == 'nt' else "-DHAVE_GUROBI") + compile_args.append("/DHAVE_GUROBI" if os.name == "nt" else "-DHAVE_GUROBI") break else: print("WARNING: GUROBI library not found") From e9bbaaacd200c8c703e687b55a83cf1f8c26ca45 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 10:55:08 -0500 Subject: [PATCH 19/26] add conda_prefix to library_dirs --- README.md | 13 ++++++------- pyproject.toml | 13 +++++++------ setup.py | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d424317..28d9cb7 100644 --- a/README.md +++ b/README.md @@ -16,17 +16,16 @@ conda install -c funkelab ilpy ## Local development -ilpy links against SCIP, so you must have SCIP installed in your environment. -(You can install via conda) +Clone the repo and install in editable mode. -```bash -conda install scip==9.1.0 -``` - -Then clone the repo and install in editable mode. +Note, `ilpy` links against SCIP, so you must have SCIP installed in your environment, +in order to build: ```bash git clone cd ilpy + +conda create -n ilpy -c conda-forge -c gurobi python scip==9.1.0 gurobi==11.0.3 +conda activate ilpy pip install -e .[dev] ``` diff --git a/pyproject.toml b/pyproject.toml index a6225e8..99df3c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,15 +25,16 @@ dependencies = [ # https://peps.python.org/pep-0621/#dependencies-optional-dependencies [project.optional-dependencies] dev = [ - "ruff", - "mypy", - "pytest", + "cython", + "gurobipy", # used on CI to confirm equality of results "ipython", + "mypy", + "numpy", + "pre-commit", "pytest-cov", - "cython", + "pytest", + "ruff", "setuptools==71.1.0", - "numpy", - "gurobipy", # used on CI to confirm equality of results ] docs = ["sphinx", "sphinx_rtd_theme", "sphinx-autodoc-typehints"] diff --git a/setup.py b/setup.py index 0673497..ff58feb 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ libraries = ["libscip"] if os.name == "nt" else ["scip"] include_dirs = ["ilpy/impl"] -library_dirs = [] +library_dirs = [CONDA_PREFIX] if CONDA_PREFIX else [] if os.name == "nt": compile_args = ["/O2", "/DHAVE_SCIP", "/std:c++17", "/wd4702"] else: From a0847236f46b170ab11b64e07d8037c344397131 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 11:00:02 -0500 Subject: [PATCH 20/26] update pre-commit --- .pre-commit-config.yaml | 6 +++--- README.md | 7 +++++++ ilpy/__init__.py | 2 +- ilpy/expressions.py | 8 ++++---- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7e35fa3..a9dabd5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,20 +5,20 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.4 + rev: v0.8.2 hooks: - id: ruff args: [--fix] - id: ruff-format - repo: https://github.com/MarcoGorelli/cython-lint - rev: v0.16.0 + rev: v0.16.6 hooks: - id: cython-lint - id: double-quote-cython-strings - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.9.0 + rev: v1.13.0 hooks: - id: mypy files: "^ilpy/" diff --git a/README.md b/README.md index 28d9cb7..ac64326 100644 --- a/README.md +++ b/README.md @@ -29,3 +29,10 @@ conda create -n ilpy -c conda-forge -c gurobi python scip==9.1.0 gurobi==11.0.3 conda activate ilpy pip install -e .[dev] ``` + +If you make local change and want to rebuild the extension quickly, you can run: + +```bash +rm -rf build +python setup.py build_ext --inplace +``` diff --git a/ilpy/__init__.py b/ilpy/__init__.py index 8888331..4a0938a 100644 --- a/ilpy/__init__.py +++ b/ilpy/__init__.py @@ -33,11 +33,11 @@ "Scip", "Sense", "Solution", - "solve", "Solver", "Solver", "Variable", "VariableType", + "solve", ] diff --git a/ilpy/expressions.py b/ilpy/expressions.py index 9595374..601cf74 100644 --- a/ilpy/expressions.py +++ b/ilpy/expressions.py @@ -2,7 +2,7 @@ import ast import sys -from collections.abc import Iterator, Sequence +from collections.abc import Iterator from contextlib import contextmanager from typing import Any, ClassVar, Union @@ -22,7 +22,7 @@ def recursion_limit_raised_by(N: int = 5000) -> Iterator[None]: sys.setrecursionlimit(old_limit) -class Expression(ast.AST): +class Expression(ast.expr): """Base class for all expression nodes. Expressions allow ilpy to represent mathematical expressions in an @@ -147,8 +147,8 @@ class Compare(Expression, ast.Compare): def __init__( self, left: Expression, - ops: Sequence[ast.cmpop], - comparators: Sequence[Expression | Number], + ops: list[ast.cmpop], + comparators: list[Expression | Number], **kwargs: Any, ) -> None: super().__init__( From 211b9b0f941be4a73f075c1d5ba782ea73d582f5 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 11:18:09 -0500 Subject: [PATCH 21/26] try generate --- .github/workflows/ci.yaml | 8 ++++++++ generate_lib.bat | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 generate_lib.bat diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 045353f..6067b68 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -66,6 +66,14 @@ jobs: run: | conda install -c conda-forge -c gurobi gurobi=11.0.3 scip=9.1.0 gcovr find $CONDA_PREFIX -name "*gurobi*" + + - name: create windows .lib + if: runner.os == 'Windows' + shell: cmd + run: | + echo %CONDA_PREFIX% + dir %CONDA_PREFIX%\gurobi110.dll + call generat_lib.bat - name: add gurobi license id: write-license diff --git a/generate_lib.bat b/generate_lib.bat new file mode 100644 index 0000000..a7302b6 --- /dev/null +++ b/generate_lib.bat @@ -0,0 +1,27 @@ +@echo off +set DLL_PATH=%CONDA_PREFIX%\gurobi110.dll +set DEF_NAME=gurobi110.def +set LIB_NAME=gurobi110.lib + +:: Check if the DLL exists +if not exist "%DLL_PATH%" ( + echo Error: %DLL_PATH% not found. + exit /b 1 +) + +:: Generate .def file from dumpbin output +dumpbin /exports "%DLL_PATH%" > temp_exports.txt + +:: Extract relevant lines for the .def file +echo LIBRARY gurobi110 > %DEF_NAME% +echo EXPORTS >> %DEF_NAME% +findstr /r "^[0-9A-F]" temp_exports.txt | for /f "tokens=4" %%G in ('findstr /r "^[0-9A-F]" temp_exports.txt') do echo %%G >> %DEF_NAME% + +:: Create .lib from the .def file +lib /def:%DEF_NAME% /out:%LIB_NAME% /machine:x64 + +:: Print success message +echo Successfully generated %LIB_NAME% + +:: Cleanup +del temp_exports.txt From 5a08ea0cb71223a66bc392af9b1f2eb4894703df Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 11:36:03 -0500 Subject: [PATCH 22/26] fix typo --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6067b68..343edf9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -73,7 +73,7 @@ jobs: run: | echo %CONDA_PREFIX% dir %CONDA_PREFIX%\gurobi110.dll - call generat_lib.bat + call generate_lib.bat - name: add gurobi license id: write-license From 70ea959092d4e7b8763aa6ac00fdf56df28dc965 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 11:41:34 -0500 Subject: [PATCH 23/26] use bash --- .github/workflows/ci.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 343edf9..f3d8707 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -69,11 +69,10 @@ jobs: - name: create windows .lib if: runner.os == 'Windows' - shell: cmd run: | echo %CONDA_PREFIX% - dir %CONDA_PREFIX%\gurobi110.dll - call generate_lib.bat + ls $CONDA_PREFIX + cmd.exe /c "generate_lib.bat" - name: add gurobi license id: write-license From 56c06f7669c5fa05ea60ec6940907d91530879e6 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 11:50:51 -0500 Subject: [PATCH 24/26] same dir --- .github/workflows/ci.yaml | 2 +- generate_lib.bat | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f3d8707..99c77d7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -71,8 +71,8 @@ jobs: if: runner.os == 'Windows' run: | echo %CONDA_PREFIX% - ls $CONDA_PREFIX cmd.exe /c "generate_lib.bat" + ls $CONDA_PREFIX - name: add gurobi license id: write-license diff --git a/generate_lib.bat b/generate_lib.bat index a7302b6..97ba3ec 100644 --- a/generate_lib.bat +++ b/generate_lib.bat @@ -1,7 +1,7 @@ -@echo off set DLL_PATH=%CONDA_PREFIX%\gurobi110.dll set DEF_NAME=gurobi110.def set LIB_NAME=gurobi110.lib +set OUTPUT_DIR=%~dpDLL_PATH% :: Check if the DLL exists if not exist "%DLL_PATH%" ( @@ -17,11 +17,17 @@ echo LIBRARY gurobi110 > %DEF_NAME% echo EXPORTS >> %DEF_NAME% findstr /r "^[0-9A-F]" temp_exports.txt | for /f "tokens=4" %%G in ('findstr /r "^[0-9A-F]" temp_exports.txt') do echo %%G >> %DEF_NAME% -:: Create .lib from the .def file -lib /def:%DEF_NAME% /out:%LIB_NAME% /machine:x64 +:: Create .lib in the same directory as the DLL +lib /def:%DEF_NAME% /out:%OUTPUT_DIR%%LIB_NAME% /machine:x64 -:: Print success message -echo Successfully generated %LIB_NAME% +:: Verify .lib creation +if not exist "%OUTPUT_DIR%%LIB_NAME%" ( + echo Error: Failed to generate %LIB_NAME% next to the DLL. + exit /b 1 +) + +:: Success message +echo Successfully generated %OUTPUT_DIR%%LIB_NAME% :: Cleanup del temp_exports.txt From 950def46aedfd0971bd8c1856bb86271f921d149 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 11:57:06 -0500 Subject: [PATCH 25/26] don't use gurobi on windows --- .github/workflows/ci.yaml | 15 +++++---------- generate_lib.bat | 33 --------------------------------- 2 files changed, 5 insertions(+), 43 deletions(-) delete mode 100644 generate_lib.bat diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 99c77d7..eb07cf7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -63,16 +63,11 @@ jobs: channel-priority: true - name: install build deps - run: | - conda install -c conda-forge -c gurobi gurobi=11.0.3 scip=9.1.0 gcovr - find $CONDA_PREFIX -name "*gurobi*" - - - name: create windows .lib - if: runner.os == 'Windows' - run: | - echo %CONDA_PREFIX% - cmd.exe /c "generate_lib.bat" - ls $CONDA_PREFIX + run: conda install -c conda-forge scip=9.1.0 gcovr + + - name: install gurobi + if: runner.os != 'Windows' + run: conda install -c gurobi gurobi=11.0.3 - name: add gurobi license id: write-license diff --git a/generate_lib.bat b/generate_lib.bat deleted file mode 100644 index 97ba3ec..0000000 --- a/generate_lib.bat +++ /dev/null @@ -1,33 +0,0 @@ -set DLL_PATH=%CONDA_PREFIX%\gurobi110.dll -set DEF_NAME=gurobi110.def -set LIB_NAME=gurobi110.lib -set OUTPUT_DIR=%~dpDLL_PATH% - -:: Check if the DLL exists -if not exist "%DLL_PATH%" ( - echo Error: %DLL_PATH% not found. - exit /b 1 -) - -:: Generate .def file from dumpbin output -dumpbin /exports "%DLL_PATH%" > temp_exports.txt - -:: Extract relevant lines for the .def file -echo LIBRARY gurobi110 > %DEF_NAME% -echo EXPORTS >> %DEF_NAME% -findstr /r "^[0-9A-F]" temp_exports.txt | for /f "tokens=4" %%G in ('findstr /r "^[0-9A-F]" temp_exports.txt') do echo %%G >> %DEF_NAME% - -:: Create .lib in the same directory as the DLL -lib /def:%DEF_NAME% /out:%OUTPUT_DIR%%LIB_NAME% /machine:x64 - -:: Verify .lib creation -if not exist "%OUTPUT_DIR%%LIB_NAME%" ( - echo Error: Failed to generate %LIB_NAME% next to the DLL. - exit /b 1 -) - -:: Success message -echo Successfully generated %OUTPUT_DIR%%LIB_NAME% - -:: Cleanup -del temp_exports.txt From 173e52327f3cf1d66fd014d5f8541e328f429bd4 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sun, 8 Dec 2024 12:16:46 -0500 Subject: [PATCH 26/26] last try --- pyproject.toml | 2 +- setup.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 99df3c7..288a19d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ [project.optional-dependencies] dev = [ "cython", - "gurobipy", # used on CI to confirm equality of results + "gurobipy==11.0.3; sys_platform!='windows' and python_version<'3.12'", # used to confirm equality of results "ipython", "mypy", "numpy", diff --git a/setup.py b/setup.py index ff58feb..cdda3cc 100644 --- a/setup.py +++ b/setup.py @@ -7,13 +7,11 @@ CONDA_PREFIX = os.environ.get("CONDA_PREFIX") if CONDA_PREFIX: + # gurobi seems to be putting its libraries in the top of the conda env os.environ["PATH"] += os.pathsep + CONDA_PREFIX else: print("CONDA_PREFIX not set!, did you active a conda environment?") -# gurobi seems to be putting its libraries in the top of the conda env -print("CONDA_PREFIX:", CONDA_PREFIX) -print("PATH:", os.environ["PATH"]) # enable test coverage tracing if CYTHON_TRACE is set to a non-zero value CYTHON_TRACE = int(os.getenv("CYTHON_TRACE") in ("1", "True"))