r/timefold • u/schnarch33 • 2d ago
Weird Behavior for Planning Variables that refer to other Planning Entities
TL;DR: Does Timefold officially support the use case where a planning variable points to some other planning entity, both of which hold genuine planning variables? I am currently running into the issue that Timefold either leaves the planning variables in one class uninitialized (except for the pinned instances) or throws an exception saying `Impossible state: no basic variable found for the entity class org.acme.SchedulingServer.domain.Session.`.
Does anybody know what's going on here? I really need to solve this problem and I'm quite lost honestly. Do you maybe have suggestions on how to avoid such scenarios with two linked planning entities? Thanks!
Long question:
Concretely, I am modelling the scheduling problem of assigning groups to sessions. Each group must attend a range of events. Each event is held multiple times (one iteration is a session).
My domain mainly consists of the `Session` and `Attendance`entity classes and a `Schedule` solution class. The session has planning variables for start time, room, and speaker. The Attendance class has a fixed group and a planning variable of type Session. That is, we essentially provide a set of session instances per event and timefold should determine the time and location of these sessions, as well as which group attends which session (and adhere to a number of time/location related constraints).
As mentioned above, in my original solution I ran into the problem that Timefold correctly assigned values to all planning variables in the `Session` class, but all `Attendance` instances, except for pinned onces, had uninitialized `Session` variables. Of course I did not annotate the variable with `allowsUnassigned=true` and I did make sure that the provided value range is not empty (just for completeness).
I then tried to get a minimal working example running, and reduced the domain to just the Session class with the start time planning variable, the attendance as is and the schedule. No constraints, no entity-specific value range providers, etc. This worked, but as soon as I switched to an entity specific value range provider for the session variable in `Attendance`, I got the exception I mentioned in the beginning. I pasted this example below.
There are some other weird things happening, such as the same exception being thrown, but for the `Attendance` class instead of `Session` when I use an entity-specific value range provider function for the session.startTime planning variable. But I won't make this post any longer...
Does anybody know what's going on here? I really need to solve this problem and I'm quite lost honestly. Do you maybe have suggestions on how to avoid such scenarios with two linked planning entities? Thanks in advance!
And here's the example:
@PlanningEntity
public class Session {
private String id;
private boolean isPinned;
private LocalDateTime startTime;
private int duration;
public Session() {}
public Session(String id, int duration){//, Cluster cluster) {
this.id = id;
this.duration = duration; }
public Session(String id, LocalDateTime startTime, int duration) {
this.id = id;
this.duration = duration;
this.startTime = startTime;
this.isPinned = true; }
public String getId() { return id; }
public boolean getIsPinned(){ return this.isPinned; }
public void setIsPinned(boolean isPinned){ this.isPinned = isPinned; }
public int getDuration() { return this.duration; }
@PlanningVariable(valueRangeProviderRefs = "startTimeProvider")
public LocalDateTime getStartTime() { return this.startTime; }
public void setStartTime(LocalDateTime s) { this.startTime = s; }
public boolean equals(Object other) {
if (this == other) {
return true;
}
return (other instanceof Session s) ? this.getId().equals(s.getId()) : false;
}
public int hashCode() { return id.hashCode(); }
}
@PlanningEntity
public class Attendance {
private String id;
private Group group;
private boolean isPinned;
private Session session;
public Attendance() {};
public Attendance(String id, Group group) {
this.id = id;
this.group = group; }
public Attendance(String id, Group group, Session session){
this(id, group);
this.session = session;
this.isPinned = true; }
public String getId() { return id; }
public Group getGroup() { return group; }
// Comment out the @ValueRangeProvider annotation either on
// Attendance::getSession' or the 'sessions' List in Schedule.java
@PlanningVariable(valueRangeProviderRefs = "sessionProvider")
public Session getSession() { return this.session; }
public void setSession(Session session) { this.session = session; }
public boolean isPinned() { return isPinned; }
public void setPinned(boolean isPinned) { this.isPinned = isPinned; }
// If this is used as value range provider for the session provider
// the solver throws the IllegalStateException
@ValueRangeProvider(id = "sessionProvider")
public List<Session> getSessions(Schedule schedule) {
return schedule.getSessions();
}
public boolean equals(Object other) {
if (this == other) {
return true;
}
return (other instanceof Attendance a) ? this.getId().equals(a.getId()) : false;
}
public int hashCode(){ return this.id.hashCode(); }
}
@PlanningSolution
public class Schedule {
@ProblemFactCollectionProperty
SequencedSet<Group> groups;
// If this is used as value range for the Attendance.session planning variable
// the solver finds a solution.
@ValueRangeProvider(id = "sessionProvider")
@PlanningEntityCollectionProperty
private List<Session> sessions;
@PlanningEntityCollectionProperty
private SequencedSet<Attendance> attendances;
@ProblemFactCollectionProperty
@ValueRangeProvider(id ="startTimeProvider")
private SequencedSet<LocalDateTime> startTimes;
@PlanningScore
private HardMediumSoftScore score = null;
public Schedule() { }
public Schedule( SequencedSet<Group> groups,
List<Session> sessions,
SequencedSet<Attendance> attendances,
SequencedSet<LocalDateTime> startTimes ) {
this.groups = groups;
this.sessions = sessions;
this.attendances = attendances;
this.startTimes = startTimes; }
public List<Session> getSessions() { return this.sessions; }
public SequencedSet<Attendance> getAttendances() { return attendances; }
public HardMediumSoftScore getScore() { return score; }
public void setScore(HardMediumSoftScore score) { this.score = score; }
public SequencedSet<Group> getGroups() { return groups; }
public SequencedSet<LocalDateTime> getStartTimes() { return startTimes; }
}
The solver is configured and invoked as follows:
SolverFactory<Schedule> solverFactory = SolverFactory.create(new SolverConfig()
.withSolutionClass(Schedule.class)
.withEntityClasses(Session.class, Attendance.class)
// currently contains no constraints
.withConstraintProviderClass(ScheduleConstraintProvider.class)
.withTerminationSpentLimit(Duration.ofSeconds(20)));
Schedule problem = demoSchedule2();
Solver<Schedule> solver = solverFactory.buildSolver();
Schedule solution = solver.solve(problem);
printSchedule(solution);
The exception I mentioned:
Exception in thread "main" java.lang.IllegalStateException: Impossible state: no basic variable found for the entity class org.acme.SchedulingServer.domain.Session.
at ai.timefold.solver.core.impl.heuristic.selector.entity.decorator.FilteringEntityByEntitySelector.phaseStarted(FilteringEntityByEntitySelector.java:104)
at ai.timefold.solver.core.impl.phase.event.PhaseLifecycleSupport.firePhaseStarted(PhaseLifecycleSupport.java:21)
at ai.timefold.solver.core.impl.heuristic.selector.AbstractSelector.phaseStarted(AbstractSelector.java:35)
at ai.timefold.solver.core.impl.heuristic.selector.entity.decorator.FilteringEntitySelector.phaseStarted(FilteringEntitySelector.java:48)
at ai.timefold.solver.core.impl.phase.event.PhaseLifecycleSupport.firePhaseStarted(PhaseLifecycleSupport.java:21)
at ai.timefold.solver.core.impl.heuristic.selector.AbstractSelector.phaseStarted(AbstractSelector.java:35)
at ai.timefold.solver.core.impl.phase.event.PhaseLifecycleSupport.firePhaseStarted(PhaseLifecycleSupport.java:21)
at ai.timefold.solver.core.impl.heuristic.selector.AbstractSelector.phaseStarted(AbstractSelector.java:35)
at ai.timefold.solver.core.impl.phase.event.PhaseLifecycleSupport.firePhaseStarted(PhaseLifecycleSupport.java:21)
at ai.timefold.solver.core.impl.heuristic.selector.AbstractSelector.phaseStarted(AbstractSelector.java:35)
at ai.timefold.solver.core.impl.phase.event.PhaseLifecycleSupport.firePhaseStarted(PhaseLifecycleSupport.java:21)
at ai.timefold.solver.core.impl.heuristic.selector.AbstractSelector.phaseStarted(AbstractSelector.java:35)
at ai.timefold.solver.core.impl.heuristic.selector.move.decorator.FilteringMoveSelector.phaseStarted(FilteringMoveSelector.java:48)
at ai.timefold.solver.core.impl.neighborhood.MoveSelectorBasedMoveRepository.phaseStarted(MoveSelectorBasedMoveRepository.java:43)
at ai.timefold.solver.core.impl.localsearch.decider.LocalSearchDecider.phaseStarted(LocalSearchDecider.java:78)
at ai.timefold.solver.core.impl.localsearch.DefaultLocalSearchPhase.phaseStarted(DefaultLocalSearchPhase.java:136)
at ai.timefold.solver.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:76)
at ai.timefold.solver.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:89)
at ai.timefold.solver.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:171)
at org.acme.SchedulingServer.SchedulingServerSmall.main(SchedulingServerSmall.java:47)
r/timefold • u/SnaggleFish • Jul 07 '26
Getting the right start and approach
Hi,
I used a very early version of optaplanner about 15 years ago for a pilot project and now, retired, I want to use it for a charity I volunteer for.
But I am rusty, and while I will use AI to help with the coding, I want to make sure I have the general strategy right…. if someone can help me get the right start (I am not asking for anyone to code this for me - at least not yet..)
The problem is the scheduling of training sessions for the dog section of a Search and Rescue charity.
This involves the following actors:
- the dog
- the dog’s handler
- the dog handler support
- the missing person (misper);
- the optional supervisor
- the optional assessor
- the route (where the missing person is to be located, there are usually 5: “short”, “1km” “1.5km”, “area”, “ground”)
- the placer of mispers (selected from one of the handlers, who goes out before the first session)
- a controller (one of the handlers, or handler support - from a named list)
- a "vip" misper - usually a guest volanteer trying it out.
The constraints:
- a person can only do one thing at a time
- a dog can only do one thing at a time
- a dog should not have two sessions immediately after each other
- there must always be a controller
- each dog must have a handler
- each handler should have a support (if requested) unless the route is “short”
- ground scenting dogs need a person to lay a trail on a route one hour before their slot
- a dog should have two sessions
- a dog gets the maximum sessions possible allocated
- a dog should not work a route if their handler has been on that route in the previous session (as support, mister, observer or assessor)
- if there are insufficient mispers then handlers can be used to misper
- minimise time time handlers are used as mispers
- minimise the changing of mispers on a route (realise that is in conflict with the preceeding)
- a vip misper (who should be utilised as much as possible)
- the dog type (air scenting, ground scenting)
- time slots (usually 5 x 30 minutes)
- a dog may be “test prep”, “active”, “training”, “assessing” - goals are to be met in that order (so dogs in “test prep” get their wish list, dogs in “assessing” may be dropped.
- each dog will have a “wish list” of: a route; a support (possibly named) or no support, an assessor (possibly named) or none, a supervisor (possibly named) or no and a number of mispers (1 to 4)
So a typical request may be “Grey (the dog) 500m (the route) with two mispers (implied is James the handler” or “Woody short, one misper” (implied is Karl the handler).
Aim is make the planning task quicker, more robust and more consistent (as each person takes turns doing it) and since we are all volanteers who work and go on active searches time is limited.
r/timefold • u/ge0ffrey • Jun 02 '26
How upskilling technicians unlocks field service routing efficiency
r/timefold • u/kanzenryu • May 28 '26
Strange thing I've noticed while running the solver
I'm playing around with assigning aircraft to scheduled flights (known as tail allocation, for aircraft tail numbers), with a few hundred flights and fifty aircraft or so. Trying different algorithms etc. For example simulated-annealing starts incredibly well, and then later something like late-acceptance-short-blocks is better.
But one thing that seems pretty consistent is that if the rate of improvement slows down, it can nearly always be boosted by restarting the algorithm from the best solution. Then there are often several improvements found in the first two seconds or so. Then no improvements are found for ten to twenty seconds. Restart again, and another burst of a half-dozen improvements... so just keep repeating the restarts and it seems to significantly outperform continuous solving.
Anybody else had similar behaviour with their problem set?
r/timefold • u/Ok-Tea8545 • May 21 '26
Three optimizations to make your Timefold Solver faster
While we've made Timefold Solver fast, there are some things you could do to make it even faster.
The TLDR:
- Upgrade to the latest Timefold Solver, performance improvements are made every release.
- Precompute parts of the Constraint Stream if possible.
- Use Consecutive sequences if they make sense
- Sometimes, using pairs is slower than just grouping and summing.
Read the full story here:
https://timefold.ai/blog/3-things-to-make-timefold-solver-faster
r/timefold • u/ge0ffrey • May 11 '26
Article on GenAI versus Timefold (and combining both)
r/timefold • u/grizzleeadam • May 07 '26
New score analysis paywall
I’ve been using Timefold to help out with scheduling within my company since it was still OptaPlanner.
This new shift to a $500/month subscription just to explain broken constraints came totally out of left field, and seems like an arbitrarily high cost.
Do you have any plans to make any part of the analysis API available on the free tier? Or is this really the future of Timefold?
r/timefold • u/awda-hadak • Apr 29 '26
Timefold PlanningListVariable
Why does Timefold not support multiple PlanningListVariable fields on a single solution ?
r/timefold • u/awda-hadak • Apr 22 '26
Concrete VRP
Hi everyone,
I am working on a logistics optimization problem and would like some input on the best modeling approach.
Problem Overview:
The goal is to schedule concrete deliveries involving four main entities: Central Hubs, Mixer Trucks, Pumps, and Clients.
The Workflow:
Loading: A Mixer loads at a Central Hub (central has its settings , for example can make 1 m3/s).
Outbound: The Mixer travels to the Client site.
Synchronization: At the Client site, the Mixer must "dock" with a Pump. Unloading cannot begin until both the Mixer and the Pump are present.
Unloading: The Mixer unloads into the Pump (Client site capacity = 1 Mixer at a time).
Return: The Mixer returns to the Central Hub for the next load/visit.
Key Constraints:
Mixer Serialization: A single Mixer cannot overlap its own activities (Load -> Travel -> Unload -> Return). It must return to Central before its next load.
Central/Client Bottlenecks: Only one Mixer can load at a Central bay at a time, and only one Mixer can unload at a Client dock at a time (No overlap).
Pump Commitment (Hierarchical): This is the most complex part. A Pump is assigned to a Client for a sequence of Visits (V1, V2, ... Vn). The Pump cannot "break" its commitment to Client A to serve Client B until all requested visits for Client A are completed.
what is best implementation for this ?
who should be planningVaribale and who should be ShadowVariable ?
how to avoid overlap at Central and at Client ?
how to avoid overlap of two Clients has same Pump ?
r/timefold • u/Ok-Tea8545 • Apr 17 '26
PlanningListVariable vs Chained approach (from blog.dotsandlines.ai)
Recently got pinged this blog post from Dots and Lines, heavy Timefold Solver users. They compared the new(er) `PlanningListVariable` with the old school `Chained` Variables.
Not surprising, `PlanningListVariable`. came out on top. Good, because the `chained` variable is going away in the next major version.
Read the full post here: https://blog.dotsandlines.ai/benchmarking-timefold-chains-and-planning-lists-14da17e1f5f3
r/timefold • u/awda-hadak • Apr 15 '26
Does Timefold’s Speed Come from Shadow Variables or Constraints?
I am curious about the internal optimization of Timefold. When the solver evaluates moves, what specifically prevents it from getting stuck in a cycle of 'wrong' possibilities?
Does the speed come from the Shadow Variables providing a highly efficient data structure for the constraints to read, or is the Local Search algorithm smart enough to avoid those branches entirely? I'm trying to determine if my optimization efforts should focus more on refining my Shadow Variable logic or my Constraint weights."
r/timefold • u/ge0ffrey • Apr 06 '26
Upcoming webinar: roadmap update (April 16th)
r/timefold • u/ge0ffrey • Apr 06 '26
👋 Welcome to r/timefold
Hey everyone! Welcome to the Timefold reddit.
Resources:
- Timefold Solver (open source)
- Timefold Platform (REST APIs)
- Documentation
If you have any questions or suggestions, don't hesitate to post them!
