Make lazy constr component compatible with Pyomo+Gurobi

dev
Alinson S. Xavier 2 years ago
parent c9eef36c4e
commit 25bbe20748

@ -38,9 +38,13 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 1,
"id": "f906fe9c",
"metadata": {
"ExecuteTime": {
"end_time": "2024-01-30T22:19:30.826123021Z",
"start_time": "2024-01-30T22:19:30.766066926Z"
},
"collapsed": false,
"jupyter": {
"outputs_hidden": false
@ -57,18 +61,18 @@
"x4 = [[0.37454012 0.9507143 0.7319939 ]\n",
" [0.5986585 0.15601864 0.15599452]\n",
" [0.05808361 0.8661761 0.601115 ]]\n",
"x5 = (2, 3)\t0.68030757\n",
" (3, 2)\t0.45049927\n",
" (4, 0)\t0.013264962\n",
" (0, 2)\t0.94220173\n",
" (4, 2)\t0.5632882\n",
" (2, 1)\t0.3854165\n",
" (1, 1)\t0.015966251\n",
" (3, 0)\t0.23089382\n",
" (4, 4)\t0.24102546\n",
" (1, 3)\t0.68326354\n",
" (3, 1)\t0.6099967\n",
" (0, 3)\t0.8331949\n"
"x5 = (3, 2)\t0.6803075671195984\n",
" (2, 3)\t0.4504992663860321\n",
" (0, 4)\t0.013264961540699005\n",
" (2, 0)\t0.9422017335891724\n",
" (2, 4)\t0.5632882118225098\n",
" (1, 2)\t0.38541650772094727\n",
" (1, 1)\t0.015966251492500305\n",
" (0, 3)\t0.2308938205242157\n",
" (4, 4)\t0.24102546274662018\n",
" (3, 1)\t0.6832635402679443\n",
" (1, 3)\t0.6099966764450073\n",
" (3, 0)\t0.83319491147995\n"
]
}
],
@ -182,6 +186,10 @@
"execution_count": 4,
"id": "ac6f8c6f",
"metadata": {
"ExecuteTime": {
"end_time": "2024-01-30T22:19:30.826707866Z",
"start_time": "2024-01-30T22:19:30.825940503Z"
},
"collapsed": false,
"jupyter": {
"outputs_hidden": false
@ -205,7 +213,7 @@
"\n",
"from miplearn.problems.tsp import (\n",
" TravelingSalesmanGenerator,\n",
" build_tsp_model,\n",
" build_tsp_model_gurobipy,\n",
")\n",
"from miplearn.io import write_pkl_gz\n",
"from miplearn.h5 import H5File\n",
@ -231,7 +239,7 @@
"# Solve all instances and collect basic solution information.\n",
"# Process at most four instances in parallel.\n",
"bc = BasicCollector()\n",
"bc.collect(glob(\"data/tsp/*.pkl.gz\"), build_tsp_model, n_jobs=4)\n",
"bc.collect(glob(\"data/tsp/*.pkl.gz\"), build_tsp_model_gurobipy, n_jobs=4)\n",
"\n",
"# Read and print some training data for the first instance.\n",
"with H5File(\"data/tsp/00000.h5\", \"r\") as h5:\n",
@ -244,6 +252,9 @@
"execution_count": null,
"id": "78f0b07a",
"metadata": {
"ExecuteTime": {
"start_time": "2024-01-30T22:19:30.826179789Z"
},
"collapsed": false,
"jupyter": {
"outputs_hidden": false
@ -269,7 +280,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
"version": "3.11.7"
}
},
"nbformat": 4,

@ -51,7 +51,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 1,
"id": "ed9a18c8",
"metadata": {
"collapsed": false,
@ -204,7 +204,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 2,
"id": "a1bc38fe",
"metadata": {
"collapsed": false,
@ -326,7 +326,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
"version": "3.11.7"
}
},
"nbformat": 4,

@ -283,7 +283,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
"version": "3.11.7"
}
},
"nbformat": 4,

@ -108,11 +108,11 @@
"execution_count": 1,
"id": "f14e560c-ef9f-4c48-8467-72d6acce5f9f",
"metadata": {
"tags": [],
"ExecuteTime": {
"end_time": "2023-11-07T16:29:48.409419720Z",
"start_time": "2023-11-07T16:29:47.824353556Z"
}
},
"tags": []
},
"outputs": [
{
@ -131,10 +131,10 @@
"9 [ 8.57 22.77 17.06 16.25 4.14 4. 1.56 22.97 14.09 19.09] 100.79\n",
"\n",
"Restricted license - for non-production use only - expires 2024-10-28\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 20 rows, 110 columns and 210 nonzeros\n",
"Model fingerprint: 0x1ff9913f\n",
@ -159,8 +159,8 @@
"H 0 0 2.0000000 1.27484 36.3% - 0s\n",
" 0 0 1.27484 0 4 2.00000 1.27484 36.3% - 0s\n",
"\n",
"Explored 1 nodes (38 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (38 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 3: 2 4 5 \n",
"\n",
@ -323,10 +323,10 @@
"capacities\n",
" [1310. 988. 1004. 1269. 1007.]\n",
"\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 5 rows, 10 columns and 50 nonzeros\n",
"Model fingerprint: 0xaf3ac15e\n",
@ -354,7 +354,7 @@
" Cover: 1\n",
"\n",
"Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 2: -1279 -804 \n",
"No other solutions better than -1279\n",
@ -498,10 +498,10 @@
"demands = [6.12 1.39 2.92 3.66 4.56 7.85 2. 5.14 5.92 0.46]\n",
"capacities = [151.89 42.63 16.26 237.22 241.41 202.1 76.15 24.42 171.06 110.04]\n",
"\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 21 rows, 110 columns and 220 nonzeros\n",
"Model fingerprint: 0x8d8d9346\n",
@ -535,8 +535,8 @@
" 0 0 86.06884 0 15 93.92000 86.06884 8.36% - 0s\n",
"* 0 0 0 91.2300000 91.23000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (70 simplex iterations) in 0.02 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (70 simplex iterations) in 0.07 seconds (0.00 work units)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 10: 91.23 93.92 93.98 ... 368.79\n",
"\n",
@ -670,10 +670,10 @@
"costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n",
" 425.33]\n",
"\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 5 rows, 10 columns and 28 nonzeros\n",
"Model fingerprint: 0xe5c2d4fa\n",
@ -688,8 +688,8 @@
"Presolve time: 0.00s\n",
"Presolve: All rows and columns removed\n",
"\n",
"Explored 0 nodes (0 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 1 (of 12 available processors)\n",
"Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 1 (of 20 available processors)\n",
"\n",
"Solution count 1: 213.49 \n",
"\n",
@ -786,10 +786,13 @@
"execution_count": 5,
"id": "cc797da7",
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2023-11-07T16:29:48.806917868Z",
"start_time": "2023-11-07T16:29:48.781619530Z"
},
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
@ -806,10 +809,10 @@
"costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n",
" 425.33]\n",
"\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 5 rows, 10 columns and 28 nonzeros\n",
"Model fingerprint: 0x4ee91388\n",
@ -824,8 +827,9 @@
"Presolve time: 0.00s\n",
"Presolve: All rows and columns removed\n",
"\n",
"Explored 0 nodes (0 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 1 (of 12 available processors)\n",
"Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 1 (of 20 available processors)\n",
"\n",
"Solution count 2: -1986.37 -1265.56 \n",
"No other solutions better than -1986.37\n",
"\n",
@ -930,10 +934,10 @@
"weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]\n",
"\n",
"Set parameter PreCrush to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 15 rows, 10 columns and 30 nonzeros\n",
"Model fingerprint: 0x3240ea4a\n",
@ -957,7 +961,7 @@
" 0 0 infeasible 0 -219.14000 -219.14000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (5 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 1: -219.14 \n",
"No other solutions better than -219.14\n",
@ -965,7 +969,7 @@
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective -2.191400000000e+02, best bound -2.191400000000e+02, gap 0.0000%\n",
"\n",
"User-callback calls 300, time in user-callback 0.00 sec\n"
"User-callback calls 299, time in user-callback 0.00 sec\n"
]
}
],
@ -975,7 +979,7 @@
"from scipy.stats import uniform, randint\n",
"from miplearn.problems.stab import (\n",
" MaxWeightStableSetGenerator,\n",
" build_stab_model,\n",
" build_stab_model_gurobipy,\n",
")\n",
"\n",
"# Set random seed to make example reproducible\n",
@ -998,7 +1002,7 @@
"print()\n",
"\n",
"# Load and optimize the first instance\n",
"model = build_stab_model(data[0])\n",
"model = build_stab_model_gurobipy(data[0])\n",
"model.optimize()"
]
},
@ -1071,10 +1075,13 @@
"execution_count": 7,
"id": "9d0c56c6",
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2023-11-07T16:29:48.958833448Z",
"start_time": "2023-11-07T16:29:48.898121017Z"
},
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
@ -1107,10 +1114,10 @@
"\n",
"Set parameter PreCrush to value 1\n",
"Set parameter LazyConstraints to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 10 rows, 45 columns and 90 nonzeros\n",
"Model fingerprint: 0x719675e5\n",
@ -1135,7 +1142,7 @@
" Lazy constraints: 3\n",
"\n",
"Explored 1 nodes (17 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 1: 2921 \n",
"\n",
@ -1150,7 +1157,10 @@
"import random\n",
"import numpy as np\n",
"from scipy.stats import uniform, randint\n",
"from miplearn.problems.tsp import TravelingSalesmanGenerator, build_tsp_model\n",
"from miplearn.problems.tsp import (\n",
" TravelingSalesmanGenerator,\n",
" build_tsp_model_gurobipy,\n",
")\n",
"\n",
"# Set random seed to make example reproducible\n",
"random.seed(42)\n",
@ -1173,7 +1183,7 @@
"print()\n",
"\n",
"# Load and optimize the first instance\n",
"model = build_tsp_model(data[0])\n",
"model = build_tsp_model_gurobipy(data[0])\n",
"model.optimize()"
]
},
@ -1283,10 +1293,13 @@
"execution_count": 8,
"id": "6217da7c",
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2023-11-07T16:29:49.061613905Z",
"start_time": "2023-11-07T16:29:48.941857719Z"
},
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
@ -1320,10 +1333,10 @@
" 828.28 775.18 834.99 959.76 865.72 1193.52 1058.92 985.19 893.92\n",
" 962.16 781.88 723.15 639.04 602.4 787.02]\n",
"\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 578 rows, 360 columns and 2128 nonzeros\n",
"Model fingerprint: 0x4dc1c661\n",
@ -1361,8 +1374,8 @@
" RLT: 1\n",
" Relax-and-lift: 7\n",
"\n",
"Explored 1 nodes (234 simplex iterations) in 0.04 seconds (0.02 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (234 simplex iterations) in 0.03 seconds (0.02 work units)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 5: 364722 368600 374044 ... 440662\n",
"\n",
@ -1487,10 +1500,10 @@
"weights[0] [37.45 95.07 73.2 59.87 15.6 15.6 5.81 86.62 60.11 70.81]\n",
"weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]\n",
"\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 15 rows, 10 columns and 30 nonzeros\n",
"Model fingerprint: 0x2d2d1390\n",
@ -1514,7 +1527,7 @@
" 0 0 infeasible 0 301.00000 301.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (8 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 1: 301 \n",
"\n",
@ -1558,13 +1571,16 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": null,
"id": "9f12e91f",
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2023-11-07T16:29:49.075852252Z",
"start_time": "2023-11-07T16:29:49.050243601Z"
},
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
@ -1587,7 +1603,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
"version": "3.11.7"
}
},
"nbformat": 4,

@ -57,7 +57,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 1,
"id": "92b09b98",
"metadata": {
"collapsed": false,
@ -70,10 +70,11 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Restricted license - for non-production use only - expires 2024-10-28\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 10 rows, 45 columns and 90 nonzeros\n",
"Model fingerprint: 0x6ddcd141\n",
@ -91,11 +92,12 @@
"\n",
"Solved in 15 iterations and 0.00 seconds (0.00 work units)\n",
"Optimal objective 2.761000000e+03\n",
"Set parameter PreCrush to value 1\n",
"Set parameter LazyConstraints to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: AMD Ryzen 9 7950X 16-Core Processor, instruction set [SSE2|AVX|AVX2|AVX512]\n",
"Thread count: 16 physical cores, 32 logical processors, using up to 32 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 10 rows, 45 columns and 90 nonzeros\n",
"Model fingerprint: 0x74ca3d0a\n",
@ -125,7 +127,7 @@
" Lazy constraints: 3\n",
"\n",
"Explored 1 nodes (16 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 1: 2796 \n",
"\n",
@ -141,7 +143,7 @@
"{'WS: Count': 1, 'WS: Number of variables set': 41.0}"
]
},
"execution_count": 3,
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
@ -162,7 +164,7 @@
"from miplearn.io import write_pkl_gz\n",
"from miplearn.problems.tsp import (\n",
" TravelingSalesmanGenerator,\n",
" build_tsp_model,\n",
" build_tsp_model_gurobipy,\n",
")\n",
"from miplearn.solvers.learning import LearningSolver\n",
"\n",
@ -189,7 +191,7 @@
"\n",
"# Collect training data\n",
"bc = BasicCollector()\n",
"bc.collect(train_data, build_tsp_model, n_jobs=4)\n",
"bc.collect(train_data, build_tsp_model_gurobipy, n_jobs=4)\n",
"\n",
"# Build learning solver\n",
"solver = LearningSolver(\n",
@ -211,7 +213,7 @@
"solver.fit(train_data)\n",
"\n",
"# Solve a test instance\n",
"solver.optimize(test_data[0], build_tsp_model)"
"solver.optimize(test_data[0], build_tsp_model_gurobipy)"
]
},
{
@ -239,7 +241,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.12"
"version": "3.11.7"
}
},
"nbformat": 4,

@ -127,7 +127,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 1,
"id": "22a67170-10b4-43d3-8708-014d91141e73",
"metadata": {
"ExecuteTime": {
@ -163,7 +163,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 2,
"id": "2f67032f-0d74-4317-b45c-19da0ec859e9",
"metadata": {
"ExecuteTime": {
@ -207,7 +207,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 3,
"id": "2a896f47",
"metadata": {
"ExecuteTime": {
@ -221,10 +221,10 @@
"output_type": "stream",
"text": [
"Restricted license - for non-production use only - expires 2024-10-28\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 7 rows, 6 columns and 15 nonzeros\n",
"Model fingerprint: 0x58dfdd53\n",
@ -250,7 +250,7 @@
"* 0 0 0 1320.0000000 1320.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (5 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 2: 1320 1400 \n",
"\n",
@ -315,7 +315,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 4,
"id": "5eb09fab",
"metadata": {
"ExecuteTime": {
@ -361,7 +361,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 5,
"id": "6156752c",
"metadata": {
"ExecuteTime": {
@ -388,7 +388,7 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 6,
"id": "7623f002",
"metadata": {
"ExecuteTime": {
@ -429,7 +429,7 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 7,
"id": "435f7bf8-4b09-4889-b1ec-b7b56e7d8ed2",
"metadata": {
"ExecuteTime": {
@ -467,7 +467,7 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 8,
"id": "9d13dd50-3dcf-4673-a757-6f44dcc0dedf",
"metadata": {
"ExecuteTime": {
@ -480,10 +480,10 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xa8b70287\n",
@ -493,7 +493,7 @@
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.00s\n",
"Presolve time: 0.01s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
@ -502,13 +502,13 @@
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x4ccd7ae3\n",
"Model fingerprint: 0xcf27855a\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
@ -516,11 +516,9 @@
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.30129e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29184e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.01s)\n",
"Loaded user MIP start with objective 8.29146e+09\n",
"User MIP start produced solution with objective 8.29153e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29153e+09 (0.01s)\n",
"Loaded user MIP start with objective 8.29153e+09\n",
"\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
@ -532,19 +530,32 @@
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2906e+09 0 1 8.2915e+09 8.2906e+09 0.01% - 0s\n",
" 0 0 8.2907e+09 0 3 8.2915e+09 8.2907e+09 0.01% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2915e+09 8.2907e+09 0.01% - 0s\n",
" 0 0 8.2907e+09 0 2 8.2915e+09 8.2907e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Cover: 1\n",
" Gomory: 1\n",
" Flow cover: 2\n",
"\n",
"Explored 1 nodes (512 simplex iterations) in 0.07 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (565 simplex iterations) in 0.03 seconds (0.01 work units)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 3: 8.29146e+09 8.29184e+09 8.30129e+09 \n",
"Solution count 1: 8.29153e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.291459497797e+09, best bound 8.290645029670e+09, gap 0.0098%\n"
"Best objective 8.291528276179e+09, best bound 8.290733258025e+09, gap 0.0096%\n"
]
},
{
"data": {
"text/plain": [
"{'WS: Count': 1, 'WS: Number of variables set': 482.0}"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
@ -565,7 +576,7 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 9,
"id": "2ff391ed-e855-4228-aa09-a7641d8c2893",
"metadata": {
"ExecuteTime": {
@ -578,10 +589,10 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xa8b70287\n",
@ -600,10 +611,10 @@
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x4cbbf7c7\n",
@ -641,14 +652,24 @@
" Gomory: 2\n",
" MIR: 1\n",
"\n",
"Explored 1 nodes (1031 simplex iterations) in 0.07 seconds (0.03 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (1031 simplex iterations) in 0.15 seconds (0.03 work units)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 4: 8.29147e+09 8.29398e+09 8.29827e+09 9.75713e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.291465302389e+09, best bound 8.290781665333e+09, gap 0.0082%\n"
]
},
{
"data": {
"text/plain": [
"{}"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
@ -679,7 +700,7 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 10,
"id": "67a6cd18",
"metadata": {
"ExecuteTime": {
@ -692,10 +713,10 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x19042f12\n",
@ -714,13 +735,13 @@
"\n",
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.253596777e+09\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x8ee64638\n",
"Model fingerprint: 0xf97cde91\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
@ -728,13 +749,16 @@
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.25814e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25814e+09 (0.00s)\n",
"User MIP start produced solution with objective 8.25512e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"User MIP start produced solution with objective 8.25483e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25483e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25483e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.01s)\n",
"Loaded user MIP start with objective 8.25459e+09\n",
"\n",
"Presolve time: 0.01s\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
@ -758,16 +782,16 @@
" StrongCG: 1\n",
" Flow cover: 1\n",
"\n",
"Explored 1 nodes (575 simplex iterations) in 0.12 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (575 simplex iterations) in 0.05 seconds (0.01 work units)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 3: 8.25459e+09 8.25512e+09 8.25814e+09 \n",
"Solution count 4: 8.25459e+09 8.25483e+09 8.25512e+09 8.25814e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.254590409970e+09, best bound 8.253768093811e+09, gap 0.0100%\n",
"obj = 8254590409.969726\n",
"x = [1.0, 1.0, 0.0]\n",
"y = [935662.0949263407, 1604270.0218116897, 0.0]\n"
"y = [935662.0949262811, 1604270.0218116897, 0.0]\n"
]
}
],
@ -805,7 +829,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
"version": "3.11.7"
}
},
"nbformat": 4,

@ -127,7 +127,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 1,
"id": "22a67170-10b4-43d3-8708-014d91141e73",
"metadata": {
"ExecuteTime": {
@ -163,7 +163,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 2,
"id": "2f67032f-0d74-4317-b45c-19da0ec859e9",
"metadata": {
"ExecuteTime": {
@ -213,7 +213,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 3,
"id": "2a896f47",
"metadata": {
"ExecuteTime": {
@ -228,10 +228,10 @@
"text": [
"Restricted license - for non-production use only - expires 2024-10-28\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 7 rows, 6 columns and 15 nonzeros\n",
"Model fingerprint: 0x15c7a953\n",
@ -257,7 +257,7 @@
"* 0 0 0 1320.0000000 1320.00000 0.00% - 0s\n",
"\n",
"Explored 1 nodes (5 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 2: 1320 1400 \n",
"\n",
@ -324,7 +324,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 4,
"id": "5eb09fab",
"metadata": {
"ExecuteTime": {
@ -370,7 +370,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 5,
"id": "6156752c",
"metadata": {
"ExecuteTime": {
@ -397,7 +397,7 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 6,
"id": "7623f002",
"metadata": {
"ExecuteTime": {
@ -438,7 +438,7 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 7,
"id": "435f7bf8-4b09-4889-b1ec-b7b56e7d8ed2",
"metadata": {
"ExecuteTime": {
@ -476,7 +476,7 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 8,
"id": "9d13dd50-3dcf-4673-a757-6f44dcc0dedf",
"metadata": {
"ExecuteTime": {
@ -490,10 +490,10 @@
"output_type": "stream",
"text": [
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x5e67c6ee\n",
@ -513,13 +513,13 @@
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0xa4a7961e\n",
"Model fingerprint: 0x4a7cfe2b\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
@ -527,37 +527,48 @@
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.30129e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29184e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29146e+09 (0.02s)\n",
"Loaded user MIP start with objective 8.29146e+09\n",
"User MIP start produced solution with objective 8.29153e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.29153e+09 (0.01s)\n",
"Loaded user MIP start with objective 8.29153e+09\n",
"\n",
"Presolve time: 0.01s\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.01 seconds (0.00 work units)\n",
"Root relaxation: objective 8.290622e+09, 512 iterations, 0.00 seconds (0.00 work units)\n",
"\n",
" Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n",
" 0 0 8.2906e+09 0 1 8.2915e+09 8.2906e+09 0.01% - 0s\n",
" 0 0 8.2907e+09 0 3 8.2915e+09 8.2907e+09 0.01% - 0s\n",
" 0 0 8.2907e+09 0 1 8.2915e+09 8.2907e+09 0.01% - 0s\n",
" 0 0 8.2907e+09 0 2 8.2915e+09 8.2907e+09 0.01% - 0s\n",
"\n",
"Cutting planes:\n",
" Cover: 1\n",
" Gomory: 1\n",
" Flow cover: 2\n",
"\n",
"Explored 1 nodes (512 simplex iterations) in 0.09 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (565 simplex iterations) in 0.04 seconds (0.01 work units)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 3: 8.29146e+09 8.29184e+09 8.30129e+09 \n",
"Solution count 1: 8.29153e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.291459497797e+09, best bound 8.290645029670e+09, gap 0.0098%\n",
"Best objective 8.291528276179e+09, best bound 8.290733258025e+09, gap 0.0096%\n",
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n"
]
},
{
"data": {
"text/plain": [
"{}"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
@ -578,7 +589,7 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 9,
"id": "2ff391ed-e855-4228-aa09-a7641d8c2893",
"metadata": {
"ExecuteTime": {
@ -592,10 +603,10 @@
"output_type": "stream",
"text": [
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x5e67c6ee\n",
@ -605,7 +616,7 @@
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.01s\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
@ -615,10 +626,10 @@
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.290621916e+09\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x8a0f9587\n",
@ -656,8 +667,8 @@
" Gomory: 2\n",
" MIR: 1\n",
"\n",
"Explored 1 nodes (1025 simplex iterations) in 0.08 seconds (0.03 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (1025 simplex iterations) in 0.12 seconds (0.03 work units)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 4: 8.29147e+09 8.29398e+09 8.29827e+09 9.75713e+09 \n",
"\n",
@ -666,6 +677,16 @@
"WARNING: Cannot get reduced costs for MIP.\n",
"WARNING: Cannot get duals for MIP.\n"
]
},
{
"data": {
"text/plain": [
"{}"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
@ -696,7 +717,7 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 10,
"id": "67a6cd18",
"metadata": {
"ExecuteTime": {
@ -710,10 +731,10 @@
"output_type": "stream",
"text": [
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x2dfe4e1c\n",
@ -723,7 +744,7 @@
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"Presolve removed 1000 rows and 500 columns\n",
"Presolve time: 0.01s\n",
"Presolve time: 0.00s\n",
"Presolved: 1 rows, 500 columns, 500 nonzeros\n",
"\n",
"Iteration Objective Primal Inf. Dual Inf. Time\n",
@ -733,13 +754,13 @@
"Solved in 1 iterations and 0.01 seconds (0.00 work units)\n",
"Optimal objective 8.253596777e+09\n",
"Set parameter QCPDual to value 1\n",
"Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (linux64)\n",
"Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (linux64)\n",
"\n",
"CPU model: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n",
"CPU model: 13th Gen Intel(R) Core(TM) i7-13800H, instruction set [SSE2|AVX|AVX2]\n",
"Thread count: 10 physical cores, 20 logical processors, using up to 20 threads\n",
"\n",
"Optimize a model with 1001 rows, 1000 columns and 2500 nonzeros\n",
"Model fingerprint: 0x20637200\n",
"Model fingerprint: 0x0f0924a1\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"Coefficient statistics:\n",
" Matrix range [1e+00, 2e+06]\n",
@ -747,13 +768,16 @@
" Bounds range [1e+00, 1e+00]\n",
" RHS range [3e+08, 3e+08]\n",
"\n",
"User MIP start produced solution with objective 8.25814e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25814e+09 (0.00s)\n",
"User MIP start produced solution with objective 8.25512e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.04s)\n",
"User MIP start produced solution with objective 8.25483e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25483e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25483e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.01s)\n",
"User MIP start produced solution with objective 8.25459e+09 (0.01s)\n",
"Loaded user MIP start with objective 8.25459e+09\n",
"\n",
"Presolve time: 0.01s\n",
"Presolve time: 0.00s\n",
"Presolved: 1001 rows, 1000 columns, 2500 nonzeros\n",
"Variable types: 500 continuous, 500 integer (500 binary)\n",
"\n",
@ -777,10 +801,10 @@
" StrongCG: 1\n",
" Flow cover: 1\n",
"\n",
"Explored 1 nodes (575 simplex iterations) in 0.11 seconds (0.01 work units)\n",
"Thread count was 12 (of 12 available processors)\n",
"Explored 1 nodes (575 simplex iterations) in 0.09 seconds (0.01 work units)\n",
"Thread count was 20 (of 20 available processors)\n",
"\n",
"Solution count 3: 8.25459e+09 8.25512e+09 8.25814e+09 \n",
"Solution count 4: 8.25459e+09 8.25483e+09 8.25512e+09 8.25814e+09 \n",
"\n",
"Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 8.254590409970e+09, best bound 8.253768093811e+09, gap 0.0100%\n",
@ -788,7 +812,7 @@
"WARNING: Cannot get duals for MIP.\n",
"obj = 8254590409.96973\n",
" x = [1.0, 1.0, 0.0, 1.0, 1.0]\n",
" y = [935662.0949263407, 1604270.0218116897, 0.0, 1369560.835229226, 602828.5321028307]\n"
" y = [935662.0949262811, 1604270.0218116897, 0.0, 1369560.835229226, 602828.5321028307]\n"
]
}
],
@ -826,7 +850,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.11.7"
}
},
"nbformat": 4,

@ -1,3 +1,28 @@
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
# Copyright (C) 2020-2022, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.
from typing import Any, Optional
import gurobipy as gp
from pyomo import environ as pe
def _gurobipy_set_params(model: gp.Model, params: Optional[dict[str, Any]]) -> None:
assert isinstance(model, gp.Model)
if params is not None:
for (param_name, param_value) in params.items():
setattr(model.params, param_name, param_value)
def _pyomo_set_params(
model: pe.ConcreteModel,
params: Optional[dict[str, Any]],
solver: str,
) -> None:
assert (
solver == "gurobi_persistent"
), "setting parameters is only supported with gurobi_persistent"
if solver == "gurobi_persistent" and params is not None:
for (param_name, param_value) in params.items():
model.solver.set_gurobi_param(param_name, param_value)

@ -18,6 +18,8 @@ from networkx import Graph
from scipy.stats import uniform, randint
from scipy.stats.distributions import rv_frozen
from . import _gurobipy_set_params, _pyomo_set_params
logger = logging.getLogger(__name__)
@ -88,11 +90,10 @@ def build_stab_model_gurobipy(
data: Union[str, MaxWeightStableSetData],
params: Optional[dict[str, Any]] = None,
) -> GurobiModel:
data = _stab_read(data)
model = gp.Model()
if params is not None:
for (param_name, param_value) in params.items():
setattr(model.params, param_name, param_value)
_gurobipy_set_params(model, params)
data = _stab_read(data)
nodes = list(data.graph.nodes)
# Variables and objective function
@ -152,18 +153,14 @@ def build_stab_model_pyomo(
for clique in violations:
m.add_constr(model.clique_eqs.add(sum(model.x[i] for i in clique) <= 1))
m = PyomoModel(
pm = PyomoModel(
model,
solver,
cuts_separate=cuts_separate,
cuts_enforce=cuts_enforce,
)
if solver == "gurobi_persistent" and params is not None:
for (param_name, param_value) in params.items():
m.solver.set_gurobi_param(param_name, param_value)
return m
_pyomo_set_params(pm, params, solver)
return pm
def _stab_read(data: Union[str, MaxWeightStableSetData]) -> MaxWeightStableSetData:

@ -2,20 +2,23 @@
# Copyright (C) 2020-2022, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.
import logging
from dataclasses import dataclass
from typing import List, Tuple, Optional, Any, Union
import gurobipy as gp
import networkx as nx
import numpy as np
import pyomo.environ as pe
from gurobipy import quicksum, GRB, tuplelist
from miplearn.io import read_pkl_gz
from miplearn.problems import _gurobipy_set_params, _pyomo_set_params
from miplearn.solvers.gurobi import GurobiModel
from scipy.spatial.distance import pdist, squareform
from scipy.stats import uniform, randint
from scipy.stats.distributions import rv_frozen
import logging
from miplearn.io import read_pkl_gz
from miplearn.solvers.gurobi import GurobiModel
from miplearn.solvers.pyomo import PyomoModel
logger = logging.getLogger(__name__)
@ -112,15 +115,18 @@ class TravelingSalesmanGenerator:
return n, cities
def build_tsp_model(data: Union[str, TravelingSalesmanData]) -> GurobiModel:
if isinstance(data, str):
data = read_pkl_gz(data)
assert isinstance(data, TravelingSalesmanData)
def build_tsp_model_gurobipy(
data: Union[str, TravelingSalesmanData],
params: Optional[dict[str, Any]] = None,
) -> GurobiModel:
model = gp.Model()
_gurobipy_set_params(model, params)
data = _tsp_read(data)
edges = tuplelist(
(i, j) for i in range(data.n_cities) for j in range(i + 1, data.n_cities)
)
model = gp.Model()
# Decision variables
x = model.addVars(edges, vtype=GRB.BINARY, name="x")
@ -173,3 +179,75 @@ def build_tsp_model(data: Union[str, TravelingSalesmanData]) -> GurobiModel:
lazy_separate=lazy_separate,
lazy_enforce=lazy_enforce,
)
def build_tsp_model_pyomo(
data: Union[str, TravelingSalesmanData],
solver: str = "gurobi_persistent",
params: Optional[dict[str, Any]] = None,
) -> PyomoModel:
model = pe.ConcreteModel()
data = _tsp_read(data)
edges = tuplelist(
(i, j) for i in range(data.n_cities) for j in range(i + 1, data.n_cities)
)
# Decision variables
model.x = pe.Var(edges, domain=pe.Boolean, name="x")
model.obj = pe.Objective(
expr=sum(model.x[i, j] * data.distances[i, j] for (i, j) in edges)
)
# Eq: Must choose two edges adjacent to each node
model.degree_eqs = pe.ConstraintList()
for i in range(data.n_cities):
model.degree_eqs.add(
sum(model.x[min(i, j), max(i, j)] for j in range(data.n_cities) if i != j)
== 2
)
# Eq: Subtour elimination
model.subtour_eqs = pe.ConstraintList()
def lazy_separate(m: PyomoModel) -> List[Any]:
violations = []
m.solver.cbGetSolution([model.x[e] for e in edges])
x_val = {e: model.x[e].value for e in edges}
selected_edges = [e for e in edges if x_val[e] > 0.5]
graph = nx.Graph()
graph.add_edges_from(selected_edges)
for component in list(nx.connected_components(graph)):
if len(component) < data.n_cities:
cut_edges = tuple(
(e[0], e[1])
for e in edges
if (e[0] in component and e[1] not in component)
or (e[0] not in component and e[1] in component)
)
violations.append(cut_edges)
return violations
def lazy_enforce(m: PyomoModel, violations: List[Any]) -> None:
logger.warning(f"Adding {len(violations)} subtour elimination constraints...")
for violation in violations:
m.add_constr(
model.subtour_eqs.add(sum(model.x[e[0], e[1]] for e in violation) >= 2)
)
pm = PyomoModel(
model,
solver,
lazy_separate=lazy_separate,
lazy_enforce=lazy_enforce,
)
_pyomo_set_params(pm, params, solver)
return pm
def _tsp_read(data: Union[str, TravelingSalesmanData]) -> TravelingSalesmanData:
if isinstance(data, str):
data = read_pkl_gz(data)
assert isinstance(data, TravelingSalesmanData)
return data

@ -53,7 +53,12 @@ class PyomoModel(AbstractModel):
assert (
self.solver_name == "gurobi_persistent"
), "Callbacks are currently only supported on gurobi_persistent"
_gurobi_add_constr(self.solver, self.where, constr)
if self.where in [AbstractModel.WHERE_CUTS, AbstractModel.WHERE_LAZY]:
_gurobi_add_constr(self.solver, self.where, constr)
else:
# outside callbacks, add_constr shouldn't do anything, as the constraint
# has already been added to the ConstraintList object
pass
def add_constrs(
self,

@ -10,53 +10,60 @@ from sklearn.neighbors import KNeighborsClassifier
from miplearn.components.lazy.mem import MemorizingLazyComponent
from miplearn.extractors.abstract import FeaturesExtractor
from miplearn.problems.tsp import build_tsp_model
from miplearn.problems.tsp import build_tsp_model_gurobipy, build_tsp_model_pyomo
from miplearn.solvers.learning import LearningSolver
def test_mem_component(
tsp_h5: List[str],
tsp_gp_h5: List[str],
tsp_pyo_h5: List[str],
default_extractor: FeaturesExtractor,
) -> None:
clf = Mock(wraps=DummyClassifier())
comp = MemorizingLazyComponent(clf=clf, extractor=default_extractor)
comp.fit(tsp_h5)
# Should call fit method with correct arguments
clf.fit.assert_called()
x, y = clf.fit.call_args.args
assert x.shape == (3, 190)
assert y.tolist() == [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0],
[1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1],
]
# Should store violations
assert comp.constrs_ is not None
assert comp.n_features_ == 190
assert comp.n_targets_ == 22
assert len(comp.constrs_) == 22
# Call before-mip
stats: Dict[str, Any] = {}
model = Mock()
comp.before_mip(tsp_h5[0], model, stats)
# Should call predict with correct args
clf.predict.assert_called()
(x_test,) = clf.predict.call_args.args
assert x_test.shape == (1, 190)
for h5 in [tsp_gp_h5, tsp_pyo_h5]:
clf = Mock(wraps=DummyClassifier())
comp = MemorizingLazyComponent(clf=clf, extractor=default_extractor)
comp.fit(tsp_gp_h5)
# Should call fit method with correct arguments
clf.fit.assert_called()
x, y = clf.fit.call_args.args
assert x.shape == (3, 190)
assert y.tolist() == [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0],
[1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1],
]
# Should store violations
assert comp.constrs_ is not None
assert comp.n_features_ == 190
assert comp.n_targets_ == 20
assert len(comp.constrs_) == 20
# Call before-mip
stats: Dict[str, Any] = {}
model = Mock()
comp.before_mip(tsp_gp_h5[0], model, stats)
# Should call predict with correct args
clf.predict.assert_called()
(x_test,) = clf.predict.call_args.args
assert x_test.shape == (1, 190)
def test_usage_tsp(
tsp_h5: List[str],
tsp_gp_h5: List[str],
tsp_pyo_h5: List[str],
default_extractor: FeaturesExtractor,
) -> None:
# Should not crash
data_filenames = [f.replace(".h5", ".pkl.gz") for f in tsp_h5]
clf = KNeighborsClassifier(n_neighbors=1)
comp = MemorizingLazyComponent(clf=clf, extractor=default_extractor)
solver = LearningSolver(components=[comp])
solver.fit(data_filenames)
solver.optimize(data_filenames[0], build_tsp_model)
for (h5, build_model) in [
(tsp_pyo_h5, build_tsp_model_pyomo),
(tsp_gp_h5, build_tsp_model_gurobipy),
]:
data_filenames = [f.replace(".h5", ".pkl.gz") for f in h5]
clf = KNeighborsClassifier(n_neighbors=1)
comp = MemorizingLazyComponent(clf=clf, extractor=default_extractor)
solver = LearningSolver(components=[comp])
solver.fit(data_filenames)
stats = solver.optimize(data_filenames[0], build_model) # type: ignore
assert stats["Lazy Constraints: AOT"] > 0

@ -47,8 +47,13 @@ def multiknapsack_h5(request: Any) -> List[str]:
@pytest.fixture()
def tsp_h5(request: Any) -> List[str]:
return _h5_fixture("tsp*.h5", request)
def tsp_gp_h5(request: Any) -> List[str]:
return _h5_fixture("tsp-gp*.h5", request)
@pytest.fixture()
def tsp_pyo_h5(request: Any) -> List[str]:
return _h5_fixture("tsp-pyo*.h5", request)
@pytest.fixture()

@ -5,7 +5,11 @@ from scipy.stats import uniform, randint
from miplearn.collectors.basic import BasicCollector
from miplearn.io import write_pkl_gz
from miplearn.problems.tsp import TravelingSalesmanGenerator, build_tsp_model
from miplearn.problems.tsp import (
TravelingSalesmanGenerator,
build_tsp_model_gurobipy,
build_tsp_model_pyomo,
)
np.random.seed(42)
gen = TravelingSalesmanGenerator(
@ -16,7 +20,27 @@ gen = TravelingSalesmanGenerator(
fix_cities=True,
round=True,
)
data = gen.generate(3)
data_filenames = write_pkl_gz(data, dirname(__file__), prefix="tsp-n20-")
params = {"seed": 42, "threads": 1}
# Gurobipy
data_filenames = write_pkl_gz(data, dirname(__file__), prefix="tsp-gp-n20-")
collector = BasicCollector()
collector.collect(data_filenames, build_tsp_model)
collector.collect(
data_filenames,
lambda d: build_tsp_model_gurobipy(d, params=params),
progress=True,
verbose=True,
)
# Pyomo
data_filenames = write_pkl_gz(data, dirname(__file__), prefix="tsp-pyo-n20-")
collector = BasicCollector()
collector.collect(
data_filenames,
lambda d: build_tsp_model_pyomo(d, params=params),
progress=True,
verbose=True,
)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -6,7 +6,7 @@ import numpy as np
from miplearn.problems.tsp import (
TravelingSalesmanData,
TravelingSalesmanGenerator,
build_tsp_model,
build_tsp_model_gurobipy,
)
from scipy.spatial.distance import pdist, squareform
from scipy.stats import randint, uniform
@ -51,7 +51,7 @@ def test_tsp() -> None:
)
),
)
model = build_tsp_model(data)
model = build_tsp_model_gurobipy(data)
model.optimize()
assert model.inner.getAttr("x", model.inner.getVars()) == [
1.0,

Loading…
Cancel
Save