Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nilsbeck/add stop balancing #67

Merged
merged 14 commits into from
Oct 24, 2024
Merged

nilsbeck/add stop balancing #67

merged 14 commits into from
Oct 24, 2024

Conversation

nilsbeck
Copy link
Collaborator

Description

This PR adds a new objective to balance the number of stops on vehicles. It can be turned on by setting the instance option to a value > 0:
"-model.objectives.stopbalance", "1000.0"

or in the model code once the options are passed, before creating the model:
options.Model.Objectives.StopBalance = 1000.0

The value given is used to penalize the imbalance.

move Move,
) float64 {
solution := move.Solution()
oldMax := t.Max(solution, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should compute the maximum and minimum in a single for loop - better for performance

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored this

return float64(t.Max(solution, nil))
}

func (t *balanceObjectiveImpl) Max(solution Solution, move SolutionMoveStops) int {
Copy link
Contributor

@dirkschumacher dirkschumacher Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Max could also be a normal, unexported function function

Copy link
Collaborator Author

@nilsbeck nilsbeck Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed it to MaxStops


// NewStopBalanceObjective returns a new StopBalanceObjective.
func NewStopBalanceObjective() ModelObjective {
return &balanceObjectiveImpl{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a pointer?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question, just followed the same structure as for the other objectives. I have no better answer than that :(

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at a few of the structures in here some time ago and it may benefit from a deeper consideration and exploration of when to use pointers versus when not to. @nilsbeck my opinion is to maintain consistency for now and we should create an issue to possibly refactor later.

vehicle = move.Vehicle()
}

for _, v := range solution.Vehicles() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does solution.Vehicles() allocate a slice? You should check that and try to avoid it if possible

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I access the slice of vehicles directly now. before, there was slice cloning involved.

}

for _, v := range solution.Vehicles() {
if max < v.NumberOfStops() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you repeat function calls often like v.NumberOfStops(). It's not always the case that the go compiler optimises that away. Better to assign v.NumberOfStops() to a variable and reuse that one. Same with v.Index() and move.StopPositionsLength().

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored it.

maxBefore := 0
moveExists := move != nil
var vehicle SolutionVehicle
if moveExists {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moveExisits is always true.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the function is used in the Value calculation without a move (because there only is a solution then). so it can be nil

maxBefore, _ := t.MaxStops(solution, nil)

return float64(maxBefore)
}

func (t *balanceObjectiveImpl) MaxStops(solution Solution, move SolutionMoveStops) (int, int) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is MaxStops an exported function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made it not exported. was at the time because I was thinking of a unit test. but left the test because it seems unnecessary.

"lon": -78.828547,
"lat": 35.962635
},
"precedes": ["s16", "s23"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there only one stop that precedes others? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the stops from another tests and apparently forgot to remove one of the precedes...removed it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, yeah. There is no way currently to provide options for a golden file test right now. I noticed that we also miss golden file tests for clustering objective / constraint and such.
Can / should we combine the options with the existing golden file testing? I could imagine having another optional file next to the input file that defines the options. 🤔
Anyway, probably not for this PR, but potentially a fast-follow one. Otherwise, I feel like we will inflate our testing considerably and we are also missing some tests for cluster objective and such. 😊

@nilsbeck nilsbeck merged commit 0e4a0ce into develop Oct 24, 2024
33 checks passed
@nilsbeck nilsbeck deleted the nilsbeck/add-stop-balancing branch October 24, 2024 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants