-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmodel_objective_vehicles_duration.go
125 lines (103 loc) · 3.23 KB
/
model_objective_vehicles_duration.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// © 2019-present nextmv.io inc
package nextroute
import "slices"
// VehiclesDurationObjective is an objective that uses the vehicle duration as an
// objective.
type VehiclesDurationObjective interface {
ModelObjective
}
// NewVehiclesDurationObjective returns a new VehiclesDurationObjective.
func NewVehiclesDurationObjective() VehiclesDurationObjective {
return &vehiclesDurationObjectiveImpl{}
}
func (t *vehiclesDurationObjectiveImpl) Lock(model Model) error {
t.canIncurWaitingTime = slices.ContainsFunc(model.Stops(), func(stop ModelStop) bool {
return stop.(*stopImpl).canIncurWaitingTime()
})
vehicleTypes := model.VehicleTypes()
t.isDependentOnTimeByVehicleType = make([]bool, len(vehicleTypes))
for _, vehicleType := range model.VehicleTypes() {
t.isDependentOnTimeByVehicleType[vehicleType.Index()] = vehicleType.
TravelDurationExpression().
IsDependentOnTime()
}
// caching the vehicle type by index for performance
t.vehicleTypesByIndex = make([]ModelVehicleType, len(vehicleTypes))
for _, vehicle := range model.Vehicles() {
t.vehicleTypesByIndex[vehicle.Index()] = vehicle.VehicleType()
}
return nil
}
type vehiclesDurationObjectiveImpl struct {
isDependentOnTimeByVehicleType []bool
vehicleTypesByIndex []ModelVehicleType
canIncurWaitingTime bool
}
func (t *vehiclesDurationObjectiveImpl) ModelExpressions() ModelExpressions {
return ModelExpressions{}
}
func (t *vehiclesDurationObjectiveImpl) EstimateDeltaValue(
move SolutionMoveStops,
) float64 {
solutionMoveStops := move.(*solutionMoveStopsImpl)
vehicle := solutionMoveStops.vehicle()
vehicleType := t.vehicleTypesByIndex[vehicle.index]
isDependentOnTime := t.isDependentOnTimeByVehicleType[vehicleType.Index()]
if !isDependentOnTime && !t.canIncurWaitingTime {
return solutionMoveStops.deltaStopTravelDurationValue(vehicleType)
}
first := true
end := 0.0
previousStop := vehicle.First()
generator := newSolutionStopGenerator(*solutionMoveStops, false, isDependentOnTime)
defer generator.release()
for solutionStop, ok := generator.next(); ok; solutionStop, ok = generator.next() {
if first {
previousStop = solutionStop
end = solutionStop.EndValue()
first = false
continue
}
_, _, _, end = vehicleType.TemporalValues(
end,
previousStop.ModelStop(),
solutionStop.ModelStop(),
)
previousStop = solutionStop
}
nextmove, _ := solutionMoveStops.next()
if nextmove.IsLast() || isDependentOnTime {
return end - vehicle.Last().EndValue()
}
for solutionStop := nextmove.Next(); !solutionStop.IsLast(); solutionStop = solutionStop.Next() {
_, _, _, end = vehicleType.TemporalValues(
end,
solutionStop.Previous().ModelStop(),
solutionStop.ModelStop(),
)
tempEnd := solutionStop.EndValue()
if tempEnd >= end {
return 0.0
}
}
last := vehicle.Last()
_, _, _, end = vehicleType.TemporalValues(
end,
last.Previous().ModelStop(),
last.ModelStop(),
)
return end - last.EndValue()
}
func (t *vehiclesDurationObjectiveImpl) Value(
solution Solution,
) float64 {
solutionImp := solution.(*solutionImpl)
score := 0.0
for _, r := range solutionImp.vehicles {
score += r.DurationValue()
}
return score
}
func (t *vehiclesDurationObjectiveImpl) String() string {
return "vehicles_duration"
}