0

I'm very confused about this. Even ChatGPT is unsure of what's wrong. So I need to turn to the real experts.

My project can be found here: https://github.com/matthewjd24/OptaPlanner-Scheduler

This code has been adapted from the Hello world quick start. In summary, I have a job shop scheduling problem, but there are no 'projects' - each job just needs to pass through a machine once and it's done. My hard and soft constraints work fine, but if I attempt to add a new problem fact/planning variable, it starts breaking the hard constraints and acting like it hasn't (as in, the hard score in the resulting solution is 0). I'll show you some relevant snippets of code:

This is my Planning Solution class:

@PlanningSolution
public class TimeTable {

@ValueRangeProvider
@ProblemFactCollectionProperty
private List<Cycle> timeslotList;
@ValueRangeProvider
@ProblemFactCollectionProperty
private List<Machine> machineList;
@ValueRangeProvider
@ProblemFactCollectionProperty
private List<Mold> moldList;
@PlanningEntityCollectionProperty
private List<Job> lessonList;

@PlanningScore
private HardSoftScore score;

This is my Planning Entity, the Job class:

@PlanningEntity
public class Job {

@PlanningId
private Long id;

public String jobName;
public Integer width;
public Integer height;
public Integer weight;

@PlanningVariable(nullable = true)
private Cycle timeslot;
@PlanningVariable(nullable = true)
private Machine machine;
@PlanningVariable(nullable = true)
private Mold mold;

public Job() {
}

public Job(Long id, String jobName, Integer width, Integer height, Integer weight) {
    this.id = id;
    this.jobName = jobName;
    this.width = width;
    this.height = height;
    this.weight = weight;
}

My constraint that applies a hard score penalty when two jobs have the same timeslot, same machine, and different IDs:

private Constraint machineProcessOneJobAtATime(ConstraintFactory constraintFactory) {
    return constraintFactory
        .forEach(Job.class)
        .join(Job.class,
            Joiners.equal(Job::getTimeslot),
            Joiners.equal(Job::getMachine),
            Joiners.lessThan(Job::getId))
        .penalize(HardSoftScore.ONE_HARD)
        .asConstraint("Multiple jobs scheduled for a machine at once");
}

If I comment out the @ValueRangeProvider and @ProblemFactCollectionProperty modifiers for the moldList in the planning solution, and @PlanningVariable(nullable = true) in the Job class, the constraint works fine. But the moment I add in the mold list as a variable, OptaPlanner starts breaking this hard constraint and saying the hard score is 0 (essentially acting like it hasn't broken the constraint). I have no constraints set up that interact with the Mold variable. Does anyone know why the machineProcessOneJobAtATime would stop working properly when the Mold planning variable is added? I'm very confused about this. Thank you.

Geoffrey De Smet
  • 26,223
  • 11
  • 73
  • 120
MattWolc24
  • 106
  • 1
  • 9
  • I assume you're running your constraint tests when this happens. If so, make sure each `@PlanningVariable` is initialized otherwise your `@PlanningEntity` is ignored by the tests, hence the 0 score. – Istvan Jul 21 '23 at 12:58

1 Answers1

1

What you're describing sounds a lot like a score corruption. Enable [FULL_ASSERT][1] to confirm that. Once confirmed, through a process of elimination, find the constraint which causes the score corruption. (Only rarely is it a combination of multiple constraints, it can usually be narrowed down to one.)

Once you know which one it is, we can discuss why.

Lukáš Petrovický
  • 3,945
  • 1
  • 11
  • 20
  • Thank you. I will look into this. – MattWolc24 Jul 13 '23 at 17:09
  • I've added `config.setEnvironmentMode(EnvironmentMode.FULL_ASSERT);` in my code, but no exceptions were thrown when I ran it again. – MattWolc24 Jul 13 '23 at 17:24
  • You may also want to try `NON_INTRUSIVE_FULL_ASSERT`. If that also comes up empty, then I question the claim that OptaPlanner breaks a constraint and yet reports 0 broken. The proof would be a runnable piece of code that demonstrates the issue. – Lukáš Petrovický Jul 13 '23 at 17:30
  • I also just tried `NON_INTRUSIVE_FULL_ASSERT` and did not see any exceptions. They would show up in the terminal right? It's entirely possible that the hard constraint in my post is not working as I expect. I'm very new to OptaPlanner. – MattWolc24 Jul 13 '23 at 17:33
  • How can I provide a runnable piece of code that demonstrates the issue? As in a fat .jar? – MattWolc24 Jul 13 '23 at 18:42
  • Preferrably in the form of a Maven/Gradle project, published either in some public repo, or e-mailed. I will need to see the source code to be able to make sense of what's happening. – Lukáš Petrovický Jul 13 '23 at 18:52
  • I will publish my Gradle project in a repository, thank you for your help. – MattWolc24 Jul 13 '23 at 19:10
  • I've published it here - https://github.com/matthewjd24/OptaPlanner-Scheduler thank you – MattWolc24 Jul 13 '23 at 19:26
  • I've figured it out... sort of. For one, I was using HILL_CLIMBING local search, which for some reason makes it start breaking my hard constraint. Additionally, if I set up any of my constraints in certain ways, the solver will start breaking the hard constraint again. Still learning why. – MattWolc24 Jul 13 '23 at 22:11
  • I have not figured it out. It seems to randomly break the hard constraint with no penalty to the score. I have upgraded to Timefold hoping that will fix it, but it did not. I have rewritten the constraint multiple times as well but it did not help. The issue persists with `FULL_ASSERT` and `NON_INTRUSIVE_FULL_ASSERT` as well. – MattWolc24 Jul 14 '23 at 14:53