stab: Implement MaxWeightStableSetPerturber; update tests and docs

This commit is contained in:
2025-12-08 10:54:19 -06:00
parent 7fd88b0a3d
commit a4cb46f73e
23 changed files with 197 additions and 152 deletions

View File

@@ -129,14 +129,15 @@
"8 [ 8.47 21.9 16.58 15.37 3.76 3.91 1.57 20.57 14.76 18.61] 94.58\n", "8 [ 8.47 21.9 16.58 15.37 3.76 3.91 1.57 20.57 14.76 18.61] 94.58\n",
"9 [ 8.57 22.77 17.06 16.25 4.14 4. 1.56 22.97 14.09 19.09] 100.79\n", "9 [ 8.57 22.77 17.06 16.25 4.14 4. 1.56 22.97 14.09 19.09] 100.79\n",
"\n", "\n",
"Restricted license - for non-production use only - expires 2026-11-23\n", "Set parameter LicenseID to value 389975\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Optimize a model with 20 rows, 110 columns and 210 nonzeros\n", "Optimize a model with 20 rows, 110 columns and 210 nonzeros (Min)\n",
"Model fingerprint: 0x1ff9913f\n", "Model fingerprint: 0x1ff9913f\n",
"Model has 10 linear objective coefficients\n",
"Variable types: 0 continuous, 110 integer (110 binary)\n", "Variable types: 0 continuous, 110 integer (110 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
" Matrix range [1e+00, 1e+02]\n", " Matrix range [1e+00, 1e+02]\n",
@@ -159,15 +160,23 @@
"H 0 0 2.0000000 1.27484 36.3% - 0s\n", "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", " 0 0 1.27484 0 4 2.00000 1.27484 36.3% - 0s\n",
"\n", "\n",
"Explored 1 nodes (38 simplex iterations) in 0.01 seconds (0.00 work units)\n", "Explored 1 nodes (38 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n", "Thread count was 16 (of 16 available processors)\n",
"\n", "\n",
"Solution count 4: 2 3 4 5 \n", "Solution count 4: 2 3 4 5 \n",
"\n", "\n",
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 2.000000000000e+00, best bound 2.000000000000e+00, gap 0.0000%\n", "Best objective 2.000000000000e+00, best bound 2.000000000000e+00, gap 0.0000%\n",
"\n", "\n",
"User-callback calls 148, time in user-callback 0.00 sec\n" "User-callback calls 149, time in user-callback 0.00 sec\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/axavier/Notebooks/[2025-12] Parallel BB Datasets/venv/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n"
] ]
} }
], ],
@@ -325,13 +334,14 @@
"capacities\n", "capacities\n",
" [1310. 988. 1004. 1269. 1007.]\n", " [1310. 988. 1004. 1269. 1007.]\n",
"\n", "\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Optimize a model with 5 rows, 10 columns and 50 nonzeros\n", "Optimize a model with 5 rows, 10 columns and 50 nonzeros (Min)\n",
"Model fingerprint: 0xaf3ac15e\n", "Model fingerprint: 0xaf3ac15e\n",
"Model has 10 linear objective coefficients\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n", "Variable types: 0 continuous, 10 integer (10 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
" Matrix range [2e+01, 1e+03]\n", " Matrix range [2e+01, 1e+03]\n",
@@ -355,7 +365,7 @@
" 0 0 -1428.7265 0 4 -1279.0000 -1428.7265 11.7% - 0s\n", " 0 0 -1428.7265 0 4 -1279.0000 -1428.7265 11.7% - 0s\n",
"\n", "\n",
"Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)\n", "Explored 1 nodes (4 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n", "Thread count was 16 (of 16 available processors)\n",
"\n", "\n",
"Solution count 3: -1279 -995 -804 \n", "Solution count 3: -1279 -995 -804 \n",
"No other solutions better than -1279\n", "No other solutions better than -1279\n",
@@ -363,7 +373,7 @@
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective -1.279000000000e+03, best bound -1.279000000000e+03, gap 0.0000%\n", "Best objective -1.279000000000e+03, best bound -1.279000000000e+03, gap 0.0000%\n",
"\n", "\n",
"User-callback calls 416, time in user-callback 0.00 sec\n" "User-callback calls 418, time in user-callback 0.00 sec\n"
] ]
} }
], ],
@@ -501,13 +511,14 @@
"demands = [6.12 1.39 2.92 3.66 4.56 7.85 2. 5.14 5.92 0.46]\n", "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", "capacities = [151.89 42.63 16.26 237.22 241.41 202.1 76.15 24.42 171.06 110.04]\n",
"\n", "\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Optimize a model with 21 rows, 110 columns and 220 nonzeros\n", "Optimize a model with 21 rows, 110 columns and 220 nonzeros (Min)\n",
"Model fingerprint: 0x8d8d9346\n", "Model fingerprint: 0x8d8d9346\n",
"Model has 90 linear objective coefficients\n",
"Variable types: 0 continuous, 110 integer (110 binary)\n", "Variable types: 0 continuous, 110 integer (110 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
" Matrix range [5e-01, 2e+02]\n", " Matrix range [5e-01, 2e+02]\n",
@@ -530,21 +541,21 @@
"H 0 0 153.5000000 0.00000 100% - 0s\n", "H 0 0 153.5000000 0.00000 100% - 0s\n",
"H 0 0 131.7700000 0.00000 100% - 0s\n", "H 0 0 131.7700000 0.00000 100% - 0s\n",
" 0 0 17.14595 0 10 131.77000 17.14595 87.0% - 0s\n", " 0 0 17.14595 0 10 131.77000 17.14595 87.0% - 0s\n",
"H 0 0 115.6500000 17.14595 85.2% - 0s\n", "H 0 0 122.8100000 17.14595 86.0% - 0s\n",
"H 0 0 114.5300000 64.28872 43.9% - 0s\n", "H 0 0 98.3900000 17.14595 82.6% - 0s\n",
"H 0 0 98.3900000 64.28872 34.7% - 0s\n", "H 0 0 92.2900000 64.28872 30.3% - 0s\n",
" 0 0 74.01104 0 15 98.39000 74.01104 24.8% - 0s\n", "H 0 0 91.6700000 64.28872 29.9% - 0s\n",
"H 0 0 91.2300000 74.01104 18.9% - 0s\n", " 0 0 64.28872 0 15 91.67000 64.28872 29.9% - 0s\n",
"H 0 0 91.2300000 64.28872 29.5% - 0s\n",
"\n", "\n",
"Cutting planes:\n", "Cutting planes:\n",
" Cover: 16\n", " Cover: 16\n",
" MIR: 1\n",
" StrongCG: 1\n", " StrongCG: 1\n",
"\n", "\n",
"Explored 1 nodes (42 simplex iterations) in 0.02 seconds (0.00 work units)\n", "Explored 1 nodes (42 simplex iterations) in 0.01 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n", "Thread count was 16 (of 16 available processors)\n",
"\n", "\n",
"Solution count 9: 91.23 98.39 114.53 ... 368.79\n", "Solution count 10: 91.23 91.67 92.29 ... 368.79\n",
"\n", "\n",
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 9.123000000000e+01, best bound 9.123000000000e+01, gap 0.0000%\n", "Best objective 9.123000000000e+01, best bound 9.123000000000e+01, gap 0.0000%\n",
@@ -678,13 +689,14 @@
"costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n", "costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n",
" 425.33]\n", " 425.33]\n",
"\n", "\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Optimize a model with 5 rows, 10 columns and 28 nonzeros\n", "Optimize a model with 5 rows, 10 columns and 28 nonzeros (Min)\n",
"Model fingerprint: 0xe5c2d4fa\n", "Model fingerprint: 0xe5c2d4fa\n",
"Model has 10 linear objective coefficients\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n", "Variable types: 0 continuous, 10 integer (10 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
" Matrix range [1e+00, 1e+00]\n", " Matrix range [1e+00, 1e+00]\n",
@@ -696,15 +708,15 @@
"Presolve time: 0.00s\n", "Presolve time: 0.00s\n",
"Presolve: All rows and columns removed\n", "Presolve: All rows and columns removed\n",
"\n", "\n",
"Explored 0 nodes (0 simplex iterations) in 0.01 seconds (0.00 work units)\n", "Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 1 (of 32 available processors)\n", "Thread count was 1 (of 16 available processors)\n",
"\n", "\n",
"Solution count 1: 213.49 \n", "Solution count 1: 213.49 \n",
"\n", "\n",
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 2.134900000000e+02, best bound 2.134900000000e+02, gap 0.0000%\n", "Best objective 2.134900000000e+02, best bound 2.134900000000e+02, gap 0.0000%\n",
"\n", "\n",
"User-callback calls 183, time in user-callback 0.00 sec\n" "User-callback calls 181, time in user-callback 0.00 sec\n"
] ]
} }
], ],
@@ -819,13 +831,14 @@
"costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n", "costs [1044.58 850.13 1014.5 944.83 697.9 971.87 213.49 220.98 70.23\n",
" 425.33]\n", " 425.33]\n",
"\n", "\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Optimize a model with 5 rows, 10 columns and 28 nonzeros\n", "Optimize a model with 5 rows, 10 columns and 28 nonzeros (Min)\n",
"Model fingerprint: 0x4ee91388\n", "Model fingerprint: 0x4ee91388\n",
"Model has 10 linear objective coefficients\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n", "Variable types: 0 continuous, 10 integer (10 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
" Matrix range [1e+00, 1e+00]\n", " Matrix range [1e+00, 1e+00]\n",
@@ -837,8 +850,8 @@
"Presolve time: 0.00s\n", "Presolve time: 0.00s\n",
"Presolve: All rows and columns removed\n", "Presolve: All rows and columns removed\n",
"\n", "\n",
"Explored 0 nodes (0 simplex iterations) in 0.01 seconds (0.00 work units)\n", "Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 1 (of 32 available processors)\n", "Thread count was 1 (of 16 available processors)\n",
"\n", "\n",
"Solution count 2: -1986.37 -1265.56 \n", "Solution count 2: -1986.37 -1265.56 \n",
"No other solutions better than -1986.37\n", "No other solutions better than -1986.37\n",
@@ -846,7 +859,7 @@
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective -1.986370000000e+03, best bound -1.986370000000e+03, gap 0.0000%\n", "Best objective -1.986370000000e+03, best bound -1.986370000000e+03, gap 0.0000%\n",
"\n", "\n",
"User-callback calls 244, time in user-callback 0.00 sec\n" "User-callback calls 242, time in user-callback 0.00 sec\n"
] ]
} }
], ],
@@ -914,14 +927,12 @@
"id": "ef030168", "id": "ef030168",
"metadata": {}, "metadata": {},
"source": [ "source": [
"\n",
"### Random instance generator\n", "### Random instance generator\n",
"\n", "\n",
"The class [MaxWeightStableSetGenerator][MaxWeightStableSetGenerator] can be used to generate random instances of this problem. The class first samples the user-provided probability distributions `n` and `p` to decide the number of vertices and the density of the graph. Then, it generates a random Erdős-Rényi graph $G_{n,p}$. We recall that, in such a graph, each potential edge is included with probabilty $p$, independently for each other. The class then samples the provided probability distribution `w` to decide the vertex weights.\n", "The class [MaxWeightStableSetGenerator][MaxWeightStableSetGenerator] can be used to generate random instances of this problem. For each instance, the generator creates a new random Erdős-Rényi graph $G_{n,p}$, where $n$ and $p$ are sampled from user-provided probability distributions `n` and `p`. For each vertex, the generator independently samples the weight $w_v$ from the user-provided probability distribution `w`. To create multiple instances with the same graph structure but different vertex weights, you can use [MaxWeightStableSetPerturber][MaxWeightStableSetPerturber]. This class takes an existing instance and generates new instances by applying random scaling factors to the vertex weights while keeping the graph fixed.\n",
"\n", "\n",
"[MaxWeightStableSetGenerator]: ../../api/problems/#miplearn.problems.stab.MaxWeightStableSetGenerator\n", "[MaxWeightStableSetGenerator]: ../../api/problems/#miplearn.problems.stab.MaxWeightStableSetGenerator\n",
"\n", "[MaxWeightStableSetPerturber]: ../../api/problems/#miplearn.problems.stab.MaxWeightStableSetPerturber\n",
"If `fix_graph=True`, then all generated instances have the same random graph. For each instance, the weights are decided by sampling `w`, as described above.\n",
"\n", "\n",
"### Example" "### Example"
] ]
@@ -942,49 +953,50 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"graph [(0, 2), (0, 4), (0, 8), (1, 2), (1, 3), (1, 5), (1, 6), (1, 9), (2, 5), (2, 9), (3, 6), (3, 7), (6, 9), (7, 8), (8, 9)]\n", "graph [(0, 2), (0, 4), (0, 8), (1, 2), (1, 3), (1, 5), (1, 6), (1, 9), (2, 5), (2, 9), (3, 6), (3, 7), (6, 9), (7, 8), (8, 9)]\n",
"weights[0] [37.45 95.07 73.2 59.87 15.6 15.6 5.81 86.62 60.11 70.81]\n", "weights[0] [33.78 94.78 71.97 55.15 14.32 14.33 5.41 82.5 56.7 65.79]\n",
"weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]\n", "weights[1] [36. 86.89 68.02 56.08 14.75 15.26 5.35 82.41 57.66 64.06]\n",
"\n", "\n",
"Set parameter PreCrush to value 1\n", "Set parameter PreCrush to value 1\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Non-default parameters:\n", "Non-default parameters:\n",
"PreCrush 1\n", "PreCrush 1\n",
"\n", "\n",
"Optimize a model with 15 rows, 10 columns and 30 nonzeros\n", "Optimize a model with 15 rows, 10 columns and 30 nonzeros (Min)\n",
"Model fingerprint: 0x3240ea4a\n", "Model fingerprint: 0xc7a32e6d\n",
"Model has 10 linear objective coefficients\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n", "Variable types: 0 continuous, 10 integer (10 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
" Matrix range [1e+00, 1e+00]\n", " Matrix range [1e+00, 1e+00]\n",
" Objective range [6e+00, 1e+02]\n", " Objective range [5e+00, 9e+01]\n",
" Bounds range [1e+00, 1e+00]\n", " Bounds range [1e+00, 1e+00]\n",
" RHS range [1e+00, 1e+00]\n", " RHS range [1e+00, 1e+00]\n",
"Found heuristic solution: objective -219.1400000\n", "Found heuristic solution: objective -211.0600000\n",
"Presolve removed 7 rows and 2 columns\n", "Presolve removed 7 rows and 2 columns\n",
"Presolve time: 0.00s\n", "Presolve time: 0.00s\n",
"Presolved: 8 rows, 8 columns, 19 nonzeros\n", "Presolved: 8 rows, 8 columns, 19 nonzeros\n",
"Variable types: 0 continuous, 8 integer (8 binary)\n", "Variable types: 0 continuous, 8 integer (8 binary)\n",
"\n", "\n",
"Root relaxation: objective -2.205650e+02, 5 iterations, 0.00 seconds (0.00 work units)\n", "Root relaxation: cutoff, 5 iterations, 0.00 seconds (0.00 work units)\n",
"\n", "\n",
" Nodes | Current Node | Objective Bounds | Work\n", " Nodes | Current Node | Objective Bounds | Work\n",
" Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n",
"\n", "\n",
" 0 0 infeasible 0 -219.14000 -219.14000 0.00% - 0s\n", " 0 0 cutoff 0 -211.06000 -211.06000 0.00% - 0s\n",
"\n", "\n",
"Explored 1 nodes (5 simplex iterations) in 0.01 seconds (0.00 work units)\n", "Explored 1 nodes (5 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n", "Thread count was 16 (of 16 available processors)\n",
"\n", "\n",
"Solution count 1: -219.14 \n", "Solution count 1: -211.06 \n",
"No other solutions better than -219.14\n", "No other solutions better than -211.06\n",
"\n", "\n",
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective -2.191400000000e+02, best bound -2.191400000000e+02, gap 0.0000%\n", "Best objective -2.110600000000e+02, best bound -2.110600000000e+02, gap 0.0000%\n",
"\n", "\n",
"User-callback calls 303, time in user-callback 0.00 sec\n" "User-callback calls 304, time in user-callback 0.00 sec\n"
] ]
} }
], ],
@@ -994,6 +1006,7 @@
"from scipy.stats import uniform, randint\n", "from scipy.stats import uniform, randint\n",
"from miplearn.problems.stab import (\n", "from miplearn.problems.stab import (\n",
" MaxWeightStableSetGenerator,\n", " MaxWeightStableSetGenerator,\n",
" MaxWeightStableSetPerturber,\n",
" build_stab_model_gurobipy,\n", " build_stab_model_gurobipy,\n",
")\n", ")\n",
"\n", "\n",
@@ -1001,14 +1014,20 @@
"random.seed(42)\n", "random.seed(42)\n",
"np.random.seed(42)\n", "np.random.seed(42)\n",
"\n", "\n",
"# Generate random instances with a fixed 10-node graph,\n", "# Generate a base instance with a 10-node graph,\n",
"# 25% density and random weights in the [0, 100] interval.\n", "# 25% density and random weights in the [0, 100] interval.\n",
"data = MaxWeightStableSetGenerator(\n", "generator = MaxWeightStableSetGenerator(\n",
" w=uniform(loc=0.0, scale=100.0),\n", " w=uniform(loc=0.0, scale=100.0),\n",
" n=randint(low=10, high=11),\n", " n=randint(low=10, high=11),\n",
" p=uniform(loc=0.25, scale=0.0),\n", " p=uniform(loc=0.25, scale=0.0),\n",
" fix_graph=True,\n", ")\n",
").generate(10)\n", "base_instance = generator.generate(1)[0]\n",
"\n",
"# Create multiple instances with the same graph but perturbed weights\n",
"perturber = MaxWeightStableSetPerturber(\n",
" w_jitter=uniform(loc=0.9, scale=0.1),\n",
")\n",
"data = perturber.perturb(base_instance, 10)\n",
"\n", "\n",
"# Print the graph and weights for two instances\n", "# Print the graph and weights for two instances\n",
"print(\"graph\", data[0].graph.edges)\n", "print(\"graph\", data[0].graph.edges)\n",
@@ -1129,17 +1148,18 @@
"\n", "\n",
"Set parameter PreCrush to value 1\n", "Set parameter PreCrush to value 1\n",
"Set parameter LazyConstraints to value 1\n", "Set parameter LazyConstraints to value 1\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Non-default parameters:\n", "Non-default parameters:\n",
"PreCrush 1\n", "PreCrush 1\n",
"LazyConstraints 1\n", "LazyConstraints 1\n",
"\n", "\n",
"Optimize a model with 10 rows, 45 columns and 90 nonzeros\n", "Optimize a model with 10 rows, 45 columns and 90 nonzeros (Min)\n",
"Model fingerprint: 0x719675e5\n", "Model fingerprint: 0x719675e5\n",
"Model has 45 linear objective coefficients\n",
"Variable types: 0 continuous, 45 integer (45 binary)\n", "Variable types: 0 continuous, 45 integer (45 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
" Matrix range [1e+00, 1e+00]\n", " Matrix range [1e+00, 1e+00]\n",
@@ -1160,15 +1180,15 @@
"Cutting planes:\n", "Cutting planes:\n",
" Lazy constraints: 3\n", " Lazy constraints: 3\n",
"\n", "\n",
"Explored 1 nodes (17 simplex iterations) in 0.01 seconds (0.00 work units)\n", "Explored 1 nodes (17 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n", "Thread count was 16 (of 16 available processors)\n",
"\n", "\n",
"Solution count 1: 2921 \n", "Solution count 1: 2921 \n",
"\n", "\n",
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 2.921000000000e+03, best bound 2.921000000000e+03, gap 0.0000%\n", "Best objective 2.921000000000e+03, best bound 2.921000000000e+03, gap 0.0000%\n",
"\n", "\n",
"User-callback calls 111, time in user-callback 0.00 sec\n" "User-callback calls 113, time in user-callback 0.00 sec\n"
] ]
} }
], ],
@@ -1297,6 +1317,14 @@
"If `fix_units=True`, then the list of generators (with their respective parameters) is kept the same for all generated instances. If `cost_jitter` and `demand_jitter` are provided, the instances will still have slightly different costs and demands." "If `fix_units=True`, then the list of generators (with their respective parameters) is kept the same for all generated instances. If `cost_jitter` and `demand_jitter` are provided, the instances will still have slightly different costs and demands."
] ]
}, },
{
"cell_type": "code",
"execution_count": null,
"id": "cf0b884a",
"metadata": {},
"outputs": [],
"source": []
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "855b87b4", "id": "855b87b4",
@@ -1307,7 +1335,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 12, "execution_count": 8,
"id": "6217da7c", "id": "6217da7c",
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
@@ -1348,13 +1376,14 @@
"demand[1]\n", "demand[1]\n",
" [ 827.37 926.76 1166.64 1128.59 939.17 948.8 950.95 639.5 ]\n", " [ 827.37 926.76 1166.64 1128.59 939.17 948.8 950.95 639.5 ]\n",
"\n", "\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Optimize a model with 162 rows, 120 columns and 512 nonzeros\n", "Optimize a model with 162 rows, 120 columns and 512 nonzeros (Min)\n",
"Model fingerprint: 0x1e3651da\n", "Model fingerprint: 0x1e3651da\n",
"Model has 120 linear objective coefficients\n",
"Model has 40 quadratic objective terms\n", "Model has 40 quadratic objective terms\n",
"Variable types: 40 continuous, 80 integer (80 binary)\n", "Variable types: 40 continuous, 80 integer (80 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
@@ -1382,43 +1411,31 @@
" 0 0 203097.772 0 4 208079.699 203097.772 2.39% - 0s\n", " 0 0 203097.772 0 4 208079.699 203097.772 2.39% - 0s\n",
" 0 0 203097.772 0 4 208079.699 203097.772 2.39% - 0s\n", " 0 0 203097.772 0 4 208079.699 203097.772 2.39% - 0s\n",
" 0 0 203097.772 0 3 208079.699 203097.772 2.39% - 0s\n", " 0 0 203097.772 0 3 208079.699 203097.772 2.39% - 0s\n",
" 0 0 203097.772 0 3 208079.699 203097.772 2.39% - 0s\n", " 0 0 203097.772 0 2 208079.699 203097.772 2.39% - 0s\n",
" 0 0 203097.772 0 3 208079.699 203097.772 2.39% - 0s\n", " 0 0 204065.874 0 2 208079.699 204065.874 1.93% - 0s\n",
" 0 0 205275.299 0 - 208079.699 205275.299 1.35% - 0s\n", " 0 0 205410.033 0 2 208079.699 205410.033 1.28% - 0s\n",
" 0 0 205777.846 0 2 208079.699 205777.846 1.11% - 0s\n", " 0 0 205413.331 0 2 208079.699 205413.331 1.28% - 0s\n",
" 0 0 205789.407 0 - 208079.699 205789.407 1.10% - 0s\n", "H 0 0 205789.40802 205458.260 0.16% - 0s\n",
" 0 0 postponed 0 208079.699 205789.407 1.10% - 0s\n", "* 0 0 0 205789.40802 205458.260 0.16% - 0s\n",
" 0 0 postponed 0 208079.699 205789.408 1.10% - 0s\n", " 0 0 - 0 205789.408 205787.978 0.00% - 0s\n",
" 0 0 205789.408 0 4 208079.699 205789.408 1.10% - 0s\n",
" 0 0 205789.408 0 4 208079.699 205789.408 1.10% - 0s\n",
" 0 0 205789.408 0 1 208079.699 205789.408 1.10% - 0s\n",
" 0 0 205789.408 0 - 208079.699 205789.408 1.10% - 0s\n",
" 0 0 205789.408 0 - 208079.699 205789.408 1.10% - 0s\n",
" 0 0 205789.408 0 - 208079.699 205789.408 1.10% - 0s\n",
" 0 0 205789.408 0 - 208079.699 205789.408 1.10% - 0s\n",
" 0 0 205789.408 0 2 208079.699 205789.408 1.10% - 0s\n",
"H 0 0 207525.63560 205789.408 0.84% - 0s\n",
" 0 0 205789.408 0 2 207525.636 205789.408 0.84% - 0s\n",
" 0 2 205789.408 0 2 207525.636 205789.408 0.84% - 0s\n",
"* 9 0 5 205789.40812 205789.408 0.00% 0.0 0s\n",
"\n", "\n",
"Cutting planes:\n", "Cutting planes:\n",
" Gomory: 1\n",
" Cover: 1\n", " Cover: 1\n",
" Implied bound: 6\n", " Implied bound: 1\n",
" MIR: 2\n", " MIR: 7\n",
" Flow cover: 2\n", " Flow cover: 3\n",
" RLT: 2\n", " Relax-and-lift: 1\n",
"\n", "\n",
"Explored 11 nodes (621 simplex iterations) in 0.32 seconds (0.19 work units)\n", "Explored 1 nodes (431 simplex iterations) in 0.02 seconds (0.01 work units)\n",
"Thread count was 32 (of 32 available processors)\n", "Thread count was 16 (of 16 available processors)\n",
"\n", "\n",
"Solution count 5: 205789 207526 208080 ... 282371\n", "Solution count 4: 205789 208080 212979 282371 \n",
"No other solutions better than 205789\n",
"\n", "\n",
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 2.057894080889e+05, best bound 2.057894081187e+05, gap 0.0000%\n", "Best objective 2.057894080182e+05, best bound 2.057879779509e+05, gap 0.0007%\n",
"\n", "\n",
"User-callback calls 650, time in user-callback 0.00 sec\n" "User-callback calls 540, time in user-callback 0.00 sec\n"
] ]
} }
], ],
@@ -1513,7 +1530,7 @@
"source": [ "source": [
"### Random instance generator\n", "### Random instance generator\n",
"\n", "\n",
"The class [MinWeightVertexCoverGenerator][MinWeightVertexCoverGenerator] can be used to generate random instances of this problem. The class accepts exactly the same parameters and behaves exactly in the same way as [MaxWeightStableSetGenerator][MaxWeightStableSetGenerator]. See the [stable set section](#Stable-Set) for more details.\n", "The class [MinWeightVertexCoverGenerator][MinWeightVertexCoverGenerator] can be used to generate random instances of this problem. The class accepts the same parameters and behaves in the same way as [MaxWeightStableSetGenerator][MaxWeightStableSetGenerator]. See the [stable set section](#Stable-Set) for more details on the generation process.\n",
"\n", "\n",
"[MinWeightVertexCoverGenerator]: ../../api/problems/#module-miplearn.problems.vertexcover\n", "[MinWeightVertexCoverGenerator]: ../../api/problems/#module-miplearn.problems.vertexcover\n",
"[MaxWeightStableSetGenerator]: ../../api/problems/#miplearn.problems.stab.MaxWeightStableSetGenerator\n", "[MaxWeightStableSetGenerator]: ../../api/problems/#miplearn.problems.stab.MaxWeightStableSetGenerator\n",
@@ -1540,13 +1557,14 @@
"weights[0] [37.45 95.07 73.2 59.87 15.6 15.6 5.81 86.62 60.11 70.81]\n", "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", "weights[1] [ 2.06 96.99 83.24 21.23 18.18 18.34 30.42 52.48 43.19 29.12]\n",
"\n", "\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Optimize a model with 15 rows, 10 columns and 30 nonzeros\n", "Optimize a model with 15 rows, 10 columns and 30 nonzeros (Min)\n",
"Model fingerprint: 0x2d2d1390\n", "Model fingerprint: 0x2d2d1390\n",
"Model has 10 linear objective coefficients\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n", "Variable types: 0 continuous, 10 integer (10 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
" Matrix range [1e+00, 1e+00]\n", " Matrix range [1e+00, 1e+00]\n",
@@ -1566,15 +1584,15 @@
"\n", "\n",
" 0 0 cutoff 0 301.00000 301.00000 0.00% - 0s\n", " 0 0 cutoff 0 301.00000 301.00000 0.00% - 0s\n",
"\n", "\n",
"Explored 1 nodes (8 simplex iterations) in 0.01 seconds (0.00 work units)\n", "Explored 1 nodes (8 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 32 (of 32 available processors)\n", "Thread count was 16 (of 16 available processors)\n",
"\n", "\n",
"Solution count 1: 301 \n", "Solution count 1: 301 \n",
"\n", "\n",
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective 3.010000000000e+02, best bound 3.010000000000e+02, gap 0.0000%\n", "Best objective 3.010000000000e+02, best bound 3.010000000000e+02, gap 0.0000%\n",
"\n", "\n",
"User-callback calls 333, time in user-callback 0.00 sec\n" "User-callback calls 335, time in user-callback 0.00 sec\n"
] ]
} }
], ],
@@ -1591,13 +1609,12 @@
"random.seed(42)\n", "random.seed(42)\n",
"np.random.seed(42)\n", "np.random.seed(42)\n",
"\n", "\n",
"# Generate random instances with a fixed 10-node graph,\n", "# Generate random instances with a 10-node graph,\n",
"# 25% density and random weights in the [0, 100] interval.\n", "# 25% density and random weights in the [0, 100] interval.\n",
"data = MinWeightVertexCoverGenerator(\n", "data = MinWeightVertexCoverGenerator(\n",
" w=uniform(loc=0.0, scale=100.0),\n", " w=uniform(loc=0.0, scale=100.0),\n",
" n=randint(low=10, high=11),\n", " n=randint(low=10, high=11),\n",
" p=uniform(loc=0.25, scale=0.0),\n", " p=uniform(loc=0.25, scale=0.0),\n",
" fix_graph=True,\n",
").generate(10)\n", ").generate(10)\n",
"\n", "\n",
"# Print the graph and weights for two instances\n", "# Print the graph and weights for two instances\n",
@@ -1686,13 +1703,14 @@
"weights[0]: [ 1 1 1 -1 -1 -1 -1 -1 -1 -1 1 -1 -1 1 1 -1 -1]\n", "weights[0]: [ 1 1 1 -1 -1 -1 -1 -1 -1 -1 1 -1 -1 1 1 -1 -1]\n",
"weights[1]: [-1 1 -1 -1 -1 1 -1 1 -1 1 -1 1 -1 -1 1 -1 1]\n", "weights[1]: [-1 1 -1 -1 -1 1 -1 1 -1 1 -1 1 -1 -1 1 -1 1]\n",
"\n", "\n",
"Gurobi Optimizer version 12.0.3 build v12.0.3rc0 (linux64 - \"Ubuntu 24.04.3 LTS\")\n", "Gurobi Optimizer version 13.0.0 build v13.0.0rc1 (linux64 - \"Ubuntu 22.04.5 LTS\")\n",
"\n", "\n",
"CPU model: AMD Ryzen 9 3950X 16-Core Processor, instruction set [SSE2|AVX|AVX2]\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", "Thread count: 16 physical cores, 16 logical processors, using up to 16 threads\n",
"\n", "\n",
"Optimize a model with 0 rows, 10 columns and 0 nonzeros\n", "Optimize a model with 0 rows, 10 columns and 0 nonzeros (Min)\n",
"Model fingerprint: 0x005f9eac\n", "Model fingerprint: 0x005f9eac\n",
"Model has 5 linear objective coefficients\n",
"Model has 17 quadratic objective terms\n", "Model has 17 quadratic objective terms\n",
"Variable types: 0 continuous, 10 integer (10 binary)\n", "Variable types: 0 continuous, 10 integer (10 binary)\n",
"Coefficient statistics:\n", "Coefficient statistics:\n",
@@ -1707,8 +1725,8 @@
"Presolve time: 0.00s\n", "Presolve time: 0.00s\n",
"Presolve: All rows and columns removed\n", "Presolve: All rows and columns removed\n",
"\n", "\n",
"Explored 0 nodes (0 simplex iterations) in 0.01 seconds (0.00 work units)\n", "Explored 0 nodes (0 simplex iterations) in 0.00 seconds (0.00 work units)\n",
"Thread count was 1 (of 32 available processors)\n", "Thread count was 1 (of 16 available processors)\n",
"\n", "\n",
"Solution count 2: -3 0 \n", "Solution count 2: -3 0 \n",
"No other solutions better than -3\n", "No other solutions better than -3\n",
@@ -1716,7 +1734,7 @@
"Optimal solution found (tolerance 1.00e-04)\n", "Optimal solution found (tolerance 1.00e-04)\n",
"Best objective -3.000000000000e+00, best bound -3.000000000000e+00, gap 0.0000%\n", "Best objective -3.000000000000e+00, best bound -3.000000000000e+00, gap 0.0000%\n",
"\n", "\n",
"User-callback calls 86, time in user-callback 0.00 sec\n" "User-callback calls 100, time in user-callback 0.00 sec\n"
] ]
} }
], ],
@@ -1770,7 +1788,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.12.3" "version": "3.11.7"
} }
}, },
"nbformat": 4, "nbformat": 4,

View File

@@ -32,14 +32,10 @@ class MaxWeightStableSetData:
class MaxWeightStableSetGenerator: class MaxWeightStableSetGenerator:
"""Random instance generator for the Maximum-Weight Stable Set Problem. """Random instance generator for the Maximum-Weight Stable Set Problem.
The generator has two modes of operation. When `fix_graph=True` is provided, Generates instances by creating a new random Erdős-Rényi graph $G_{n,p}$ for each
one random Erdős-Rényi graph $G_{n,p}$ is generated in the constructor, where $n$ instance, where $n$ and $p$ are sampled from user-provided probability distributions
and $p$ are sampled from user-provided probability distributions `n` and `p`. To `n` and `p`. For each instance, the generator independently samples each $w_v$ from
generate each instance, the generator independently samples each $w_v$ from the the user-provided probability distribution `w`.
user-provided probability distribution `w`.
When `fix_graph=False`, a new random graph is generated for each instance; the
remaining parameters are sampled in the same way.
""" """
def __init__( def __init__(
@@ -47,7 +43,6 @@ class MaxWeightStableSetGenerator:
w: rv_frozen = uniform(loc=10.0, scale=1.0), w: rv_frozen = uniform(loc=10.0, scale=1.0),
n: rv_frozen = randint(low=250, high=251), n: rv_frozen = randint(low=250, high=251),
p: rv_frozen = uniform(loc=0.05, scale=0.0), p: rv_frozen = uniform(loc=0.05, scale=0.0),
fix_graph: bool = True,
): ):
"""Initialize the problem generator. """Initialize the problem generator.
@@ -66,17 +61,10 @@ class MaxWeightStableSetGenerator:
self.w = w self.w = w
self.n = n self.n = n
self.p = p self.p = p
self.fix_graph = fix_graph
self.graph = None
if fix_graph:
self.graph = self._generate_graph()
def generate(self, n_samples: int) -> List[MaxWeightStableSetData]: def generate(self, n_samples: int) -> List[MaxWeightStableSetData]:
def _sample() -> MaxWeightStableSetData: def _sample() -> MaxWeightStableSetData:
if self.graph is not None: graph = self._generate_graph()
graph = self.graph
else:
graph = self._generate_graph()
weights = np.round(self.w.rvs(graph.number_of_nodes()), 2) weights = np.round(self.w.rvs(graph.number_of_nodes()), 2)
return MaxWeightStableSetData(graph, weights) return MaxWeightStableSetData(graph, weights)
@@ -86,6 +74,42 @@ class MaxWeightStableSetGenerator:
return nx.generators.random_graphs.binomial_graph(self.n.rvs(), self.p.rvs()) return nx.generators.random_graphs.binomial_graph(self.n.rvs(), self.p.rvs())
class MaxWeightStableSetPerturber:
"""Perturbation generator for existing Maximum-Weight Stable Set instances.
Takes an existing MaxWeightStableSetData instance and generates new instances
by applying randomization factors to the existing weights while keeping the graph fixed.
"""
def __init__(
self,
w_jitter: rv_frozen = uniform(loc=0.9, scale=0.2),
):
"""Initialize the perturbation generator.
Parameters
----------
w_jitter: rv_continuous
Probability distribution for randomization factors applied to vertex weights.
"""
assert isinstance(
w_jitter, rv_frozen
), "w_jitter should be a SciPy probability distribution"
self.w_jitter = w_jitter
def perturb(
self,
instance: MaxWeightStableSetData,
n_samples: int,
) -> List[MaxWeightStableSetData]:
def _sample() -> MaxWeightStableSetData:
jitter_factors = self.w_jitter.rvs(instance.graph.number_of_nodes())
weights = np.round(instance.weights * jitter_factors, 2)
return MaxWeightStableSetData(instance.graph, weights)
return [_sample() for _ in range(n_samples)]
def build_stab_model_gurobipy( def build_stab_model_gurobipy(
data: Union[str, MaxWeightStableSetData], data: Union[str, MaxWeightStableSetData],
params: Optional[dict[str, Any]] = None, params: Optional[dict[str, Any]] = None,

View File

@@ -29,9 +29,8 @@ class MinWeightVertexCoverGenerator:
w: rv_frozen = uniform(loc=10.0, scale=1.0), w: rv_frozen = uniform(loc=10.0, scale=1.0),
n: rv_frozen = randint(low=250, high=251), n: rv_frozen = randint(low=250, high=251),
p: rv_frozen = uniform(loc=0.05, scale=0.0), p: rv_frozen = uniform(loc=0.05, scale=0.0),
fix_graph: bool = True,
): ):
self._generator = MaxWeightStableSetGenerator(w, n, p, fix_graph) self._generator = MaxWeightStableSetGenerator(w, n, p)
def generate(self, n_samples: int) -> List[MinWeightVertexCoverData]: def generate(self, n_samples: int) -> List[MinWeightVertexCoverData]:
return [ return [

View File

@@ -28,17 +28,17 @@ def test_mem_component_gp(
clf.fit.assert_called() clf.fit.assert_called()
x, y = clf.fit.call_args.args x, y = clf.fit.call_args.args
assert x.shape == (3, 50) assert x.shape == (3, 50)
assert y.shape == (3, 412) assert y.shape == (3, 382)
y = y.tolist() y = y.tolist()
assert y[0][40:50] == [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] assert y[0][40:50] == [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
assert y[1][40:50] == [1, 1, 0, 1, 1, 1, 1, 1, 1, 1] assert y[1][40:50] == [1, 1, 1, 0, 1, 1, 1, 1, 1, 1]
assert y[2][40:50] == [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] assert y[2][40:50] == [1, 1, 1, 1, 0, 0, 1, 1, 1, 1]
# Should store violations # Should store violations
assert comp.constrs_ is not None assert comp.constrs_ is not None
assert comp.n_features_ == 50 assert comp.n_features_ == 50
assert comp.n_targets_ == 412 assert comp.n_targets_ == 382
assert len(comp.constrs_) == 412 assert len(comp.constrs_) == 382
# Call before-mip # Call before-mip
stats: Dict[str, Any] = {} stats: Dict[str, Any] = {}
@@ -54,7 +54,7 @@ def test_mem_component_gp(
model.set_cuts.assert_called() model.set_cuts.assert_called()
(cuts_aot_,) = model.set_cuts.call_args.args (cuts_aot_,) = model.set_cuts.call_args.args
assert cuts_aot_ is not None assert cuts_aot_ is not None
assert len(cuts_aot_) == 256 assert len(cuts_aot_) == 247
def test_usage_stab( def test_usage_stab(

View File

@@ -7,6 +7,7 @@ from miplearn.collectors.basic import BasicCollector
from miplearn.io import write_pkl_gz from miplearn.io import write_pkl_gz
from miplearn.problems.stab import ( from miplearn.problems.stab import (
MaxWeightStableSetGenerator, MaxWeightStableSetGenerator,
MaxWeightStableSetPerturber,
build_stab_model_gurobipy, build_stab_model_gurobipy,
build_stab_model_pyomo, build_stab_model_pyomo,
) )
@@ -17,9 +18,12 @@ gen = MaxWeightStableSetGenerator(
w=uniform(10.0, scale=1.0), w=uniform(10.0, scale=1.0),
n=randint(low=50, high=51), n=randint(low=50, high=51),
p=uniform(loc=0.5, scale=0.0), p=uniform(loc=0.5, scale=0.0),
fix_graph=True,
) )
data = gen.generate(3) pr = MaxWeightStableSetPerturber(
w_jitter=uniform(0.9, scale=0.2),
)
base_instance = gen.generate(1)[0]
data = pr.perturb(base_instance, 3)
params = {"seed": 42, "threads": 1} params = {"seed": 42, "threads": 1}

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.