From c21c0cf1330eea0d94e67e916c0c52f5ea56d813 Mon Sep 17 00:00:00 2001 From: Dirk Schumacher Date: Fri, 10 May 2024 16:33:10 +0200 Subject: [PATCH] Improve multi stop plan unit generation --- solution_sequence_generator.go | 46 ++++++++++++++++++++++++++++++---- solution_vehicle.go | 6 ++--- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/solution_sequence_generator.go b/solution_sequence_generator.go index 878fd5e..046b352 100644 --- a/solution_sequence_generator.go +++ b/solution_sequence_generator.go @@ -5,7 +5,6 @@ package nextroute import ( "math/rand" "slices" - "sync/atomic" ) // SequenceGeneratorChannel generates all possible sequences of solution stops @@ -31,10 +30,10 @@ func SequenceGeneratorChannel( ) chan SolutionStops { planUnit := pu.(*solutionPlanStopsUnitImpl) solution := planUnit.solution() - maxSequences := int64(solution.Model().SequenceSampleSize()) solutionStops := planUnit.SolutionStops() ch := make(chan SolutionStops) go func() { + maxSequences := int64(solution.Model().SequenceSampleSize()) defer close(ch) switch planUnit.ModelPlanStopsUnit().NumberOfStops() { case 1: @@ -64,7 +63,7 @@ func SequenceGeneratorChannel( select { case <-quit: return - case ch <- solutionStops: + case ch <- slices.Clone(solutionStops): } }, -1, @@ -85,9 +84,13 @@ func sequenceGenerator( yield func(SolutionStops), directSuccessor int, ) { + if *maxSequences == 0 { + return + } if len(sequence) == len(stops) { - if atomic.AddInt64(maxSequences, -1) >= 0 { - yield(slices.Clone(sequence)) + *maxSequences-- + if *maxSequences >= 0 { + yield(sequence) } return } @@ -143,3 +146,36 @@ func sequenceGenerator( } } } + +func sequenceGeneratorSync( + pu SolutionPlanUnit, + yield func(SolutionStops), +) { + planUnit := pu.(*solutionPlanStopsUnitImpl) + solutionStops := planUnit.SolutionStops() + if planUnit.ModelPlanStopsUnit().NumberOfStops() == 1 { + yield(solutionStops) + return + } + solution := planUnit.solution() + maxSequences := int64(solution.Model().SequenceSampleSize()) + used := make([]bool, len(solutionStops)) + inDegree := make(map[int]int, len(solutionStops)) + modelPlanUnit := planUnit.ModelPlanUnit().(*planMultipleStopsImpl) + dag := modelPlanUnit.dag.(*directedAcyclicGraphImpl) + for _, arc := range dag.arcs { + inDegree[arc.Destination().Index()]++ + } + + sequenceGenerator( + solutionStops, + make([]SolutionStop, 0, len(solutionStops)), + used, + inDegree, + dag, + solution.Random(), + &maxSequences, + yield, + -1, + ) +} diff --git a/solution_vehicle.go b/solution_vehicle.go index 7b2f92d..9b8134c 100644 --- a/solution_vehicle.go +++ b/solution_vehicle.go @@ -385,12 +385,10 @@ func (v solutionVehicleImpl) bestMovePlanMultipleStops( preAllocatedMoveContainer *PreAllocatedMoveContainer, ) SolutionMove { var bestMove SolutionMove = newNotExecutableSolutionMoveStops(planUnit) - quitSequenceGenerator := make(chan struct{}) - defer close(quitSequenceGenerator) - for sequence := range SequenceGeneratorChannel(planUnit, quitSequenceGenerator) { + sequenceGeneratorSync(planUnit, func(sequence SolutionStops) { newMove := v.bestMoveSequence(ctx, planUnit, sequence, preAllocatedMoveContainer) bestMove = takeBestInPlace(bestMove, newMove) - } + }) return bestMove }