Search code examples
javaspring-bootoptaplannertimefold

How to select the constraint type dynamically in TimeFold


I have a RuleSetting class that is a problem fact. It stores the type which can be Soft, Medium, and Hard. Based on it the rule type will be changed.

I have implemented the constraint stream as follows:

   Constraint daysCountMoreThanMaximumNumberOfDaysInContractPerWeek(ConstraintFactory 
    
        constraintFactory) {
              return constraintFactory.forEach(RuleSetting.class)
                        .filter(ruleSetting -> ruleSetting.getRuleName().equals("E005")&& ruleSetting.getIsActive() == true)
                        .join(Shift.class)
                        .filter((ruleSetting, shift) -> shift.getEmployee().getContracts().getMaxDaysPerWeek() != null && shift.getEmployee().getContracts().getMaxDaysPerWeek() > 0)
                        .groupBy((ruleSetting, shift)->ruleSetting,
                                (ruleSetting, shift)->shift.getEmployee(),
                                (ruleSetting, shift)->shift.getWeekNo(),
                
    
                    ConstraintCollectors.countBi())
                        .filter((ruleSetting, employee, weekNo, noDays) ->  noDays > employee.getContracts().getMaxDaysPerWeek())
                        .penalize(HardMediumSoftScore.ONE_SOFT
    
// This section is hardcoded to SOFT, I would like to make it dynamic.        
// Like ruleSetting.getType().equals("Soft") ? HardMediumSoftScore.ONE_SOFT: HardMediumSoftScore.ONE_HARD

    , (ruleSetting, employee, weekNo, noDays)->{
                                return (int)Math.abs(((double)ruleSetting.getWeight() * (double)noDays / (double) employee.getContracts().getMaxDaysPerWeek()));
                         })
                         .indictWith((ruleSetting, employee, weekNo, noDays) ->{
                             EmployeeScoreKeyItems res = new EmployeeScoreKeyItems(EmployeeScoreKeyItems.KeyType.BY_WEEK,
                                        ruleSetting.getRuleName(),
                                        employee.getEmployeeId(), 
                                        null, null, weekNo, null);
        
                                return List.of(res);    
                         })
                         .asConstraint("Days Count More Than Maximum Number Of Days In Contract Per Week");
                      
            }

Please recommended the way of solution. I would prefer not to use the Configurable option. But if there is no way, then may be I have to use that option.


Solution

  • This is exactly why @ConstraintConfiguration, @ConstraintWeight and penalizeConfigurable() were created.

    By using those, you won't even pay for the performance cost of the constraint streams of that constraint when the constraint weight is zero.