├── ampl ├── circle2.mod ├── circle_loop.mod ├── multiobj.mod └── multiobjloop.mod ├── gurobi ├── cutstock │ ├── Makefile │ ├── README.md │ ├── cutstock.cpp │ └── cutstock.py ├── locationtransport │ ├── Makefile │ ├── README.md │ ├── locationtransport.cpp │ ├── locationtransport.py │ ├── locationtransport2.cpp │ └── loctrans.dat ├── multicommodity │ ├── Makefile │ ├── README.md │ ├── multicommodity.cpp │ ├── multicommodity.dat │ └── multicommodity.py └── warehouse │ ├── Makefile │ ├── README.md │ ├── warehouse.cpp │ ├── warehouse.dat │ ├── warehouse.py │ └── warehouse2.cpp └── lindoapi ├── circle ├── Makefile ├── README.md ├── circle.c └── circle.lng └── peak ├── Makefile ├── README.md ├── peak.c └── peak.lng /ampl/circle2.mod: -------------------------------------------------------------------------------- 1 | # packing circles in rectangle 2 | 3 | param n = 126; 4 | param l = 471; 5 | param w = 196; 6 | 7 | set dim = 1..n; 8 | 9 | var x {dim}; 10 | var y {dim}; 11 | var r >= 0; 12 | 13 | maximize robj: r; 14 | 15 | subject to distance{i in dim, j in dim: j > i}: 16 | (x[i] - x[j])^2 + (y[i] - y[j])^2 >= 4*r^2; 17 | 18 | subject to xbup {i in dim}: 19 | x[i] <= l - r; 20 | 21 | subject to xblow {i in dim}: 22 | x[i] >= r; 23 | 24 | subject to ybup {i in dim}: 25 | y[i] <= w - r; 26 | 27 | subject to yblow {i in dim}: 28 | y[i] >= r; 29 | 30 | option log_file "circle2.log"; 31 | 32 | # option solver knitro; 33 | # option knitro_options 'outlev 0 par_numthreads 4 linsolver 6'; 34 | 35 | option solver ipopt; 36 | option ipopt_options 'linear_solver pardiso'; 37 | 38 | solve; 39 | 40 | printf "\n\n ********Solution Report******** \n"; 41 | printf "\nObjective:\n"; 42 | printf " %.12f\n", robj; 43 | printf "\nVariables:\n"; 44 | printf " Dim X Y\n"; 45 | for {i in dim} { 46 | printf " %-3d %18.12f %18.12f\n", i, x[i], y[i]; 47 | } 48 | 49 | exit; 50 | 51 | # Current best known solution obtained by Ipopt with pardiso as linear solver, 4 threads 52 | # 53 | # ********Solution Report******** 54 | # 55 | #Objective: 56 | # 14.005166318974 57 | # 58 | #Variables: 59 | # Dim X Y 60 | # 1 30.763996936231 181.994834967071 61 | # 2 58.774336851277 181.994834925280 62 | # 3 56.020680614400 38.262825456825 63 | # 4 14.005167276539 111.035800232333 64 | # 5 142.805363358318 133.479519034610 65 | # 6 58.774337489728 133.479517532031 66 | # 7 114.795020817401 133.479518882183 67 | # 8 114.795021429455 84.964202058304 68 | # 9 100.789850288995 109.221860260530 69 | # 10 70.025851613659 14.005167054673 70 | # 11 159.564190948208 62.520484577252 71 | # 12 72.779507530333 157.737176415185 72 | # 13 28.010337797300 86.778141754391 73 | # 14 14.005167285401 62.520483288694 74 | # 15 100.789849465108 157.737176922376 75 | # 16 173.569362135703 86.778142817505 76 | # 17 114.795020672191 181.994835007702 77 | # 18 44.769166765729 157.737175996905 78 | # 19 42.015509616781 62.520483854368 79 | # 20 128.800192090050 157.737177060203 80 | # 21 86.784680198653 84.964201374784 81 | # 22 28.010338934569 38.262825479600 82 | # 23 142.805363852084 181.994834945372 83 | # 24 386.400604162796 157.737182668242 84 | # 25 198.826049531266 181.994834793945 85 | # 26 156.810533819548 109.221860544935 86 | # 27 243.595217578084 111.035797933083 87 | # 28 302.369557853085 109.221860582740 88 | # 29 170.815706036184 133.479518410395 89 | # 30 246.348874630291 157.737175708211 90 | # 31 86.784679009500 133.479518392641 91 | # 32 456.711393995716 180.723440517624 92 | # 33 187.574530889637 14.005166939113 93 | # 34 285.610736976754 38.262824950895 94 | # 35 400.406263063458 181.994710862925 95 | # 36 128.800192016310 109.221860765384 96 | # 37 201.579701816448 38.262825147079 97 | # 38 260.354043995117 181.994834951363 98 | # 39 173.569360783801 38.262825671447 99 | # 40 344.385071214655 181.994835024426 100 | # 41 184.820878251895 157.737176322068 101 | # 42 14.005167314934 159.551118162796 102 | # 43 170.815707282100 181.994834858730 103 | # 44 302.369553031472 157.737176476387 104 | # 45 28.010337025152 135.293459156075 105 | # 46 156.810535359383 157.737176920519 106 | # 47 428.416758317213 181.994830883034 107 | # 48 142.805362479747 84.964202225294 108 | # 49 215.584872582681 14.005166887586 109 | # 50 56.020679676390 86.778142606144 110 | # 51 316.374726778525 133.479520029146 111 | # 52 114.795021704622 36.448884529966 112 | # 53 229.590046473466 86.778139869193 113 | # 54 131.553850429899 14.005167008909 114 | # 55 243.595217498302 62.520481287683 115 | # 56 100.789851238683 60.706543127647 116 | # 57 215.584876303735 111.035798937974 117 | # 58 72.779509058181 109.221859566676 118 | # 59 299.615910750300 14.005167416028 119 | # 60 274.359215439814 109.221857941460 120 | # 61 145.559020520652 38.262825884655 121 | # 62 347.138731118361 38.262827466212 122 | # 63 375.149067545381 38.262827240371 123 | # 64 215.584877464841 159.551116376021 124 | # 65 375.149073572834 86.778149747931 125 | # 66 344.385071249667 133.479523369109 126 | # 67 271.605564654656 14.005167130990 127 | # 68 187.574531845683 62.520483895848 128 | # 69 42.015509755484 14.005167021206 129 | # 70 257.600388646815 86.778139220974 130 | # 71 42.015507906631 111.035800619437 131 | # 72 70.025850895748 62.520484231144 132 | # 73 229.590047422816 135.293457109588 133 | # 74 128.800191919774 60.706543476748 134 | # 75 288.364384167285 133.479517269916 135 | # 76 14.005167917262 14.005167434225 136 | # 77 201.579704049773 86.778141435422 137 | # 78 84.031022057419 38.262825817667 138 | # 79 187.574534265535 111.035800472353 139 | # 80 302.369563386346 60.706544535396 140 | # 81 201.579706370849 135.293458121362 141 | # 82 159.564190484429 14.005166988142 142 | # 83 98.036192664091 14.005167086651 143 | # 84 288.364382850925 181.994835045100 144 | # 85 86.784678100650 181.994834966739 145 | # 86 243.595217821061 14.005166974247 146 | # 87 274.359213651773 157.737175855819 147 | # 88 372.395422689838 181.994834915599 148 | # 89 229.590044934479 38.262824159526 149 | # 90 330.379896502377 157.737178991255 150 | # 91 358.390246572662 157.737179390074 151 | # 92 288.364389091427 84.964201025513 152 | # 93 232.343704884319 181.994834904106 153 | # 94 271.605562447691 62.520481949800 154 | # 95 316.374722688341 181.994835174964 155 | # 96 260.354044591893 133.479516575319 156 | # 97 257.600390826658 38.262824063423 157 | # 98 215.584874082315 62.520482551387 158 | # 99 330.379901402456 109.221864104547 159 | # 100 372.395424427102 133.479525219005 160 | # 101 406.251220033131 137.975303846553 161 | # 102 456.994837802692 49.109162023459 162 | # 103 316.374736979265 36.448887643649 163 | # 104 417.141692800642 112.168785145616 164 | # 105 333.133562006298 14.005167215059 165 | # 106 389.154235346790 14.005166974624 166 | # 107 389.154276142757 111.035824936579 167 | # 108 361.143900962640 62.520488095471 168 | # 109 361.143898979542 14.005167142483 169 | # 110 330.379906351439 60.706547895289 170 | # 111 344.385075972865 84.964208161793 171 | # 112 316.374732324584 84.964204364792 172 | # 113 429.227487838459 153.996228737517 173 | # 114 358.390246690245 109.221868169346 174 | # 115 417.164573655273 14.005167199887 175 | # 116 455.532870278899 15.330244349559 176 | # 117 431.146820225276 87.911101728586 177 | # 118 403.159408991223 86.778144634694 178 | # 119 389.154236668062 62.520487208948 179 | # 120 418.025283767978 63.016663117141 180 | # 121 456.994834863634 150.314736017812 181 | # 122 403.159403228724 38.262826908811 182 | # 123 440.436871787245 127.722394126256 183 | # 124 456.994722288944 105.129913810207 184 | # 125 456.994837796395 77.119496062052 185 | # 126 431.169736643189 38.262830156504 -------------------------------------------------------------------------------- /ampl/circle_loop.mod: -------------------------------------------------------------------------------- 1 | param n integer; 2 | param niter integer; 3 | param dtime; 4 | 5 | param cR = 7.0; 6 | param cr = 1.0; 7 | 8 | set dim = 1..n; 9 | 10 | var x {dim}; 11 | var y {dim}; 12 | var r >= 0; 13 | 14 | maximize robj: r; 15 | 16 | subject to distance{i in dim, j in dim: j > i}: 17 | (x[i] - x[j])^2 + (y[i] - y[j])^2 >= 4*r^2; 18 | 19 | subject to each{i in dim}: 20 | x[i]^2 + y[i]^2 <= (cR - r)^2; 21 | 22 | subject to xbound_rhs{i in dim}: 23 | x[i] <= cR - r; 24 | 25 | subject to xbound_lhs{i in dim}: 26 | x[i] >= r - cR; 27 | 28 | subject to ybound_rhs{i in dim}: 29 | y[i] <= cR - r; 30 | 31 | subject to ybound_lhs{i in dim}: 32 | y[i] >= r - cR; 33 | 34 | let n := floor(cR^2 / cr); 35 | 36 | option log_file "circle_loop.log"; 37 | option solver_msg 0; 38 | option reset_initial_guesses 1; # unset warm start to avoid poor solution 39 | 40 | # option solver knitro; 41 | # option knitro_options 'outlev 0'; 42 | option solver ipopt; 43 | option ipopt_options 'outlev 0 linear_solver pardiso'; 44 | 45 | let niter := 1; 46 | let dtime := 0.0; 47 | 48 | repeat { 49 | solve; 50 | 51 | if robj - cr < 1e-6 then { 52 | let n := n - 1; 53 | let niter := niter + 1; 54 | let dtime := dtime + _solve_elapsed_time; 55 | } 56 | else 57 | break; 58 | 59 | if niter >= 100 then { 60 | break; 61 | } 62 | } 63 | 64 | printf "\n\n ********Solution Report******** \n"; 65 | printf "\nObjective:\n"; 66 | printf " %.12f\n", robj; 67 | printf "\nVariables:\n"; 68 | printf " Dim X Y\n"; 69 | for {i in dim} { 70 | printf " %-2d %15.12f %15.12f\n", i, x[i], y[i]; 71 | } 72 | printf "\nIterations: %d\n", niter; 73 | printf "\nElapsed time: %.3f (seconds)\n", dtime; 74 | 75 | exit; -------------------------------------------------------------------------------- /ampl/multiobj.mod: -------------------------------------------------------------------------------- 1 | # non-loop style multi-objective model in AMPL 2 | # ref: http://www.gurobi.com/documentation/7.5/examples/multiobj_cpp_cpp.html 3 | # author: wujianw@stu.xjtu.edu.cn 4 | 5 | set Groundset = 0..19; 6 | set Subsets = 0..3; 7 | 8 | param Budget; 9 | param ObjCoeff {Subsets, Groundset}; 10 | 11 | var Elem {Groundset} binary; 12 | 13 | maximize Objective_one: sum {j in Groundset} ObjCoeff[0, j] * Elem[j]; 14 | maximize Objective_two: sum {j in Groundset} ObjCoeff[1, j] * Elem[j]; 15 | maximize Objective_three: sum {j in Groundset} ObjCoeff[2, j] * Elem[j]; 16 | maximize Objective_four: sum {j in Groundset} ObjCoeff[3, j] * Elem[j]; 17 | 18 | subject to conBudget: 19 | sum {j in Groundset} Elem[j] <= Budget; 20 | 21 | # assign parameter 22 | data; 23 | param Budget := 12; 24 | param ObjCoeff : 25 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 := 26 | 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 27 | 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 28 | 2 0 0 0 1 1 0 1 1 0 0 0 0 0 1 1 0 1 1 0 0 29 | 3 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0; 30 | 31 | suffix objpriority IN, integer, >= 0, <= 999; 32 | suffix objweight IN; 33 | suffix objreltol IN; 34 | suffix objabstol IN; 35 | 36 | # assign objective priority 37 | let Objective_one.objpriority := 3; 38 | let Objective_two.objpriority := 2; 39 | let Objective_three.objpriority := 2; 40 | let Objective_four.objpriority := 1; 41 | 42 | # assign objective weight 43 | let Objective_one.objweight := 1.0; 44 | let Objective_two.objweight := 0.25; 45 | let Objective_three.objweight := 1.25; 46 | let Objective_four.objweight := 1.0; 47 | 48 | # assign relative tolerance 49 | let Objective_one.objreltol := 0.01; 50 | let Objective_two.objreltol := 0.01; 51 | let Objective_three.objreltol := 0.01; 52 | let Objective_four.objreltol := 0.01; 53 | 54 | # assign absolute tolerance 55 | let Objective_one.objabstol := 1.0; 56 | let Objective_two.objabstol := 2.0; 57 | let Objective_three.objabstol := 3.0; 58 | let Objective_four.objabstol := 4.0; 59 | 60 | # assign options to solver 61 | option solver gurobi; 62 | option gurobi_options 'poolsolutions 100 multiobj 1'; 63 | 64 | # solve model 65 | solve; 66 | 67 | # display solution 68 | display Objective_one; 69 | display Objective_two; 70 | display Objective_three; 71 | display Objective_four; 72 | display Elem; 73 | 74 | # exit program 75 | exit; -------------------------------------------------------------------------------- /ampl/multiobjloop.mod: -------------------------------------------------------------------------------- 1 | # loop style multi-objective model in AMPL 2 | # ref: http://www.gurobi.com/documentation/7.5/examples/multiobj_cpp_cpp.html 3 | # author: wujianw@stu.xjtu.edu.cn 4 | 5 | set Groundset = 0..19; 6 | set Subsets = 0..3; 7 | 8 | param Budget; 9 | param ObjCoeff {Subsets, Groundset}; 10 | 11 | var Elem {Groundset} binary; 12 | 13 | maximize MultiObject {i in Subsets}: 14 | sum {j in Groundset} ObjCoeff[i, j] * Elem[j]; 15 | 16 | subject to conBudget: 17 | sum {j in Groundset} Elem[j] <= Budget; 18 | 19 | # assign parameter 20 | data; 21 | param Budget := 12; 22 | param ObjCoeff (tr): 23 | 0 1 2 3 := 24 | 0 1 0 0 0 25 | 1 1 0 0 0 26 | 2 1 0 0 0 27 | 3 1 0 1 1 28 | 4 1 0 1 1 29 | 5 1 1 0 1 30 | 6 1 1 1 0 31 | 7 1 1 1 0 32 | 8 1 1 0 0 33 | 9 1 1 0 1 34 | 10 0 0 0 1 35 | 11 0 0 0 1 36 | 12 0 0 0 0 37 | 13 0 0 1 0 38 | 14 0 0 1 0 39 | 15 0 1 0 1 40 | 16 0 1 1 1 41 | 17 0 1 1 1 42 | 18 0 1 0 0 43 | 19 0 1 0 0; 44 | 45 | suffix objpriority IN; 46 | suffix objweight IN; 47 | suffix objreltol IN; 48 | suffix objabstol IN; 49 | 50 | # assign objective priority 51 | let MultiObject[0].objpriority := 3; 52 | let MultiObject[1].objpriority := 2; 53 | let MultiObject[2].objpriority := 2; 54 | let MultiObject[3].objpriority := 1; 55 | 56 | # assign objective weight 57 | let MultiObject[0].objweight := 1.0; 58 | let MultiObject[1].objweight := 0.25; 59 | let MultiObject[2].objweight := 1.25; 60 | let MultiObject[3].objweight := 1.0; 61 | 62 | # assign relative tolerance 63 | let {i in Subsets} MultiObject[i].objreltol := 0.01; 64 | 65 | # assign absolute tolerance 66 | let {i in Subsets} MultiObject[i].objabstol := 1.0 + i; 67 | 68 | # assign options to solver 69 | option solver gurobi; 70 | option gurobi_options 'poolsolutions 100 multiobj 1'; 71 | 72 | # solve model 73 | solve; 74 | 75 | # display solution 76 | display MultiObject; 77 | display Elem; 78 | 79 | # exit program 80 | exit; -------------------------------------------------------------------------------- /gurobi/cutstock/Makefile: -------------------------------------------------------------------------------- 1 | # change this if necessary 2 | GRB_VER = 75 3 | MSVC_VER = 2013 4 | PRB_NAME = cutstock 5 | # end change 6 | 7 | CXX = cl 8 | CXXFLAGS = /nologo /MD /Ox /EHsc /DNDEBUG 9 | 10 | LD = link 11 | LDFLAGS = /nologo 12 | 13 | INCL = -I$(GUROBI_HOME)\include 14 | ADDINCLFLAGS = 15 | 16 | LIBS = $(GUROBI_HOME)\lib\gurobi$(GRB_VER).lib $(GUROBI_HOME)\lib\gurobi_c++md$(MSVC_VER).lib 17 | ADDLIBS = 18 | 19 | PRB_OBJS = $(PRB_NAME).obj 20 | PRB_TARGET = $(PRB_NAME).exe 21 | 22 | all: $(PRB_TARGET) 23 | 24 | $(PRB_TARGET): $(PRB_OBJS) 25 | $(LD) $(LDFLAGS) $(LIBS) $(ADDLIBS) $** 26 | 27 | .cpp.obj: 28 | $(CXX) $(CXXFLAGS) -c $(INCL) $(ADDINCLFLAGS) $< 29 | 30 | clean: 31 | @del /s /q $(PRB_OBJS) $(PRB_TARGET) > nul -------------------------------------------------------------------------------- /gurobi/cutstock/README.md: -------------------------------------------------------------------------------- 1 | ## Brief Introduction 2 | 3 | **Tools** 4 | - [`Gurobi`](http://www.gurobi.com): State-of-the-art mathematical programming solver 5 | 6 | **Version**: 7.5 7 | 8 | **Files** 9 | - cutstock.cpp: Mathematical model for [`Cutting stock problem`](https://en.wikipedia.org/wiki/Cutting_stock_problem) using [`Column generation`](https://en.wikipedia.org/wiki/Column_generation) with [`C++ API`](http://www.gurobi.com/documentation/7.5/refman/cpp_api_overview.html#sec:C++) 10 | - cutstock.py: Mathematical model for [`Cutting stock problem`](https://en.wikipedia.org/wiki/Cutting_stock_problem) using [`Column generation`](https://en.wikipedia.org/wiki/Column_generation) with [`Python API`](http://www.gurobi.com/documentation/7.5/refman/py_python_api_overview.html#sec:Python) 11 | - Makefile: NMake makefile 12 | 13 | **Contact** 14 | - `wujianjack2@163.com` (personal) 15 | - `wujianw@stu.xjtu.edu.cn` (educational) 16 | 17 | **Wu Jian** 18 | 19 | `July 14th, 2017` -------------------------------------------------------------------------------- /gurobi/cutstock/cutstock.cpp: -------------------------------------------------------------------------------- 1 | #include "gurobi_c++.h" 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define MAX_CGTIME 1000 8 | 9 | void reportRMP(GRBModel &model); 10 | void reportSUB(GRBModel &model); 11 | void reportMIP(GRBModel &model); 12 | 13 | int main(int argc, char *argv[]) { 14 | try { 15 | // Input data 16 | size_t rollwidth = 115; 17 | size_t size[5] = {25, 40, 50, 55, 70}; 18 | size_t amount[5] = {50, 36, 24, 8, 30}; 19 | size_t nwidth = 5; 20 | // End data 21 | 22 | GRBEnv env = GRBEnv(); 23 | GRBModel rmp = GRBModel(env); 24 | GRBModel sub = GRBModel(env); 25 | 26 | GRBConstr *rmp_con = NULL; 27 | GRBVar *rmp_var = NULL; 28 | GRBVar *sub_var = new GRBVar[nwidth]; 29 | 30 | GRBLinExpr lexpr = 0; 31 | 32 | double *rmp_pi = new double [nwidth]; 33 | double *rmp_coeff = new double [nwidth]; 34 | 35 | rmp.set(GRB_IntParam_OutputFlag, 0); 36 | sub.set(GRB_IntParam_OutputFlag, 0); 37 | 38 | // Construct RMP 39 | rmp_con = rmp.addConstrs(nwidth); 40 | 41 | for (size_t i = 0; i < nwidth; ++i) { 42 | rmp_con[i].set(GRB_CharAttr_Sense, GRB_GREATER_EQUAL); 43 | rmp_con[i].set(GRB_DoubleAttr_RHS, amount[i]); 44 | } 45 | 46 | for (size_t i = 0; i < nwidth; ++i) 47 | rmp_coeff[i] = 0.0; 48 | 49 | for (size_t i = 0; i < nwidth; ++i) { 50 | rmp_coeff[i] = (size_t) (rollwidth / size[i]); 51 | rmp.addVar(0, GRB_INFINITY, 1.0, GRB_CONTINUOUS, nwidth, rmp_con, rmp_coeff); 52 | rmp_coeff[i] = 0.0; 53 | } 54 | 55 | rmp.set(GRB_IntAttr_ModelSense, GRB_MINIMIZE); 56 | // End RMP 57 | 58 | // Construct SUB 59 | for (size_t i = 0; i < nwidth; ++i) 60 | sub_var[i] = sub.addVar(0.0, GRB_INFINITY, 0.0, GRB_INTEGER); 61 | 62 | for (size_t i = 0; i < nwidth; ++i) 63 | lexpr += size[i] * sub_var[i]; 64 | 65 | sub.addConstr(lexpr, GRB_LESS_EQUAL, rollwidth); 66 | // End SUB 67 | 68 | cout << " *** Column Generation Loop *** " << endl; 69 | for (size_t niter = 0; niter < MAX_CGTIME; ++niter) { 70 | cout << "Iteration: " << niter << endl; 71 | 72 | rmp.optimize(); 73 | reportRMP(rmp); 74 | 75 | for (size_t i = 0; i < nwidth; ++i) 76 | rmp_pi[i] = rmp_con[i].get(GRB_DoubleAttr_Pi); 77 | 78 | lexpr = 1; 79 | for (size_t i = 0; i < nwidth; ++i) 80 | lexpr += -rmp_pi[i] * sub_var[i]; 81 | 82 | sub.setObjective(lexpr, GRB_MINIMIZE); 83 | sub.optimize(); 84 | reportSUB(sub); 85 | 86 | if (sub.get(GRB_DoubleAttr_ObjVal) > -1e-6) 87 | break; 88 | 89 | for (size_t i = 0; i < nwidth; ++i) 90 | rmp_coeff[i] = sub_var[i].get(GRB_DoubleAttr_X); 91 | 92 | rmp.addVar(0, GRB_INFINITY, 1.0, GRB_CONTINUOUS, nwidth, rmp_con, rmp_coeff); 93 | } 94 | cout << " *** End Loop *** " << endl; 95 | 96 | rmp_var = rmp.getVars(); 97 | 98 | for (size_t i = 0; i < rmp.get(GRB_IntAttr_NumVars); ++i) 99 | rmp_var[i].set(GRB_CharAttr_VType, GRB_INTEGER); 100 | 101 | rmp.optimize(); 102 | reportMIP(rmp); 103 | 104 | delete [] rmp_con; 105 | delete [] sub_var; 106 | delete [] rmp_pi; 107 | delete [] rmp_coeff; 108 | } 109 | catch (GRBException e) { 110 | cout << "Error code = " << e.getErrorCode() << endl; 111 | cout << e.getMessage() << endl; 112 | } 113 | catch(...) { 114 | cout << "Exception during optimization" << endl; 115 | } 116 | 117 | return 0; 118 | } 119 | 120 | void reportRMP(GRBModel &model) { 121 | if (model.get(GRB_IntAttr_Status) == GRB_OPTIMAL) { 122 | cout << "Using " << model.get(GRB_DoubleAttr_ObjVal) << " rolls" << endl; 123 | cout << endl; 124 | 125 | GRBVar *var = model.getVars(); 126 | for (size_t i = 0; i < model.get(GRB_IntAttr_NumVars); ++i) 127 | cout << var[i].get(GRB_StringAttr_VarName) << " = " << var[i].get(GRB_DoubleAttr_X) << endl; 128 | cout << endl; 129 | 130 | GRBConstr *con = model.getConstrs(); 131 | for (size_t i = 0; i < model.get(GRB_IntAttr_NumConstrs); ++i) 132 | cout << con[i].get(GRB_StringAttr_ConstrName) << " = " << con[i].get(GRB_DoubleAttr_Pi) << endl; 133 | cout << endl; 134 | } 135 | } 136 | 137 | void reportSUB(GRBModel &model) { 138 | if (model.get(GRB_IntAttr_Status) == GRB_OPTIMAL) { 139 | cout << "Pi: " << model.get(GRB_DoubleAttr_ObjVal) << endl; 140 | cout << endl; 141 | 142 | if (model.get(GRB_DoubleAttr_ObjVal) <= -1e-6) { 143 | GRBVar *var = model.getVars(); 144 | 145 | for (size_t i = 0; i < model.get(GRB_IntAttr_NumVars); ++i) 146 | cout << var[i].get(GRB_StringAttr_VarName) << " = " << var[i].get(GRB_DoubleAttr_X) << endl; 147 | cout << endl; 148 | } 149 | } 150 | } 151 | 152 | void reportMIP(GRBModel &model) { 153 | if (model.get(GRB_IntAttr_Status) == GRB_OPTIMAL) { 154 | cout << endl; 155 | cout << "Best MIP Solution: " << model.get(GRB_DoubleAttr_ObjVal) << " rolls" << endl; 156 | cout << endl; 157 | 158 | GRBVar *var = model.getVars(); 159 | for (size_t i = 0; i < model.get(GRB_IntAttr_NumVars); ++i) 160 | cout << var[i].get(GRB_StringAttr_VarName) << " = " << var[i].get(GRB_DoubleAttr_X) << endl; 161 | cout << endl; 162 | } 163 | } -------------------------------------------------------------------------------- /gurobi/cutstock/cutstock.py: -------------------------------------------------------------------------------- 1 | from __future__ import division, print_function 2 | 3 | from gurobipy import * 4 | 5 | 6 | rollwidth = 115 7 | size = [25, 40, 50, 55, 70] 8 | amount = [50, 36, 24, 8, 30] 9 | nwidth = 5 10 | 11 | MAX_CGTIME = 1000 12 | 13 | def reportRMP(model): 14 | if model.status == GRB.OPTIMAL: 15 | print("Using ", model.objVal, " rolls\n") 16 | 17 | var = model.getVars() 18 | for i in range(model.numVars): 19 | print(var[i].varName, " = ", var[i].x) 20 | print("\n") 21 | 22 | con = model.getConstrs() 23 | for i in range(model.numConstrs): 24 | print(con[i].constrName, " = ", con[i].pi) 25 | print("\n") 26 | 27 | 28 | def reportSUB(model): 29 | if model.status == GRB.OPTIMAL: 30 | print("Pi: ", model.objVal, "\n") 31 | 32 | if model.objVal <= 1e-6: 33 | var = model.getVars() 34 | 35 | for i in range(model.numVars): 36 | print(var[i].varName, " = ", var[i].x) 37 | print("\n") 38 | 39 | def reportMIP(model): 40 | if model.status == GRB.OPTIMAL: 41 | print("Best MIP Solution: ", model.objVal, " rolls\n") 42 | 43 | var = model.getVars() 44 | for i in range(model.numVars): 45 | print(var[i].varName, " = ", var[i].x) 46 | 47 | try: 48 | rmp = Model("rmp") 49 | sub = Model("sub") 50 | 51 | rmp.setParam("OutputFlag", 0) 52 | sub.setParam("OutputFlag", 0) 53 | 54 | # construct RMP 55 | rmp_var = [] 56 | for i in range(nwidth): 57 | rmp_var.append(rmp.addVar(0.0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, "rmp_" + str(i))) 58 | 59 | rmp_con = [] 60 | row_coeff = [0.0] * nwidth 61 | for i in range(nwidth): 62 | row_coeff[i] = int(rollwidth / size[i]) 63 | rmp_con.append(rmp.addConstr(quicksum(rmp_var[j] * row_coeff[j] for j in range(nwidth)) >= amount[i], "rmpcon_" + str(i))) 64 | row_coeff[i] = 0.0 65 | 66 | rmp.setAttr("ModelSense", GRB.MINIMIZE) 67 | # end RMP 68 | 69 | # construct SUB 70 | sub_var = [] 71 | for i in range(nwidth): 72 | sub_var.append(sub.addVar(0.0, GRB.INFINITY, 0.0, GRB.INTEGER, "sub_" + str(i))) 73 | 74 | sub.addConstr(quicksum(sub_var[i] * size[i] for i in range(nwidth)) <= rollwidth, "subcon") 75 | # end SUB 76 | 77 | print(" *** Column Generation Loop *** \n") 78 | for i in range(MAX_CGTIME): 79 | print("Iteration: ", i, "\n") 80 | 81 | rmp.optimize() 82 | reportRMP(rmp) 83 | 84 | rmp_pi = rmp.getAttr("Pi", rmp.getConstrs()) 85 | 86 | sub.setObjective(1 - quicksum(sub_var[i] * rmp_pi[i] for i in range(nwidth)), GRB.MINIMIZE) 87 | sub.optimize() 88 | reportSUB(sub) 89 | 90 | if sub.objVal > -1e-6: 91 | break 92 | 93 | rmp_coeff = sub.getAttr("X", sub.getVars()) 94 | rmp_col = Column(rmp_coeff, rmp_con) 95 | rmp.addVar(0.0, GRB.INFINITY, 1.0, GRB.CONTINUOUS, "cg_" + str(i), rmp_col) 96 | 97 | print(" *** End Loop *** \n") 98 | 99 | mip_var = rmp.getVars() 100 | for i in range(rmp.numVars): 101 | mip_var[i].setAttr("VType", GRB.INTEGER) 102 | 103 | rmp.optimize() 104 | reportMIP(rmp) 105 | 106 | except GurobiError as e: 107 | print('Error code ' + str(e.errno) + ": " + str(e)) 108 | 109 | except AttributeError: 110 | print('Encountered an attribute error') -------------------------------------------------------------------------------- /gurobi/locationtransport/Makefile: -------------------------------------------------------------------------------- 1 | # change this if necessary 2 | GRB_VER = 75 3 | MSVC_VER = 2013 4 | PRB_NAME = locationtransport 5 | # end change 6 | 7 | CXX = cl 8 | CXXFLAGS = /nologo /MD /Ox /EHsc /DNDEBUG 9 | 10 | LD = link 11 | LDFLAGS = /nologo 12 | 13 | INCL = -I$(GUROBI_HOME)\include 14 | ADDINCLFLAGS = 15 | 16 | LIBS = $(GUROBI_HOME)\lib\gurobi$(GRB_VER).lib $(GUROBI_HOME)\lib\gurobi_c++md$(MSVC_VER).lib 17 | ADDLIBS = 18 | 19 | PRB_OBJS = $(PRB_NAME).obj 20 | PRB_TARGET = $(PRB_NAME).exe 21 | 22 | all: $(PRB_TARGET) 23 | 24 | $(PRB_TARGET): $(PRB_OBJS) 25 | $(LD) $(LDFLAGS) $(LIBS) $(ADDLIBS) $** 26 | 27 | .cpp.obj: 28 | $(CXX) $(CXXFLAGS) -c $(INCL) $(ADDINCLFLAGS) $< 29 | 30 | clean: 31 | @del /s /q $(PRB_OBJS) $(PRB_TARGET) > nul -------------------------------------------------------------------------------- /gurobi/locationtransport/README.md: -------------------------------------------------------------------------------- 1 | ## Brief Introduction 2 | 3 | **Tools** 4 | - [`Gurobi`](http://www.gurobi.com): State-of-the-art mathematical programming solver 5 | 6 | **Version**: 7.5 7 | 8 | **Files** 9 | - locationtransport.cpp: Mathematical model for Location transportation problem using [`Lagrangian relaxation`](https://en.wikipedia.org/wiki/Lagrangian_relaxation) with [`C++ API`](http://www.gurobi.com/documentation/7.5/refman/cpp_api_overview.html#sec:C++) 10 | - locationtransport2.cpp: Mathematical model for Location transportation problem using [`Lagrangian relaxation`](https://en.wikipedia.org/wiki/Lagrangian_relaxation) with [`C++ API`](http://www.gurobi.com/documentation/7.5/refman/cpp_api_overview.html#sec:C++) 11 | - locationtransport.py: Mathematical model for Location transportation problem using [`Lagrangian relaxation`](https://en.wikipedia.org/wiki/Lagrangian_relaxation) with [`Python API`](http://www.gurobi.com/documentation/7.5/refman/py_python_api_overview.html#sec:Python) 12 | - Makefile: NMake makefile 13 | - loctrans.dat: Test data 14 | 15 | **Note** 16 | - `locationtransport.cpp` and `locationtransport2.cpp` differ in implementation 17 | 18 | **Contact** 19 | - `wujianjack2@163.com` (personal) 20 | - `wujianw@stu.xjtu.edu.cn` (educational) 21 | 22 | **Wu Jian** 23 | 24 | `July 14th, 2017` -------------------------------------------------------------------------------- /gurobi/locationtransport/locationtransport.cpp: -------------------------------------------------------------------------------- 1 | #include "gurobi_c++.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef WIN32 10 | #define NOMINMAX 1 11 | #endif 12 | 13 | using namespace std; 14 | 15 | double relaxUB(GRBModel &model); 16 | double calculateNorm(double *slack, size_t ncites); 17 | void reportLog(double *LBlog, double *UBlog, double *scalelog, double *steplog, size_t count); 18 | 19 | int main(int argc, char *argv[]) { 20 | try { 21 | // Input data 22 | ifstream data("loctrans.dat"); 23 | 24 | size_t buildlimit = 0; 25 | size_t ncites = 0; 26 | 27 | data >> buildlimit; 28 | data >> ncites; 29 | 30 | double *supply = new double [ncites]; 31 | double *demand = new double [ncites]; 32 | 33 | double **shipcost = new double *[ncites]; 34 | for (size_t i = 0; i < ncites; ++i) 35 | shipcost[i] = new double [ncites]; 36 | 37 | for (size_t i = 0; i < ncites; ++i) 38 | data >> supply[i]; 39 | 40 | for (size_t i = 0; i < ncites; ++i) 41 | data >> demand[i]; 42 | 43 | for (size_t i = 0; i < ncites; ++i) 44 | for (size_t j = 0; j < ncites; ++j) 45 | data >> shipcost[i][j]; 46 | data.close(); 47 | // End data 48 | 49 | // Define parameters 50 | size_t iterlimit = 200; 51 | size_t samelimit = 3; 52 | size_t same = 0; 53 | double norm = 0.0; 54 | double step = 0.0; 55 | double scale = 1.0; 56 | double LB = 0.0; 57 | double UB = 0.0; 58 | double *lambda = new double [ncites]; 59 | double *slack = new double [ncites]; 60 | double *steplog = new double [iterlimit]; 61 | double *scalelog = new double [iterlimit]; 62 | double *LBlog = new double [iterlimit]; 63 | double *UBlog = new double [iterlimit]; 64 | // End parameters 65 | 66 | // Initialize parameters 67 | for (size_t i = 0; i < iterlimit; ++i) { 68 | LBlog[i] = 0.0; 69 | UBlog[i] = 0.0; 70 | } 71 | 72 | for (size_t i = 0; i < ncites; ++i) { 73 | lambda[i] = 0.0; 74 | slack[i] = 0.0; 75 | } 76 | // End initialization 77 | 78 | GRBEnv env = GRBEnv(); 79 | GRBModel trans = GRBModel(env); 80 | 81 | GRBVar **ship = new GRBVar *[ncites]; 82 | for (size_t i = 0; i < ncites; ++i) 83 | ship[i] = new GRBVar [ncites]; 84 | 85 | GRBVar *build = new GRBVar[ncites]; 86 | 87 | for (size_t i = 0; i < ncites; ++i) { 88 | for (size_t j = 0; j < ncites; ++j) 89 | ship[i][j] = trans.addVar(0.0, demand[j], 0.0, GRB_INTEGER, "ship_" + to_string(i) + "_" + to_string(j)); 90 | } 91 | 92 | for (size_t i = 0; i < ncites; ++i) 93 | build[i] = trans.addVar(0.0, 1.0, 0.0, GRB_BINARY, "build_" + to_string(i)); 94 | 95 | GRBLinExpr con_supply = 0.0; 96 | for (size_t i = 0; i < ncites; ++i) { 97 | for (size_t j = 0; j < ncites; ++j) 98 | con_supply += ship[i][j]; 99 | 100 | trans.addConstr(con_supply <= supply[i] * build[i], "supply_" + to_string(i)); 101 | con_supply = 0.0; 102 | } 103 | 104 | GRBLinExpr con_limit = 0.0; 105 | for (size_t i = 0; i < ncites; ++i) 106 | con_limit += build[i]; 107 | 108 | trans.addConstr(con_limit <= buildlimit, string("limit")); 109 | 110 | // update is necessary so far (Gurobi v7.5) 111 | trans.update(); 112 | 113 | GRBModel transLB = GRBModel(trans); 114 | GRBModel transUB = GRBModel(trans); 115 | 116 | transLB.set(GRB_IntParam_OutputFlag, 0); 117 | transUB.set(GRB_IntParam_OutputFlag, 0); 118 | 119 | GRBLinExpr con_demand = 0.0; 120 | for (size_t j = 0; j < ncites; ++j) { 121 | for (size_t i = 0; i < ncites; ++i) 122 | con_demand += ship[i][j]; 123 | 124 | transUB.addConstr(con_demand >= demand[j], "demand_" + to_string(j)); 125 | con_demand = 0.0; 126 | } 127 | 128 | GRBLinExpr obj_shipcost = 0.0; 129 | for (size_t i = 0; i < ncites; ++i) { 130 | for (size_t j = 0; j < ncites; ++j) 131 | obj_shipcost += ship[i][j] * shipcost[i][j]; 132 | } 133 | 134 | transUB.setObjective(obj_shipcost, GRB_MINIMIZE); 135 | 136 | // initial 'LB' 137 | LB = relaxUB(transUB); 138 | 139 | // initial 'UB' 140 | double *rowmax = new double [ncites]; 141 | for (size_t i = 0; i < ncites; ++i) 142 | rowmax[i] = *max_element(shipcost[i], shipcost[i] + ncites); 143 | 144 | for (size_t i = 0; i < ncites; ++i) 145 | UB += rowmax[i]; 146 | 147 | delete [] rowmax; 148 | 149 | GRBLinExpr obj_lagrange = 0.0; 150 | GRBLinExpr sum_ship = 0.0; 151 | double sumsbval = 0.0; 152 | double sumdemand = 0.0; 153 | // main lagrange relaxation loop 154 | cout << " *** Larange Relaxation *** " << endl; 155 | for (size_t i = 0; i < iterlimit; ++i) { 156 | // solve lower bound 157 | obj_lagrange = 0.0; 158 | sum_ship = 0.0; 159 | for (size_t j = 0; j < ncites; ++j) { 160 | for (size_t i = 0; i < ncites; ++i) 161 | sum_ship += ship[i][j]; 162 | 163 | obj_lagrange += lambda[j] * (demand[j] - sum_ship); 164 | sum_ship = 0.0; 165 | } 166 | 167 | transLB.setObjective(obj_shipcost + obj_lagrange, GRB_MINIMIZE); 168 | 169 | // LB model 170 | transLB.optimize(); 171 | 172 | // calculate 'slack' 173 | for (size_t j = 0; j < ncites; ++j) { 174 | double sum_shipval = 0.0; 175 | GRBVar shipvar; 176 | 177 | for (size_t ii = 0; ii < ncites; ++ii) { 178 | shipvar = transLB.getVarByName("ship_" + to_string(ii) + "_" + to_string(j)); 179 | sum_shipval += shipvar.get(GRB_DoubleAttr_X); 180 | } 181 | 182 | slack[j] = sum_shipval - demand[j]; 183 | } 184 | 185 | // improve lower bound 186 | if (transLB.get(GRB_DoubleAttr_ObjVal) > LB + 1e-6) { 187 | LB = transLB.get(GRB_DoubleAttr_ObjVal); 188 | same = 0; 189 | } 190 | else 191 | ++same; 192 | 193 | // update 'scale' if no improvment in 'samelimit' iteration 194 | if (same == samelimit) { 195 | scale /= 2.0; 196 | same = 0; 197 | } 198 | 199 | // calculate 'norm' 200 | norm = calculateNorm(slack, ncites); 201 | 202 | // update 'step' 203 | step = scale * (UB - transLB.get(GRB_DoubleAttr_ObjVal)) / norm; 204 | 205 | // update 'lambda' 206 | for (size_t j = 0; j < ncites; ++j) { 207 | if (lambda[j] > (step * slack[j])) 208 | lambda[j] -= step * slack[j]; 209 | else 210 | lambda[j] = 0.0; 211 | } 212 | 213 | // solve upper bound 214 | sumsbval = 0.0; 215 | for (size_t j = 0; j < ncites; ++j) { 216 | GRBVar buildvar; 217 | 218 | buildvar = transLB.getVarByName("build_" + to_string(j)); 219 | sumsbval += supply[j] * buildvar.get(GRB_DoubleAttr_X); 220 | } 221 | 222 | sumdemand = 0.0; 223 | for (size_t j = 0; j < ncites; ++j) 224 | sumdemand += demand[j]; 225 | 226 | if (sumsbval - sumdemand >= -1e-6) { 227 | // retrieve solution from LB model and fix it 228 | for (size_t j = 0; j < ncites; ++j) { 229 | GRBVar buildvarl; 230 | GRBVar buildvaru; 231 | 232 | buildvarl = transLB.getVarByName("build_" + to_string(j)); 233 | buildvaru = transUB.getVarByName("build_" + to_string(j)); 234 | buildvaru.set(GRB_DoubleAttr_LB, buildvarl.get(GRB_DoubleAttr_X)); 235 | buildvaru.set(GRB_DoubleAttr_UB, buildvarl.get(GRB_DoubleAttr_X)); 236 | } 237 | 238 | transUB.optimize(); 239 | 240 | UB = min(UB, transUB.get(GRB_DoubleAttr_ObjVal)); 241 | 242 | // reset to initial bound 243 | for (size_t j = 0; j < ncites; ++j) { 244 | GRBVar buildvaru; 245 | 246 | buildvaru = transUB.getVarByName("build_" + to_string(j)); 247 | buildvaru.set(GRB_DoubleAttr_LB, 0.0); 248 | buildvaru.set(GRB_DoubleAttr_UB, 1.0); 249 | } 250 | } 251 | 252 | // update 'LBlog', 'UBlog', 'steplog', 'scalelog' 253 | LBlog[i] = LB; 254 | UBlog[i] = UB; 255 | steplog[i] = step; 256 | scalelog[i] = scale; 257 | } 258 | 259 | // show the total process 260 | reportLog(LBlog, UBlog, scalelog, steplog, iterlimit); 261 | 262 | delete [] supply; 263 | delete [] demand; 264 | 265 | for (size_t i = 0; i < ncites; ++i) 266 | delete [] shipcost[i]; 267 | delete [] shipcost; 268 | 269 | for (size_t i = 0; i < ncites; ++i) 270 | delete [] ship[i]; 271 | delete [] ship; 272 | 273 | delete [] build; 274 | delete [] lambda; 275 | delete [] slack; 276 | delete [] steplog; 277 | delete [] scalelog; 278 | delete [] LBlog; 279 | delete [] UBlog; 280 | } 281 | catch (GRBException e) { 282 | cout << "Error code = " << e.getErrorCode() << endl; 283 | cout << e.getMessage() << endl; 284 | } 285 | catch(...) { 286 | cout << "Exception during optimization" << endl; 287 | } 288 | 289 | return 0; 290 | } 291 | 292 | double relaxUB(GRBModel &model) { 293 | double LB = 0.0; 294 | size_t numvars = model.get(GRB_IntAttr_NumVars); 295 | char *vtype = new char [numvars]; 296 | GRBVar *vars = model.getVars(); 297 | 298 | for (size_t i = 0; i < numvars; ++i) { 299 | vtype[i] = vars[i].get(GRB_CharAttr_VType); 300 | vars[i].set(GRB_CharAttr_VType, GRB_CONTINUOUS); 301 | } 302 | 303 | model.optimize(); 304 | 305 | LB = model.get(GRB_DoubleAttr_ObjVal); 306 | 307 | for (size_t i = 0; i < numvars; ++i) 308 | vars[i].set(GRB_CharAttr_VType, vtype[i]); 309 | 310 | delete [] vtype; 311 | 312 | return LB; 313 | } 314 | 315 | double calculateNorm(double *slack, size_t ncites) { 316 | double norm = 0.0; 317 | 318 | for (size_t i = 0; i < ncites; ++i) 319 | norm += pow(slack[i], 2.0); 320 | 321 | return norm; 322 | } 323 | 324 | void reportLog(double *LBlog, double *UBlog, double *scalelog, double *steplog, size_t count) { 325 | printf("\n *** Summary Report *** \n"); 326 | printf(" Iter LB UB scale step\n"); 327 | 328 | for (size_t i = 0; i < count; ++i) 329 | printf(" %3d %12.6f %12.6f %8.6f %8.6f\n", i, LBlog[i], UBlog[i], scalelog[i], steplog[i]); 330 | } -------------------------------------------------------------------------------- /gurobi/locationtransport/locationtransport.py: -------------------------------------------------------------------------------- 1 | from __future__ import division, print_function 2 | 3 | import gurobipy as GRBPY 4 | 5 | 6 | class LocationTransport: 7 | def __init__(self, name=None): 8 | # initialize data 9 | self.buildlimit = 0 10 | self.ncites = 0 11 | self.supply = [] 12 | self.demand = [] 13 | self.shipcost = [] 14 | 15 | # initialize parameters 16 | self.iterlimit = 100 17 | self.samelimit = 3 18 | self.steplog = [] 19 | self.scalelog = [] 20 | self.xLBlog = [] 21 | self.xUBlog = [] 22 | 23 | if name is not None: 24 | self.name = name 25 | else: 26 | self.name = "demo" 27 | 28 | self.vship = [] 29 | self.vbuild = [] 30 | self.crelax = [] 31 | 32 | def read(self, filename): 33 | with open(filename, "r") as data: 34 | self.buildlimit = int(data.readline()) 35 | self.ncites = int(data.readline()) 36 | 37 | column = data.readline().split() 38 | for i in range(self.ncites): 39 | self.supply.append(float(column[i])) 40 | 41 | column = data.readline().split() 42 | for i in range(self.ncites): 43 | self.demand.append(float(column[i])) 44 | 45 | for i in range(self.ncites): 46 | column = data.readline().split() 47 | lshipcost = [] 48 | for j in range(self.ncites): 49 | lshipcost.append(float(column[j])) 50 | self.shipcost.append(lshipcost) 51 | 52 | def build(self): 53 | try: 54 | self.mtrans = GRBPY.Model(self.name) 55 | 56 | # discard output information 57 | self.mtrans.setParam("OutputFlag", 0) 58 | 59 | # construct model 60 | for i in range(self.ncites): 61 | shipvar = [] 62 | for j in range(self.ncites): 63 | shipvar.append(self.mtrans.addVar(0.0, self.demand[j], 0.0, GRBPY.GRB.INTEGER)) 64 | self.vship.append(shipvar) 65 | 66 | for i in range(self.ncites): 67 | self.vbuild.append(self.mtrans.addVar(0.0, 1.0, 0.0, GRBPY.GRB.BINARY)) 68 | 69 | for i in range(self.ncites): 70 | self.mtrans.addConstr(GRBPY.quicksum(self.vship[i][j] for j in range(self.ncites)) \ 71 | <= self.supply[i] * self.vbuild[i]) 72 | 73 | self.mtrans.addConstr(GRBPY.quicksum(self.vbuild[i] for i in range(self.ncites)) \ 74 | <= self.buildlimit) 75 | 76 | for j in range(self.ncites): 77 | self.crelax.append(self.mtrans.addConstr(GRBPY.quicksum(self.vship[i][j] \ 78 | for i in range(self.ncites)) \ 79 | >= self.demand[j])) 80 | 81 | self.mtrans.setObjective(GRBPY.quicksum(self.vship[i][j] * self.shipcost[i][j] \ 82 | for i in range(self.ncites) \ 83 | for j in range(self.ncites)), GRBPY.GRB.MINIMIZE) 84 | 85 | # update is necessary 86 | self.mtrans.update() 87 | except GRBPY.GurobiError as e: 88 | print('Error code' + str(e.errno) + ': ' + str(e)) 89 | except AttributeError as e: 90 | print('Encountered an attribute error: ' + str(e)) 91 | 92 | def solve(self): 93 | # 'Lagrangian Relaxation' parameters 94 | same = 0 95 | norm = 0.0 96 | step = 0.0 97 | scale = 1.0 98 | xLB = 0.0 99 | xUB = 0.0 100 | xlambda = [0.0] * self.ncites 101 | slack = [0.0] * self.ncites 102 | 103 | # build model 104 | self.build() 105 | 106 | # initial 'xLB' 107 | xLB = self.relaxUB(self.mtrans) 108 | 109 | # initial 'xUB' 110 | for i in range(self.ncites): 111 | xUB += max(self.shipcost[i]) 112 | 113 | # temporary linear expression 114 | obj_shipcost = GRBPY.quicksum(self.vship[i][j] * self.shipcost[i][j] \ 115 | for i in range(self.ncites) \ 116 | for j in range(self.ncites)) 117 | 118 | # sentinel flag 119 | lbmodel = 0 120 | 121 | # main 'Lagrangian Relaxation' loop 122 | for iter in range(self.iterlimit): 123 | # solve lower bound 124 | if lbmodel == 0: 125 | lbmodel = 1 126 | 127 | lenrelax = len(self.crelax) 128 | for i in range(lenrelax): 129 | self.mtrans.remove(self.crelax[i]) 130 | self.crelax = [] 131 | 132 | obj_lagrangian = GRBPY.quicksum(xlambda[j] * (self.demand[j] - \ 133 | GRBPY.quicksum(self.vship[i][j] for i in range(self.ncites))) \ 134 | for j in range(self.ncites)) 135 | self.mtrans.setObjective(obj_shipcost + obj_lagrangian, GRBPY.GRB.MINIMIZE) 136 | 137 | # 'LB' model 138 | self.mtrans.optimize() 139 | 140 | # calculate 'slack' 141 | for j in range(self.ncites): 142 | slack[j] = sum(self.vship[i][j].x for i in range(self.ncites)) - self.demand[j] 143 | 144 | # improve lower bound 145 | if self.mtrans.objval > xLB + 1e-6: 146 | xLB = self.mtrans.objval 147 | same = 0 148 | else: 149 | same += 1 150 | 151 | # update 'scale' if no improvement in 'samelimit' iteration 152 | if same == self.samelimit: 153 | scale /= 2.0 154 | same = 0 155 | 156 | # calculate 'norm' 157 | norm = sum(slack[i]**2.0 for i in range(self.ncites)) 158 | 159 | # update 'step' 160 | step = scale * (xUB - self.mtrans.objval) / norm 161 | 162 | # update 'lambda' 163 | for i in range(self.ncites): 164 | if xlambda[i] > step * slack[i]: 165 | xlambda[i] -= step * slack[i] 166 | else: 167 | xlambda[i] = 0.0 168 | 169 | # solve upper bound 170 | sumsbval = sum(self.supply[i] * self.vbuild[i].x for i in range(self.ncites)) 171 | sumdemand = sum(self.demand) 172 | 173 | if sumsbval - sumdemand >= 1e-6: 174 | lbmodel = 0 175 | 176 | for j in range(self.ncites): 177 | self.crelax.append(self.mtrans.addConstr(GRBPY.quicksum(self.vship[i][j] \ 178 | for i in range(self.ncites)) >= self.demand[j])) 179 | 180 | # retrieve solution from LB model and fix it 181 | for i in range(self.ncites): 182 | self.vbuild[i].lb = self.vbuild[i].x 183 | self.vbuild[i].ub = self.vbuild[i].x 184 | 185 | self.mtrans.setObjective(obj_shipcost, GRBPY.GRB.MINIMIZE) 186 | 187 | self.mtrans.optimize() 188 | 189 | xUB = min(xUB, self.mtrans.objval) 190 | 191 | # reset to initial bound 192 | for i in range(self.ncites): 193 | self.vbuild[i].lb = 0.0 194 | self.vbuild[i].ub = 1.0 195 | 196 | # update 'xLBlog', 'xUBlog', 'steplog', 'scalelog' 197 | self.xLBlog.append(xLB) 198 | self.xUBlog.append(xUB) 199 | self.steplog.append(step) 200 | self.scalelog.append(scale) 201 | 202 | def relaxUB(self, mtrans): 203 | mrelax = mtrans.relax() 204 | 205 | mrelax.optimize() 206 | 207 | return mrelax.objval 208 | 209 | def report(self): 210 | print("\n *** Summary Report *** \n") 211 | print(" Iter LB UB scale step") 212 | 213 | for i in range(len(self.xLBlog)): 214 | print(" %3d %12.6f %12.6f %8.6f %8.6f" \ 215 | % (i, self.xLBlog[i], self.xUBlog[i], self.scalelog[i], self.steplog[i])) 216 | 217 | if __name__ == "__main__": 218 | loctrans = LocationTransport() 219 | loctrans.read("loctrans.dat") 220 | loctrans.solve() 221 | loctrans.report() -------------------------------------------------------------------------------- /gurobi/locationtransport/locationtransport2.cpp: -------------------------------------------------------------------------------- 1 | #include "gurobi_c++.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef WIN32 10 | #define NOMINMAX 1 11 | #endif 12 | 13 | using namespace std; 14 | 15 | double relaxUB(GRBModel &model); 16 | double calculateNorm(double *slack, size_t ncites); 17 | void reportLog(double *LBlog, double *UBlog, double *scalelog, double *steplog, size_t count); 18 | 19 | int main(int argc, char *argv[]) { 20 | try { 21 | // Input data 22 | ifstream data("loctrans.dat"); 23 | 24 | size_t buildlimit = 0; 25 | size_t ncites = 0; 26 | 27 | data >> buildlimit; 28 | data >> ncites; 29 | 30 | double *supply = new double [ncites]; 31 | double *demand = new double [ncites]; 32 | 33 | double **shipcost = new double *[ncites]; 34 | for (size_t i = 0; i < ncites; ++i) 35 | shipcost[i] = new double [ncites]; 36 | 37 | for (size_t i = 0; i < ncites; ++i) 38 | data >> supply[i]; 39 | 40 | for (size_t i = 0; i < ncites; ++i) 41 | data >> demand[i]; 42 | 43 | for (size_t i = 0; i < ncites; ++i) 44 | for (size_t j = 0; j < ncites; ++j) 45 | data >> shipcost[i][j]; 46 | 47 | data.close(); 48 | // End data 49 | 50 | // Define parameters 51 | size_t iterlimit = 200; 52 | size_t samelimit = 3; 53 | size_t same = 0; 54 | double norm = 0.0; 55 | double step = 0.0; 56 | double scale = 1.0; 57 | double LB = 0.0; 58 | double UB = 0.0; 59 | double *lambda = new double [ncites]; 60 | double *slack = new double [ncites]; 61 | double *steplog = new double [iterlimit]; 62 | double *scalelog = new double [iterlimit]; 63 | double *LBlog = new double [iterlimit]; 64 | double *UBlog = new double [iterlimit]; 65 | // End parameters 66 | 67 | // Initialize parameters 68 | for (size_t i = 0; i < iterlimit; ++i) { 69 | LBlog[i] = 0.0; 70 | UBlog[i] = 0.0; 71 | } 72 | 73 | for (size_t i = 0; i < ncites; ++i) { 74 | lambda[i] = 0.0; 75 | slack[i] = 0.0; 76 | } 77 | // End initialization 78 | 79 | GRBEnv env = GRBEnv(); 80 | GRBModel trans = GRBModel(env); 81 | 82 | GRBVar **ship = new GRBVar *[ncites]; 83 | for (size_t i = 0; i < ncites; ++i) 84 | ship[i] = new GRBVar [ncites]; 85 | 86 | GRBVar *build = new GRBVar[ncites]; 87 | GRBConstr *relax = new GRBConstr [ncites]; 88 | 89 | trans.set(GRB_IntParam_OutputFlag, 0); 90 | 91 | for (size_t i = 0; i < ncites; ++i) { 92 | for (size_t j = 0; j < ncites; ++j) 93 | ship[i][j] = trans.addVar(0.0, demand[j], 0.0, GRB_INTEGER, "ship_" + to_string(i) + "_" + to_string(j)); 94 | } 95 | 96 | for (size_t i = 0; i < ncites; ++i) 97 | build[i] = trans.addVar(0.0, 1.0, 0.0, GRB_BINARY, "build_" + to_string(i)); 98 | 99 | GRBLinExpr con_supply = 0.0; 100 | for (size_t i = 0; i < ncites; ++i) { 101 | for (size_t j = 0; j < ncites; ++j) 102 | con_supply += ship[i][j]; 103 | 104 | trans.addConstr(con_supply <= supply[i] * build[i], "supply_" + to_string(i)); 105 | con_supply = 0.0; 106 | } 107 | 108 | // update is necessary so far (Gurobi v7.5) 109 | trans.update(); 110 | 111 | GRBLinExpr con_limit = 0.0; 112 | for (size_t i = 0; i < ncites; ++i) 113 | con_limit += build[i]; 114 | 115 | trans.addConstr(con_limit <= buildlimit, string("limit")); 116 | 117 | GRBLinExpr con_demand = 0.0; 118 | for (size_t j = 0; j < ncites; ++j) { 119 | for (size_t i = 0; i < ncites; ++i) 120 | con_demand += ship[i][j]; 121 | 122 | relax[j] = trans.addConstr(con_demand >= demand[j], "demand_" + to_string(j)); 123 | con_demand = 0.0; 124 | } 125 | 126 | GRBLinExpr obj_shipcost = 0.0; 127 | for (size_t i = 0; i < ncites; ++i) { 128 | for (size_t j = 0; j < ncites; ++j) 129 | obj_shipcost += ship[i][j] * shipcost[i][j]; 130 | } 131 | 132 | trans.setObjective(obj_shipcost, GRB_MINIMIZE); 133 | 134 | // initial 'LB' 135 | LB = relaxUB(trans); 136 | 137 | // initial 'UB' 138 | double *rowmax = new double [ncites]; 139 | for (size_t i = 0; i < ncites; ++i) 140 | rowmax[i] = *max_element(shipcost[i], shipcost[i] + ncites); 141 | 142 | for (size_t i = 0; i < ncites; ++i) 143 | UB += rowmax[i]; 144 | 145 | delete [] rowmax; 146 | 147 | GRBLinExpr obj_lagrange = 0.0; 148 | GRBLinExpr sum_ship = 0.0; 149 | 150 | size_t lbmodel = 0; 151 | double sumshipval = 0.0; 152 | double sumsbval = 0.0; 153 | double sumdemand = 0.0; 154 | // main lagrange relaxation loop 155 | cout << " *** Larange Relaxation *** " << endl; 156 | for (size_t i = 0; i < iterlimit; ++i) { 157 | // solve lower bound 158 | if (lbmodel == 0) { 159 | lbmodel = 1; 160 | 161 | for (size_t j = 0; j < ncites; ++j) 162 | trans.remove(relax[j]); 163 | } 164 | 165 | obj_lagrange = 0.0; 166 | sum_ship = 0.0; 167 | for (size_t j = 0; j < ncites; ++j) { 168 | for (size_t ii = 0; ii < ncites; ++ii) 169 | sum_ship += ship[ii][j]; 170 | 171 | obj_lagrange += lambda[j] * (demand[j] - sum_ship); 172 | sum_ship = 0.0; 173 | } 174 | 175 | trans.setObjective(obj_shipcost + obj_lagrange, GRB_MINIMIZE); 176 | 177 | // LB model 178 | trans.optimize(); 179 | 180 | // calculate 'slack' 181 | for (size_t j = 0; j < ncites; ++j) { 182 | sumshipval = 0.0; 183 | 184 | for (size_t ii = 0; ii < ncites; ++ii) 185 | sumshipval += ship[ii][j].get(GRB_DoubleAttr_X); 186 | 187 | slack[j] = sumshipval - demand[j]; 188 | } 189 | 190 | // improve lower bound 191 | if (trans.get(GRB_DoubleAttr_ObjVal) > LB + 1e-6) { 192 | LB = trans.get(GRB_DoubleAttr_ObjVal); 193 | same = 0; 194 | } 195 | else 196 | ++same; 197 | 198 | // update 'scale' if no improvment in 'samelimit' iteration 199 | if (same == samelimit) { 200 | scale /= 2.0; 201 | same = 0; 202 | } 203 | 204 | // calculate 'norm' 205 | norm = calculateNorm(slack, ncites); 206 | 207 | // update 'step' 208 | step = scale * (UB - trans.get(GRB_DoubleAttr_ObjVal)) / norm; 209 | 210 | // update 'lambda' 211 | for (size_t j = 0; j < ncites; ++j) { 212 | if (lambda[j] > (step * slack[j])) 213 | lambda[j] -= step * slack[j]; 214 | else 215 | lambda[j] = 0.0; 216 | } 217 | 218 | // solve upper bound 219 | sumsbval = 0.0; 220 | for (size_t j = 0; j < ncites; ++j) 221 | sumsbval += supply[j] * build[j].get(GRB_DoubleAttr_X); 222 | 223 | sumdemand = 0.0; 224 | for (size_t j = 0; j < ncites; ++j) 225 | sumdemand += demand[j]; 226 | 227 | if (sumsbval - sumdemand >= -1e-6) { 228 | lbmodel = 0; 229 | con_demand = 0.0; 230 | for (size_t j = 0; j < ncites; ++j) { 231 | for (size_t ii = 0; ii < ncites; ++ii) 232 | con_demand += ship[ii][j]; 233 | 234 | relax[j] = trans.addConstr(con_demand >= demand[j], "demand_" + to_string(j)); 235 | con_demand = 0.0; 236 | } 237 | 238 | // retrieve solution from LB model and fix it 239 | for (size_t j = 0; j < ncites; ++j) { 240 | build[j].set(GRB_DoubleAttr_LB, build[j].get(GRB_DoubleAttr_X)); 241 | build[j].set(GRB_DoubleAttr_UB, build[j].get(GRB_DoubleAttr_X)); 242 | } 243 | 244 | trans.setObjective(obj_shipcost, GRB_MINIMIZE); 245 | 246 | trans.optimize(); 247 | 248 | UB = min(UB, trans.get(GRB_DoubleAttr_ObjVal)); 249 | 250 | // reset to initial bound 251 | for (size_t j = 0; j < ncites; ++j) { 252 | build[j].set(GRB_DoubleAttr_LB, 0.0); 253 | build[j].set(GRB_DoubleAttr_UB, 1.0); 254 | } 255 | } 256 | 257 | // update 'LBlog', 'UBlog', 'steplog', 'scalelog' 258 | LBlog[i] = LB; 259 | UBlog[i] = UB; 260 | steplog[i] = step; 261 | scalelog[i] = scale; 262 | } 263 | 264 | // show the total process 265 | reportLog(LBlog, UBlog, scalelog, steplog, iterlimit); 266 | 267 | delete [] supply; 268 | delete [] demand; 269 | 270 | for (size_t i = 0; i < ncites; ++i) 271 | delete [] shipcost[i]; 272 | delete [] shipcost; 273 | 274 | for (size_t i = 0; i < ncites; ++i) 275 | delete [] ship[i]; 276 | delete [] ship; 277 | 278 | delete [] build; 279 | delete [] relax; 280 | delete [] lambda; 281 | delete [] slack; 282 | delete [] steplog; 283 | delete [] scalelog; 284 | delete [] LBlog; 285 | delete [] UBlog; 286 | } 287 | catch (GRBException e) { 288 | cout << "Error code = " << e.getErrorCode() << endl; 289 | cout << e.getMessage() << endl; 290 | } 291 | catch(...) { 292 | cout << "Exception during optimization" << endl; 293 | } 294 | 295 | return 0; 296 | } 297 | 298 | double relaxUB(GRBModel &model) { 299 | double LB = 0.0; 300 | size_t numvars = model.get(GRB_IntAttr_NumVars); 301 | char *vtype = new char [numvars]; 302 | GRBVar *vars = model.getVars(); 303 | 304 | for (size_t i = 0; i < numvars; ++i) { 305 | vtype[i] = vars[i].get(GRB_CharAttr_VType); 306 | vars[i].set(GRB_CharAttr_VType, GRB_CONTINUOUS); 307 | } 308 | 309 | model.optimize(); 310 | 311 | LB = model.get(GRB_DoubleAttr_ObjVal); 312 | 313 | for (size_t i = 0; i < numvars; ++i) 314 | vars[i].set(GRB_CharAttr_VType, vtype[i]); 315 | 316 | delete [] vtype; 317 | 318 | return LB; 319 | } 320 | 321 | double calculateNorm(double *slack, size_t ncites) { 322 | double norm = 0.0; 323 | 324 | for (size_t i = 0; i < ncites; ++i) 325 | norm += pow(slack[i], 2.0); 326 | 327 | return norm; 328 | } 329 | 330 | void reportLog(double *LBlog, double *UBlog, double *scalelog, double *steplog, size_t count) { 331 | printf("\n *** Summary Report *** \n"); 332 | printf(" Iter LB UB scale step\n"); 333 | 334 | for (size_t i = 0; i < count; ++i) 335 | printf(" %3d %12.6f %12.6f %8.6f %8.6f\n", i, LBlog[i], UBlog[i], scalelog[i], steplog[i]); 336 | } -------------------------------------------------------------------------------- /gurobi/locationtransport/loctrans.dat: -------------------------------------------------------------------------------- 1 | 8 2 | 30 3 | 19 13 20 18 23 25 22 28 18 16 17 14 22 13 18 20 15 23 25 19 18 19 22 22 21 19 17 21 15 25 4 | 4 1 2 7 9 9 3 9 5 2 4 1 9 3 1 7 5 9 2 4 9 6 5 4 5 6 8 9 5 6 5 | 0 61 35 35 53 16 11 58 28 34 43 18 48 30 68 15 27 53 26 32 13 41 54 36 51 68 29 20 49 48 6 | 61 0 96 88 29 77 50 92 57 75 48 47 76 32 77 74 34 75 87 68 70 38 8 87 71 82 39 78 104 106 7 | 35 96 0 18 88 21 45 72 58 53 65 49 51 66 93 22 61 76 14 40 33 76 88 43 76 91 64 17 43 33 8 | 35 88 18 0 87 27 42 84 62 62 51 42 33 62 100 20 55 85 26 25 39 76 81 55 83 100 63 16 59 51 9 | 53 29 88 87 0 67 45 66 37 54 62 47 85 26 49 68 35 48 77 73 57 14 27 67 44 54 24 73 85 90 10 | 16 77 21 27 67 0 27 57 36 34 55 32 51 46 73 10 43 57 10 37 12 54 69 29 57 73 43 12 38 34 11 | 11 50 45 42 45 27 0 64 29 40 35 8 46 20 68 24 16 55 37 31 23 35 43 44 52 69 22 29 60 59 12 | 58 92 72 84 66 57 64 0 37 24 99 72 106 65 31 67 72 19 60 90 47 54 87 30 23 26 56 69 38 49 13 | 28 57 58 62 37 36 29 37 0 18 62 36 74 28 40 41 34 26 45 59 24 23 51 30 24 41 19 46 48 54 14 | 34 75 53 62 54 34 40 24 18 0 75 48 81 45 41 43 50 24 39 66 23 40 69 15 24 39 37 46 32 39 15 | 43 48 65 51 62 55 35 99 62 75 0 27 29 39 99 46 30 88 63 27 57 59 41 79 85 101 48 49 92 89 16 | 18 47 49 42 47 32 8 72 36 48 27 0 40 21 74 27 13 62 42 27 31 39 39 52 60 77 26 31 67 65 17 | 48 76 51 33 85 51 46 106 74 81 29 40 0 60 114 41 51 100 55 15 59 79 69 80 98 115 66 40 89 82 18 | 30 32 66 62 26 46 20 65 28 45 39 21 60 0 60 44 10 51 56 48 38 19 25 55 48 63 10 49 72 74 19 | 68 77 93 100 49 73 68 31 40 41 99 74 114 60 0 80 69 17 79 99 61 42 75 53 17 6 51 85 67 77 20 | 15 74 22 20 68 10 24 67 41 43 46 27 41 44 80 0 39 65 17 26 20 56 66 39 63 80 44 5 48 43 21 | 27 34 61 55 35 43 16 72 34 50 30 13 51 10 69 39 0 59 53 39 38 29 27 58 56 72 18 44 74 74 22 | 53 75 76 85 48 57 55 19 26 24 88 62 100 51 17 65 59 0 63 85 45 37 70 37 4 15 42 69 51 60 23 | 26 87 14 26 77 10 37 60 45 39 63 42 55 56 79 17 53 63 0 42 21 64 80 30 63 78 53 15 34 27 24 | 32 68 40 25 73 37 31 90 59 66 27 27 15 48 99 26 39 85 42 0 44 65 61 65 83 100 52 27 75 69 25 | 13 70 33 39 57 12 23 47 24 23 57 31 59 38 61 20 38 45 21 44 0 44 63 22 44 61 34 24 36 36 26 | 41 38 76 76 14 54 35 54 23 40 59 39 79 19 42 56 29 37 64 65 44 0 34 53 33 46 13 61 71 76 27 | 54 8 88 81 27 69 43 87 51 69 41 39 69 25 75 66 27 70 80 61 63 34 0 80 67 79 32 71 97 99 28 | 36 87 43 55 67 29 44 30 30 15 79 52 80 55 53 39 58 37 30 65 22 53 80 0 38 51 48 41 18 25 29 | 51 71 76 83 44 57 52 23 24 24 85 60 98 48 17 63 56 4 63 83 44 33 67 38 0 17 38 68 53 62 30 | 68 82 91 100 54 73 69 26 41 39 101 77 115 63 6 80 72 15 78 100 61 46 79 51 17 0 54 84 63 73 31 | 29 39 64 63 24 43 22 56 19 37 48 26 66 10 51 44 18 42 53 52 34 13 32 48 38 54 0 49 66 69 32 | 20 78 17 16 73 12 29 69 46 46 49 31 40 49 85 5 44 69 15 27 24 61 71 41 68 84 49 0 48 42 33 | 49 104 43 59 85 38 60 38 48 32 92 67 89 72 67 48 74 51 34 75 36 71 97 18 53 63 66 48 0 12 34 | 48 106 33 51 90 34 59 49 54 39 89 65 82 74 77 43 74 60 27 69 36 76 99 25 62 73 69 42 12 0 35 | -------------------------------------------------------------------------------- /gurobi/multicommodity/Makefile: -------------------------------------------------------------------------------- 1 | # change this if necessary 2 | GRB_VER = 75 3 | MSVC_VER = 2013 4 | PRB_NAME = multicommodity 5 | # end change 6 | 7 | CXX = cl 8 | CXXFLAGS = /nologo /MD /Ox /EHsc /DNDEBUG 9 | 10 | LD = link 11 | LDFLAGS = /nologo 12 | 13 | INCL = -I$(GUROBI_HOME)\include 14 | ADDINCLFLAGS = 15 | 16 | LIBS = $(GUROBI_HOME)\lib\gurobi$(GRB_VER).lib $(GUROBI_HOME)\lib\gurobi_c++md$(MSVC_VER).lib 17 | ADDLIBS = 18 | 19 | PRB_OBJS = $(PRB_NAME).obj 20 | PRB_TARGET = $(PRB_NAME).exe 21 | 22 | all: $(PRB_TARGET) 23 | 24 | $(PRB_TARGET): $(PRB_OBJS) 25 | $(LD) $(LDFLAGS) $(LIBS) $(ADDLIBS) $** 26 | 27 | .cpp.obj: 28 | $(CXX) $(CXXFLAGS) -c $(INCL) $(ADDINCLFLAGS) $< 29 | 30 | clean: 31 | @del /s /q $(PRB_OBJS) $(PRB_TARGET) > nul -------------------------------------------------------------------------------- /gurobi/multicommodity/README.md: -------------------------------------------------------------------------------- 1 | ## Brief Introduction 2 | 3 | **Tools** 4 | - [`Gurobi`](http://www.gurobi.com): State-of-the-art mathematical programming solver 5 | 6 | **Version**: 7.5 7 | 8 | **Files** 9 | - multicommodity.cpp: Implementation of [`Dantzig-Wolfe decomposition`](https://en.wikipedia.org/wiki/Dantzig%E2%80%93Wolfe_decomposition) with [`C++ API`](http://www.gurobi.com/documentation/7.5/refman/cpp_api_overview.html#sec:C++) 10 | - multicommodity.py: Implementation of [`Dantzig-Wolfe decomposition`](https://en.wikipedia.org/wiki/Dantzig%E2%80%93Wolfe_decomposition) with [`Python API`](http://www.gurobi.com/documentation/7.5/refman/py_python_api_overview.html#sec:Python) 11 | - Makefile: NMake makefile 12 | - multicommodity.dat: Test data 13 | 14 | **Contact** 15 | - `wujianjack2@163.com` (personal) 16 | - `wujianw@stu.xjtu.edu.cn` (educational) 17 | 18 | **Wu Jian** 19 | 20 | `July 18th, 2017` -------------------------------------------------------------------------------- /gurobi/multicommodity/multicommodity.cpp: -------------------------------------------------------------------------------- 1 | #include "gurobi_c++.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | int main(int argc, char *argv[]) { 12 | try { 13 | // input data 14 | ifstream data("multicommodity.dat"); 15 | 16 | size_t norig = 0; 17 | size_t ndest = 0; 18 | size_t nprod = 0; 19 | 20 | data >> norig; 21 | data >> ndest; 22 | data >> nprod; 23 | 24 | double **supply = new double *[norig]; 25 | for (size_t i = 0; i < norig; ++i) 26 | supply[i] = new double [nprod]; 27 | 28 | double **demand = new double *[ndest]; 29 | for (size_t j = 0; j < ndest; ++j) 30 | demand[j] = new double [nprod]; 31 | 32 | double **limit = new double *[norig]; 33 | for (size_t i = 0; i < norig; ++i) 34 | limit[i] = new double [ndest]; 35 | 36 | double ***cost = new double **[norig]; 37 | for (size_t i = 0; i < norig; ++i) { 38 | cost[i] = new double *[ndest]; 39 | 40 | for (size_t j = 0; j < ndest; ++j) 41 | cost[i][j] = new double [nprod]; 42 | } 43 | 44 | for (size_t i = 0; i < norig; ++i) 45 | for (size_t j = 0; j < nprod; ++j) 46 | data >> supply[i][j]; 47 | 48 | for (size_t j = 0; j < ndest; ++j) 49 | for (size_t k = 0; k < nprod; ++k) 50 | data >> demand[j][k]; 51 | 52 | for (size_t i = 0; i < norig; ++i) 53 | for (size_t j = 0; j < ndest; ++j) 54 | data >> limit[i][j]; 55 | 56 | for (size_t i = 0; i < norig; ++i) 57 | for (size_t j = 0; j < ndest; ++j) 58 | for (size_t k = 0; k < nprod; ++k) 59 | data >> cost[i][j][k]; 60 | 61 | data.close(); 62 | 63 | // environment and models 64 | GRBEnv env = GRBEnv(); 65 | GRBModel master = GRBModel(env); 66 | GRBModel sub = GRBModel(env); 67 | 68 | // disable log information 69 | master.set(GRB_IntParam_OutputFlag, 0); 70 | sub.set(GRB_IntParam_OutputFlag, 0); 71 | 72 | // iteration count 73 | size_t iter = 0; 74 | 75 | // variables, constraints and parameters in mater problem 76 | GRBConstr **multi = new GRBConstr *[norig]; 77 | for (size_t i = 0; i < norig; ++i) 78 | multi[i] = new GRBConstr [ndest]; 79 | 80 | GRBConstr *convex = NULL; 81 | 82 | vector weight; 83 | GRBVar excess; 84 | 85 | GRBLinExpr obj_masteri = 0.0; 86 | GRBLinExpr obj_masterii = 0.0; 87 | GRBLinExpr obj_masteriii = 0.0; 88 | 89 | GRBColumn col; 90 | 91 | double **xtrans = NULL; 92 | double sum_xtrans = 0.0; 93 | double sum_costxtrans = 0.0; 94 | vector propcost; 95 | 96 | // variables and parameters in sub problem 97 | GRBVar ***trans = new GRBVar **[norig]; 98 | for (size_t i = 0; i < norig; ++i) { 99 | trans[i] = new GRBVar *[ndest]; 100 | 101 | for (size_t j = 0; j < ndest; ++j) 102 | trans[i][j] = new GRBVar [nprod]; 103 | } 104 | 105 | GRBLinExpr obj_subi = 0.0; 106 | GRBLinExpr obj_subii = 0.0; 107 | 108 | GRBLinExpr con_supply = 0.0; 109 | GRBLinExpr con_demand = 0.0; 110 | 111 | GRBLinExpr con_optmulti = 0.0; 112 | 113 | double priceconvex = 1.0; 114 | double **price = new double *[norig]; 115 | for (size_t i = 0; i < norig; ++i) 116 | price[i] = new double [ndest]; 117 | 118 | for (size_t i = 0; i < norig; ++i) 119 | for (size_t j = 0; j < ndest; ++j) 120 | price[i][j] = 0.0; 121 | 122 | double **optship = new double *[norig]; 123 | for (size_t i = 0; i < norig; ++i) 124 | optship[i] = new double [ndest]; 125 | 126 | // add variable 'excess' for master problem 127 | excess = master.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, string("excess")); 128 | 129 | // add temporary constraints 'multi' for master problem 130 | for (size_t i = 0; i < norig; ++i) 131 | for (size_t j = 0; j < ndest; ++j) 132 | multi[i][j] = master.addConstr(-excess <= limit[i][j], "multi" + to_string(i) + to_string(j)); 133 | 134 | // add temporary constraint 'convex' for master problem 135 | convex = master.addConstrs(1); 136 | convex[0].set(GRB_CharAttr_Sense, GRB_EQUAL); 137 | convex[0].set(GRB_DoubleAttr_RHS, 1.0); 138 | convex[0].set(GRB_StringAttr_ConstrName, string("convex")); 139 | 140 | // set objective for master problem in 'Phase I' 141 | obj_masteri = excess; 142 | 143 | // add variables 'trans' for subproblem 144 | for (size_t i = 0; i < norig; ++i) 145 | for (size_t j = 0; j < ndest; ++j) 146 | for (size_t k = 0; k < nprod; ++k) 147 | trans[i][j][k] = sub.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "trans" + to_string(i) + to_string(j) + to_string(k)); 148 | 149 | // add constraints 'supply' for subproblem 150 | for (size_t i = 0; i < norig; ++i) { 151 | for (size_t k = 0; k < nprod; ++k) { 152 | for (size_t j = 0; j < ndest; ++j) 153 | con_supply += trans[i][j][k]; 154 | 155 | sub.addConstr(con_supply == supply[i][k], "supply" + to_string(i) + to_string(k)); 156 | con_supply = 0.0; 157 | } 158 | } 159 | 160 | // add constraints 'demand' for subproblem 161 | for (size_t j = 0; j < ndest; ++j) { 162 | for (size_t k = 0; k < nprod; ++k) { 163 | for (size_t i = 0; i < norig; ++i) 164 | con_demand += trans[i][j][k]; 165 | 166 | sub.addConstr(con_demand == demand[j][k], "demand" + to_string(j) + to_string(k)); 167 | con_demand = 0.0; 168 | } 169 | } 170 | 171 | // set objective for subproblem in 'Phase I' 172 | for (size_t i = 0; i < norig; ++i) 173 | for (size_t j = 0; j < ndest; ++j) 174 | for (size_t k = 0; k < nprod; ++k) 175 | obj_subi -= price[i][j] * trans[i][j][k]; 176 | 177 | obj_subi -= priceconvex; 178 | 179 | // dantzig-wolfe decomposition 180 | cout << " *** Dantzig-Wolfe Decomposition *** " << endl; 181 | cout << endl; 182 | 183 | // set objective for subproblem in 'Phase I' 184 | sub.setObjective(obj_subi, GRB_MINIMIZE); 185 | 186 | // set objective for master problem in 'Phase I' 187 | master.setObjective(obj_masteri, GRB_MINIMIZE); 188 | 189 | // 'Phase I' of dantzig-wolfe decomposition 190 | cout << "Phase I: " << endl; 191 | for (;;) { 192 | cout << "Iteration: " << iter << endl; 193 | 194 | // solve subproblem in 'Phase I' 195 | sub.optimize(); 196 | 197 | if (sub.get(GRB_DoubleAttr_ObjVal) >= -1e-6) { 198 | cout << "No feasible solution..." << endl; 199 | break; 200 | } 201 | else { 202 | ++iter; 203 | 204 | // calculate parameters for master problem 205 | xtrans = new double *[norig]; 206 | for (size_t i = 0; i < norig; ++i) 207 | xtrans[i] = new double [ndest]; 208 | 209 | sum_xtrans = 0.0; 210 | for (size_t i = 0; i < norig; ++i) { 211 | for (size_t j = 0; j < ndest; ++j) { 212 | for (size_t k = 0; k < nprod; ++k) 213 | sum_xtrans += trans[i][j][k].get(GRB_DoubleAttr_X); 214 | 215 | xtrans[i][j] = sum_xtrans; 216 | sum_xtrans = 0.0; 217 | } 218 | } 219 | 220 | sum_costxtrans = 0.0; 221 | for (size_t i = 0; i < norig; ++i) 222 | for (size_t j = 0; j < ndest; ++j) 223 | for (size_t k = 0; k < nprod; ++k) 224 | sum_costxtrans += cost[i][j][k] * trans[i][j][k].get(GRB_DoubleAttr_X); 225 | 226 | propcost.push_back(sum_costxtrans); 227 | 228 | // update constraints in master problem 229 | col = GRBColumn(); 230 | for (size_t i = 0; i < norig; ++i) 231 | for (size_t j = 0; j < ndest; ++j) 232 | col.addTerm(xtrans[i][j], multi[i][j]); 233 | 234 | col.addTerm(1.0, convex[0]); 235 | 236 | // add variable 'weight' 237 | weight.push_back(master.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, col, "weight" + to_string(iter))); 238 | 239 | // deallocate heap memory 240 | for (size_t i = 0; i < norig; ++i) 241 | delete [] xtrans[i]; 242 | delete [] xtrans; 243 | 244 | // solve master problem in 'Phase I' 245 | master.optimize(); 246 | 247 | // update price 248 | if (master.get(GRB_DoubleAttr_ObjVal) <= 1e-6) 249 | break; 250 | else { 251 | for (size_t i = 0; i < norig; ++i) 252 | for (size_t j = 0; j < ndest; ++j) 253 | price[i][j] = multi[i][j].get(GRB_DoubleAttr_Pi); 254 | 255 | priceconvex = convex[0].get(GRB_DoubleAttr_Pi); 256 | } 257 | 258 | // reset objective for subproblem in 'Phase I' 259 | obj_subi = 0.0; 260 | for (size_t i = 0; i < norig; ++i) 261 | for (size_t j = 0; j < ndest; ++j) 262 | for (size_t k = 0; k < nprod; ++k) 263 | obj_subi -= price[i][j] * trans[i][j][k]; 264 | 265 | obj_subi -= priceconvex; 266 | 267 | sub.setObjective(obj_subi, GRB_MINIMIZE); 268 | } 269 | } 270 | 271 | // setting up for 'Phase II' 272 | cout << "Setting up for Phase II..." << endl; 273 | 274 | // set objective for master problem in 'Phase II' 275 | for (size_t i = 0; i < weight.size(); ++i) 276 | obj_masterii += propcost[i] * weight[i]; 277 | 278 | master.setObjective(obj_masterii, GRB_MINIMIZE); 279 | 280 | // fix variable 'excess' 281 | double xexcess = excess.get(GRB_DoubleAttr_X); 282 | 283 | excess.set(GRB_DoubleAttr_LB, xexcess); 284 | excess.set(GRB_DoubleAttr_UB, xexcess); 285 | 286 | // solve master problem in 'Phase II' 287 | master.optimize(); 288 | 289 | // update price 290 | for (size_t i = 0; i < norig; ++i) 291 | for (size_t j = 0; j < ndest; ++j) 292 | price[i][j] = multi[i][j].get(GRB_DoubleAttr_Pi); 293 | 294 | priceconvex = convex[0].get(GRB_DoubleAttr_Pi); 295 | 296 | // set objective for subproblem in 'Phase II' 297 | for (size_t i = 0; i < norig; ++i) 298 | for (size_t j = 0; j < ndest; ++j) 299 | for (size_t k = 0; k < nprod; ++k) 300 | obj_subii += (cost[i][j][k] - price[i][j]) * trans[i][j][k]; 301 | 302 | obj_subii -= priceconvex; 303 | 304 | sub.setObjective(obj_subii, GRB_MINIMIZE); 305 | 306 | // increase iteration count 307 | ++iter; 308 | 309 | // 'Phase II' of dantzig-wolfe decomposition 310 | cout << "Phase II: " << endl; 311 | for (;;) { 312 | cout << "Iteration: " << iter << endl; 313 | 314 | // solve subproblem in 'Phase II' 315 | sub.optimize(); 316 | 317 | if (sub.get(GRB_DoubleAttr_ObjVal) >= -1e-6) { 318 | cout << "Optimal solution..." << endl; 319 | break; 320 | } 321 | else { 322 | ++iter; 323 | 324 | // calculate parameters for master problem 325 | xtrans = new double *[norig]; 326 | for (size_t i = 0; i < norig; ++i) 327 | xtrans[i] = new double [ndest]; 328 | 329 | sum_xtrans = 0.0; 330 | for (size_t i = 0; i < norig; ++i) { 331 | for (size_t j = 0; j < ndest; ++j) { 332 | for (size_t k = 0; k < nprod; ++k) 333 | sum_xtrans += trans[i][j][k].get(GRB_DoubleAttr_X); 334 | 335 | xtrans[i][j] = sum_xtrans; 336 | sum_xtrans = 0.0; 337 | } 338 | } 339 | 340 | sum_costxtrans = 0.0; 341 | for (size_t i = 0; i < norig; ++i) 342 | for (size_t j = 0; j < ndest; ++j) 343 | for (size_t k = 0; k < nprod; ++k) 344 | sum_costxtrans += cost[i][j][k] * trans[i][j][k].get(GRB_DoubleAttr_X); 345 | 346 | // update constraints in master problem 347 | col = GRBColumn(); 348 | for (size_t i = 0; i < norig; ++i) 349 | for (size_t j = 0; j < ndest; ++j) 350 | col.addTerm(xtrans[i][j], multi[i][j]); 351 | 352 | col.addTerm(1.0, convex[0]); 353 | 354 | // add variable 'weight' 355 | weight.push_back(master.addVar(0.0, GRB_INFINITY, sum_costxtrans, GRB_CONTINUOUS, col, "weight" + to_string(iter))); 356 | 357 | // deallocate heap memory 358 | for (size_t i = 0; i < norig; ++i) 359 | delete [] xtrans[i]; 360 | delete [] xtrans; 361 | 362 | // solve master problem in 'Phase II' 363 | master.optimize(); 364 | 365 | // update price 366 | for (size_t i = 0; i < norig; ++i) 367 | for (size_t j = 0; j < ndest; ++j) 368 | price[i][j] = multi[i][j].get(GRB_DoubleAttr_Pi); 369 | 370 | priceconvex = convex[0].get(GRB_DoubleAttr_Pi); 371 | 372 | // set objective for subproblem in 'Phase II' 373 | obj_subii = 0.0; 374 | for (size_t i = 0; i < norig; ++i) 375 | for (size_t j = 0; j < ndest; ++j) 376 | for (size_t k = 0; k < nprod; ++k) 377 | obj_subii += (cost[i][j][k] - price[i][j]) * trans[i][j][k]; 378 | 379 | obj_subii -= priceconvex; 380 | 381 | sub.setObjective(obj_subii, GRB_MINIMIZE); 382 | } 383 | } 384 | 385 | // 'Phase III' of dantzig-wolfe decomposition 386 | cout << "Phase III: " << endl; 387 | 388 | // set objective for master problem in 'Phase III' 389 | for (size_t i = 0; i < norig; ++i) 390 | for (size_t j = 0; j < ndest; ++j) 391 | optship[i][j] = limit[i][j] + excess.get(GRB_DoubleAttr_X) - multi[i][j].get(GRB_DoubleAttr_Slack); 392 | 393 | for (size_t i = 0; i < norig; ++i) 394 | for (size_t j = 0; j < ndest; ++j) 395 | for (size_t k = 0; k < nprod; ++k) 396 | obj_masteriii += cost[i][j][k] * trans[i][j][k]; 397 | 398 | sub.setObjective(obj_masteriii, GRB_MINIMIZE); 399 | 400 | for (size_t i = 0; i < norig; ++i) { 401 | for (size_t j = 0; j < ndest; ++j) { 402 | for (size_t k = 0; k < nprod; ++k) 403 | con_optmulti += trans[i][j][k]; 404 | 405 | sub.addConstr(con_optmulti == optship[i][j], "optmulti" + to_string(i) + to_string(j)); 406 | con_optmulti = 0.0; 407 | } 408 | } 409 | 410 | // solve master problem in 'Phase III' 411 | sub.optimize(); 412 | 413 | // end loop 414 | cout << " *** End Loop *** " << endl; 415 | 416 | // report solution 417 | cout << " *** Summary Report *** " << endl; 418 | cout << "Objective: " << sub.get(GRB_DoubleAttr_ObjVal) << endl; 419 | cout << "Variables: " << endl; 420 | for (size_t i = 0; i < norig; ++i) { 421 | for (size_t j = 0; j < ndest; ++j) { 422 | for (size_t k = 0; k < nprod; ++k) { 423 | if (fabs(trans[i][j][k].get(GRB_DoubleAttr_X)) >= 1e-6) 424 | printf(" trans[%d][%d][%d] = %12.6f\n", i, j, k, trans[i][j][k].get(GRB_DoubleAttr_X)); 425 | } 426 | } 427 | } 428 | 429 | // deallocate heap memory 430 | for (size_t i = 0; i < norig; ++i) 431 | delete [] supply[i]; 432 | delete [] supply; 433 | 434 | for (size_t i = 0; i < ndest; ++i) 435 | delete [] demand[i]; 436 | delete [] demand; 437 | 438 | for (size_t i = 0; i < norig; ++i) 439 | delete [] limit[i]; 440 | delete [] limit; 441 | 442 | for (size_t i = 0; i < norig; ++i) { 443 | for (size_t j = 0; j < ndest; ++j) 444 | delete [] cost[i][j]; 445 | delete [] cost[i]; 446 | } 447 | delete [] cost; 448 | 449 | for (size_t i = 0; i < norig; ++i) 450 | delete [] multi[i]; 451 | delete [] multi; 452 | 453 | for (size_t i = 0; i < norig; ++i) { 454 | for (size_t j = 0; j < ndest; ++j) 455 | delete [] trans[i][j]; 456 | delete [] trans[i]; 457 | } 458 | delete [] trans; 459 | 460 | for (size_t i = 0; i < norig; ++i) 461 | delete [] price[i]; 462 | delete [] price; 463 | 464 | for (size_t i = 0; i < norig; ++i) 465 | delete [] optship[i]; 466 | delete [] optship; 467 | } 468 | catch (GRBException e) { 469 | cout << "Error code = " << e.getErrorCode() << endl; 470 | cout << e.getMessage() << endl; 471 | } 472 | catch(...) { 473 | cout << "Exception during optimization" << endl; 474 | } 475 | 476 | return 0; 477 | } -------------------------------------------------------------------------------- /gurobi/multicommodity/multicommodity.dat: -------------------------------------------------------------------------------- 1 | 3 2 | 7 3 | 3 4 | 400 800 200 5 | 700 1600 300 6 | 800 1800 300 7 | 300 500 100 8 | 300 750 100 9 | 100 400 0 10 | 75 250 50 11 | 650 950 200 12 | 225 850 100 13 | 250 500 250 14 | 625 625 625 625 625 625 625 15 | 625 625 625 625 625 625 625 16 | 625 625 625 625 625 625 625 17 | 30 39 41 18 | 10 14 15 19 | 8 11 12 20 | 10 14 16 21 | 11 16 17 22 | 71 82 86 23 | 6 8 8 24 | 22 27 29 25 | 7 9 9 26 | 10 12 13 27 | 7 9 9 28 | 21 26 28 29 | 82 95 99 30 | 13 17 18 31 | 19 24 26 32 | 11 14 14 33 | 12 17 17 34 | 10 13 13 35 | 25 28 31 36 | 83 99 104 37 | 15 20 20 38 | -------------------------------------------------------------------------------- /gurobi/multicommodity/multicommodity.py: -------------------------------------------------------------------------------- 1 | from __future__ import division, print_function 2 | 3 | import gurobipy as GRBPY 4 | 5 | 6 | class Multicommodity: 7 | def __init__(self): 8 | # initialize data 9 | self.norig = 0 10 | self.ndest = 0 11 | self.nprod = 0 12 | self.supply = [] 13 | self.demand = [] 14 | self.limit = [] 15 | self.cost = [] 16 | 17 | # initialize variables and constraints 18 | self.cmulti = [] 19 | self.vtrans = [] 20 | self.vweight = [] 21 | 22 | # initialize parameters 23 | self.iter = 0 24 | self.priceconvex = 1.0 25 | self.price = [] 26 | self.propcost = [] 27 | 28 | def read(self, filename): 29 | # input data 30 | with open(filename, "r") as data: 31 | self.norig = int(data.readline()) 32 | self.ndest = int(data.readline()) 33 | self.nprod = int(data.readline()) 34 | 35 | for i in range(self.norig): 36 | column = data.readline().split() 37 | lsupply = [] 38 | for k in range(self.nprod): 39 | lsupply.append(float(column[k])) 40 | self.supply.append(lsupply) 41 | 42 | for j in range(self.ndest): 43 | column = data.readline().split() 44 | ldemand = [] 45 | for k in range(self.nprod): 46 | ldemand.append(float(column[k])) 47 | self.demand.append(ldemand) 48 | 49 | for i in range(self.norig): 50 | column = data.readline().split() 51 | llimit = [] 52 | for j in range(self.ndest): 53 | llimit.append(float(column[j])) 54 | self.limit.append(llimit) 55 | 56 | for i in range(self.norig): 57 | lcost = [] 58 | for j in range(self.ndest): 59 | column = data.readline().split() 60 | llcost = [] 61 | for k in range(self.nprod): 62 | llcost.append(float(column[k])) 63 | lcost.append(llcost) 64 | self.cost.append(lcost) 65 | 66 | def build(self): 67 | try: 68 | # define models for 'master' and 'sub' 69 | self.master = GRBPY.Model("master") 70 | self.sub = GRBPY.Model("sub") 71 | 72 | # disable log information 73 | self.master.setParam("OutputFlag", 0) 74 | self.sub.setParam("OutputFlag", 0) 75 | 76 | # add variable 'excess' for master problem 77 | self.vexcess = self.master.addVar(0.0, GRBPY.GRB.INFINITY, 0.0, GRBPY.GRB.CONTINUOUS) 78 | 79 | # add temporary constraints 'multi' for master problem 80 | for i in range(self.norig): 81 | lmulti = [] 82 | for j in range(self.ndest): 83 | lmulti.append(self.master.addConstr(-self.vexcess <= self.limit[i][j])) 84 | self.cmulti.append(lmulti) 85 | 86 | # tricky approach to add temporary constraint 'convex' for master problem 87 | self.cconvex = self.master.addConstr(1e-6 * self.vexcess == 1.0) 88 | 89 | # add variables 'trans' for subproblem 90 | for i in range(self.norig): 91 | ltrans = [] 92 | for j in range(self.ndest): 93 | lltrans = [] 94 | for k in range(self.nprod): 95 | lltrans.append(self.sub.addVar(0.0, GRBPY.GRB.INFINITY, 0.0, GRBPY.GRB.CONTINUOUS)) 96 | ltrans.append(lltrans) 97 | self.vtrans.append(ltrans) 98 | 99 | # add constraints 'supply' for subproblem 100 | for i in range(self.norig): 101 | for k in range(self.nprod): 102 | self.sub.addConstr(GRBPY.quicksum(self.vtrans[i][j][k] for j in range(self.ndest)) \ 103 | == self.supply[i][k]) 104 | 105 | # add constraints 'demand' for subproblem 106 | for j in range(self.ndest): 107 | for k in range(self.nprod): 108 | self.sub.addConstr(GRBPY.quicksum(self.vtrans[i][j][k] for i in range(self.norig)) \ 109 | == self.demand[j][k]) 110 | except GRBPY.GurobiError as e: 111 | print('Error code' + str(e.errno) + ': ' + str(e)) 112 | except AttributeError as e: 113 | print('Encountered an attribute error: ' + str(e)) 114 | 115 | def solvePhaseI(self): 116 | # initialize parameters 117 | for i in range(self.norig): 118 | lprice = [0.0] * self.ndest 119 | self.price.append(lprice) 120 | 121 | obj_masteri = self.vexcess 122 | obj_subi = -GRBPY.quicksum(self.price[i][j] * self.vtrans[i][j][k] \ 123 | for i in range(self.norig) \ 124 | for j in range(self.ndest) \ 125 | for k in range(self.nprod)) - self.priceconvex 126 | 127 | # set objective for master problem in 'Phase I' 128 | self.master.setObjective(obj_masteri, GRBPY.GRB.MINIMIZE) 129 | 130 | # set objective for subproblem in 'Phase I' 131 | self.sub.setObjective(obj_subi, GRBPY.GRB.MINIMIZE) 132 | 133 | # ok, forget this 134 | self.master.chgCoeff(self.cconvex, self.vexcess, 0.0) 135 | 136 | # 'Phase I' of dantzig-wolfe decomposition 137 | print("Phase I: ") 138 | 139 | while True: 140 | print("Iteration: ", self.iter) 141 | 142 | # solve subproblem in 'Phase I' 143 | self.sub.optimize() 144 | 145 | if self.sub.objval >= -1e-6: 146 | print("No feasible solution...") 147 | break 148 | else: 149 | self.iter += 1 150 | 151 | # calculate parameters for master problem 152 | sum_costxtrans = sum(self.cost[i][j][k] * self.vtrans[i][j][k].x \ 153 | for i in range(self.norig) \ 154 | for j in range(self.ndest) \ 155 | for k in range(self.nprod)) 156 | 157 | self.propcost.append(sum_costxtrans) 158 | 159 | # update constraints in master problem 160 | col = GRBPY.Column() 161 | for i in range(self.norig): 162 | for j in range(self.ndest): 163 | col.addTerms(sum(self.vtrans[i][j][k].x for k in range(self.nprod)), self.cmulti[i][j]) 164 | 165 | col.addTerms(1.0, self.cconvex) 166 | 167 | # add variable 'weight' 168 | self.vweight.append(self.master.addVar(0.0, GRBPY.GRB.INFINITY, 0.0, GRBPY.GRB.CONTINUOUS, "", col)) 169 | 170 | # solve master problem in 'Phase I' 171 | self.master.optimize() 172 | 173 | # update price 174 | if self.master.objval <= 1e-6: 175 | break 176 | else: 177 | for i in range(self.norig): 178 | for j in range(self.ndest): 179 | self.price[i][j] = self.cmulti[i][j].pi 180 | 181 | self.priceconvex = self.cconvex.pi 182 | 183 | # reset objective for subproblem in 'Phase I' 184 | obj_subi = -GRBPY.quicksum(self.price[i][j] * self.vtrans[i][j][k] \ 185 | for i in range(self.norig) \ 186 | for j in range(self.ndest) \ 187 | for k in range(self.nprod)) - self.priceconvex 188 | 189 | self.sub.setObjective(obj_subi, GRBPY.GRB.MINIMIZE) 190 | 191 | def setupPhaseII(self): 192 | # setting up for 'Phase II' 193 | print("Setting up for Phase II...") 194 | 195 | # set objective for master problem in 'Phase II' 196 | obj_masterii = GRBPY.quicksum(self.propcost[i] * self.vweight[i] for i in range(len(self.propcost))) 197 | 198 | self.master.setObjective(obj_masterii, GRBPY.GRB.MINIMIZE) 199 | 200 | # fix variable 'excess' 201 | self.vexcess.lb = self.vexcess.x 202 | self.vexcess.ub = self.vexcess.x 203 | 204 | # solve master problem in 'Phase II' 205 | self.master.optimize() 206 | 207 | # update price 208 | for i in range(self.norig): 209 | for j in range(self.ndest): 210 | self.price[i][j] = self.cmulti[i][j].pi 211 | 212 | self.priceconvex = self.cconvex.pi 213 | 214 | # set objective for subproblem in 'Phase II' 215 | obj_subii = GRBPY.quicksum((self.cost[i][j][k] - self.price[i][j]) * self.vtrans[i][j][k] \ 216 | for i in range(self.norig) \ 217 | for j in range(self.ndest) \ 218 | for k in range(self.nprod)) - self.priceconvex 219 | 220 | self.sub.setObjective(obj_subii, GRBPY.GRB.MINIMIZE) 221 | 222 | # increase iteration count 223 | self.iter += 1 224 | 225 | def solvePhaseII(self): 226 | # 'Phase II' of dantzig-wolfe decomposition 227 | print("Phase II: ") 228 | 229 | while True: 230 | print("Iteration: ", self.iter) 231 | 232 | # solve subproblem in 'Phase II' 233 | self.sub.optimize() 234 | 235 | if self.sub.objval >= -1e-6: 236 | print("Optimal solution...") 237 | break 238 | else: 239 | self.iter += 1 240 | 241 | # calculate parameters for master problem 242 | sum_costxtrans = sum(self.cost[i][j][k] * self.vtrans[i][j][k].x \ 243 | for i in range(self.norig) \ 244 | for j in range(self.ndest) \ 245 | for k in range(self.nprod)) 246 | 247 | # update constraints in master problem 248 | col = GRBPY.Column() 249 | for i in range(self.norig): 250 | for j in range(self.ndest): 251 | col.addTerms(sum(self.vtrans[i][j][k].x for k in range(self.nprod)), self.cmulti[i][j]) 252 | 253 | col.addTerms(1.0, self.cconvex) 254 | 255 | # add variable 'weight' 256 | self.vweight.append(self.master.addVar(0.0, GRBPY.GRB.INFINITY, sum_costxtrans, GRBPY.GRB.CONTINUOUS, "", col)) 257 | 258 | # solve master problem in 'Phase II' 259 | self.master.optimize() 260 | 261 | # update price 262 | for i in range(self.norig): 263 | for j in range(self.ndest): 264 | self.price[i][j] = self.cmulti[i][j].pi 265 | 266 | self.priceconvex = self.cconvex.pi 267 | 268 | # reset objective for subproblem in 'Phase II' 269 | obj_subii = GRBPY.quicksum((self.cost[i][j][k] - self.price[i][j]) * self.vtrans[i][j][k] \ 270 | for i in range(self.norig) \ 271 | for j in range(self.ndest) \ 272 | for k in range(self.nprod)) - self.priceconvex 273 | 274 | self.sub.setObjective(obj_subii, GRBPY.GRB.MINIMIZE) 275 | 276 | def solvePhaseIII(self): 277 | optship = [] 278 | for i in range(self.norig): 279 | loptship = [0.0] * self.ndest 280 | optship.append(loptship) 281 | 282 | # 'Phase III' of dantzig-wolfe decomposition 283 | print("Phase III:") 284 | 285 | # set objective for master problem in 'Phase III' 286 | for i in range(self.norig): 287 | for j in range(self.ndest): 288 | optship[i][j] = self.limit[i][j] + self.vexcess.x - self.cmulti[i][j].slack 289 | 290 | obj_masteriii = GRBPY.quicksum(self.cost[i][j][k] * self.vtrans[i][j][k] \ 291 | for i in range(self.norig) \ 292 | for j in range(self.ndest) \ 293 | for k in range(self.nprod)) 294 | 295 | self.sub.setObjective(obj_masteriii, GRBPY.GRB.MINIMIZE) 296 | 297 | for i in range(self.norig): 298 | for j in range(self.ndest): 299 | self.sub.addConstr(GRBPY.quicksum(self.vtrans[i][j][k] for k in range(self.nprod)) == optship[i][j]) 300 | 301 | # solve master problem in 'Phase III' 302 | self.sub.optimize() 303 | 304 | def solve(self): 305 | # build 'master' and 'sub' 306 | self.build() 307 | 308 | # dantzig-wolfe decomposition 309 | print(" *** Dantzig-Wolfe Decomposition *** ") 310 | self.solvePhaseI() 311 | 312 | self.setupPhaseII() 313 | 314 | self.solvePhaseII() 315 | 316 | self.solvePhaseIII() 317 | print(" *** End Loop *** ") 318 | 319 | def report(self): 320 | # report solution 321 | print(" *** Summary Report *** ") 322 | print("Objective: ", self.sub.objval) 323 | print("Variables: ") 324 | for i in range(self.norig): 325 | for j in range(self.ndest): 326 | for k in range(self.nprod): 327 | if abs(self.vtrans[i][j][k].x) >= 1e-6: 328 | print(" trans[%d][%d][%d] = %12.6f" % (i, j, k, self.vtrans[i][j][k].x)) 329 | 330 | if __name__ == "__main__": 331 | multicomm = Multicommodity() 332 | multicomm.read("multicommodity.dat") 333 | multicomm.solve() 334 | multicomm.report() -------------------------------------------------------------------------------- /gurobi/warehouse/Makefile: -------------------------------------------------------------------------------- 1 | # change this if necessary 2 | GRB_VER = 75 3 | MSVC_VER = 2013 4 | PRB_NAME = warehouse 5 | # end change 6 | 7 | CXX = cl 8 | CXXFLAGS = /nologo /MD /Ox /EHsc /DNDEBUG 9 | 10 | LD = link 11 | LDFLAGS = /nologo 12 | 13 | INCL = -I$(GUROBI_HOME)\include 14 | ADDINCLFLAGS = 15 | 16 | LIBS = $(GUROBI_HOME)\lib\gurobi$(GRB_VER).lib $(GUROBI_HOME)\lib\gurobi_c++md$(MSVC_VER).lib 17 | ADDLIBS = 18 | 19 | PRB_OBJS = $(PRB_NAME).obj 20 | PRB_TARGET = $(PRB_NAME).exe 21 | 22 | all: $(PRB_TARGET) 23 | 24 | $(PRB_TARGET): $(PRB_OBJS) 25 | $(LD) $(LDFLAGS) $(LIBS) $(ADDLIBS) $** 26 | 27 | .cpp.obj: 28 | $(CXX) $(CXXFLAGS) -c $(INCL) $(ADDINCLFLAGS) $< 29 | 30 | clean: 31 | @del /s /q $(PRB_OBJS) $(PRB_TARGET) > nul -------------------------------------------------------------------------------- /gurobi/warehouse/README.md: -------------------------------------------------------------------------------- 1 | ## Brief Introduction 2 | 3 | **Tools** 4 | - [`Gurobi`](http://www.gurobi.com): State-of-the-art mathematical programming solver 5 | 6 | **Version**: 7.5 7 | 8 | **Files** 9 | - warehouse.cpp: Loop-style implementation of [`Benders decomposition`](https://en.wikipedia.org/wiki/Benders_decomposition) with [`C++ API`](http://www.gurobi.com/documentation/7.5/refman/cpp_api_overview.html#sec:C++) 10 | - warehouse2.cpp: Implementation of [`Benders decomposition`](https://en.wikipedia.org/wiki/Benders_decomposition) using [`Lazy constraints`](https://www.gurobi.com/documentation/7.5/refman/cpp_grbcallback_addlazy.html) callback with [`C++ API`](http://www.gurobi.com/documentation/7.5/refman/cpp_api_overview.html#sec:C++) 11 | - warehouse.py: Implementation of [`Benders decomposition`](https://en.wikipedia.org/wiki/Benders_decomposition) using [`Lazy constraints`](https://www.gurobi.com/documentation/7.5/refman/cpp_grbcallback_addlazy.html) callback with [`Python API`](http://www.gurobi.com/documentation/7.5/refman/py_python_api_overview.html#sec:Python) 12 | - Makefile: NMake makefile 13 | - warehouse.dat: Test data 14 | 15 | **Contact** 16 | - `wujianjack2@163.com` (personal) 17 | - `wujianw@stu.xjtu.edu.cn` (educational) 18 | 19 | **Wu Jian** 20 | 21 | `July 15th, 2017` -------------------------------------------------------------------------------- /gurobi/warehouse/warehouse.cpp: -------------------------------------------------------------------------------- 1 | #include "gurobi_c++.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main(int argc, char *argv[]) { 11 | try { 12 | // input data 13 | ifstream data("warehouse.dat"); 14 | 15 | size_t nwarehouse = 0; 16 | size_t nstore = 0; 17 | 18 | data >> nwarehouse; 19 | data >> nstore; 20 | 21 | double *supply = new double [nwarehouse]; 22 | double *demand = new double [nstore]; 23 | double *fixcost = new double [nwarehouse]; 24 | 25 | double **varcost = new double *[nwarehouse]; 26 | for (size_t i = 0; i < nwarehouse; ++i) 27 | varcost[i] = new double [nstore]; 28 | 29 | for (size_t i = 0; i < nwarehouse; ++i) 30 | data >> supply[i]; 31 | 32 | for (size_t i = 0; i < nstore; ++i) 33 | data >> demand[i]; 34 | 35 | for (size_t i = 0; i < nwarehouse; ++i) 36 | data >> fixcost[i]; 37 | 38 | for (size_t i = 0; i < nwarehouse; ++i) 39 | for (size_t j = 0; j < nstore; ++j) 40 | data >> varcost[i][j]; 41 | 42 | data.close(); 43 | 44 | // environment and models 45 | GRBEnv env = GRBEnv(); 46 | GRBModel master = GRBModel(env); 47 | GRBModel sub = GRBModel(env); 48 | 49 | // variables and parameters in master problem 50 | GRBVar *mbuild = new GRBVar [nwarehouse]; 51 | GRBVar maxshipcost; 52 | 53 | // variables and constraints in subproblem 54 | GRBVar **ship = new GRBVar *[nwarehouse]; 55 | for (size_t i = 0; i < nwarehouse; ++i) 56 | ship[i] = new GRBVar [nstore]; 57 | 58 | GRBVar *sbuild = new GRBVar [nwarehouse]; 59 | 60 | GRBConstr *consupply = new GRBConstr [nwarehouse]; 61 | GRBConstr *condemand = new GRBConstr [nstore]; 62 | 63 | // disable log information 64 | master.set(GRB_IntParam_OutputFlag, 0); 65 | sub.set(GRB_IntParam_OutputFlag, 0); 66 | 67 | // disable presolving in subproblem 68 | sub.set(GRB_IntParam_Presolve, 0); 69 | 70 | // required to obtain farkas dual 71 | sub.set(GRB_IntParam_InfUnbdInfo, 1); 72 | 73 | // use dual simplex 74 | sub.set(GRB_IntParam_Method, 1); 75 | 76 | // construct master problem 77 | for (size_t i = 0; i < nwarehouse; ++i) 78 | mbuild[i] = master.addVar(0.0, 1.0, 0.0, GRB_BINARY, "mbuild_" + to_string(i)); 79 | 80 | maxshipcost = master.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "maxshipcost"); 81 | 82 | GRBLinExpr obj_totalcost = 0.0; 83 | for (size_t i = 0; i < nwarehouse; ++i) 84 | obj_totalcost += fixcost[i] * mbuild[i]; 85 | 86 | master.setObjective(obj_totalcost + maxshipcost, GRB_MINIMIZE); 87 | 88 | // construct subproblem 89 | for (size_t i = 0; i < nwarehouse; ++i) 90 | for (size_t j = 0; j < nstore; ++j) 91 | ship[i][j] = sub.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "ship_" + to_string(i) + "_" + to_string(j)); 92 | 93 | for (size_t i = 0; i < nwarehouse; ++i) 94 | sbuild[i] = sub.addVar(0.0, 1.0, 0.0, GRB_CONTINUOUS, "sbuild_" + to_string(i)); 95 | 96 | GRBLinExpr con_supply = 0.0; 97 | for (size_t i = 0; i < nwarehouse; ++i) { 98 | for (size_t j = 0; j < nstore; ++j) 99 | con_supply += ship[i][j]; 100 | 101 | consupply[i] = sub.addConstr(con_supply <= supply[i] * sbuild[i], "supply_" + to_string(i)); 102 | con_supply = 0.0; 103 | } 104 | 105 | GRBLinExpr con_demand = 0.0; 106 | for (size_t j = 0; j < nstore; ++j) { 107 | for (size_t i = 0; i < nwarehouse; ++i) 108 | con_demand += ship[i][j]; 109 | 110 | condemand[j] = sub.addConstr(con_demand == demand[j], "demand_" + to_string(j)); 111 | con_demand = 0.0; 112 | } 113 | 114 | GRBLinExpr obj_shipcost = 0.0; 115 | for (size_t i = 0; i < nwarehouse; ++i) 116 | for (size_t j = 0; j < nstore; ++j) 117 | obj_shipcost += varcost[i][j] * ship[i][j]; 118 | 119 | sub.setObjective(obj_shipcost, GRB_MINIMIZE); 120 | 121 | // run master once 122 | master.optimize(); 123 | 124 | // temporary linear expression to be added 125 | GRBLinExpr con_lazycut = 0.0; 126 | 127 | // set iteration limit 128 | size_t iterlimit = 100; 129 | 130 | // set 'sbuild' value for initial subproblem 131 | for (size_t i = 0; i < nwarehouse; ++i) { 132 | sbuild[i].set(GRB_DoubleAttr_LB, 1.0); 133 | sbuild[i].set(GRB_DoubleAttr_UB, 1.0); 134 | } 135 | 136 | // main benders loop 137 | cout << " *** Benders Decomposition Loop *** " << endl; 138 | for (size_t iter = 0; iter < iterlimit; ++iter) { 139 | cout << "Iteration: " << iter << endl; 140 | 141 | sub.optimize(); 142 | 143 | if (sub.get(GRB_IntAttr_Status) == GRB_INFEASIBLE) { 144 | cout << "Adding feasibility cut..." << endl; 145 | cout << endl; 146 | 147 | con_lazycut = 0.0; 148 | 149 | for (size_t i = 0; i < nwarehouse; ++i) 150 | con_lazycut += consupply[i].get(GRB_DoubleAttr_FarkasDual) * supply[i] * mbuild[i]; 151 | 152 | for (size_t j = 0; j < nstore; ++j) 153 | con_lazycut += condemand[j].get(GRB_DoubleAttr_FarkasDual) * demand[j]; 154 | 155 | master.addConstr(con_lazycut >= 0); 156 | } 157 | else if (sub.get(GRB_IntAttr_Status) == GRB_OPTIMAL) { 158 | if (sub.get(GRB_DoubleAttr_ObjVal) > maxshipcost.get(GRB_DoubleAttr_X) + 1e-6) { 159 | cout << "Adding optimality cut..." << endl; 160 | cout << endl; 161 | 162 | con_lazycut = 0.0; 163 | 164 | for (size_t i = 0; i < nwarehouse; ++i) 165 | con_lazycut += consupply[i].get(GRB_DoubleAttr_Pi) * supply[i] * mbuild[i]; 166 | 167 | for (size_t j = 0; j < nstore; ++j) 168 | con_lazycut += condemand[j].get(GRB_DoubleAttr_Pi) * demand[j]; 169 | 170 | master.addConstr(maxshipcost >= con_lazycut); 171 | } 172 | else 173 | break; 174 | } 175 | else 176 | break; 177 | 178 | master.optimize(); 179 | 180 | for (size_t i = 0; i < nwarehouse; ++i) { 181 | sbuild[i].set(GRB_DoubleAttr_LB, mbuild[i].get(GRB_DoubleAttr_X)); 182 | sbuild[i].set(GRB_DoubleAttr_UB, mbuild[i].get(GRB_DoubleAttr_X)); 183 | } 184 | } 185 | cout << " *** End Loop *** " << endl; 186 | 187 | // display solution 188 | cout << endl; 189 | cout << " *** Summary Report *** " << endl; 190 | printf("Objective: %.6f\n", master.get(GRB_DoubleAttr_ObjVal)); 191 | cout << endl; 192 | cout << "Variables:: " << endl; 193 | for (size_t i = 0; i < nwarehouse; ++i) { 194 | if (fabs(mbuild[i].get(GRB_DoubleAttr_X)) > 1e-6) 195 | printf(" Build[%d] = %.0f\n", i, mbuild[i].get(GRB_DoubleAttr_X)); 196 | } 197 | cout << endl; 198 | 199 | for (size_t i = 0; i < nwarehouse; ++i) { 200 | for (size_t j = 0; j < nstore; ++j) { 201 | if (fabs(ship[i][j].get(GRB_DoubleAttr_X)) > 1e-6) 202 | printf(" Ship[%d][%d] = %.6f\n", i, j, ship[i][j].get(GRB_DoubleAttr_X)); 203 | } 204 | } 205 | cout << endl; 206 | 207 | // deallocate heap memory 208 | for (size_t i = 0; i < nwarehouse; ++i) 209 | delete [] ship[i]; 210 | delete [] ship; 211 | 212 | delete [] mbuild; 213 | delete [] consupply; 214 | delete [] condemand; 215 | 216 | for (size_t i = 0; i < nwarehouse; ++i) 217 | delete [] varcost[i]; 218 | delete [] varcost; 219 | 220 | delete [] fixcost; 221 | delete [] demand; 222 | delete [] supply; 223 | delete [] sbuild; 224 | } 225 | catch (GRBException e) { 226 | cout << "Error code = " << e.getErrorCode() << endl; 227 | cout << e.getMessage() << endl; 228 | } 229 | catch(...) { 230 | cout << "Exception during optimization" << endl; 231 | } 232 | 233 | return 0; 234 | } -------------------------------------------------------------------------------- /gurobi/warehouse/warehouse.dat: -------------------------------------------------------------------------------- 1 | 25 2 | 6 3 | 23070 18290 20010 15080 17540 21090 16650 18420 19160 18860 22690 19360 22330 15440 19330 17110 15380 18690 20720 21220 16720 21540 16500 15310 18970 4 | 12000 12000 14000 13500 25000 29000 5 | 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 500000 6 | 73.78 14.76 86.82 91.19 51.03 76.49 7 | 60.28 20.92 76.43 83.99 58.84 68.86 8 | 58.18 21.64 69.84 72.39 61.64 58.39 9 | 50.37 21.74 61.49 65.72 60.48 56.68 10 | 42.73 35.19 44.11 58.08 65.76 55.51 11 | 44.62 39.21 44.44 48.32 76.12 51.17 12 | 49.31 51.72 36.27 42.96 84.52 49.61 13 | 50.79 59.25 22.53 33.22 94.30 49.66 14 | 51.93 72.13 21.66 29.39 93.52 49.63 15 | 65.90 13.07 79.59 86.07 46.83 69.55 16 | 50.79 9.99 67.83 78.81 49.34 60.79 17 | 47.51 12.95 59.57 67.71 51.13 54.65 18 | 39.36 19.01 56.39 62.37 57.25 47.91 19 | 33.55 30.16 40.66 48.50 60.83 42.51 20 | 34.17 40.46 40.23 47.10 66.22 38.94 21 | 41.68 53.03 22.56 30.89 77.22 35.88 22 | 42.75 62.94 18.58 27.02 80.36 40.11 23 | 46.46 71.17 17.17 21.16 91.65 41.56 24 | 56.83 8.84 83.99 91.88 41.38 67.79 25 | 46.21 2.92 68.94 76.86 38.89 60.38 26 | 41.67 11.69 61.05 70.06 43.24 48.48 27 | 25.57 17.59 54.93 57.07 44.93 43.97 28 | 28.16 29.39 38.64 46.48 50.16 34.20 29 | 26.97 41.62 29.72 40.61 59.56 31.21 30 | 34.24 54.09 22.13 28.43 69.68 24.09 31 | -------------------------------------------------------------------------------- /gurobi/warehouse/warehouse.py: -------------------------------------------------------------------------------- 1 | from __future__ import division, print_function 2 | 3 | import gurobipy as GRBPY 4 | 5 | 6 | # awkward restriction for 'callback' 7 | def cbwarehouse(model, where): 8 | if where == GRBPY.GRB.Callback.MIPSOL: 9 | if model._iter >= 1: 10 | for i in range(model._nwarehouse): 11 | model._csupply[i].rhs = model.cbGetSolution(model._vmbuild[i]) * model._supply[i] 12 | 13 | model._sub.optimize() 14 | 15 | if model._sub.status == GRBPY.GRB.INFEASIBLE: 16 | print("Iteration: ", model._iter) 17 | print("Adding feasibility cut...\n") 18 | 19 | lazycut = GRBPY.quicksum(model._csupply[i].farkasdual * model._supply[i] * model._vmbuild[i] \ 20 | for i in range(model._nwarehouse)) + \ 21 | sum(model._cdemand[i].farkasdual * model._demand[i] for i in range(model._nstore)) 22 | 23 | model.cbLazy(lazycut >= 0) 24 | 25 | model._iter += 1 26 | elif model._sub.status == GRBPY.GRB.OPTIMAL: 27 | if model._sub.objval > model.cbGetSolution(model._maxshipcost) + 1e-6: 28 | print("Iteration: ", model._iter) 29 | print("Adding optimality cut...\n") 30 | 31 | lazycut = GRBPY.quicksum(model._csupply[i].pi * model._supply[i] * model._vmbuild[i] \ 32 | for i in range(model._nwarehouse)) + \ 33 | sum(model._cdemand[i].pi * model._demand[i] for i in range(model._nstore)) 34 | 35 | model.cbLazy(model._maxshipcost >= lazycut) 36 | 37 | model._iter += 1 38 | else: 39 | model.terminate() 40 | 41 | class WareHouse: 42 | def __init__(self): 43 | # initialize data 44 | self.nwarehouse = 0 45 | self.nstore = 0 46 | self.supply = [] 47 | self.demand = [] 48 | self.fixcost = [] 49 | self.varcost = [] 50 | 51 | # initialize variables and constraints 52 | self.vmbuild = [] 53 | self.vship = [] 54 | self.csupply = [] 55 | self.cdemand = [] 56 | 57 | def read(self, filename): 58 | # input data 59 | with open(filename, "r") as data: 60 | self.nwarehouse = int(data.readline()) 61 | self.nstore = int(data.readline()) 62 | 63 | column = data.readline().split() 64 | for i in range(self.nwarehouse): 65 | self.supply.append(float(column[i])) 66 | 67 | column = data.readline().split() 68 | for i in range(self.nstore): 69 | self.demand.append(float(column[i])) 70 | 71 | column = data.readline().split() 72 | for i in range(self.nwarehouse): 73 | self.fixcost.append(float(column[i])) 74 | 75 | for i in range(self.nwarehouse): 76 | column = data.readline().split() 77 | lvarcost = [] 78 | for j in range(self.nstore): 79 | lvarcost.append(float(column[j])) 80 | self.varcost.append(lvarcost) 81 | 82 | def build(self): 83 | try: 84 | # define models for 'master' and 'sub' 85 | self.master = GRBPY.Model("master") 86 | self.sub = GRBPY.Model("sub") 87 | 88 | # disable log information 89 | self.master.setParam("OutputFlag", 0) 90 | self.sub.setParam("OutputFlag", 0) 91 | 92 | # use lazy constraints 93 | self.master.setParam("LazyConstraints", 1) 94 | 95 | # disable presolving in subproblem 96 | self.sub.setParam("Presolve", 0) 97 | 98 | # required to obtain farkas dual 99 | self.sub.setParam("InfUnbdInfo", 1) 100 | 101 | # use dual simplex 102 | self.sub.setParam("Method", 1) 103 | 104 | # construct master problem 105 | for i in range(self.nwarehouse): 106 | self.vmbuild.append(self.master.addVar(0.0, 1.0, 0.0, GRBPY.GRB.BINARY)) 107 | 108 | self.maxshipcost = self.master.addVar(0.0, GRBPY.GRB.INFINITY, 0.0, GRBPY.GRB.CONTINUOUS) 109 | 110 | self.master.setObjective(GRBPY.quicksum(self.fixcost[i] * self.vmbuild[i] \ 111 | for i in range(self.nwarehouse)) + \ 112 | self.maxshipcost, GRBPY.GRB.MINIMIZE) 113 | 114 | # construct subproblem 115 | for i in range(self.nwarehouse): 116 | lvship = [] 117 | for j in range(self.nstore): 118 | lvship.append(self.sub.addVar(0.0, GRBPY.GRB.INFINITY, 0.0, GRBPY.GRB.CONTINUOUS)) 119 | self.vship.append(lvship) 120 | 121 | for i in range(self.nwarehouse): 122 | self.csupply.append(self.sub.addConstr(GRBPY.quicksum(self.vship[i][j] \ 123 | for j in range(self.nstore)) \ 124 | <= self.supply[i] * 1.0)) 125 | 126 | for j in range(self.nstore): 127 | self.cdemand.append(self.sub.addConstr(GRBPY.quicksum(self.vship[i][j] \ 128 | for i in range(self.nwarehouse)) \ 129 | == self.demand[j])) 130 | 131 | self.sub.setObjective(GRBPY.quicksum(self.varcost[i][j] * self.vship[i][j] \ 132 | for i in range(self.nwarehouse) \ 133 | for j in range(self.nstore)), GRBPY.GRB.MINIMIZE) 134 | except GRBPY.GurobiError as e: 135 | print('Error code' + str(e.errno) + ': ' + str(e)) 136 | except AttributeError as e: 137 | print('Encountered an attribute error: ' + str(e)) 138 | 139 | def solve(self): 140 | # build 'master' and 'sub' 141 | self.build() 142 | 143 | # register callback 144 | self.master._iter = 0 145 | self.master._nwarehouse = self.nwarehouse 146 | self.master._nstore = self.nstore 147 | self.master._supply = self.supply 148 | self.master._demand = self.demand 149 | 150 | self.master._csupply = self.csupply 151 | self.master._cdemand = self.cdemand 152 | self.master._vmbuild = self.vmbuild 153 | self.master._maxshipcost = self.maxshipcost 154 | 155 | self.master._sub = self.sub 156 | 157 | # optimize master problem 158 | print(" *** Benders Decomposition Loop *** ") 159 | self.master.optimize(cbwarehouse) 160 | print(" *** End Loop *** ") 161 | 162 | # it seems that 64-bit needs this extra work 163 | for i in range(self.nwarehouse): 164 | self.csupply[i].rhs = self.vmbuild[i].x * self.supply[i] 165 | 166 | self.sub.optimize() 167 | 168 | def report(self): 169 | print(" *** Summary Report *** ") 170 | print("Objective: %.6f" % self.master.objval) 171 | print("Variables:") 172 | for i in range(self.nwarehouse): 173 | if abs(self.vmbuild[i].x) > 1e-6: 174 | print(" Build[%d] = %.0f" % (i, self.vmbuild[i].x)) 175 | 176 | for i in range(self.nwarehouse): 177 | for j in range(self.nstore): 178 | if abs(self.vship[i][j].x) > 1e-6: 179 | print(" Ship[%d][%d] = %.6f" % (i, j, self.vship[i][j].x)) 180 | 181 | if __name__ == "__main__": 182 | warehouse = WareHouse() 183 | warehouse.read("warehouse.dat") 184 | warehouse.solve() 185 | warehouse.report() -------------------------------------------------------------------------------- /gurobi/warehouse/warehouse2.cpp: -------------------------------------------------------------------------------- 1 | #include "gurobi_c++.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class warehousebenders: public GRBCallback { 11 | public: 12 | // models 13 | GRBModel master; 14 | GRBModel sub; 15 | 16 | // variables in master problem 17 | GRBVar *mbuild; 18 | GRBVar maxshipcost; 19 | 20 | // variables and constraints in subproblem 21 | GRBVar **ship; 22 | GRBConstr *consupply; 23 | GRBConstr *condemand; 24 | 25 | // data to build model 26 | size_t nwarehouse; 27 | size_t nstore; 28 | 29 | double *supply; 30 | double *demand; 31 | double *fixcost; 32 | 33 | double **varcost; 34 | 35 | // lazycut to be added 36 | GRBLinExpr lazycut; 37 | 38 | // iteration count 39 | size_t iter; 40 | 41 | warehousebenders(GRBEnv &env) : iter(0), master(GRBModel(env)), sub(GRBModel(env)) {} 42 | 43 | ~warehousebenders() { 44 | // deallocate heap memory 45 | for (size_t i = 0; i < nwarehouse; ++i) 46 | delete [] ship[i]; 47 | delete [] ship; 48 | 49 | delete [] mbuild; 50 | delete [] consupply; 51 | delete [] condemand; 52 | 53 | for (size_t i = 0; i < nwarehouse; ++i) 54 | delete [] varcost[i]; 55 | delete [] varcost; 56 | 57 | delete [] fixcost; 58 | delete [] demand; 59 | delete [] supply; 60 | } 61 | 62 | void read(const char *name) { 63 | // input data 64 | std::ifstream data; 65 | 66 | data.open(name, std::ifstream::in); 67 | 68 | data >> nwarehouse; 69 | data >> nstore; 70 | 71 | supply = new double [nwarehouse]; 72 | demand = new double [nstore]; 73 | fixcost = new double [nwarehouse]; 74 | 75 | varcost = new double *[nwarehouse]; 76 | for (size_t i = 0; i < nwarehouse; ++i) 77 | varcost[i] = new double [nstore]; 78 | 79 | for (size_t i = 0; i < nwarehouse; ++i) 80 | data >> supply[i]; 81 | 82 | for (size_t i = 0; i < nstore; ++i) 83 | data >> demand[i]; 84 | 85 | for (size_t i = 0; i < nwarehouse; ++i) 86 | data >> fixcost[i]; 87 | 88 | for (size_t i = 0; i < nwarehouse; ++i) 89 | for (size_t j = 0; j < nstore; ++j) 90 | data >> varcost[i][j]; 91 | 92 | data.close(); 93 | // end data 94 | } 95 | 96 | void build() { 97 | // variables in master problem 98 | mbuild = new GRBVar [nwarehouse]; 99 | 100 | // variables and constraints in subproblem 101 | ship = new GRBVar *[nwarehouse]; 102 | for (size_t i = 0; i < nwarehouse; ++i) 103 | ship[i] = new GRBVar [nstore]; 104 | 105 | consupply = new GRBConstr [nwarehouse]; 106 | condemand = new GRBConstr [nstore]; 107 | 108 | // disable log information 109 | master.set(GRB_IntParam_OutputFlag, 0); 110 | sub.set(GRB_IntParam_OutputFlag, 0); 111 | 112 | // use lazy constraints 113 | master.set(GRB_IntParam_LazyConstraints, 1); 114 | 115 | // disable presolving in subproblem 116 | sub.set(GRB_IntParam_Presolve, 0); 117 | 118 | // required to obtain farkas dual 119 | sub.set(GRB_IntParam_InfUnbdInfo, 1); 120 | 121 | // use dual simplex 122 | sub.set(GRB_IntParam_Method, 1); 123 | 124 | // construct master problem 125 | for (size_t i = 0; i < nwarehouse; ++i) 126 | mbuild[i] = master.addVar(0.0, 1.0, 0.0, GRB_BINARY, "mbuild_" + to_string(i)); 127 | 128 | maxshipcost = master.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "maxshipcost"); 129 | 130 | GRBLinExpr obj_totalcost = 0.0; 131 | for (size_t i = 0; i < nwarehouse; ++i) 132 | obj_totalcost += fixcost[i] * mbuild[i]; 133 | 134 | master.setObjective(obj_totalcost + maxshipcost, GRB_MINIMIZE); 135 | 136 | // construct subproblem 137 | for (size_t i = 0; i < nwarehouse; ++i) 138 | for (size_t j = 0; j < nstore; ++j) 139 | ship[i][j] = sub.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "ship_" + to_string(i) + "_" + to_string(j)); 140 | 141 | GRBLinExpr con_supply = 0.0; 142 | for (size_t i = 0; i < nwarehouse; ++i) { 143 | for (size_t j = 0; j < nstore; ++j) 144 | con_supply += ship[i][j]; 145 | 146 | consupply[i] = sub.addConstr(con_supply <= supply[i] * 1.0, "supply_" + to_string(i)); 147 | con_supply = 0.0; 148 | } 149 | 150 | GRBLinExpr con_demand = 0.0; 151 | for (size_t j = 0; j < nstore; ++j) { 152 | for (size_t i = 0; i < nwarehouse; ++i) 153 | con_demand += ship[i][j]; 154 | 155 | condemand[j] = sub.addConstr(con_demand == demand[j], "demand_" + to_string(j)); 156 | con_demand = 0.0; 157 | } 158 | 159 | GRBLinExpr obj_shipcost = 0.0; 160 | for (size_t i = 0; i < nwarehouse; ++i) 161 | for (size_t j = 0; j < nstore; ++j) 162 | obj_shipcost += varcost[i][j] * ship[i][j]; 163 | 164 | sub.setObjective(obj_shipcost, GRB_MINIMIZE); 165 | } 166 | 167 | void run() { 168 | // build master and sub 169 | build(); 170 | 171 | // register callback 172 | master.setCallback(this); 173 | 174 | // optimize master 175 | cout << " *** Benders Decomposition Loop *** " << endl; 176 | master.optimize(); 177 | cout << " *** End Loop *** " << endl; 178 | 179 | // it seems that 64-bit needs this extra work 180 | for (size_t i = 0; i < nwarehouse; ++i) 181 | consupply[i].set(GRB_DoubleAttr_RHS, mbuild[i].get(GRB_DoubleAttr_X) * supply[i]); 182 | 183 | sub.optimize(); 184 | } 185 | 186 | void solution() { 187 | // display solution 188 | cout << endl; 189 | cout << " *** Summary Report *** " << endl; 190 | printf("Objective: %.6f\n", master.get(GRB_DoubleAttr_ObjVal)); 191 | cout << endl; 192 | cout << "Variables:: " << endl; 193 | for (size_t i = 0; i < nwarehouse; ++i) { 194 | if (fabs(mbuild[i].get(GRB_DoubleAttr_X)) > 1e-6) 195 | printf(" Build[%d] = %.0f\n", i, mbuild[i].get(GRB_DoubleAttr_X)); 196 | } 197 | cout << endl; 198 | 199 | for (size_t i = 0; i < nwarehouse; ++i) { 200 | for (size_t j = 0; j < nstore; ++j) { 201 | if (fabs(ship[i][j].get(GRB_DoubleAttr_X)) > 1e-6) 202 | printf(" Ship[%d][%d] = %.6f\n", i, j, ship[i][j].get(GRB_DoubleAttr_X)); 203 | } 204 | } 205 | cout << endl; 206 | } 207 | 208 | protected: 209 | void callback() { 210 | try { 211 | if (where == GRB_CB_MIPSOL) { 212 | if (iter >= 1) { 213 | for (size_t i = 0; i < nwarehouse; ++i) 214 | consupply[i].set(GRB_DoubleAttr_RHS, getSolution(mbuild[i]) * supply[i]); 215 | } 216 | 217 | sub.optimize(); 218 | 219 | if (sub.get(GRB_IntAttr_Status) == GRB_INFEASIBLE) { 220 | cout << "Iteration: " << iter << endl; 221 | cout << "Adding feasibility cut..." << endl; 222 | cout << endl; 223 | 224 | lazycut = 0.0; 225 | 226 | for (size_t i = 0; i < nwarehouse; ++i) 227 | lazycut += consupply[i].get(GRB_DoubleAttr_FarkasDual) * supply[i] * mbuild[i]; 228 | 229 | for (size_t i = 0; i < nstore; ++i) 230 | lazycut += condemand[i].get(GRB_DoubleAttr_FarkasDual) * demand[i]; 231 | 232 | addLazy(lazycut >= 0); 233 | 234 | ++iter; 235 | } 236 | else if (sub.get(GRB_IntAttr_Status) == GRB_OPTIMAL) { 237 | if (sub.get(GRB_DoubleAttr_ObjVal) > getSolution(maxshipcost) + 1e-6) { 238 | cout << "Iteration: " << iter << endl; 239 | cout << "Adding optimality cut..." << endl; 240 | cout << endl; 241 | 242 | lazycut = 0.0; 243 | 244 | for (size_t i = 0; i < nwarehouse; ++i) 245 | lazycut += consupply[i].get(GRB_DoubleAttr_Pi) * supply[i] * mbuild[i]; 246 | 247 | for (size_t i = 0; i < nstore; ++i) 248 | lazycut += condemand[i].get(GRB_DoubleAttr_Pi) * demand[i]; 249 | 250 | addLazy(maxshipcost >= lazycut); 251 | 252 | ++iter; 253 | } 254 | } 255 | else 256 | abort(); 257 | } 258 | } 259 | catch (GRBException e) { 260 | cout << "Error number: " << e.getErrorCode() << endl; 261 | cout << e.getMessage() << endl; 262 | } 263 | catch (...) { 264 | cout << "Error during callback" << endl; 265 | } 266 | } 267 | }; 268 | 269 | int main(int argc, char *argv[]) { 270 | GRBEnv env = GRBEnv(); 271 | 272 | warehousebenders warehouse = warehousebenders(env); 273 | 274 | warehouse.read("warehouse.dat"); 275 | 276 | warehouse.run(); 277 | 278 | warehouse.solution(); 279 | 280 | return 0; 281 | } -------------------------------------------------------------------------------- /lindoapi/circle/Makefile: -------------------------------------------------------------------------------- 1 | # change if necessary 2 | PRB_NAME = circle 3 | LINDOAPI_VERSION = 11 4 | # end change 5 | 6 | CC = cl 7 | CFLAGS = /nologo /MT /Ox /EHsc /DNDEBUG /D_LINDO_DLL_ 8 | 9 | LD = link 10 | LDFALGS = /nologo 11 | 12 | INCL = -I"$(LINDOAPI_HOME)include" 13 | 14 | LIBS = -libpath:"$(LINDOAPI_HOME)lib\win32" lindo$(LINDOAPI_VERSION)_0.lib 15 | 16 | PRB_OBJS = $(PRB_NAME).obj 17 | PRB_TARGET = $(PRB_NAME).exe 18 | 19 | all: $(PRB_TARGET) 20 | 21 | $(PRB_TARGET): $(PRB_OBJS) 22 | $(LD) $(LDFALGS) -out:$@ $** $(LIBS) 23 | 24 | .c.obj: 25 | $(CC) $(CFLAGS) $(INCL) -c $< 26 | 27 | clean: 28 | @del /s /q $(PRB_OBJS) $(PRB_TARGET) > nul -------------------------------------------------------------------------------- /lindoapi/circle/README.md: -------------------------------------------------------------------------------- 1 | ## Brief Introduction 2 | 3 | **Tools** 4 | - [`Lindo API`](http://www.lindo.com) 5 | 6 | **Version**: 11.0 7 | 8 | **Files** 9 | - circle.c: Implementation for `circle.lng` using [`C API`](http://www.lindo.com/downloads/PDF/API.pdf) with `Multistart Optimizer` 10 | - Makefile: NMake makefile 11 | 12 | **Contact** 13 | - `wujianjack2@163.com` (personal) 14 | - `wujianw@stu.xjtu.edu.cn` (educational) 15 | 16 | **Wu Jian** 17 | 18 | `July 16th, 2017` -------------------------------------------------------------------------------- /lindoapi/circle/circle.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "lindo.h" 7 | 8 | #define APIERRORCHECK \ 9 | if (nErrorCode) { \ 10 | if (pEnv) { \ 11 | LSgetErrorMessage(pEnv, nErrorCode, cErrorMessage); \ 12 | printf("Errorcode = %d: %s\n", nErrorCode, cErrorMessage); \ 13 | } else \ 14 | printf("Fatal Error\n"); \ 15 | \ 16 | exit(1); \ 17 | } 18 | 19 | int ntotal = 5; 20 | double rtotal = 5.0; 21 | 22 | static void LS_CALLTYPE getLogInfo(pLSmodel pModel, char *line, void *userdata) { 23 | if (line) printf("%s", line); 24 | } 25 | 26 | int loadModel(pLSmodel pModel) { 27 | int nObjs = 1; 28 | int *panObjSense = (int *) malloc(nObjs * sizeof(int)); 29 | int *paiObj = (int *) malloc(nObjs * sizeof(int)); 30 | int *panObj = (int *) malloc(nObjs * sizeof(int)); 31 | 32 | int nCons = ntotal * (ntotal - 1) / 2 + 5 * ntotal; 33 | char *pacConType = (char *) malloc(nCons * sizeof(char)); 34 | int *paiRows = (int *) malloc(nCons * sizeof(int)); 35 | int *panRows = (int *) malloc(nCons * sizeof(int)); 36 | 37 | int nVars = 2 * ntotal + 1; 38 | char *pacVarType = (char *) malloc(nVars * sizeof(char)); 39 | int *paiVars = NULL; 40 | double *padX0 = (double *) malloc(nVars * sizeof(double)); 41 | double *padL = (double *) malloc(nVars * sizeof(double)); 42 | double *padU = (double *) malloc(nVars * sizeof(double)); 43 | 44 | int nNums = 3; 45 | double *padVals = (double *) malloc(nNums * sizeof(double)); 46 | 47 | int nCode = 10000; 48 | int *panCode = (int *) malloc(nCode * sizeof(int)); 49 | 50 | int i, j, nErrorCode; 51 | int ikod = 0, iobj = 0, icon = 0; 52 | 53 | for (i = 0; i < nVars; i++) { 54 | if (i == nVars - 1) { 55 | padL[i] = 0.0; 56 | padU[i] = rtotal; 57 | } else { 58 | padL[i] = -rtotal; 59 | padU[i] = rtotal; 60 | } 61 | 62 | padX0[i] = 0.00000; 63 | pacVarType[i] = 'C'; 64 | } 65 | 66 | // 67 | padVals[0] = 2.0; 68 | padVals[1] = 4.0; 69 | padVals[2] = rtotal; 70 | // 71 | 72 | /********************* 73 | variable name vs index 74 | * 0 ~ ntotal-1 X 75 | * ntotal ~ 2*ntotal - 1 Y 76 | * 2*ntotal R 77 | **********************/ 78 | 79 | // MAX R 80 | panObjSense[iobj] = LS_MAX; 81 | paiObj[iobj] = ikod; 82 | panCode[ikod++] = EP_PUSH_VAR; 83 | panCode[ikod++] = nVars - 1; 84 | panObj[iobj] = ikod - paiObj[iobj]; 85 | iobj++; 86 | 87 | // @FOR(DIM(I): @FOR(DIM(J)| J #GT# I: (X(I) - X(J))^2 + (Y(I) - Y(J))^2 >= 4*R^2)); 88 | for (i = 0; i < ntotal; i++) { 89 | for (j = 0; j < ntotal; j++) { 90 | if (j > i) { 91 | pacConType[icon] = 'G'; 92 | paiRows[icon] = ikod; 93 | panCode[ikod++] = EP_PUSH_VAR; 94 | panCode[ikod++] = i; 95 | panCode[ikod++] = EP_PUSH_VAR; 96 | panCode[ikod++] = j; 97 | panCode[ikod++] = EP_MINUS; 98 | panCode[ikod++] = EP_PUSH_NUM; 99 | panCode[ikod++] = 0; 100 | panCode[ikod++] = EP_POWER; 101 | panCode[ikod++] = EP_PUSH_VAR; 102 | panCode[ikod++] = i + ntotal; 103 | panCode[ikod++] = EP_PUSH_VAR; 104 | panCode[ikod++] = j + ntotal; 105 | panCode[ikod++] = EP_MINUS; 106 | panCode[ikod++] = EP_PUSH_NUM; 107 | panCode[ikod++] = 0; 108 | panCode[ikod++] = EP_POWER; 109 | panCode[ikod++] = EP_PLUS; 110 | panCode[ikod++] = EP_PUSH_NUM; 111 | panCode[ikod++] = 1; 112 | panCode[ikod++] = EP_PUSH_VAR; 113 | panCode[ikod++] = nVars - 1; 114 | panCode[ikod++] = EP_PUSH_NUM; 115 | panCode[ikod++] = 0; 116 | panCode[ikod++] = EP_POWER; 117 | panCode[ikod++] = EP_MULTIPLY; 118 | panCode[ikod++] = EP_MINUS; 119 | panRows[icon] = ikod - paiRows[icon]; 120 | icon++; 121 | } 122 | } 123 | } 124 | 125 | // @FOR(DIM(I): X(I)^2 + Y(I)^2 <= (C - R)^2); 126 | for (i = 0; i < ntotal; i++) { 127 | pacConType[icon] = 'L'; 128 | paiRows[icon] = ikod; 129 | panCode[ikod++] = EP_PUSH_VAR; 130 | panCode[ikod++] = i; 131 | panCode[ikod++] = EP_PUSH_NUM; 132 | panCode[ikod++] = 0; 133 | panCode[ikod++] = EP_POWER; 134 | panCode[ikod++] = EP_PUSH_VAR; 135 | panCode[ikod++] = i + ntotal; 136 | panCode[ikod++] = EP_PUSH_NUM; 137 | panCode[ikod++] = 0; 138 | panCode[ikod++] = EP_POWER; 139 | panCode[ikod++] = EP_PLUS; 140 | panCode[ikod++] = EP_PUSH_NUM; 141 | panCode[ikod++] = 2; 142 | panCode[ikod++] = EP_PUSH_VAR; 143 | panCode[ikod++] = nVars - 1; 144 | panCode[ikod++] = EP_MINUS; 145 | panCode[ikod++] = EP_PUSH_NUM; 146 | panCode[ikod++] = 0; 147 | panCode[ikod++] = EP_POWER; 148 | panCode[ikod++] = EP_MINUS; 149 | panRows[icon] = ikod - paiRows[icon]; 150 | icon++; 151 | } 152 | 153 | // @FOR(DIM(I): X(I) >= R - C; X(I) <= C - R); 154 | for (i = 0; i < ntotal; i++) { 155 | pacConType[icon] = 'G'; 156 | paiRows[icon] = ikod; 157 | panCode[ikod++] = EP_PUSH_VAR; 158 | panCode[ikod++] = i; 159 | panCode[ikod++] = EP_PUSH_VAR; 160 | panCode[ikod++] = nVars - 1; 161 | panCode[ikod++] = EP_MINUS; 162 | panCode[ikod++] = EP_PUSH_NUM; 163 | panCode[ikod++] = 1; 164 | panCode[ikod++] = EP_PLUS; 165 | panRows[icon] = ikod - paiRows[icon]; 166 | icon++; 167 | } 168 | 169 | for (i = 0; i < ntotal; i++) { 170 | pacConType[icon] = 'L'; 171 | paiRows[icon] = ikod; 172 | panCode[ikod++] = EP_PUSH_VAR; 173 | panCode[ikod++] = i; 174 | panCode[ikod++] = EP_PUSH_VAR; 175 | panCode[ikod++] = nVars - 1; 176 | panCode[ikod++] = EP_PLUS; 177 | panCode[ikod++] = EP_PUSH_NUM; 178 | panCode[ikod++] = 1; 179 | panCode[ikod++] = EP_MINUS; 180 | panRows[icon] = ikod - paiRows[icon]; 181 | icon++; 182 | } 183 | 184 | // @FOR(DIM(I): Y(I) >= R - C; Y(I) <= C - R); 185 | for (i = 0; i < ntotal; i++) { 186 | pacConType[icon] = 'G'; 187 | paiRows[icon] = ikod; 188 | panCode[ikod++] = EP_PUSH_VAR; 189 | panCode[ikod++] = i + ntotal; 190 | panCode[ikod++] = EP_PUSH_VAR; 191 | panCode[ikod++] = nVars - 1; 192 | panCode[ikod++] = EP_MINUS; 193 | panCode[ikod++] = EP_PUSH_NUM; 194 | panCode[ikod++] = 1; 195 | panCode[ikod++] = EP_PLUS; 196 | panRows[icon] = ikod - paiRows[icon]; 197 | icon++; 198 | } 199 | 200 | for (i = 0; i < ntotal; i++) { 201 | pacConType[icon] = 'L'; 202 | paiRows[icon] = ikod; 203 | panCode[ikod++] = EP_PUSH_VAR; 204 | panCode[ikod++] = i + ntotal; 205 | panCode[ikod++] = EP_PUSH_VAR; 206 | panCode[ikod++] = nVars - 1; 207 | panCode[ikod++] = EP_PLUS; 208 | panCode[ikod++] = EP_PUSH_NUM; 209 | panCode[ikod++] = 1; 210 | panCode[ikod++] = EP_MINUS; 211 | panRows[icon] = ikod - paiRows[icon]; 212 | icon++; 213 | } 214 | 215 | nCode = ikod; 216 | 217 | nErrorCode = LSloadInstruct(pModel, nCons, nObjs, nVars, nNums, panObjSense, 218 | pacConType, pacVarType, panCode, nCode, paiVars, padVals, 219 | padX0, paiObj, panObj, paiRows, panRows, padL, padU); 220 | 221 | free(panObjSense); 222 | free(paiObj); 223 | free(panObj); 224 | 225 | free(pacConType); 226 | free(paiRows); 227 | free(panRows); 228 | 229 | free(pacVarType); 230 | // free(paiVars); 231 | free(padX0); 232 | free(padL); 233 | free(padU); 234 | 235 | free(padVals); 236 | 237 | free(panCode); 238 | 239 | return nErrorCode; 240 | } 241 | 242 | int main(int argc, char *argv[]) { 243 | int nErrorCode; 244 | char cErrorMessage[LS_MAX_ERROR_MESSAGE_LENGTH]; 245 | 246 | pLSenv pEnv; 247 | pLSmodel pModel; 248 | 249 | pEnv = LScreateEnv(&nErrorCode, NULL); 250 | if (nErrorCode == LSERR_NO_VALID_LICENSE) { 251 | printf("Invalid License Key!\n"); 252 | exit(1); 253 | } 254 | APIERRORCHECK; 255 | 256 | pModel = LScreateModel(pEnv, &nErrorCode); 257 | APIERRORCHECK; 258 | 259 | nErrorCode = loadModel(pModel); 260 | APIERRORCHECK; 261 | 262 | nErrorCode = LSsetModelLogfunc(pModel, (printModelLOG_t)getLogInfo, NULL); 263 | APIERRORCHECK; 264 | nErrorCode = LSsetModelIntParameter(pModel, LS_IPARAM_NLP_AUTODERIV, 1); 265 | APIERRORCHECK; 266 | nErrorCode = LSsetModelIntParameter(pModel, LS_IPARAM_NLP_PRINTLEVEL, 1); 267 | APIERRORCHECK; 268 | nErrorCode = LSsetModelIntParameter(pModel, LS_IPARAM_GOP_PRINTLEVEL, 1); 269 | APIERRORCHECK; 270 | // nErrorCode = LSsetModelIntParameter(pModel, LS_IPARAM_GOP_TIMLIM, 100); 271 | // APIERRORCHECK; 272 | 273 | nErrorCode = LSsetModelIntParameter(pModel, LS_IPARAM_NLP_SOLVER, LS_NMETHOD_MSW_GRG); 274 | APIERRORCHECK; 275 | nErrorCode = LSoptimize(pModel, LS_METHOD_FREE, NULL); 276 | APIERRORCHECK; 277 | 278 | // nErrorCode = LSsolveGOP(pModel, NULL); 279 | // APIERRORCHECK; 280 | 281 | printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); 282 | { 283 | int i, nVars, nCons, nStatus; 284 | double pObjVal; 285 | double *primalSol; 286 | 287 | nErrorCode = LSgetInfo(pModel, LS_IINFO_MODEL_STATUS, &nStatus); 288 | APIERRORCHECK; 289 | 290 | if (nStatus == LS_STATUS_OPTIMAL || nStatus == LS_STATUS_BASIC_OPTIMAL || 291 | nStatus == LS_STATUS_LOCAL_OPTIMAL || nStatus == LS_STATUS_FEASIBLE) { 292 | nErrorCode = LSgetInfo(pModel, LS_IINFO_NUM_VARS, &nVars); 293 | APIERRORCHECK; 294 | nErrorCode = LSgetInfo(pModel, LS_IINFO_NUM_CONS, &nCons); 295 | APIERRORCHECK; 296 | nErrorCode = LSgetInfo(pModel, LS_DINFO_POBJ, &pObjVal); 297 | APIERRORCHECK; 298 | 299 | primalSol = (double *)malloc(nVars * sizeof(double)); 300 | nErrorCode = LSgetPrimalSolution(pModel, primalSol); 301 | APIERRORCHECK; 302 | 303 | printf("\n\t *** Solution Report *** \n"); 304 | printf("Objective value: \n %.12f\n", pObjVal); 305 | 306 | printf("\nVariables: \n"); 307 | for (i = 0; i < nVars; i++) 308 | printf(" x[%d] = %.12f\n", i, primalSol[i]); 309 | 310 | free(primalSol); 311 | } else if (nStatus == LS_STATUS_INFEASIBLE) 312 | printf("\n\nNo feasible solution.\n"); 313 | } 314 | 315 | nErrorCode = LSdeleteModel(&pModel); 316 | APIERRORCHECK; 317 | 318 | nErrorCode = LSdeleteEnv(&pEnv); 319 | APIERRORCHECK; 320 | 321 | return 0; 322 | } -------------------------------------------------------------------------------- /lindoapi/circle/circle.lng: -------------------------------------------------------------------------------- 1 | MODEL: 2 | 3 | SETS: 4 | DIM: X, Y; 5 | ENDSETS 6 | 7 | DATA: 8 | DIM = 1..5; 9 | C = 5; 10 | ENDDATA 11 | 12 | MAX = R; 13 | 14 | @FOR(DIM(I): @FOR(DIM(J)| J #GT# I: (X(I) - X(J))^2 + (Y(I) - Y(J))^2 >= 4*R^2)); 15 | 16 | @FOR(DIM(I): X(I)^2 + Y(I)^2 <= (C - R)^2); 17 | 18 | @FOR(DIM(I): X(I) >= R - C; X(I) <= C - R); 19 | @FOR(DIM(I): Y(I) >= R - C; Y(I) <= C - R); 20 | 21 | @FOR(DIM(I): @BND(-C, X(I), C); @BND(-C, Y(I), C)); 22 | @BND(0, R, C); 23 | 24 | END 25 | -------------------------------------------------------------------------------- /lindoapi/peak/Makefile: -------------------------------------------------------------------------------- 1 | # change if necessary 2 | PRB_NAME = peak 3 | LINDOAPI_VERSION = 11 4 | # end change 5 | 6 | CC = cl 7 | CFLAGS = /nologo /MT /Ox /EHsc /DNDEBUG /D_LINDO_DLL_ 8 | 9 | LD = link 10 | LDFALGS = /nologo 11 | 12 | INCL = -I"$(LINDOAPI_HOME)include" 13 | 14 | LIBS = -libpath:"$(LINDOAPI_HOME)lib\win32" lindo$(LINDOAPI_VERSION)_0.lib 15 | 16 | PRB_OBJS = $(PRB_NAME).obj 17 | PRB_TARGET = $(PRB_NAME).exe 18 | 19 | all: $(PRB_TARGET) 20 | 21 | $(PRB_TARGET): $(PRB_OBJS) 22 | $(LD) $(LDFALGS) -out:$@ $** $(LIBS) 23 | 24 | .c.obj: 25 | $(CC) $(CFLAGS) $(INCL) -c $< 26 | 27 | clean: 28 | @del /s /q $(PRB_OBJS) $(PRB_TARGET) > nul -------------------------------------------------------------------------------- /lindoapi/peak/README.md: -------------------------------------------------------------------------------- 1 | ## Brief Introduction 2 | 3 | **Tools** 4 | - [`Lindo API`](http://www.lindo.com) 5 | 6 | **Version**: 11.0 7 | 8 | **Files** 9 | - peak.c: Implementation for `peak.lng` using [`C API`](http://www.lindo.com/downloads/PDF/API.pdf) with `Local/Global Optimizer` 10 | - Makefile: NMake makefile 11 | 12 | **Contact** 13 | - `wujianjack2@163.com` (personal) 14 | - `wujianw@stu.xjtu.edu.cn` (educational) 15 | 16 | **Wu Jian** 17 | 18 | `July 15th, 2017` -------------------------------------------------------------------------------- /lindoapi/peak/peak.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "lindo.h" 7 | 8 | #define APIERRORCHECK \ 9 | if (nErrorCode) { \ 10 | if (pEnv) { \ 11 | LSgetErrorMessage(pEnv, nErrorCode, cErrorMessage); \ 12 | printf("Errorcode = %d: %s\n", nErrorCode, cErrorMessage); \ 13 | } else \ 14 | printf("Fatal Error\n"); \ 15 | \ 16 | exit(1); \ 17 | } 18 | 19 | int main(int argc, char *argv[]) { 20 | int nErrorCode; 21 | char cErrorMessage[LS_MAX_ERROR_MESSAGE_LENGTH]; 22 | 23 | pLSenv pEnv; 24 | pLSmodel pModel; 25 | 26 | pEnv = LScreateEnv(&nErrorCode, NULL); 27 | if (nErrorCode == LSERR_NO_VALID_LICENSE) { 28 | printf("Invalid License Key!\n"); 29 | exit(1); 30 | } 31 | APIERRORCHECK; 32 | 33 | pModel = LScreateModel(pEnv, &nErrorCode); 34 | APIERRORCHECK; 35 | 36 | { // Problem Setting Block 37 | /* Number of objectives */ 38 | int nobjs = 1; 39 | int *objsense = (int *) malloc(nobjs * sizeof(int)); 40 | int *objs_beg = (int *) malloc(nobjs * sizeof(int)); 41 | int *objs_length = (int *) malloc(nobjs * sizeof(int)); 42 | 43 | /* Number of constraints */ 44 | int ncons = 1; 45 | char *ctype = (char *) malloc(ncons * sizeof(char)); 46 | int *cons_beg = (int *) malloc(ncons * sizeof(int)); 47 | int *cons_length = (int *) malloc(ncons * sizeof(int)); 48 | 49 | /* Number of variables */ 50 | int nvars = 3; 51 | char *vtype = (char *) malloc(nvars * sizeof(char)); 52 | double *varval = (double *) malloc(nvars * sizeof(double)); 53 | double *lwrbnd = (double *) malloc(nvars * sizeof(double)); 54 | double *uprbnd = (double *) malloc(nvars * sizeof(double)); 55 | 56 | /* Number of real number constants */ 57 | int nnums = 3; 58 | double *numval = (double *) malloc(nnums * sizeof(double)); 59 | 60 | /* Number of items in the instruction lists */ 61 | int lsize = 29; 62 | int *code = (int *) malloc(lsize * sizeof(int)); 63 | 64 | /* Count for instruction code */ 65 | int ikod = 0; 66 | /* Count for objective row */ 67 | int iobj = 0; 68 | /* Count for constraint row */ 69 | int icon = 0; 70 | 71 | int i; 72 | int nLinearz, nAutoDeriv, nConvexRelax, nCRAlgReform; 73 | 74 | /* Numerical constants in model */ 75 | numval[0] = 1.0; 76 | numval[1] = 50.0; 77 | numval[2] = exp(1.0); 78 | 79 | /* Lower & upper bounds of variables */ 80 | for (i = 0; i < nvars; ++i) { 81 | if (i == nvars - 1) { 82 | lwrbnd[i] = numval[2]; 83 | uprbnd[i] = 1e20; 84 | } else { 85 | lwrbnd[i] = 0.0; 86 | uprbnd[i] = 100.0; 87 | } 88 | } 89 | 90 | /* Starting point of variables */ 91 | for (i = 0; i < nvars; ++i) varval[i] = 1.234567; 92 | 93 | /* Variable type, C = continuous, B = binary */ 94 | for (i = 0; i < nvars; ++i) vtype[i] = 'C'; 95 | 96 | /* 97 | * Instruction code of the objective: 98 | * max sin(x[2]) / x[2] + 1; 99 | */ 100 | 101 | /* Direction of optimization */ 102 | objsense[iobj] = LS_MAX; 103 | /* Beginning position of objective */ 104 | objs_beg[iobj] = ikod; 105 | /* Instruction list code */ 106 | code[ikod++] = EP_PUSH_VAR; 107 | code[ikod++] = 2; 108 | code[ikod++] = EP_SIN; 109 | code[ikod++] = EP_PUSH_VAR; 110 | code[ikod++] = 2; 111 | code[ikod++] = EP_DIVIDE; 112 | code[ikod++] = EP_PUSH_NUM; 113 | code[ikod++] = 0; 114 | code[ikod++] = EP_PLUS; 115 | 116 | /* Length of objective */ 117 | objs_length[iobj] = ikod - objs_beg[iobj]; 118 | /* Increment the objective count */ 119 | iobj++; 120 | 121 | /* 122 | * Instruction code of constraint 0: 123 | * x[2] - sqrt(sqr(x[0] - 50.0) + sqr(x[1] - 50)) - exp(1) = 0; 124 | */ 125 | 126 | /* Constraint type */ 127 | ctype[icon] = 'E'; /* less or than or equal to */ 128 | /* Beginning position of constraint 0 */ 129 | cons_beg[icon] = ikod; 130 | /* Instruction list code */ 131 | code[ikod++] = EP_PUSH_VAR; 132 | code[ikod++] = 2; 133 | code[ikod++] = EP_PUSH_VAR; 134 | code[ikod++] = 0; 135 | code[ikod++] = EP_PUSH_NUM; 136 | code[ikod++] = 1; 137 | code[ikod++] = EP_MINUS; 138 | code[ikod++] = EP_SQR; 139 | code[ikod++] = EP_PUSH_VAR; 140 | code[ikod++] = 1; 141 | code[ikod++] = EP_PUSH_NUM; 142 | code[ikod++] = 1; 143 | code[ikod++] = EP_MINUS; 144 | code[ikod++] = EP_SQR; 145 | code[ikod++] = EP_PLUS; 146 | code[ikod++] = EP_SQRT; 147 | code[ikod++] = EP_MINUS; 148 | code[ikod++] = EP_PUSH_NUM; 149 | code[ikod++] = 2; 150 | code[ikod++] = EP_MINUS; 151 | 152 | /* Length of constraint 0 */ 153 | cons_length[icon] = ikod - cons_beg[icon]; 154 | /* Increment the constraint count */ 155 | icon++; 156 | 157 | /* Total number of items in the instruction list */ 158 | lsize = ikod; 159 | 160 | /* Set linearization level, before a call to LSloadNLPCode. 161 | * If not specified, the solver will decide */ 162 | nLinearz = 1; 163 | nErrorCode = LSsetModelIntParameter(pModel, LS_IPARAM_NLP_LINEARZ, nLinearz); 164 | APIERRORCHECK; 165 | 166 | /* Select algebraic reformulation level in convex relaxation*/ 167 | nCRAlgReform = 1; 168 | nErrorCode = LSsetModelIntParameter(pModel, LS_IPARAM_NLP_CR_ALG_REFORM, nCRAlgReform); 169 | APIERRORCHECK; 170 | 171 | /* Select convex relax level */ 172 | nConvexRelax = 0; 173 | nErrorCode = LSsetModelIntParameter(pModel, LS_IPARAM_NLP_CONVEXRELAX, nConvexRelax); 174 | APIERRORCHECK; 175 | 176 | /* Set up automatic differentiation, before a call to LSloadNLPCode. 177 | * If not specified, the numerical derivative will be applied */ 178 | nAutoDeriv = 1; 179 | nErrorCode = LSsetModelIntParameter(pModel, LS_IPARAM_NLP_AUTODERIV, nAutoDeriv); 180 | APIERRORCHECK; 181 | 182 | /* Pass the instruction list to problem structure by a call to 183 | * LSloadNLPCode() */ 184 | nErrorCode = LSloadInstruct(pModel, ncons, nobjs, nvars, nnums, objsense, ctype, 185 | vtype, code, lsize, NULL, numval, varval, objs_beg, 186 | objs_length, cons_beg, cons_length, lwrbnd, uprbnd); 187 | APIERRORCHECK; 188 | 189 | free(objsense); 190 | free(objs_beg); 191 | free(objs_length); 192 | 193 | free(ctype); 194 | free(cons_beg); 195 | free(cons_length); 196 | 197 | free(vtype); 198 | free(varval); 199 | free(lwrbnd); 200 | free(uprbnd); 201 | 202 | free(numval); 203 | 204 | free(code); 205 | } 206 | 207 | if (argc == 2) { 208 | if (strcmp(argv[1], "-gop") == 0) { 209 | printf("Solving with 'Global Optimizer'...\n"); 210 | nErrorCode = LSsolveGOP(pModel, NULL); 211 | } else { 212 | printf("usage: peak.exe -gop\n"); 213 | exit(1); 214 | } 215 | } else { 216 | printf("Solving with 'Local Nonlinear Optimizer'...\n"); 217 | nErrorCode = LSoptimize(pModel, LS_METHOD_FREE, NULL); 218 | } 219 | APIERRORCHECK; 220 | 221 | { // Solution Report Block 222 | int i, status, nvars; 223 | double pobjval; 224 | double *primal; 225 | 226 | /* Report the status of solution */ 227 | nErrorCode = LSgetInfo(pModel, LS_IINFO_MODEL_STATUS, &status); 228 | APIERRORCHECK; 229 | 230 | /* Get the optimization result */ 231 | nErrorCode = LSgetInfo(pModel, LS_IINFO_NUM_VARS, &nvars); 232 | APIERRORCHECK; 233 | 234 | nErrorCode = LSgetInfo(pModel, LS_DINFO_POBJ, &pobjval); 235 | APIERRORCHECK; 236 | 237 | primal = (double *) malloc(nvars * sizeof(double)); 238 | nErrorCode = LSgetPrimalSolution(pModel, primal); 239 | APIERRORCHECK; 240 | 241 | if (status == LS_STATUS_OPTIMAL || status == LS_STATUS_BASIC_OPTIMAL || 242 | status == LS_STATUS_LOCAL_OPTIMAL || status == LS_STATUS_FEASIBLE) { 243 | printf("\n\t *** Solution Report *** \n"); 244 | printf("Objective value: \n %.12f\n", pobjval); 245 | 246 | printf("\nVariables: \n"); 247 | for (i = 0; i < nvars; i++) 248 | printf(" x[%d] = %.12f\n", i, primal[i]); 249 | } else if (status == LS_STATUS_INFEASIBLE) 250 | printf("\n\nNo feasible solution. \n"); 251 | 252 | free(primal); 253 | } 254 | 255 | nErrorCode = LSdeleteModel(&pModel); 256 | APIERRORCHECK; 257 | 258 | LSdeleteEnv(&pEnv); 259 | APIERRORCHECK; 260 | 261 | return 0; 262 | } -------------------------------------------------------------------------------- /lindoapi/peak/peak.lng: -------------------------------------------------------------------------------- 1 | MAX = @SIN(R) / R + 1; 2 | 3 | R = @SQRT((X - 50)^2 + (Y - 50)^2) + @EXP(1); 4 | 5 | @BND(0, X, 100); 6 | @BND(0, Y, 100); --------------------------------------------------------------------------------