Fleet Configuration:
Shovels: 4
Trucks: 12
Payload: 220 tonnes
Crusher: 10000 t/h capacity
Shovel Details:
Unit Location Dig Rate Cycle
-----------------------------------------------
Shovel A Pit North 3500 t/h 18 min
Shovel B Pit South 4000 t/h 22 min
Excavator C Pit East 2800 t/h 25 min
Excavator D Pit West 3200 t/h 20 min
4 Mathematical Formulation
Decision variables:\(x_i\) = trucks assigned to shovel \(i\)
from optyx import VectorVariable# Productivity (t/h per truck)productivity = truck_payload *60/ cycle_times# Decision variables: trucks per shovel (continuous relaxation)# We set lb=1 to ensure minimum trucks per active shovelx = VectorVariable("trucks", n_shovels, lb=1, ub=n_trucks)# Total throughput: dot product of productivity and truckstotal_throughput = productivity @ x# Build problemprob = Problem("fleet_dispatch").maximize(total_throughput)# Constraintsprob.subject_to(x.sum() <= n_trucks)prob.subject_to(total_throughput <= crusher_capacity)# Shovel capacity constraints# Each shovel's throughput must not exceed its dig ratefor i inrange(n_shovels): prob.subject_to(x[i] * productivity[i] <= shovel_dig_rates[i])
=======================================================
FLEET DISPATCH SOLUTION
=======================================================
Status: OPTIMAL
Solve time: 230.7ms
Optimal Truck Assignments:
Shovel Trucks Throughput Utilization
--------------------------------------------------
Shovel A 4.8 3500 t/h 100%
Shovel B 1.4 827 t/h 21%
Excavator C 1.0 528 t/h 19%
Excavator D 4.8 3200 t/h 100%
--------------------------------------------------
TOTAL 12.0 8055 t/h
7 Real-Time Re-Optimization
One of Optyx’s strengths is fast re-solving when conditions change.
7.1 Scenario: Shovel B Breaks Down
# Shovel B (index 1) is downactive_shovels = [0, 2, 3] # A, C, D onlyn_active =len(active_shovels)# Rebuild with reduced fleetx2 = [Variable(f"trucks_{i}", lb=0, ub=n_trucks) for i in active_shovels]throughputs2 = [ x2[j] * truck_payload *60/ cycle_times[active_shovels[j]] for j inrange(n_active)]total_throughput2 =sum(throughputs2)prob2 = Problem("dispatch_breakdown").maximize(total_throughput2)prob2.subject_to(sum(x2) <= n_trucks)prob2.subject_to(total_throughput2 <= crusher_capacity)for j inrange(n_active): i = active_shovels[j] prob2.subject_to(throughputs2[j] <= shovel_dig_rates[i]) prob2.subject_to(x2[j] >=1)start = time.time()solution2 = prob2.solve()reopt_time = (time.time() - start) *1000print("\n"+"="*55)print("RE-OPTIMIZED (Shovel B down)")print("="*55)print(f"Re-optimization time: {reopt_time:.1f}ms")print()print("New Assignments:")for j, i inenumerate(active_shovels): trucks = solution2[f"trucks_{i}"]print(f" {shovel_names[i]:<15}: {trucks:.1f} trucks")loss = solution.objective_value - solution2.objective_valueprint(f"\nThroughput: {solution2.objective_value:,.0f} t/h")print(f"Loss from breakdown: {loss:,.0f} t/h ({loss/solution.objective_value*100:.1f}%)")
=======================================================
RE-OPTIMIZED (Shovel B down)
=======================================================
Re-optimization time: 2.2ms
New Assignments:
Shovel A : 4.8 trucks
Excavator C : 2.4 trucks
Excavator D : 4.8 trucks
Throughput: 7,956 t/h
Loss from breakdown: 99 t/h (1.2%)
8 Shift Change Scenario
At shift change, crew availability drops. Re-dispatch with fewer trucks:
n_trucks_shift =8# Reduced crewx3 = [Variable(f"trucks_{i}", lb=0, ub=n_trucks_shift) for i inrange(n_shovels)]throughputs3 = [x3[i] * truck_payload *60/ cycle_times[i] for i inrange(n_shovels)]solution3 = ( Problem("shift_change") .maximize(sum(throughputs3)) .subject_to(sum(x3) <= n_trucks_shift) .subject_to(sum(throughputs3) <= crusher_capacity) .solve())print("\nShift Change (8 trucks available):")print(f" Throughput: {solution3.objective_value:,.0f} t/h")print(f" Efficiency: {solution3.objective_value/n_trucks_shift:,.0f} t/h per truck")