Problem
The problem (from [1]) is to determine where to pump gasoline (and how much) during a trip, where prices between gas stations fluctuate.
We consider some different objectives:
- minimize cost
- minimize number of stops
- minimize number of stops followed by minimize cost
Data
I invented some data:
----34 SET i locations
start , Station1 , Station2 , Station3 , Station4 , Station5 , Station6 , Station7
Station8 , Station9 , Station10, Station11, Station12, Station13, Station14, Station15
Station16, Station17, Station18, Station19, Station20, finish
----34 SET g gas stations
Station1 , Station2 , Station3 , Station4 , Station5 , Station6 , Station7 , Station8
Station9 , Station10, Station11, Station12, Station13, Station14, Station15, Station16
Station17, Station18, Station19, Station20
----34 PARAMETER efficiency =18.000 [miles/gallon]
PARAMETER capacity =50.000 tank-capacity [gallons]
PARAMETER initgas =25.000 initial amount of gasoline in tank [gallons]
PARAMETER finalgas =10.000 minimum final amount of gas in tank [gallons]
PARAMETER triplen =2000.000 length of trip [miles]
----34 PARAMETER price [$/gallon]
Station1 3.002, Station2 3.630, Station3 3.616, Station4 3.126, Station5 3.167, Station6 3.603
Station7 2.067, Station8 3.281, Station9 3.748, Station10 3.783, Station11 3.065, Station12 2.349
Station13 3.135, Station14 2.928, Station15 3.527, Station16 3.585, Station17 3.305, Station18 3.460
Station19 3.320, Station20 2.375
----34 PARAMETER distance [miles]
Station1 Station2 Station3 Station4 Station5 Station6 Station7 Station8 Station9
incr 88.074174.2273.250157.6711.847140.24779.275166.355117.030
cumul 88.074262.301265.550423.221425.068565.315644.590810.945927.975
+ Station10 Station11 Station12 Station13 Station14 Station15 Station16 Station17 Station18
incr 136.78716.51723.499167.570127.41831.52091.88591.36374.604
cumul 1064.7621081.2791104.7781272.3481399.7671431.2861523.1721614.5351689.139
+ Station19 Station20 finish
incr 148.78818.876143.198
cumul 1837.9261856.8022000.000
Prices and distances were produced using a random number generator.
Note that I added the constraint that we need a little bit left over gas in the tank when arriving at the finish. That requirement was not in the original problem [1]. We can drop this constraint by just setting the parameter \(\mathit{finalgas}=0\).
We also have some derived data: the amount of gas we use for each leg of the trip. This is just the length of the leg divided by the efficiency of the car:
----34 PARAMETER use gas usage from previous location [gallons]
Station1 4.893, Station2 9.679, Station3 0.181, Station4 8.760, Station5 0.103, Station6 7.791
Station7 4.404, Station8 9.242, Station9 6.502, Station10 7.599, Station11 0.918, Station12 1.305
Station13 9.309, Station14 7.079, Station15 1.751, Station16 5.105, Station17 5.076, Station18 4.145
Station19 8.266, Station20 1.049, finish 7.955
Problem 1: minimize cost
The first problem is to minimize fuel cost. I have modeled this by observing three stages at each way point:
- First is the amount of gas in the tank when arriving at point \(i\). This amount should be non-negative: we cannot drive when the tank is empty. This variable is denoted by \(f_{\mathit{before},i}\ge 0\).
- The amount we pump is the second stage. This amount is bounded by \([0,\mathrm{capacity}]\). This variable is denoted by \(f_{\mathit{pumped},g}\).
- The amount in the tank after pumping. This amount cannot exceed the capacity of the tank. This is \(f_{\mathit{after},i} \in [0,\mathrm{capacity}]\).
This problem is a little bit like modeling inventory: keep track of what is going out and what is added. The LP model can look like:
Min Cost Model |
---|
\[\begin{align} \min \> & \color{darkred}{\mathit{cost}}\\ & \color{darkred}{\mathit{cost}} = \sum_g \color{darkred}f_{\mathit{pumped},g} \cdot \color{darkblue}{\mathit{price}}_g \\ & \color{darkred}f_{\mathit{before},i} = \color{darkred}f_{\mathit{after},i-1} - \color{darkblue}{\mathit{use}}_i && \forall i \ne \mathit{start} \\ & \color{darkred}f_{\mathit{after},g} = \color{darkred}f_{\mathit{before},g} + \color{darkred}f_{\mathit{pumped},g} && \forall g \\ & \color{darkred}f_{\mathit{after},\mathit{start}} = \color{darkblue}{\mathit{initgas}} \\ & \color{darkred}f_{\mathit{before},\mathit{finish}} \ge \color{darkblue}{\mathit{finalgas}} \\ & \color{darkred}f_{k,i} \in [0,\color{darkblue}{\mathit{capacity}}] \end{align}\] |
Note that the set \(g\) is a subset of set \(i\): \(g\) indicates the locations with gas stations between \(\mathit{start}\) and \(\mathit{finish}\). Also note that we cannot just substitute out the variable \(f_{\mathit{before},i}\): we need to make sure this quantity is non-negative. Similarly, we cannot substitute out the variable \(f_{\mathit{after},i}\): this must obey the tank capacity bound.
The results look like:
----66 VARIABLE f.L amounts of fuel
start Station1 Station2 Station3 Station4 Station5 Station6 Station7 Station8
before 20.10721.23821.05812.29812.1964.40440.758
pumped 10.81150.000
after 25.00030.91821.23821.05812.29812.1964.40450.00040.758
+ Station9 Station10 Station11 Station12 Station13 Station14 Station15 Station16 Station17
before 34.25626.65725.74024.43440.69133.61231.86126.75621.680
pumped 25.566
after 34.25626.65725.74050.00040.69133.61231.86126.75621.680
+ Station18 Station19 Station20 finish
before 17.5359.2708.22110.000
pumped 9.735
after 17.5359.27017.955
----66 VARIABLE cost.L =218.998
We see we pump the most at station 7. Looking at the prices this makes sense: gasoline is cheapest at that gas station.
The number of stops where we pump gas is 4, and the total gas bill is $219.
Problem 2: minimize number of stops
In the previous section we solved the minimize cost problem. This gave us 4 stops to refuel with total fuel cost of $219. Now, let's try to minimize the number of times we visit a gas station. Counting in general needs binary variables, and this is no exception. The model can look like:
Min Number of Stops Model |
---|
\[\begin{align} \min \> & \color{darkred}{\mathit{numstops}}\\ & \color{darkred}{\mathit{numstops}} = \sum_g \color{darkred} \delta_g \\ & \color{darkred}{\mathit{cost}} = \sum_g \color{darkred}f_{\mathit{pumped},g} \cdot \color{darkblue}{\mathit{price}}_g \\ & \color{darkred}f_{\mathit{before},i} = \color{darkred}f_{\mathit{after},i-1} - \color{darkblue}{\mathit{use}}_i && \forall i \ne \mathit{start} \\ & \color{darkred}f_{\mathit{after},g} = \color{darkred}f_{\mathit{before},g} + \color{darkred}f_{\mathit{pumped},g} && \forall g \\ & \color{darkred}f_{\mathit{after},\mathit{start}} = \color{darkblue}{\mathit{initgas}} \\ & \color{darkred}f_{\mathit{before},\mathit{finish}} \ge \color{darkblue}{\mathit{finalgas}} \\ & \color{darkred} f_{\mathit{pumped},g} \le \color{darkred} \delta_g \cdot \color{darkblue}{\mathit{capacity}} && \forall g \\ & \color{darkred}f_{k,i} \in [0,\color{darkblue}{\mathit{capacity}}] \\ & \color{darkred} \delta_g \in \{0,1\} \end{align}\] |
Because we have binary variables, this is now a MIP model. The constraint \(f_{\mathit{pumped},g} \le \delta_g \cdot \mathit{capacity}\) implements the implication: \[\delta_g=0 \Rightarrow f_{\mathit{pumped},g}=0\]When we solve this we see:
----71 VARIABLE f.L amounts of fuel
start Station1 Station2 Station3 Station4 Station5 Station6 Station7 Station8
before 20.10710.42810.2471.4881.38541.95432.712
pumped 6.40646.358
after 25.00020.10710.42810.2471.4887.79146.35841.95432.712
+ Station9 Station10 Station11 Station12 Station13 Station14 Station15 Station16 Station17
before 26.21118.61117.69416.3887.07941.59536.49031.415
pumped 43.346
after 26.21118.61117.69416.3887.07943.34641.59536.49031.415
+ Station18 Station19 Station20 finish
before 27.27019.00417.95510.000
after 27.27019.00417.955
----71 VARIABLE delta.L
Station5 1.000, Station6 1.000, Station14 1.000
----71 VARIABLE cost.L =314.254
VARIABLE numstops.L =3.000
So instead of 4 stops, now we only need 3 stops. We ignored the cost in this model. This causes the fuel cost to skyrocket to $314 (from $219 in the min cost model).
I kept the cost constraint in the problem for two reasons. First, it functions as an accounting constraint. Such a constraint is just for informational purposes (it is not meant to change or restrict the solution). A second reason is that we use the cost variable in a second solve in order to minimize cost while keeping the number of stops optimal. This is explained in the next section.
Problem 3: minimize number of stops followed by minimizing cost
After solving the min number of stops problem (previous section), we can fix the number of stops variable \(\mathit{numstops}\) to the optimal value and resolve minimizing the cost. This is essentially a lexicographic approach to solving the multi-objective problem min numstops, min cost. If we do this we get as solution:
----76 VARIABLE f.L amounts of fuel
start Station1 Station2 Station3 Station4 Station5 Station6 Station7 Station8
before 20.10721.23821.05812.29812.1964.40440.758
pumped 10.81150.000
after 25.00030.91821.23821.05812.29812.1964.40450.00040.758
+ Station9 Station10 Station11 Station12 Station13 Station14 Station15 Station16 Station17
before 34.25626.65725.74024.43415.1258.04641.59536.49031.415
pumped 35.301
after 34.25626.65725.74024.43415.12543.34641.59536.49031.415
+ Station18 Station19 Station20 finish
before 27.27019.00417.95510.000
after 27.27019.00417.955
----76 VARIABLE delta.L
Station1 1.000, Station7 1.000, Station14 1.000
----76 VARIABLE cost.L =239.188
VARIABLE numstops.L =3.000
Now we have a solution with 3 stops and a fuel cost of $239. This is my proposal for a solution strategy for the problem stated in [1].
An alternative would be to create a single optimization problem with a weighted sum objective: \[\min \> \mathit{numstops} + w \cdot \mathit{cost}\] with \(w\) a small constant to make sure that \(\mathit{numstops}\) is the most important variable. As the value of \(w\) requires some thought, it may be better to use the lexicographic approach.
Filling up the gas tank
Suppose that when pumping gas we always fill up the tank completely. This alternative is not too difficult to handle. We need to add the implication: \[\delta_g=1 \Rightarrow f_{\mathit{pumped},g}=\mathit{capacity}-f_{\mathit{before},g}\] This can be handled using the inequality: \[f_{\mathit{pumped},g} \ge \delta_g \cdot \mathit{capacity}-f_{\mathit{before},g}\]
If we add this constraint and solve the min cost model we see:
----84 VARIABLE f.L amounts of fuel
start Station1 Station2 Station3 Station4 Station5 Station6 Station7 Station8
before 20.10740.32140.14031.38131.27823.48719.08240.758
pumped 29.89330.918
after 25.00050.00040.32140.14031.38131.27823.48750.00040.758
+ Station9 Station10 Station11 Station12 Station13 Station14 Station15 Station16 Station17
before 34.25626.65725.74024.43440.69133.61248.24943.14438.068
pumped 25.56616.388
after 34.25626.65725.74050.00040.69150.00048.24943.14438.068
+ Station18 Station19 Station20 finish
before 33.92425.65824.60916.654
after 33.92425.65824.609
----84 VARIABLE delta.L
Station1 1.000, Station7 1.000, Station12 1.000, Station14 1.000
----84 VARIABLE cost.L =261.709
VARIABLE numstops.L =4.000
In this case we have a little bit more gasoline left in the tank at the finish than strictly needed. Notice how in each case we pump gas, we end up with with a full tank. This fill-up strategy is surprisingly expensive.
Conclusion
Here we see the advantages of using an optimization model compared to a tailored algorithm. We can adapt the optimization model to different situations. From the basic min cost model, we can quickly react to new questions.
References
- Gas Station Problem - cheapest and least amount of stations, https://stackoverflow.com/questions/58289424/gas-station-problem-cheapest-and-least-amount-of-stations
- Shamir Khuller, Azarakhsh Malekian, Julian Mestre, To Fill or not to Fill: The Gas Station Problem, ACM Transactions on Algorithms, Volume 7, Issue 3, July 2011.