简体   繁体   中英

Optaplanner Constraint streams: Dynamically define if its a hard or a soft score

I am solving an employee rostering problem with optaplanner. Currently I'm rewriting my rules written in DRL to Constraint Streams. I have constraints, where the user can define, if he wants the rule as a hard or a soft constraint. In DRL in the then part I had access to my roster object and with this I could find out if I have to add a hardConstraintMatch or a softConstraintMatch .

How can I achieve that with Constraint Streams?

Here an example:

 Constraint holiday(ConstraintFactory constraintFactory) { return constraintFactory.forEach(Shift.class).join( Absence.class, Joiners.equal(Shift::getEmployee, Absence::getEmployee), Joiners.greaterThanOrEqual(Shift::getDate, Absence::getStartDate), Joiners.lessThanOrEqual(Shift::getDate, Absence::getEndDate) ).penalize( "holiday", // Here I would need something like roster.getRules().get("holiday").getType() // to define dynamically if I have to add ONE_HARD or ONE_SOFT HardMediumSoftLongScore.ONE_HARD, (shift,absence) -> { Roster roster = shift.getRoster(); return roster.getRules().get("holiday").getPenaltyValue(); } ); }

Has someone an idea how to achieve that?

What you're looking for is called Constraint Configuration .

After introducing @ConstraintConfiguration on the solution, your constraint would then look like so:

 Constraint holiday(ConstraintFactory constraintFactory) { return constraintFactory.forEach(Shift.class).join(Absence.class, Joiners.equal(Shift::getEmployee, Absence::getEmployee), Joiners.greaterThanOrEqual(Shift::getDate, Absence::getStartDate), Joiners.lessThanOrEqual(Shift::getDate, Absence::getEndDate)).penalizeConfigurable( "holiday", (shift, absence) -> 1); }

For optimal results, change the match weight ( 1 ) to something that reflects the magnitude of the impact. (For example, if the absence length were used as the match weight, then longer absences would have counted for more if broken.)

In my ConstraintConfiguration I would then do something like this in the constructor:

 public EmployeeRosterConstraintConfiguration(Roster roster) { Rule rule = roster.getRules().get("holiday"); if(rule == null) { holidayConflict = HardMediumSoftLongScore.ofSoft(0); } else if(rule.getType() == HARD_CONSTRAINT) { holidayConflict = HardMediumSoftLongScore.ofHard(rule.getPenaltyValue()); } else { holidayConflict = HardMediumSoftLongScore.ofSoft(rule.getPenaltyValue()); } }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM