Implement TravelingSalesmanPerturber

This commit is contained in:
2025-12-08 15:10:24 -06:00
parent 4137378bb8
commit 1d44980a7b
23 changed files with 128 additions and 90 deletions

View File

@@ -1108,15 +1108,18 @@
"source": [
"### Random instance generator\n",
"\n",
"The class [TravelingSalesmanGenerator][TravelingSalesmanGenerator] can be used to generate random instances of this problem. Initially, the class samples the user-provided probability distribution `n` to decide how many cities to generate. Then, for each city $i$, the class generates its geographical location $(x_i, y_i)$ by sampling the provided distributions `x` and `y`. The distance $d_{ij}$ between cities $i$ and $j$ is then set to\n",
"The class [TravelingSalesmanGenerator][TravelingSalesmanGenerator] can be used to generate random instances of this problem. The class samples the user-provided probability distribution `n` to decide how many cities to generate. Then, for each city $i$, the class generates its geographical location $(x_i, y_i)$ by sampling the provided distributions `x` and `y`. The distance $d_{ij}$ between cities $i$ and $j$ is then set to\n",
"$$\n",
"\\gamma_{ij} \\sqrt{(x_i - x_j)^2 + (y_i - y_j)^2},\n",
"$$\n",
"where $\\gamma$ is a random scaling factor sampled from the provided probability distribution `gamma`.\n",
"\n",
"If `fix_cities=True`, then the list of cities is kept the same for all generated instances. The $\\gamma$ values, however, and therefore also the distances, are still different. By default, all distances $d_{ij}$ are rounded to the nearest integer. If `round=False` is provided, this rounding will be disabled.\n",
"By default, all distances $d_{ij}$ are rounded to the nearest integer. If `round=False` is provided, this rounding will be disabled.\n",
"\n",
"[TravelingSalesmanGenerator]: ../../api/problems/#miplearn.problems.tsp.TravelingSalesmanGenerator"
"To create multiple instances with the same cities but slightly different distances, you can use [TravelingSalesmanPerturber][TravelingSalesmanPerturber]. This class takes an existing TravelingSalesmanData instance and generates new instances by applying fresh randomization factors to the distances computed from the original cities while keeping the city locations fixed.\n",
"\n",
"[TravelingSalesmanGenerator]: ../../api/problems/#miplearn.problems.tsp.TravelingSalesmanGenerator\n",
"[TravelingSalesmanPerturber]: ../../api/problems/#miplearn.problems.tsp.TravelingSalesmanPerturber"
]
},
{
@@ -1129,7 +1132,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 11,
"id": "9d0c56c6",
"metadata": {
"ExecuteTime": {
@@ -1146,6 +1149,17 @@
"name": "stdout",
"output_type": "stream",
"text": [
"cities\n",
" [[374.54011885 950.71430641]\n",
" [731.99394181 598.6584842 ]\n",
" [156.01864044 155.99452034]\n",
" [ 58.08361217 866.17614577]\n",
" [601.11501174 708.0725778 ]\n",
" [ 20.5844943 969.90985216]\n",
" [832.4426408 212.33911068]\n",
" [181.82496721 183.40450985]\n",
" [304.24224296 524.75643163]\n",
" [431.94501864 291.2291402 ]]\n",
"distances[0]\n",
" [[ 0. 513. 762. 358. 325. 374. 932. 731. 391. 634.]\n",
" [ 513. 0. 726. 765. 163. 754. 409. 719. 446. 400.]\n",
@@ -1221,6 +1235,7 @@
"from scipy.stats import uniform, randint\n",
"from miplearn.problems.tsp import (\n",
" TravelingSalesmanGenerator,\n",
" TravelingSalesmanPerturber,\n",
" build_tsp_model_gurobipy,\n",
")\n",
"\n",
@@ -1228,18 +1243,25 @@
"random.seed(42)\n",
"np.random.seed(42)\n",
"\n",
"# Generate random instances with a fixed ten cities in the 1000x1000 box\n",
"# and random distance scaling factors in the [0.90, 1.10] interval.\n",
"data = TravelingSalesmanGenerator(\n",
"# Generate a reference instance with ten cities in the 1000x1000 box\n",
"generator = TravelingSalesmanGenerator(\n",
" n=randint(low=10, high=11),\n",
" x=uniform(loc=0.0, scale=1000.0),\n",
" y=uniform(loc=0.0, scale=1000.0),\n",
" gamma=uniform(loc=0.90, scale=0.20),\n",
" fix_cities=True,\n",
" gamma=uniform(loc=1.0, scale=0.0),\n",
" round=True,\n",
").generate(10)\n",
")\n",
"reference_instance = generator.generate(1)[0]\n",
"\n",
"# Generate perturbed instances with the same cities but different distance scaling factors\n",
"perturber = TravelingSalesmanPerturber(\n",
" gamma=uniform(loc=0.90, scale=0.20),\n",
" round=True,\n",
")\n",
"data = perturber.perturb(reference_instance, 10)\n",
"\n",
"# Print distance matrices for the first two instances\n",
"print(\"cities\\n\", data[0].cities)\n",
"print(\"distances[0]\\n\", data[0].distances)\n",
"print(\"distances[1]\\n\", data[1].distances)\n",
"print()\n",