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

feat: introduce conflict-based replanning #2931

Merged
merged 5 commits into from
Nov 17, 2023
Merged

Conversation

sebhoerl
Copy link
Contributor

This PR introduces a very generic feature to replanning: conflict resolution.

Context
Often, we experiment with simulations in which certain modes or resources are limited/capacitated/restricted. That means that agents compete over them, and often we can imagine some kind of reservation logic. We may want agents to reserve charging slots, parking spots, and we might want to synchronize car-pooling rides between agents or set up peer-to-peer systems in which some agents use others' cars while they perform activities.

We may also see such a reservation logic in the sense that agents have synchronized over the limited resources "in the long term" with no need to figure out restrictions through a long scoring process with stuck agents.

Proposition
The code proposed here introduces a conflict-resolution stage to replanning. Specifically, we perform a standard replanning as usual. This means that agents will end up with new plans, that may potentially conflict because agents make use of the same resources at the same time. In such a situation, we apply a custom ConflictResolver. Such a resolver iterates over the whole population and returns a list of agent IDs. Those agents get their currently selected plan rejected. Rejection means that the agent switches back to a plan in memory that is non-conflicting. Those are plans that, for instance, don't contain the mode in question or make not use of any resource that is limited by the specific ConflictResolver. For the example of car-pooling, the resolver may find viable matchings and then reject all plans that could not be matched. They will switch back to a previous plan that does not make use of the car-pooling mode. To make sure that this is possible, we introduce the WorstPlanSelectorForRemovalWithConflicts that should be used whenever conflict resolution is in place. It queries ConflictResolver to check if plans are potentially conflicting and makes sure that always at least one that is not potentially conflicting remains in memory. Of course, a precondition is that all agents start with at least one plan that fulfils this condition (otherwise, eventually, the conflict logic may find that there is no plan to switch back and deliberately produce an exception).

Implementation
I moved a relatively independent implementation into the core with this PR, because I think that this is sufficiently generic functionality that may be useful for many other use cases. If the community does not agree, we will probably rather move this code into the shared_mobility contrib.

Example
A minimal example can be found as a unit test. It lets agents choose between two modes and limits the number of agents using one of them. Further more use-case-oriented examples will be added in future PRs, specifically on peer-to-peer car-sharing.

The conflict-resolution logic, together with the peer-to-peer example, can also be checked out in more detail in the following paper for ABMTRANS: https://www.sciencedirect.com/science/article/pii/S1877050923006269

@sebhoerl
Copy link
Contributor Author

sebhoerl commented Nov 13, 2023

Currently, there are a couple of tests failing, because the output population is not the same any more. This is because each plan, before replanning, now gets an attribute that indicates whether the plan isInitialPlan. This is useful for various conflict implementations because to stabilize replanning, one might want to keep those agents that initially already used a certain resource and reject new users with higher priority. I'll take care of those tests once we establish whether this is worth integrating in the core or not :)

@sebhoerl
Copy link
Contributor Author

Dear all, for DRT-related PRs I know that Michal is the right person to involve. For these general things, I'm actually not sure who is in charge. I got some thumbs up further up, but I'm not sure if this is sufficient. What is our current process? :)

@marecabo
Copy link
Contributor

This looks great, really looking forward to work with this! 🚀

@steffenaxer
Copy link
Collaborator

What a wonderful contribution!

@sebhoerl sebhoerl merged commit cf073d4 into master Nov 17, 2023
48 checks passed
@sebhoerl sebhoerl deleted the feat/conflict-replanning branch November 17, 2023 10:14
@markusstraub
Copy link
Contributor

@sebhoerl great addition, I'm currently using this for the DRS module. However, I noticed that conflicting plans still remain in the user's plans and even get a score. Is this a problem? (Since I'm not sure if it actually is a problem I'm commenting here and not opening an issue)

What I noticed when using SubtourModeChoice (as an example)

  1. SubtourModeChoice (or actually ChooseRandomLegModeForSubtour) sets new modes into the copied plan (and keeps the plans' score)
  2. ConflictManager denies the plan and selects a different one
  3. We now have an invalid plan with a more or less random score (it's the score of whatever plan was copied) in the person's plans

Doesn't this mean that if the invalid plan by chance gets a very good score it will also be selected by SelectExpBeta quite often? Even though in the replanning phase the ConflictManager will again detect it and randomly select a working plan (in PlansReplanningImpl) - but the random selection could then defeat the SelectExpBeta?

Would it make more sense if the ConflictManager deleted the conflicting plan (or at least the score)?

@sebhoerl
Copy link
Contributor Author

Interesting, I think everything you describe makes sense. Yes, probably it is best to delete that plan.

@markusstraub
Copy link
Contributor

Great, I deleted the plans (in the drs module) and everything seems to work :)

In case you touch the ConflictManager - I have a feature idea: make it configurable when the ConflictManager runs. Now it is running in PlansReplanningImpl, which can be too early. My use case was:

  1. SubtourModeChoice introduces a mode
  2. I have a ReplanningListener that adjusts the plans for a certain mode
  3. The ConflictManager should reject plans that do not work out

However, now the ConflictManager runs before my step 2 because ControlerListenerManagerImpl first runs the core listeners, and PlansReplanningImpl is one of them (or actually the only one). Only after that the custom ReplanningListener are run.

So I would propse: the ConflictManager should run in the "custom" ReplanningListener phase with an adjustable priority (see ControlerListener.priority())

For now I worked around the problem.. and maybe I have time in the future to provide a pull request - if you think the approach is useful in general.

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