<commit_before>[[repeatedPlanning]]
= Repeated Planning
:doctype: book
:imagesdir: ..
:sectnums:
:toc: left
:icons: font
:experimental:

[[introductionToRepeatedPlanning]]
== Introduction to Repeated Planning

The problem facts used to create a solution may change before or during the execution of that solution. Delaying planning in order to lower the risk of problem facts changing is not ideal, as an incomplete plan is preferable to no plan.

The following examples demonstrate situations where planning solutions need to be altered due to unpredictable changes:

* _Unforeseen fact changes_ 

** An employee assigned to a shift calls in sick. 
** An airplane scheduled to take off has a technical delay.
** One of the machines or vehicles break down.
+ 
Unforeseen fact changes benefit from using _backup planning_.

* _Cannot assign all entities immediately_
+
Leave some unassigned. For example:
+
** There are 10 shifts at the same time to assign but only nine employees to handle shifts. 
+
For this type of planning, use <<overconstrainedPlanning,_overconstrained planning_>>.

* _Unknown long term future facts_
+
For example:

** Hospital admissions for the next two weeks are reliable, but those for week three and four are less reliable, and for week five and beyond are not worth planning yet. 
+
This problem benefits from <<continuousPlanning,_continuous planning_>>.

* _Constantly changing problem facts_
+
Use <<realTimePlanning,_real-time planning_>>.

More CPU time results in a better planning solution.

Planner allows you to start planning earlier, despite unforeseen changes, as the optimization algorithms support planning a solution that has already been partially planned. This is known as repeated planning.


[[backupPlanning]]
== Backup Planning

Backup planning adds extra score constraints to create space in the planning for when things go wrong. That creates a backup plan within the plan itself.

An example of backup planning is as follows:

. Create an extra score constraint. For example:
+
* Assign an employee as the spare employee (one for every 10 shifts at the same time).
* Keep one hospital bed open in each department.
. Change the planning problem when an unforeseen event occurs. 
+
For example, if an employee calls in sick: 
+
* Delete the sick employee and leave their shifts unassigned.
* Restart the planning, starting from that solution, which now has a different score.

The construction heuristics fills in the newly created gaps (probably with the spare employee) and the metaheuristics will improve it even further.


[[overconstrainedPlanning]]
== Overconstrained Planning

When there is no feasible solution to assign all planning entities, it is preferable to assign as many entities as possible without breaking hard constraints.
This is called overconstrained planning.

By default, Planner assigns all planning entities, overloads the planning values, and therefore breaks hard constraints.
There are two ways to avoid this:

* Use <<nullablePlanningVariable,nullable>> planning variables, so that some entities are unassigned.
* Add virtual values to catch the unassigned entities.


[[overconstrainedPlanningWithNullableVariables]]
=== Overconstrained Planning with Nullable Variables

If we handle overconstrained planning with nullable variables, the overload entities will be left unassigned:

image::RepeatedPlanning/overconstrainedPlanning.png[align="center"]

To implement this:

. Add an additional score level (usually a medium level between the hard and soft level) by switching <<scoreType,`Score` type>>.
. Make the planning variable <<nullablePlanningVariable,nullable>>.
. Add a score constraint on the new level (usually a medium constraint) to penalize the number of unassigned entities (or a weighted sum of them).


[[overconstrainedPlanningWithVirutalValues]]
=== Overconstrained Planning with Virtual Values

In overconstrained planning it is often useful to know which resources are lacking.
In overconstrained planning with virtual values, the solution indicates which resources to buy.

To implement this:

. Add an additional score level (usually a medium level between the hard and soft level) by switching <<scoreType,`Score` type>>.
. Add a number of virtual values. It can be difficult to determine a good formula to calculate that number:
** Do not add too many, as that will decrease solver efficiency.
** Importantly, do not add too few as that will lead to an infeasible solution.
. Add a score constraint on the new level (usually a medium constraint) to penalize the number of virtual assigned entities (or a weighted sum of them).
. Optionally, change all soft constraints to ignore virtual assigned entities.

[[continuousPlanning]]
== Continuous Planning (Windowed Planning)

Continuous planning is the technique of planning one or more upcoming planning periods at the same time and repeating that process monthly, weekly, daily, hourly, or even more frequently.
However, as time is infinite, planning all future time periods is impossible.

A planning window allows you to have a fixed number of upcoming planning time periods.

The planning window can be split up in several parts:

* _History_ 
+
Immutable past time periods. It contains only immovable entities.
+
** Historic entities can also affect score constraints that apply to movable entities. For example, in nurse rostering, a nurse that has worked the last five historic days in a row should not be assigned on the first tentative day of the planning window, they will have worked too many consecutive days.
** Do not load all historic entities in memory: even though immovable entities do not affect solving performance, they can cause out of memory problems when the data grows to years. Only load those that might still affect the current constraints with a good safety margin, for example load the past year.
* _Tentative_ 
+
The first few time periods that are being planned freely for the last time. After this planning, their planning entities become <<immovablePlanningEntities,immovable>> or <<nonvolatileReplanning,semi-immovable>>.
+
** The result of the tentative planning is usually shared with the business. For example, in nurse rostering, the nurses will use this schedule to plan their personal lives. Changing that schedule later becomes disruptive, however, were exceptions force us to do so, disruption can be minimized (see <<nonvolatileReplanning,Nonvolatile Replanning>>).
* _Draft_ 
+
The latter time periods that are being planned freely, but not for the last time. They are likely to change again in the next planning effort.
+
** The draft part is needed to assure that the tentatively planned entities will allow room of a good, feasible planning afterwards. 
+
** That draft part is usually not shared with the business yet, because it is too volatile. However, it is stored in the database and used a starting point for the next plan.

* _Future_ (out of scope)
+ 
Planning entities that are not in the current planning window.
+
** If <<assigningTimeToPlanningEntities,time is a planning variable>>, there is no future part. Instead, if the planning window is too small to plan all entities, see  <<overconstrainedPlanning,overconstrained planning>>.

image::RepeatedPlanning/continuousPlanningEmployeeRostering.png[align="center"]

In the employee rostering example above, we re-plan every four days.
Each time, we actually plan a window of 12 days, but we only share the tentative roster of the next four days with the employees.

[NOTE]
====
The start of the planning window (so the first tentative time period) does _not_ need to be now.
That too can be a week in advance.
====

image::RepeatedPlanning/continuousPlanningPatientAdmissionSchedule.png[align="center"]

In the hospital bed planning example above, notice the difference between the original planning of November 1st and the new planning of November 5th: some problem facts (F, H, I, J, K) changed in the meantime, which results in unrelated planning entities (G) changing too.


[[immovablePlanningEntities]]
=== Immovable Planning Entities

An immovable planning entity doesn't change during solving.
This is commonly used by users to pin down one or more specific assignments
and force Planner to schedule around those fixed assignments.

[[pinDownPlanningEntities]]
==== Pin Down Planning Entities with @PlanningPin

To make some planning entities immovable, add an `@PlanningPin` annotation
on a boolean getter or field of the planning entity class.
That boolean is `true` if the entity is immovable (pinned down to its current planning values) and `false` otherwise.

. Add the `@PlanningPin` annotation on a `boolean`:
+
[source,java,options="nowrap"]
----<commit_msg>continuousPublishingAndRotation.png: docs + website<commit_after>[[repeatedPlanning]]
= Repeated Planning
:doctype: book
:imagesdir: ..
:sectnums:
:toc: left
:icons: font
:experimental:

[[introductionToRepeatedPlanning]]
== Introduction to Repeated Planning

The problem facts used to create a solution may change before or during the execution of that solution. Delaying planning in order to lower the risk of problem facts changing is not ideal, as an incomplete plan is preferable to no plan.

The following examples demonstrate situations where planning solutions need to be altered due to unpredictable changes:

* _Unforeseen fact changes_ 

** An employee assigned to a shift calls in sick. 
** An airplane scheduled to take off has a technical delay.
** One of the machines or vehicles break down.
+ 
Unforeseen fact changes benefit from using _backup planning_.

* _Cannot assign all entities immediately_
+
Leave some unassigned. For example:
+
** There are 10 shifts at the same time to assign but only nine employees to handle shifts. 
+
For this type of planning, use <<overconstrainedPlanning,_overconstrained planning_>>.

* _Unknown long term future facts_
+
For example:

** Hospital admissions for the next two weeks are reliable, but those for week three and four are less reliable, and for week five and beyond are not worth planning yet. 
+
This problem benefits from <<continuousPlanning,_continuous planning_>>.

* _Constantly changing problem facts_
+
Use <<realTimePlanning,_real-time planning_>>.

More CPU time results in a better planning solution.

Planner allows you to start planning earlier, despite unforeseen changes, as the optimization algorithms support planning a solution that has already been partially planned. This is known as repeated planning.


[[backupPlanning]]
== Backup Planning

Backup planning adds extra score constraints to create space in the planning for when things go wrong. That creates a backup plan within the plan itself.

An example of backup planning is as follows:

. Create an extra score constraint. For example:
+
* Assign an employee as the spare employee (one for every 10 shifts at the same time).
* Keep one hospital bed open in each department.
. Change the planning problem when an unforeseen event occurs. 
+
For example, if an employee calls in sick: 
+
* Delete the sick employee and leave their shifts unassigned.
* Restart the planning, starting from that solution, which now has a different score.

The construction heuristics fills in the newly created gaps (probably with the spare employee) and the metaheuristics will improve it even further.


[[overconstrainedPlanning]]
== Overconstrained Planning

When there is no feasible solution to assign all planning entities, it is preferable to assign as many entities as possible without breaking hard constraints.
This is called overconstrained planning.

By default, Planner assigns all planning entities, overloads the planning values, and therefore breaks hard constraints.
There are two ways to avoid this:

* Use <<nullablePlanningVariable,nullable>> planning variables, so that some entities are unassigned.
* Add virtual values to catch the unassigned entities.


[[overconstrainedPlanningWithNullableVariables]]
=== Overconstrained Planning with Nullable Variables

If we handle overconstrained planning with nullable variables, the overload entities will be left unassigned:

image::RepeatedPlanning/overconstrainedPlanning.png[align="center"]

To implement this:

. Add an additional score level (usually a medium level between the hard and soft level) by switching <<scoreType,`Score` type>>.
. Make the planning variable <<nullablePlanningVariable,nullable>>.
. Add a score constraint on the new level (usually a medium constraint) to penalize the number of unassigned entities (or a weighted sum of them).


[[overconstrainedPlanningWithVirutalValues]]
=== Overconstrained Planning with Virtual Values

In overconstrained planning it is often useful to know which resources are lacking.
In overconstrained planning with virtual values, the solution indicates which resources to buy.

To implement this:

. Add an additional score level (usually a medium level between the hard and soft level) by switching <<scoreType,`Score` type>>.
. Add a number of virtual values. It can be difficult to determine a good formula to calculate that number:
** Do not add too many, as that will decrease solver efficiency.
** Importantly, do not add too few as that will lead to an infeasible solution.
. Add a score constraint on the new level (usually a medium constraint) to penalize the number of virtual assigned entities (or a weighted sum of them).
. Optionally, change all soft constraints to ignore virtual assigned entities.

[[continuousPlanning]]
== Continuous Planning (Windowed Planning)

Continuous planning is the technique of planning one or more upcoming planning periods at the same time
and repeating that process monthly, weekly, daily, hourly, or even more frequently.
However, as time is infinite, planning all future time periods is impossible.

image::RepeatedPlanning/continuousPlanningEmployeeRostering.png[align="center"]

In the employee rostering example above, we re-plan every four days.
Each time, we actually plan a window of 12 days, but we only publish the first four days,
which is stable enough to share with the employees, so they can plan their social life accordingly.

image::RepeatedPlanning/continuousPlanningPatientAdmissionSchedule.png[align="center"]

In the hospital bed planning example above, notice the difference
between the original planning of November 1st and the new planning of November 5th:
some problem facts (F, H, I, J, K) changed in the meantime, which results in unrelated planning entities (G) changing too.

The planning window can be split up in several stages:

* _History_ 
+
Immutable past time periods. It contains only immovable entities.
+
** Recent historic entities can also affect score constraints that apply to movable entities.
For example, in nurse rostering, a nurse that has worked the last three historic weekends in a row
should not be assigned to three more weekends in a row,
because she requires a one free weekend per month.
** Do not load all historic entities in memory:
even though immovable entities do not affect solving performance,
they can cause out of memory problems when the data grows to years.
Only load those that might still affect the current constraints with a good safety margin.

* _Published_
+
Upcoming time periods that have been published.
They contain only <<immovablePlanningEntities,Immovable>> and/or <<nonvolatileReplanning,semi-immovable>> planning entities.
+
** The published schedule has been shared with the business.
For example, in nurse rostering, the nurses will use this schedule to plan their personal lives,
so they require a publish notice of for example 3 weeks in advance.
Normal planning will not change that part of schedule.
+
Changing that schedule later is disruptive, but were exceptions force us to do them anyway
(for example someone calls in sick), do change this part of the planning
while minimizing disruption with <<nonvolatileReplanning,non-disruptive replanning>>.

* _Draft_
+
Upcoming time periods after the published time periods that can change freely.
They contain movable planning entities, except for any that are immovable for other reasons
(such as being <<pinDownPlanningEntities,pinned by a user>>).
+
** The first part of the _draft_ will be published, so these planning entities can change one last time.
The publishing frequency, for example once per week, determines the number of time periods that changes from _draft_ to _published_.
** The latter time periods of the _draft_ are likely change again in later planning efforts,
especially if some of the problem facts change by then (for example nurse Ann doesn't want to work on one of those days).
+
Despite that these latter planning entities might still change a lot,
we can't leave them out for later, because we would risk _painting ourselves in a corner_.
For example, in employee rostering we could have all our rare skilled employees working the last 5 days of the week that gets published,
which won't reduce the score of that week, but will make it impossible for us to deliver a feasible schedule the next week.
So the draft length needs to be longer than the part that will be published first.
** That draft part is usually not shared with the business yet, because it is too volatile and it would only raise false expectations.
However, it is stored in the database and used as a starting point for the next solver.

* _Unplanned_ (out of scope)
+ 
Planning entities that are not in the current planning window.
+
** If the planning window is too small to plan all entities, you're dealing with <<overconstrainedPlanning,overconstrained planning>>.
** If <<assigningTimeToPlanningEntities,time is a planning variable>>, the size of the planning window is determined dynamically,
in which case the _unplanned_ stage is not applicable.

image::RepeatedPlanning/continuousPublishingWithRotation.png[align="center"]


[[immovablePlanningEntities]]
=== Immovable Planning Entities

An immovable planning entity doesn't change during solving.
This is commonly used by users to pin down one or more specific assignments
and force Planner to schedule around those fixed assignments.

[[pinDownPlanningEntities]]
==== Pin Down Planning Entities with @PlanningPin

To make some planning entities immovable, add an `@PlanningPin` annotation
on a boolean getter or field of the planning entity class.
That boolean is `true` if the entity is immovable (pinned down to its current planning values) and `false` otherwise.

. Add the `@PlanningPin` annotation on a `boolean`:
+
[source,java,options="nowrap"]
----
{'fraction_non_alphanumeric': 0.04932228915662651, 'fraction_numerical': 0.00096815834767642, 'mean_word_length': 5.044538361508453, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4743842', 'n_tokens_mistral': 4521, 'n_tokens_neox': 4320, 'n_words': 2614}