javaspring-bootnp-hardtimefold

How to increase cardinality more than 4 using .map() and Joins 5 facts in constraint streams


For a rule, I need to increase the cardinality to 5. I am unsure how to add the .map function and downstream the data. Also, after downstream how to extract the data. Please see the following code what I am trying to develop. The commented section inside the code I am trying to fill out the .map and .penalizeConfigurable section I am trying to extract it.

return constraintFactory.forEach(RuleSetting.class)
            .filter(ruleSetting -> ruleSetting.getRuleName().equals("E015")&& ruleSetting.getIsActive() == true)
            .join(Shift.class)
            .join(ForeignerType.class)
            .filter((ruleSetting, shift, foreignerType) -> shift.getEmployee().getForeignerType() != null
                                            && foreignerType.getForeignerType().equals(shift.getEmployee().getForeignerType())
                                            && shift.getWeekNo() != null
                                            )
            .groupBy((ruleSetting, shift, foreignerType)->ruleSetting,
                    (ruleSetting, shift, foreignerType)->shift.getEmployee(),
                    (ruleSetting, shift, foreignerType)->shift.getWeekNo(),
                     ConstraintCollectors.sumLong((ruleSetting, shift, foreignerType)->shift.getWorkMinutes()))
            .filter((ruleSetting, employee, weekNo, totalDuration) ->  totalDuration > employee.getContracts().getMaxMinutesPerWeek())
            .map(//How to fill the map function??
                )   
            .join(ForeignerType.class)
            .penalizeConfigurable((first, foreigner)->{
                //How to extract the data here.
                    Double result = Math.abs(((double)totalDuration / (double) employee.getContracts().getMaxMinutesPerWeek()));
                    result = result * Math.abs(ruleSetting.getWeight());
                    return result.intValue();
             })
            .indictWith((ruleSetting, employee, weekNo, totalDuration) ->{
                 EmployeeScoreKeyItems res = new EmployeeScoreKeyItems(EmployeeScoreKeyItems.KeyType.BY_WEEK,
                            ruleSetting.getRuleName(),
                            employee.getEmployeeId(), 
                            null, null, weekNo, null);

                    return List.of(res);    
             })
             .asConstraint("E015")

Solution

  • map(...) allows you to change between cardinalities arbitrarily, up to the maximum cardinality of 4. If you need to go above 4, there is a trick - you can pack several of the arguments into another type.

    Consider a Java record like this:

    record QuadTuple<A, B, C, D>(A a, B b, C c, D d) {
    }
    

    We can pack a Quad stream to a Uni stream like so:

    .map((a, b, c, d) -> new QuadTuple<>(a, b, c, d))
    

    Or, to use a method reference:

    .map(QuadTuple::new)
    

    In a subsequent filter, for example, you'd do:

    .filter(quadTuple -> quadTuple.a() > 0)
    

    Once you have a Uni stream like this, you can treat it like any other stream, and start joining on it.