-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding option for early termination when plateauing
- Loading branch information
1 parent
f0dc5de
commit 30fb509
Showing
11 changed files
with
699 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// © 2019-present nextmv.io inc | ||
|
||
package nextroute | ||
|
||
import ( | ||
"time" | ||
) | ||
|
||
type plateauTracker struct { | ||
// progression is the value progression of the solver. This is tracked | ||
// separately of any other progression tracking to avoid conflicts. | ||
progression []ProgressionEntry | ||
// durationIndex is the current index of the first progression entry within | ||
// the duration cutoff. | ||
durationIndex int | ||
// iterationsIndex is the current index of the first progression entry | ||
// within the iterations cutoff. | ||
iterationsIndex int | ||
// options are the options for the plateau tracker. | ||
options PlateauOptions | ||
} | ||
|
||
func newPlateauTracker(options PlateauOptions) *plateauTracker { | ||
return &plateauTracker{ | ||
progression: make([]ProgressionEntry, 0), | ||
durationIndex: 0, | ||
iterationsIndex: 0, | ||
options: options, | ||
} | ||
} | ||
|
||
// plateauTrackingActivated returns true if the plateau tracking should be | ||
// activated based on the provided options. | ||
func plateauTrackingActivated(options PlateauOptions) bool { | ||
// We need to be testing within some duration or iteration cutoff. | ||
return (options.Duration > 0 || options.Iterations > 0) && | ||
// We need to have some threshold configured (negative threshold is deactivating the corresponding check). | ||
(options.AbsoluteThreshold >= 0 || options.RelativeThreshold >= 0) | ||
} | ||
|
||
// onImprovement is called to update the plateau tracker whenever a new | ||
// improvement is found. | ||
func (t *plateauTracker) onImprovement(elapsed float64, iterations int, value float64) { | ||
if t == nil { | ||
return | ||
} | ||
// Add the new progression entry. | ||
t.progression = append(t.progression, ProgressionEntry{ | ||
ElapsedSeconds: elapsed, | ||
Value: value, | ||
Iterations: iterations, | ||
}) | ||
} | ||
|
||
// IsStop returns true if the solver should stop due to a detected plateau. | ||
func (t *plateauTracker) IsStop(iterations int, elapsed time.Duration) bool { | ||
if t == nil { | ||
return false | ||
} | ||
|
||
currentValue := t.progression[len(t.progression)-1].Value | ||
|
||
// Check if no significantly improving solutions were found during the | ||
// configured duration. | ||
if t.options.Duration > 0 { | ||
cutoffSeconds := t.options.Duration.Seconds() | ||
elapsedSeconds := elapsed.Seconds() | ||
// Move the duration index to the first entry within the cutoff. | ||
for t.durationIndex < len(t.progression) && | ||
(elapsedSeconds-t.progression[t.durationIndex].ElapsedSeconds) > cutoffSeconds { | ||
t.durationIndex++ | ||
} | ||
// If the duration index is at the end of the progression, no | ||
// improvement was found within the cutoff. | ||
if t.durationIndex == len(t.progression) { | ||
return true | ||
} | ||
// Compare the current value to the value at the duration index. | ||
cutoffValue := t.progression[t.durationIndex].Value | ||
if t.options.AbsoluteThreshold >= 0 && | ||
currentValue-cutoffValue < t.options.AbsoluteThreshold { | ||
return true | ||
} | ||
if t.options.RelativeThreshold >= 0 && | ||
currentValue > 0 && // Relative threshold is only supported for positive values. | ||
(currentValue-cutoffValue)/currentValue < t.options.RelativeThreshold { | ||
return true | ||
} | ||
} | ||
|
||
// Check if no significantly improving solutions were found during the | ||
// configured iterations. | ||
if t.options.Iterations > 0 { | ||
// Move the iterations index to the first entry within the cutoff. | ||
for t.iterationsIndex < len(t.progression) && | ||
iterations-t.progression[t.iterationsIndex].Iterations > t.options.Iterations { | ||
t.iterationsIndex++ | ||
} | ||
// If the iterations index is at the end of the progression, no | ||
// improvement was found within the cutoff. | ||
if t.iterationsIndex == len(t.progression) { | ||
return true | ||
} | ||
// Compare the current value to the value at the iterations index. | ||
cutoffValue := t.progression[t.iterationsIndex].Value | ||
if t.options.AbsoluteThreshold >= 0 && | ||
currentValue-cutoffValue < t.options.AbsoluteThreshold { | ||
return true | ||
} | ||
if t.options.RelativeThreshold >= 0 && | ||
currentValue > 0 && // Relative threshold is only supported for positive values. | ||
(currentValue-cutoffValue)/currentValue < t.options.RelativeThreshold { | ||
return true | ||
} | ||
} | ||
|
||
// No plateau detected. | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"defaults": { | ||
"vehicles": { | ||
"speed": 20, | ||
"start_time": "2023-01-01T06:00:00-06:00", | ||
"end_time": "2023-01-01T10:00:00-06:00" | ||
} | ||
}, | ||
"stops": [ | ||
{ | ||
"id": "Fushimi Inari Taisha", | ||
"location": { "lon": 135.772695, "lat": 34.967146 } | ||
} | ||
], | ||
"vehicles": [ | ||
{ | ||
"id": "v1", | ||
"start_location": { "lon": 135.672009, "lat": 35.017209 } | ||
} | ||
] | ||
} |
Oops, something went wrong.