feat: Implement Pareto-front ranking integration with multi-criteria sorting
- Add RankingMode field to SearchOptions (fastest/fewest_transfers/cheapest) - Update FindRoutesPareto to respect ranking mode when sorting - Add ranking_mode query parameter to RouteSearch endpoint - Add TestParetoFrontGeneration with subtests for all three modes Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -764,6 +764,10 @@ type SearchOptions struct {
|
||||
MCT int
|
||||
// FarTerm indicates if the search date is far-term (affects caching/TTL).
|
||||
FarTerm bool
|
||||
// RankingMode determines the ranking/sort order for Pareto-optimal routes.
|
||||
// Supported values: "fastest" (default, sort by duration), "fewest_transfers" (sort by number of transfers),
|
||||
// "cheapest" (sort by cost).
|
||||
RankingMode string
|
||||
}
|
||||
|
||||
// Itinerary represents a complete route with legs and summary metrics.
|
||||
@@ -798,7 +802,9 @@ type SearchResult struct {
|
||||
|
||||
// FindRoutesPareto finds Pareto-optimal routes (time, transfers, cost) from origin to destination.
|
||||
// It runs the search algorithm and returns multiple routes that are not dominated by any other
|
||||
// route in all three metrics simultaneously.
|
||||
// route in all three metrics simultaneously. Routes are sorted according to the RankingMode
|
||||
// in SearchOptions: "fastest" (default, by duration), "fewest_transfers" (by transfers),
|
||||
// or "cheapest" (by cost).
|
||||
func (g *Graph) FindRoutesPareto(originID, destID string, opts SearchOptions) []*Itinerary {
|
||||
// Run multiple searches with different strategies to find diverse routes
|
||||
var allItineraries []*Itinerary
|
||||
@@ -814,16 +820,39 @@ func (g *Graph) FindRoutesPareto(originID, destID string, opts SearchOptions) []
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by total duration (primary), then transfers (secondary), then cost (tertiary)
|
||||
sort.Slice(allItineraries, func(i, j int) bool {
|
||||
if allItineraries[i].TotalDuration != allItineraries[j].TotalDuration {
|
||||
return allItineraries[i].TotalDuration < allItineraries[j].TotalDuration
|
||||
}
|
||||
if allItineraries[i].TotalTransfers != allItineraries[j].TotalTransfers {
|
||||
// Sort according to the specified RankingMode
|
||||
switch opts.RankingMode {
|
||||
case "fewest_transfers":
|
||||
sort.Slice(allItineraries, func(i, j int) bool {
|
||||
if allItineraries[i].TotalTransfers != allItineraries[j].TotalTransfers {
|
||||
return allItineraries[i].TotalTransfers < allItineraries[j].TotalTransfers
|
||||
}
|
||||
if allItineraries[i].TotalDuration != allItineraries[j].TotalDuration {
|
||||
return allItineraries[i].TotalDuration < allItineraries[j].TotalDuration
|
||||
}
|
||||
return allItineraries[i].Cost < allItineraries[j].Cost
|
||||
})
|
||||
case "cheapest":
|
||||
sort.Slice(allItineraries, func(i, j int) bool {
|
||||
if allItineraries[i].Cost != allItineraries[j].Cost {
|
||||
return allItineraries[i].Cost < allItineraries[j].Cost
|
||||
}
|
||||
if allItineraries[i].TotalDuration != allItineraries[j].TotalDuration {
|
||||
return allItineraries[i].TotalDuration < allItineraries[j].TotalDuration
|
||||
}
|
||||
return allItineraries[i].TotalTransfers < allItineraries[j].TotalTransfers
|
||||
}
|
||||
return allItineraries[i].Cost < allItineraries[j].Cost
|
||||
})
|
||||
})
|
||||
default: // "fastest" or any other value - sort by duration (primary), transfers (secondary), cost (tertiary)
|
||||
sort.Slice(allItineraries, func(i, j int) bool {
|
||||
if allItineraries[i].TotalDuration != allItineraries[j].TotalDuration {
|
||||
return allItineraries[i].TotalDuration < allItineraries[j].TotalDuration
|
||||
}
|
||||
if allItineraries[i].TotalTransfers != allItineraries[j].TotalTransfers {
|
||||
return allItineraries[i].TotalTransfers < allItineraries[j].TotalTransfers
|
||||
}
|
||||
return allItineraries[i].Cost < allItineraries[j].Cost
|
||||
})
|
||||
}
|
||||
|
||||
// Pareto filter: remove dominated routes
|
||||
// A route is dominated if another route is better or equal in all metrics (time, transfers, cost)
|
||||
|
||||
Reference in New Issue
Block a user