Skip to content

Conversation

@dirkschumacher
Copy link
Contributor

@dirkschumacher dirkschumacher commented Sep 30, 2025

This improves the performance by doing a few things:

  • Speed and SpeedUnit are now simple structs allowing for better inlining. E.g. speed.Value now takes 90% less time than before.
  • Location is now encoded as two float64s in radians. This makes the location struct smaller and improves Haversine calculation. It comes at a cost of a multiplication to get Lat/Lon back.

Computational experiments also very promising.

In theory these changes are breaking so they go into the draft branch for now.


// haversineDistance processes the locations to make sure that they are valid
// to return the corresponding distance.
func haversineDistance(from, to common.Location) common.Distance {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function is really quite expensive. It is now replaced by a simpler function that still makes these validation checks on locations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also dropped this function because haversineDistance could not be inlined because of the if branch.

Copy link
Member

Choose a reason for hiding this comment

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

The math functions in it are also a little bit of a drag. Sqrt is typically not very fast, right?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR optimizes location-related performance by making Speed and SpeedUnit simple structs for better inlining and encoding locations in radians internally. The changes significantly improve performance - speed.Value takes 90% less time and Haversine calculations are more efficient due to eliminating degree-to-radian conversions.

  • Converted Speed and SpeedUnit from interfaces to structs to enable inlining
  • Changed Location internal storage to use radians instead of degrees
  • Replaced haversineDistance function with optimized Haversine0 method

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
solution_unplan.go Updated to use new Haversine0 function
model_haversine.go Removed obsolete haversineDistance wrapper function
model_expression_haversine.go Updated to use Haversine0 instead of haversineDistance
model_cluster.go Updated multiple calls to use Haversine0
common/speed_test.go Added benchmark test for speed value conversion
common/speed.go Converted Speed/SpeedUnit from interfaces to structs
common/location.go Changed internal storage to radians, updated validation logic
common/haversine.go Added Haversine0 function, optimized calculations
common/distance.go Minor formatting cleanup

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

// NewInvalidLocation creates a new invalid Location. Longitude and latitude
// are not important.
func NewInvalidLocation() Location {
// Invalid locations are encoded as NaN in the longitude.
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

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

The comment should clarify that invalid locations are encoded as NaN in the longitude radians, since the field name is longitudeRadians.

Suggested change
// Invalid locations are encoded as NaN in the longitude.
// Invalid locations are encoded as NaN in the longitude radians.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

Quite picky. 😅

// Equals returns true if the invoking location is equal to the other location.
func (l Location) Equals(other Location) bool {
return l.longitude == other.Longitude() && l.latitude == other.Latitude()
return l.longitudeRadians == other.longitudeRadians && l.latitudeRadians == other.latitudeRadians
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

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

Direct floating-point equality comparison may fail due to precision issues. Consider using a small epsilon for comparison or document that exact equality is intended for radians converted from the same degree values.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

Normally this should be fine, since no computation is done on these values. They are read from JSON typically, where to equal values should result in an equal float representation.

@dirkschumacher dirkschumacher marked this pull request as ready for review September 30, 2025 10:41
Copy link
Member

@merschformann merschformann left a comment

Choose a reason for hiding this comment

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

Thanks! <3

// NewInvalidLocation creates a new invalid Location. Longitude and latitude
// are not important.
func NewInvalidLocation() Location {
// Invalid locations are encoded as NaN in the longitude.
Copy link
Member

Choose a reason for hiding this comment

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

Quite picky. 😅

// Equals returns true if the invoking location is equal to the other location.
func (l Location) Equals(other Location) bool {
return l.longitude == other.Longitude() && l.latitude == other.Latitude()
return l.longitudeRadians == other.longitudeRadians && l.latitudeRadians == other.latitudeRadians
Copy link
Member

Choose a reason for hiding this comment

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

Normally this should be fine, since no computation is done on these values. They are read from JSON typically, where to equal values should result in an equal float representation.


// haversineDistance processes the locations to make sure that they are valid
// to return the corresponding distance.
func haversineDistance(from, to common.Location) common.Distance {
Copy link
Member

Choose a reason for hiding this comment

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

The math functions in it are also a little bit of a drag. Sqrt is typically not very fast, right?

@dirkschumacher dirkschumacher merged commit 5346999 into draft-v1.2 Oct 1, 2025
32 checks passed
@dirkschumacher dirkschumacher deleted the perf/locations branch October 1, 2025 08:15
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.

3 participants