All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.drools.planner.examples.nurserostering.solver.nurseRosteringScoreRules.drl Maven / Gradle / Ivy

/*
 * Copyright 2010 JBoss Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.drools.planner.examples.nurserostering.solver;
    dialect "java"

import org.drools.planner.core.score.calculator.HardAndSoftConstraintScoreCalculator;
import org.drools.planner.core.score.constraint.IntConstraintOccurrence;
import org.drools.planner.core.score.constraint.ConstraintType;

import org.drools.planner.examples.nurserostering.domain.DayOfWeek;
import org.drools.planner.examples.nurserostering.domain.Employee;
import org.drools.planner.examples.nurserostering.domain.ShiftAssignment;
import org.drools.planner.examples.nurserostering.domain.FreeBefore2DaysWithAWorkDayPattern;
import org.drools.planner.examples.nurserostering.domain.NurseRoster;
import org.drools.planner.examples.nurserostering.domain.Pattern;
import org.drools.planner.examples.nurserostering.domain.RosterInfo;
import org.drools.planner.examples.nurserostering.domain.Shift;
import org.drools.planner.examples.nurserostering.domain.ShiftDate;
import org.drools.planner.examples.nurserostering.domain.ShiftType;
import org.drools.planner.examples.nurserostering.domain.ShiftType2DaysPattern;
import org.drools.planner.examples.nurserostering.domain.ShiftType3DaysPattern;
import org.drools.planner.examples.nurserostering.domain.ShiftTypeSkillRequirement;
import org.drools.planner.examples.nurserostering.domain.Skill;
import org.drools.planner.examples.nurserostering.domain.SkillProficiency;
import org.drools.planner.examples.nurserostering.domain.WeekendDefinition;
import org.drools.planner.examples.nurserostering.domain.WorkBeforeFreeSequencePattern;
import org.drools.planner.examples.nurserostering.domain.contract.Contract;
import org.drools.planner.examples.nurserostering.domain.contract.BooleanContractLine;
import org.drools.planner.examples.nurserostering.domain.contract.ContractLine;
import org.drools.planner.examples.nurserostering.domain.contract.ContractLineType;
import org.drools.planner.examples.nurserostering.domain.contract.MinMaxContractLine;
import org.drools.planner.examples.nurserostering.domain.contract.PatternContractLine;
import org.drools.planner.examples.nurserostering.domain.request.DayOffRequest;
import org.drools.planner.examples.nurserostering.domain.request.DayOnRequest;
import org.drools.planner.examples.nurserostering.domain.request.ShiftOffRequest;
import org.drools.planner.examples.nurserostering.domain.request.ShiftOnRequest;
import org.drools.planner.examples.nurserostering.domain.solver.EmployeeAssignmentTotal;
import org.drools.planner.examples.nurserostering.domain.solver.EmployeeConsecutiveAssignmentEnd;
import org.drools.planner.examples.nurserostering.domain.solver.EmployeeConsecutiveAssignmentStart;
import org.drools.planner.examples.nurserostering.domain.solver.EmployeeConsecutiveWeekendAssignmentEnd;
import org.drools.planner.examples.nurserostering.domain.solver.EmployeeConsecutiveWeekendAssignmentStart;
import org.drools.planner.examples.nurserostering.domain.solver.EmployeeFreeSequence;
import org.drools.planner.examples.nurserostering.domain.solver.EmployeeWeekendSequence;
import org.drools.planner.examples.nurserostering.domain.solver.EmployeeWorkSequence;

global HardAndSoftConstraintScoreCalculator scoreCalculator;

// ############################################################################
// Hard constraints
// ############################################################################

// This rule is build in
// All demanded shifts must be assigned to a nurse
//rule "requiredEmployeeSizePerShift"
//    when
//        $shift : Shift(requiredEmployeeSize > 0, $requiredEmployeeSize : requiredEmployeeSize)
//
//        $totalEmployeeSize : Number(intValue != $requiredEmployeeSize) from accumulate(
//            $assignment : ShiftAssignment(shift == $shift),
//            count($assignment)
//        )
//    then
//        insertLogical(new IntConstraintOccurrence("requiredEmployeeSizePerShift", ConstraintType.NEGATIVE_HARD,
//                Math.abs($requiredEmployeeSize - $totalEmployeeSize.intValue()),
//                $shift));
//end

// a nurse can only work one shift per day, i.e. no two shift can be assigned to the same nurse on a day.
rule "oneShiftPerDay"
    when
        $leftAssignment : ShiftAssignment($leftId : id, $employee : employee, $shiftDate : shiftDate)
        $rightAssignment : ShiftAssignment(employee == $employee, shiftDate == $shiftDate, id > $leftId)
    then
        insertLogical(new IntConstraintOccurrence("oneShiftPerDay", ConstraintType.NEGATIVE_HARD,
                1,
                $leftAssignment, $rightAssignment));
end

// ############################################################################
// Soft constraints
// ############################################################################

rule "insertEmployeeAssignmentTotal"
        salience 1 // Do these rules first (optional, for performance)
    when
        MinMaxContractLine(contractLineType == ContractLineType.TOTAL_ASSIGNMENTS, enabled == true,
            $contract : contract)
        $employee : Employee(contract == $contract)
        $assignmentTotal : Number() from accumulate(
            $assignment : ShiftAssignment(employee == $employee),
            count($assignment)
        )
    then
        insertLogical(new EmployeeAssignmentTotal($employee, $assignmentTotal.intValue()));
end

// Minimum number of assignments
rule "minimumTotalAssignments"
    when
        $contractLine : MinMaxContractLine(
            contractLineType == ContractLineType.TOTAL_ASSIGNMENTS, minimumEnabled == true,
            $contract : contract, $minimumValue : minimumValue
        )
        EmployeeAssignmentTotal(employeeContract == $contract, total < $minimumValue,
            $employee : employee, $total : total)
    then
        insertLogical(new IntConstraintOccurrence("minimumTotalAssignments", ConstraintType.NEGATIVE_SOFT,
                ($minimumValue - $total) * $contractLine.getMinimumWeight(),
                $employee));
end

// Maximum number of assignments
rule "maximumTotalAssignments"
    when
        $contractLine : MinMaxContractLine(
            contractLineType == ContractLineType.TOTAL_ASSIGNMENTS, maximumEnabled == true,
            $contract : contract, $maximumValue : maximumValue
        )
        EmployeeAssignmentTotal(employeeContract == $contract, total > $maximumValue,
            $employee : employee, $total : total)
    then
        insertLogical(new IntConstraintOccurrence("maximumTotalAssignments", ConstraintType.NEGATIVE_SOFT,
                ($total - $maximumValue) * $contractLine.getMaximumWeight(),
                $employee));
end


rule "insertEmployeeConsecutiveAssignmentStart"
        salience 2 // Do these rules first (optional, for performance)
    when
        ShiftAssignment(
            $employee : employee,
            $dayIndex : shiftDateDayIndex,
            $shiftDate : shiftDate
        )
        // The first day has no working day before it
        not ShiftAssignment(employee == $employee, shiftDateDayIndex == ($dayIndex - 1))
    then
        insertLogical(new EmployeeConsecutiveAssignmentStart($employee, $shiftDate));
end
rule "insertEmployeeConsecutiveAssignmentEnd"
        salience 2 // Do these rules first (optional, for performance)
    when
        ShiftAssignment(
            $employee : employee,
            $dayIndex : shiftDateDayIndex,
            $shiftDate : shiftDate
        )
        // The last day has no working day after it
        not ShiftAssignment(employee == $employee, shiftDateDayIndex == ($dayIndex + 1))
    then
        insertLogical(new EmployeeConsecutiveAssignmentEnd($employee, $shiftDate));
end

rule "insertEmployeeWorkSequence"
        salience 1 // Do these rules first (optional, for performance)
    when
        EmployeeConsecutiveAssignmentStart(
            $employee : employee,
            $firstDayIndex : shiftDateDayIndex
        )

        EmployeeConsecutiveAssignmentEnd(
            employee == $employee,
            shiftDateDayIndex >= $firstDayIndex,
            $lastDayIndex : shiftDateDayIndex
        )

        // There are no free days between the first and last day
        not EmployeeConsecutiveAssignmentEnd(
            employee == $employee,
            shiftDateDayIndex >= $firstDayIndex && < $lastDayIndex
        )
    then
        insertLogical(new EmployeeWorkSequence($employee, $firstDayIndex, $lastDayIndex));
end

// Minimum number of consecutive working days
rule "minimumConsecutiveWorkingDays"
    when
        $contractLine : MinMaxContractLine(
            contractLineType == ContractLineType.CONSECUTIVE_WORKING_DAYS, minimumEnabled == true,
            $contract : contract, $minimumValue : minimumValue
        )
        $employee : Employee(contract == $contract)

        $employeeWorkSequence : EmployeeWorkSequence(
            employee == $employee,
            dayLength < $minimumValue,
            $dayLength : dayLength
        )
    then
        insertLogical(new IntConstraintOccurrence("minimumConsecutiveWorkingDays", ConstraintType.NEGATIVE_SOFT,
                ($minimumValue - $dayLength) * $contractLine.getMinimumWeight(),
                $employeeWorkSequence));
end

// Maximum number of consecutive working days
rule "maximumConsecutiveWorkingDays"
    when
        $contractLine : MinMaxContractLine(
            contractLineType == ContractLineType.CONSECUTIVE_WORKING_DAYS, maximumEnabled == true,
            $contract : contract, $maximumValue : maximumValue
        )
        $employee : Employee(contract == $contract)

        $employeeWorkSequence : EmployeeWorkSequence(
            employee == $employee,
            dayLength > $maximumValue,
            $dayLength : dayLength
        )
    then
        insertLogical(new IntConstraintOccurrence("maximumConsecutiveWorkingDays", ConstraintType.NEGATIVE_SOFT,
                ($dayLength - $maximumValue) * $contractLine.getMaximumWeight(),
                $employeeWorkSequence));
end


rule "insertEmployeeFreeSequence"
        salience 1 // Do these rules first (optional, for performance)
    when
        EmployeeConsecutiveAssignmentEnd(
            $employee : employee,
            $firstDayIndexMinusOne : shiftDateDayIndex
        )

        EmployeeConsecutiveAssignmentStart(
            employee == $employee,
            shiftDateDayIndex > $firstDayIndexMinusOne,
            $lastDayIndexPlusOne : shiftDateDayIndex
        )

        // There are no working days between the first and last day
        not EmployeeConsecutiveAssignmentStart(
            employee == $employee,
            shiftDateDayIndex > $firstDayIndexMinusOne && < $lastDayIndexPlusOne
        )
    then
        insertLogical(new EmployeeFreeSequence($employee, $firstDayIndexMinusOne + 1, $lastDayIndexPlusOne - 1));
end
rule "insertFirstEmployeeFreeSequence"
        salience 1 // Do these rules first (optional, for performance)
    when
        EmployeeConsecutiveAssignmentStart(
            $employee : employee,
            $lastDayIndexPlusOne : shiftDateDayIndex
        )

        // There are no working days before the first day
        not EmployeeConsecutiveAssignmentEnd(
            employee == $employee,
            shiftDateDayIndex < $lastDayIndexPlusOne
        )
        RosterInfo(firstShiftDateDayIndex < $lastDayIndexPlusOne, $firstDayIndex : firstShiftDateDayIndex)
    then
        insertLogical(new EmployeeFreeSequence($employee, $firstDayIndex, $lastDayIndexPlusOne - 1));
end
rule "insertLastEmployeeFreeSequence"
        salience 1 // Do these rules first (optional, for performance)
    when
        EmployeeConsecutiveAssignmentEnd(
            $employee : employee,
            $firstDayIndexMinusOne : shiftDateDayIndex
        )

        // There are no working days after the last day
        not EmployeeConsecutiveAssignmentStart(
            employee == $employee,
            shiftDateDayIndex > $firstDayIndexMinusOne
        )
        RosterInfo(lastShiftDateDayIndex > $firstDayIndexMinusOne, $lastDayIndex : lastShiftDateDayIndex)
    then
        insertLogical(new EmployeeFreeSequence($employee, $firstDayIndexMinusOne + 1, $lastDayIndex));
end
rule "insertEntireEmployeeFreeSequence"
        salience 1 // Do these rules first (optional, for performance)
    when
        $employee : Employee()
        // There are no working days after the last day
        not EmployeeConsecutiveAssignmentStart(
            employee == $employee
        )
        RosterInfo($firstDayIndex : firstShiftDateDayIndex, $lastDayIndex : lastShiftDateDayIndex)
    then
        insertLogical(new EmployeeFreeSequence($employee, $firstDayIndex, $lastDayIndex));
end

// Minimum number of consecutive free days
rule "minimumConsecutiveFreeDays"
    when
        $contractLine : MinMaxContractLine(
            contractLineType == ContractLineType.CONSECUTIVE_FREE_DAYS, minimumEnabled == true,
            $contract : contract, $minimumValue : minimumValue
        )
        $employee : Employee(contract == $contract)

        $employeeFreeSequence : EmployeeFreeSequence(
            employee == $employee,
            dayLength < $minimumValue,
            $dayLength : dayLength
        )
    then
        insertLogical(new IntConstraintOccurrence("minimumConsecutiveFreeDays", ConstraintType.NEGATIVE_SOFT,
                ($minimumValue - $dayLength) * $contractLine.getMinimumWeight(),
                $employeeFreeSequence));
end

// Maximum number of consecutive free days
rule "maximumConsecutiveFreeDays"
    when
        $contractLine : MinMaxContractLine(
            contractLineType == ContractLineType.CONSECUTIVE_FREE_DAYS, maximumEnabled == true,
            $contract : contract, $maximumValue : maximumValue
        )
        $employee : Employee(contract == $contract)

        $employeeFreeSequence : EmployeeFreeSequence(
            employee == $employee,
            dayLength > $maximumValue,
            $dayLength : dayLength
        )
    then
        insertLogical(new IntConstraintOccurrence("maximumConsecutiveFreeDays", ConstraintType.NEGATIVE_SOFT,
                ($dayLength - $maximumValue) * $contractLine.getMaximumWeight(),
                $employeeFreeSequence));
end


rule "insertEmployeeConsecutiveWeekendAssignmentStart"
        salience 2 // Do these rules first (optional, for performance)
    when
        ShiftAssignment(
            weekend == true,
            $employee : employee,
            $weekendSundayIndex : weekendSundayIndex
        )
        // The first working weekend has no working weekend before it
        not ShiftAssignment(
            weekend == true,
            employee == $employee,
            weekendSundayIndex == ($weekendSundayIndex - 7)
        )
    then
        insertLogical(new EmployeeConsecutiveWeekendAssignmentStart($employee, $weekendSundayIndex));
end
rule "insertEmployeeConsecutiveWeekendAssignmentEnd"
        salience 2 // Do these rules first (optional, for performance)
    when
        ShiftAssignment(
            weekend == true,
            $employee : employee,
            $weekendSundayIndex : weekendSundayIndex
        )
        // The last working weekend has no working weekend after it
        not ShiftAssignment(
            weekend == true,
            employee == $employee,
            weekendSundayIndex == ($weekendSundayIndex + 7)
        )
    then
        insertLogical(new EmployeeConsecutiveWeekendAssignmentEnd($employee, $weekendSundayIndex));
end

rule "insertEmployeeWeekendSequence"
    when
        EmployeeConsecutiveWeekendAssignmentStart(
            $employee : employee,
            $firstSundayIndex : sundayIndex
        )

        EmployeeConsecutiveWeekendAssignmentEnd(
            employee == $employee,
            sundayIndex >= $firstSundayIndex,
            $lastSundayIndex : sundayIndex
        )

        // There are no free weekends between the first and last weekend
        not EmployeeConsecutiveWeekendAssignmentEnd(
            employee == $employee,
            sundayIndex >= $firstSundayIndex && < $lastSundayIndex
        )
    then
        insertLogical(new EmployeeWeekendSequence($employee, $firstSundayIndex, $lastSundayIndex));
end

// Minimum number of consecutive working weekends
rule "minimumConsecutiveWorkingWeekends"
    when
        $contractLine : MinMaxContractLine(
            contractLineType == ContractLineType.CONSECUTIVE_WORKING_WEEKENDS, minimumEnabled == true,
            $contract : contract, $minimumValue : minimumValue
        )
        $employee : Employee(contract == $contract)

        $employeeWeekendSequence : EmployeeWeekendSequence(
            employee == $employee,
            weekendLength < $minimumValue,
            $weekendLength : weekendLength
        )
    then
        insertLogical(new IntConstraintOccurrence("minimumConsecutiveWorkingWeekends", ConstraintType.NEGATIVE_SOFT,
                ($minimumValue - $weekendLength) * $contractLine.getMinimumWeight(),
                $employeeWeekendSequence));
end

// Maximum number of consecutive working weekends
rule "maximumConsecutiveWorkingWeekends"
    when
        $contractLine : MinMaxContractLine(
            contractLineType == ContractLineType.CONSECUTIVE_WORKING_WEEKENDS, maximumEnabled == true,
            $contract : contract, $maximumValue : maximumValue
        )
        $employee : Employee(contract == $contract)

        $employeeWeekendSequence : EmployeeWeekendSequence(
            employee == $employee,
            weekendLength > $maximumValue,
            $weekendLength : weekendLength
        )
    then
        insertLogical(new IntConstraintOccurrence("maximumConsecutiveWorkingWeekends", ConstraintType.NEGATIVE_SOFT,
                ($weekendLength - $maximumValue) * $contractLine.getMaximumWeight(),
                $employeeWeekendSequence));
end


// Complete weekends
rule "startOnNotFirstDayOfWeekend"
    when
        $contractLine : BooleanContractLine(
            contractLineType == ContractLineType.COMPLETE_WEEKENDS, enabled == true,
            $contract : contract
        )
        $employeeConsecutiveAssignmentStart : EmployeeConsecutiveAssignmentStart(
            weekendAndNotFirstDayOfWeekend == true,
            contract == $contract,
            $distanceToFirstDayOfWeekend : distanceToFirstDayOfWeekend
        )
    then
        insertLogical(new IntConstraintOccurrence("startOnNotFirstDayOfWeekend", ConstraintType.NEGATIVE_SOFT,
                $distanceToFirstDayOfWeekend * $contractLine.getWeight(),
                $employeeConsecutiveAssignmentStart));
end
rule "endOnNotLastDayOfWeekend"
    when
        $contractLine : BooleanContractLine(
            contractLineType == ContractLineType.COMPLETE_WEEKENDS, enabled == true,
            $contract : contract
        )
        $employeeConsecutiveAssignmentEnd : EmployeeConsecutiveAssignmentEnd(
            weekendAndNotLastDayOfWeekend == true,
            contract == $contract,
            $distanceToLastDayOfWeekend : distanceToLastDayOfWeekend
        )
    then
        insertLogical(new IntConstraintOccurrence("endOnNotLastDayOfWeekend", ConstraintType.NEGATIVE_SOFT,
                $distanceToLastDayOfWeekend * $contractLine.getWeight(),
                $employeeConsecutiveAssignmentEnd));
end

// Identical shiftTypes during a weekend
rule "identicalShiftTypesDuringWeekend"
    when
        $contractLine : BooleanContractLine(contractLineType == ContractLineType.IDENTICAL_SHIFT_TYPES_DURING_WEEKEND,
            enabled == true, $contract : contract)
        $employee : Employee(contract == $contract, $weekendLength : weekendLength)
        ShiftDate(dayOfWeek == DayOfWeek.SUNDAY, $sundayIndex : dayIndex)
        $shiftType : ShiftType()
        $weekendAssignmentTotal : Number(intValue > 0 && < $weekendLength) from accumulate(
            $assignment : ShiftAssignment(
                weekend == true,
                weekendSundayIndex == $sundayIndex,
                employee == $employee,
                shiftType == $shiftType),
            count($assignment)
        )
    then
        insertLogical(new IntConstraintOccurrence("identicalShiftTypesDuringWeekend", ConstraintType.NEGATIVE_SOFT,
                ($weekendLength - $weekendAssignmentTotal.intValue()) * $contractLine.getWeight(),
                $employee, $sundayIndex, $shiftType));
end

// Two free days after a night shift
// TODO

// Requested day on/off
rule "dayOffRequest"
    when
        $dayOffRequest : DayOffRequest($employee : employee, $shiftDate : shiftDate, $weight : weight)
        $assignment : ShiftAssignment(employee == $employee, shiftDate == $shiftDate)
    then
        insertLogical(new IntConstraintOccurrence("dayOffRequest", ConstraintType.NEGATIVE_SOFT,
                $weight,
                $dayOffRequest, $assignment));
end
rule "dayOnRequest"
    when
        $dayOnRequest : DayOnRequest($employee : employee, $shiftDate : shiftDate, $weight : weight)
        not ShiftAssignment(employee == $employee, shiftDate == $shiftDate)
    then
        insertLogical(new IntConstraintOccurrence("dayOnRequest", ConstraintType.NEGATIVE_SOFT,
                $weight,
                $dayOnRequest));
end

// Requested shift on/off
rule "shiftOffRequest"
    when
        $shiftOffRequest : ShiftOffRequest($employee : employee, $shift : shift, $weight : weight)
        $assignment : ShiftAssignment(employee == $employee, shift == $shift)
    then
        insertLogical(new IntConstraintOccurrence("shiftOffRequest", ConstraintType.NEGATIVE_SOFT,
                $weight,
                $shiftOffRequest, $assignment));
end
rule "shiftOnRequest"
    when
        $shiftOnRequest : ShiftOnRequest($employee : employee, $shift : shift, $weight : weight)
        not ShiftAssignment(employee == $employee, shift == $shift)
    then
        insertLogical(new IntConstraintOccurrence("shiftOnRequest", ConstraintType.NEGATIVE_SOFT,
                $weight,
                $shiftOnRequest));
end

// Alternative skill
rule "alternativeSkill"
    when
        $contractLine : BooleanContractLine(contractLineType == ContractLineType.ALTERNATIVE_SKILL_CATEGORY,
            $contract : contract)
        $assignment : ShiftAssignment(contract == $contract, $employee : employee, $shiftType : shiftType)
        ShiftTypeSkillRequirement(shiftType == $shiftType, $skill : skill)
        not SkillProficiency(employee == $employee, skill == $skill)
    then
        insertLogical(new IntConstraintOccurrence("alternativeSkill", ConstraintType.NEGATIVE_SOFT,
                $contractLine.getWeight(),
                $assignment));
end

// Unwanted patterns
rule "unwantedPatternFreeBefore2DaysWithAWorkDayPattern"
    when
        $pattern : FreeBefore2DaysWithAWorkDayPattern(
            $freeDayOfWeek : freeDayOfWeek
        )
        PatternContractLine(
            pattern == $pattern, $contract : contract
        )
        ShiftDate(dayOfWeek == $freeDayOfWeek, $freeDayIndex : dayIndex)

        ShiftAssignment(
            contract == $contract,
            shiftDateDayIndex == ($freeDayIndex + 1) || shiftDateDayIndex == ($freeDayIndex + 2),
            $employee : employee
        )
        not ShiftAssignment(
            employee == $employee,
            shiftDateDayIndex == $freeDayIndex
        )
    then
        insertLogical(new IntConstraintOccurrence("unwantedPatternFreeBefore2DaysWithAWorkDayPattern",
                ConstraintType.NEGATIVE_SOFT,
                $pattern.getWeight(),
                $employee, $pattern, $freeDayIndex));
end
// TODO support WorkBeforeFreeSequencePattern too (not needed for competition)
//rule "unwantedPatternWorkBeforeFreeSequencePattern"
//    when
//        $pattern : WorkBeforeFreeSequencePattern(
//            $workDayOfWeek : workDayOfWeek,
//            $workShiftType : workShiftType,
//            $freeDayLength : freeDayLength
//        )
//        PatternContractLine(
//            pattern == $pattern, $contract : contract
//        )
//
//        ShiftAssignment(
//            eval($workDayOfWeek == null) || (shiftDateDayOfWeek == $workDayOfWeek),
//            eval($workShiftType == null) || (shiftType == $workShiftType),
//            contract == $contract,
//            $employee : employee, $workDayIndex : shiftDateDayIndex
//        )
//        EmployeeFreeSequence(
//            employee == $employee,
//            firstDayIndex == ($workDayIndex + 1),
//            dayLength >= $freeDayLength
//        )
//    then
//        insertLogical(new IntConstraintOccurrence("unwantedPatternWorkBeforeFreeSequencePattern",
//                ConstraintType.NEGATIVE_SOFT,
//                $pattern.getWeight(),
//                $employee, $pattern, $workDayIndex));
//end
rule "unwantedPatternShiftType2DaysPattern"
    when
        $pattern : ShiftType2DaysPattern(
            $dayIndex0ShiftType : dayIndex0ShiftType,
            $dayIndex1ShiftType : dayIndex1ShiftType
        )
        PatternContractLine(
            pattern == $pattern, $contract : contract
        )

        ShiftAssignment(
            shiftType == $dayIndex0ShiftType,
            contract == $contract,
            $employee : employee, $firstDayIndex : shiftDateDayIndex
        )
        ShiftAssignment(
            eval($dayIndex1ShiftType == null) || (shiftType == $dayIndex1ShiftType),
            employee == $employee,
            shiftDateDayIndex == ($firstDayIndex + 1)
        )
    then
        insertLogical(new IntConstraintOccurrence("unwantedPatternShiftType2DaysPattern", ConstraintType.NEGATIVE_SOFT,
                $pattern.getWeight(),
                $employee, $pattern, $firstDayIndex));
end
rule "unwantedPatternShiftType3DaysPattern"
    when
        $pattern : ShiftType3DaysPattern(
            $dayIndex0ShiftType : dayIndex0ShiftType,
            $dayIndex1ShiftType : dayIndex1ShiftType,
            $dayIndex2ShiftType : dayIndex2ShiftType
        )
        PatternContractLine(
            pattern == $pattern, $contract : contract
        )

        ShiftAssignment(
            shiftType == $dayIndex0ShiftType,
            contract == $contract,
            $employee : employee, $firstDayIndex : shiftDateDayIndex
        )
        ShiftAssignment(
            shiftType == $dayIndex1ShiftType,
            employee == $employee,
            shiftDateDayIndex == ($firstDayIndex + 1)
        )
        ShiftAssignment(
            shiftType == $dayIndex2ShiftType,
            employee == $employee,
            shiftDateDayIndex == ($firstDayIndex + 2)
        )
    then
        insertLogical(new IntConstraintOccurrence("unwantedPatternShiftType3DaysPattern", ConstraintType.NEGATIVE_SOFT,
                $pattern.getWeight(),
                $employee, $pattern, $firstDayIndex));
end

// ############################################################################
// Calculate score
// ############################################################################

// Accumulate hard constraints
rule "hardConstraintsBroken"
        salience -1 // Do the other rules first (optional, for performance)
    when
        $hardTotal : Number() from accumulate(
            IntConstraintOccurrence(constraintType == ConstraintType.NEGATIVE_HARD, $weight : weight),
            sum($weight) // Vote for http://jira.jboss.com/jira/browse/JBRULES-1075
        )
    then
        scoreCalculator.setHardConstraintsBroken($hardTotal.intValue());
end

// Accumulate soft constraints
rule "softConstraintsBroken"
        salience -1 // Do the other rules first (optional, for performance)
    when
        $softTotal : Number() from accumulate(
            IntConstraintOccurrence(constraintType == ConstraintType.NEGATIVE_SOFT, $weight : weight),
            sum($weight) // Vote for http://jira.jboss.com/jira/browse/JBRULES-1075
        )
    then
        scoreCalculator.setSoftConstraintsBroken($softTotal.intValue());
end




© 2015 - 2024 Weber Informatics LLC | Privacy Policy