-
Notifications
You must be signed in to change notification settings - Fork 1
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
Nav 47 refactor raptor algorithm #68
Conversation
- Legs --> Labels - Departure / Arrival --> Source / Target
…on is only favored because same stop transfer time is subtracted. Additionally add a method that reduces travel time be departing later (DEPARTURE) or arriving earlier (ARRIVAL) to reduce travel time by combining the last labels (when possible)
… labels and best times
…g them on the objective
… in route scanner
…t isolines and connections
Eventually we could move the marked stops also into the Objective class? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice work, now I can follow my own code better :)
Although, I don't see any deal breaking issues with this PR, which prevent approval. Some comments to discuss.
- Connection - Comparable. I would not implement comparable for connections, I believe comparing them by arrival time does not make any sense, or at least comparisons by departure time, travel time or number of transfers are just as likely.
- Raptor / Objective: I like having this objective container for handling query specific attributes. And I agree that the markedStops should be managed by the spawnFromStop method. However, maybe we should rename the Raptor class to Router or RaptorRouter (which implements the RaptorAlgorithm) and the Objective to Request (because in my opinion it's not only a objective container). The idea behind is, that we can accept requests via the interface through the raptor algorithm and keep all constant raptor relevant data in this class, however move all of the request processing to the request class instance (which will only keep data relevant to the request), this could reduce the argument passing around even more. As a result, spawnFromStops would also be moved to Request.
- Impl: I now know why I like having interface names starting with i (or some other convention). Can we rename the raptor Interfaces to RaptorLeg / RaptorConnection and the implementations to Leg/Connection?
|
||
public interface RaptorAlgorithm { | ||
|
||
static RaptorBuilder builder(int sameStopTransferTime) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't really work looking forward. I think the raptor builder is too much implementation specific that we can keep it in the interface. Anyway at the moment the Raptor Builder is inside the Impl package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, I think we will have to implement a factory for the Raptor.
- Update license descriptions accordingly.
@clukas1, thanks for the review and feedback!
My rationale behind using
Agree to renaming However I vote against renaming I may not fully understand the suggestion to move the
Can you further elaborate on this? But you are also right about the
We should discuss these points in more detail at our meeting on Wednesday. |
I would still prefer not to implement it, the problem is that by implementing it, in my opinion it has to be 100% clear why and how it is intended or at least easy to explain. In this case here, I think there are many logical ways to implement it and none over weighs the other, hence I think it's cleaner not to implement it to make it explicit that one has to define how one wants to sort / compare the connections.
Thanks
I get why you want to name it
I agree, that I wouldn't want to see a Impl postfix outside of the package. But I also get a cold shiver down my back if I see Impl inside the package, so thanks for renaming. The reason I would also like to name the Interfaces RaptorLeg/RaptorConnection instead of Leg/Connection is that we would prevent working with two implementations of Leg/Connection on the service level, resulting in Type Annotations specifying the full definition (e.g. |
@@ -29,7 +29,7 @@ class Query { | |||
private final TimeType timeType; | |||
|
|||
private final int[] targetStops; | |||
private final int cutOffTime; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, to be picky. but cut off is not one word 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry again, my bad. Turns out American English uses cutoff, just feels wrong (and I prefer British English).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should define what dialect to use and then apply this consistently throughout our codebase.
Based on a short research (https://stackoverflow.com/questions/157807/gb-english-or-us-english), American English seems to be the preferred choice in programming.
There are also some British English that are kind of unusual for me:
American English | British English |
---|---|
Color | Colour |
Initialize | Initialise |
Optimize | Optimise |
Center | Centre |
License | Licence |
Traveler | Traveller |
Program | Programme |
@@ -29,7 +29,7 @@ class Query { | |||
private final TimeType timeType; | |||
|
|||
private final int[] targetStops; | |||
private final int cutOffTime; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry again, my bad. Turns out American English uses cutoff, just feels wrong (and I prefer British English).
@@ -131,7 +131,7 @@ private List<Query.Label[]> spawnFromStops(int[] sourceStopIndices, int[] target | |||
// initially relax all source stops and add the newly improved stops by relaxation to the marked stops | |||
Set<Integer> markedStops = query.initialize(); | |||
markedStops.addAll(footpathRelaxer.relaxInitial(sourceStopIndices)); | |||
markedStops = query.removeSubOptimalLabelsForRound(0, markedStops); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although not orthographically correct, camel casing in our company treats prefixes (sub, super, pre, post, etc.) as independent words. I generally prefer this because it improves readability but know that it's strictly speaking incorrect.
@@ -31,18 +31,18 @@ class FootpathRelaxer { | |||
|
|||
/** | |||
* @param raptorRouter the current raptor instance for access to the data structures. | |||
* @param objective the best time per stop and label per stop and round. | |||
* @param query the best time per stop and label per stop and round. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The param description for query should be ~ object containing query configuration and intermediate working variables
or something of this sort.
@@ -9,10 +9,10 @@ | |||
import java.util.*; | |||
|
|||
/** | |||
* The objective stores the progress of the raptor algorithm. Each request needs a new objective instance. | |||
* The query stores the progress of the raptor algorithm. Each request needs a new query instance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The query stores the configuration of the raptor routing request and holds working variables to store the progress of the raptor algorithm.
@@ -31,20 +31,20 @@ class RouteScanner { | |||
|
|||
/** | |||
* @param raptorRouter the current raptor instance for access to the data structures. | |||
* @param objective the best time per stop and label per stop and round. | |||
* @param query the best time per stop and label per stop and round. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
@@ -15,7 +15,7 @@ | |||
@NoArgsConstructor(access = AccessLevel.PACKAGE) | |||
@Getter | |||
@ToString | |||
class RaptorConnection implements Connection { | |||
class RaptorConnection implements Connection, Comparable<Connection> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why implement the Comparable? I still don't see a reason to keep this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly the problem that I try to explain, we don't use it, but we should.
We should sort all our returned connections in RaptorAlgorithm / Router
, by calling sort before return in the LabelProcessor
:
return connections.stream().sorted().toList();
Which will then implicitly call the compareTo
required by the Comparable
Interface.
If we do this now, most of our tests fail. This is not because the Raptor is not working, but simply due to sorting issues. The problem is that the way we implement the Raptor currently influences the order of the results, which is not very stable. Additionally, if we implement further versions (native or mcRaptor), this instability will cause further issues.
In my opinion, the necessity to sort connections is an essential property. Otherwise, the order is not transparent for the user.
- Query holds now the complete routing logic. - Objective stores the labels and best times and serves as single point for their modification. - Introduce raptor data interface.
@clukas1, thanks for the feedback! I tried to address most of it, feel free to continue. I will not work on the refactoring until our meeting on Wednesday to avoid conflicts.
I did my best to move the main routing logic from the RaptorRouter to the Additionally, I have discovered a strange issue in the
My interpretation is that we can remove this method and directly use |
…ng in reverse order over rounds.
@munterfi some final touches from my side. Good to merge in my opinion. Summary of changes:
Actually both methods are needed (one of the reasons I introduced the transfer only test). The problem if you use the comparableBestTime as cut-off value all transfer legs will be removed at the end of the round. While writing this now, I just realized that the best way would have been to make add/subtract the same transfer time to route arrivals/departures instead of subtracting/adding them to transfers. Which would have solved this (improvement for a later issue)... However, I've renamed the methods and added a docstring to clarify when which one should be used in e2ce8f4.
Actually, they are sorted by default by the number of rounds (route trip legs) and arrival/departure time in descending/ascending order. I've reworded the docstring return value in the RaptorAlgorithm interface to be more explicit about this in c17df10
As you might have guessed, I disagreed with the Objective name. I've renamed it to StopLabelsAndTimes to be explicit about what it contains (44c6a2f). Hope you can also live with that name. Like the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@munterfi cannot add you as reviewer since it's your PR. In my opinion this PR is good to merge. Please review my final touches and approve / merge or re-open the discussion.
Hi @clukas1 and @Brunner246,
A PR for the refactoring of the Raptor algorithm we started together.
Summary:
This PR goes across the project, so avoid starting new branches at the moment. Let's finish the refactoring first. I think it would make sense to discuss the changes in a short meeting.