RFC: Spans-based Scheduling #217
Replies: 6 comments 24 replies
-
I 100% thought this was how it worked based on our discussions. So I am 100% in agreement with making it align with this proposal as it makes the most sense to me. Personally, fewer special concepts applied more often > more special concepts applied less often. That is, having to combine the simple concepts of windows in more complex ways is better than managing more conceptual ideas. We are essentially creating an algebra for these things and reducing it down to the simplest axiom building blocks provides for the easiest understanding of it. |
Beta Was this translation helpful? Give feedback.
-
One of my concerns around Conditions really "want" to have the first interpretation; a condition is all about deciding, for each time, whether the state of the world meets our condition. Whole spans don't really have an identity at this point, and the coalescing behavior is what we want. On the other hand, typical scheduling rules seem to work in terms of spans with identity. We often want to take some action for each activity of a given type (a set of spans which may overlap!) in the same way that we often want to take some action for each contiguous span of time over which a condition is true. While I agree with Dylan that fewer general-purpose concepts are better, I struggled (and still struggle) to see how these two interpretations can be unified while addressing all use-cases. Originally, I had hoped that a coercion (ideally implicit) would lift a condition's
As I recall, |
Beta Was this translation helpful? Give feedback.
-
The primary motivation for attaching activity metadata to Windows is actually for constraints. Currently |
Beta Was this translation helpful? Give feedback.
-
Great work. I have a first set of questions/remarks:
|
Beta Was this translation helpful? Give feedback.
-
RevisionWe had a meeting with some customers in Clipper. Problems and missing features that this RFC needs to address:
Coalescing WindowsThe folks at clipper were supportive of the idea of separating Given this decision, the ImplementationThe eDSL should have two separate classes,
Activity Builder / Pattern changesThe other three problems I think are best solved by expanding how activity patterns are constructed. The
Exampleexport default (): Goal => {
let pickSpans = Spans.ForEachActivity(
ActivityType.PickBanana,
pick => pick.span()
);
// Create the goal
return Goal.From(pickSpans)
.then(spans => ActivityBuilder.For(ActivityType.PeelBanana)
.parameters({/* ... */})
.precededBy(spans)
);
} After each pick activity, place a peel activity and then two bite activities when the peel ends export default (): Goal => {
let pickSpans = Spans.ForEachActivity(
ActivityType.PickBanana,
pick => pick.span()
);
let windowsWithoutBiteBanana = Spans.ForEachActivity( // Make sure the bites are not placed at the same time
ActivityType.BiteBanana
bite => bite.span()
).windows().invert();
// Prepare the function that generates bite banana activities, because it is reused.
let biteActivities = peelSpans => ActivityBuilder.For(ActivityType.BiteBanana)
.parameters({/* ... */})
.precededBy(peelSpans)
.placeWhen(windowsWithoutBiteBanana);
// Create the goal
return Goal.From(pickSpans)
.then(spans => ActivityBuilder.For(ActivityType.PeelBanana)
.parameters({/* ... */})
.precededBy(spans)
.then(biteActivities)
// The placeWhen from above will kick in here to ensure that the second bite is placed after the first
.then(biteActivities)
);
} How .then worksUnlike the original proposal, I think this revision might require changes to the solver. Once spans are calculated and its time to place activities, the scheduler will need to check which activities already exist based on the interval relations.
Then the scheduler will need to collect the spans associated with those activities and use them to evaluate the This would require creating a new Extra benefitAdrien exposed a few unsoundness problems with scheduling in #244. One of them is that later goals in the priority order can invalidate the results of earlier goals, at best making scheduling not idempotent. Compared to other types of goals, Spans-based goals can more easily detect this behavior, because the Unfortunately, that is no longer true if the scheduler needs to automatically respect constraints. |
Beta Was this translation helpful? Give feedback.
-
TasksThe checkboxes represent the smallest indivisible pieces of work. The top-level bullet points represent tickets.
|
Beta Was this translation helpful? Give feedback.
-
RFC: Windows-Based Scheduling
This proposes changes to the Windows API and a redesign of the Scheduling API, which would use
Windows
as the primary way of determining how a Goal should behave. The two main reasons for these proposals are:These proposals use the ideas of "windows patterns" and "activity patterns". These are just collections of windows or activities that have relative positions but no absolute position. We won't need special classes to handle these objects though. A "windows pattern" is just a normal
Windows
object, but the function that uses it is allowed to move the absolute time anywhere it wants.Updates to Windows API
Each item below is marked as whether it would be required in order to accomodate the proposed Scheduling redesign.
ForEachActivity
produces Windows (required)Change it to produce
Windows
instead ofConstraint
. This would require a refactor to theWindows
Java object to keep metadata about the activities that generated it. New usage:The new
ForEachActivity
would just perform a Union of the generatedWindows
. Also, given the pattern that a lack of window is a violation, we'll have to store the activity metadata in the gaps between windows wheninvert()
is called.ForbiddenActivityOverlap
produces Windows (free)Change it to a windows-producing
ActivityOverlap
. New usage:This would allow it to be used in scheduling too. This change would be free because the above change to
ForEachActivity
would make this happen naturally.Manual Window Creation (required)
Ability to create windows separate from profiles. Usage:
The case of creating a window with a start time and duration would be handled by Adrien's
shiftBy
operator:Windows.Instant(dateTime).shiftBy(0, duration)
Bound Inclusivity (optional)
Ability to toggle inclusivity of Windows bounds. Usage:
Repetition (required)
There are two kinds of repetition likely to be useful. Both use the concept of a "windows pattern", which is the relative positions and durations of a Windows set, without the absolute locations. This doesn't require a special class to represent it though.
Separation-based
We need to repeat based on a duration. I imagine that this operation would repeat a windows pattern both forward and backward to both horizons, and the user could then filter the result; but that is up for debate. Usage:
Number-based
We also need to repeat a fixed number of times in a range. This could be done in a number of ways.
N
equally-spaced instantaneous windows for each window of thethis
Windows object. (I think of this like MATLAB or numpy'slinspace
.)N
equally-sized windows by removingN-1
instants in the middle.spacedInstants
but with a custom windows pattern. Aligns the start of the first pattern instance with the start of the window, and the end of the last pattern instance with the end of the window. Ensures equal spacing in between pattern instances.repeatInside
is a more general version ofspacedInstants
, because:windows.spacedInstants(N) == Windows.Instant(0).repeatInside(windows, N)
. Personally, I think implementing bothrepeatInside
andsplit
would be ideal.Starts and Ends (useful, maybe not required)
Ability to replace windows with their start or end points. Useful for making windows on directional transitions in Real profiles. Example usage:
Unlike
Real.Resource("soc").equal(0.3)
, this produces an instantaneous window only whenstate of charge
drops below 30%, not when it rises above 30%.This particular example could also be achieved with a transition operator on the
Real
class:Real.Resource("soc").crossesFromAbove(0.3)
, but thestarts()
operation is more general.Windows-Based Scheduling
The concept is that all scheduling boils down to a set of windows that need an activity pattern, and a process for adding those activities if they are not present. I believe that only the following are required for a fully functional Scheduling API:
start = 0
)Real
andDiscrete
classes from the Constraints API, possibly referencing Resource values.Placement
enum, but it can be easily replaced with something more flexible.The algorithm for applying a Goal will be much simpler than before:
ForEachActivity
, createMissingAssociationConflict
s when appropriate.I argue that with liberal use of the
.split()
operation, there should be no need to ever place more than one activity pattern in a window. Please try to think of counter-examples though, because this proposal will lose a lot of simplicity if that's not true.Examples
Expand
Place a
BiteBanana
within 10 seconds of everyPeelBanana
:Place two
GrowBanana
activities in every day of the"Banana Season"
mission phase:Place a pattern of 2
ThrowBanana
s after everyPickBanana
withquantity > 2
:After every
PickBanana
, place both aThrowBanana
and aPeelBanana
in one operation, but without a rigid relative time specified by a pattern.Limitations
Beta Was this translation helpful? Give feedback.
All reactions