package com.chinaztt.mes.aps.core.solver; import cn.hutool.core.collection.CollUtil; import com.chinaztt.mes.aps.core.domain.Task; import com.chinaztt.mes.aps.core.helper.ApsConstraintHelper; import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; import org.optaplanner.core.api.score.stream.Constraint; import org.optaplanner.core.api.score.stream.ConstraintFactory; import org.optaplanner.core.api.score.stream.ConstraintProvider; import java.time.Duration; /** * @Author: zhangxy * @Date: 2020-10-20 10:26 */ public class ApsConstraintProvider implements ConstraintProvider { @Override public Constraint[] defineConstraints(ConstraintFactory constraintFactory) { return new Constraint[]{ capabilityConflict(constraintFactory), timeOverlapConflict(constraintFactory), delayConflict(constraintFactory), firstDelayConflict(constraintFactory), }; } /** * 第一道工序开工越快越好 * * @param constraintFactory * @return */ private Constraint firstDelayConflict(ConstraintFactory constraintFactory) { return constraintFactory.from(Task.class) .filter(t -> { if (t.getPredecessorOfRouting() == null && t.getResourceBo() != null) { if (t.getPlanStartTime().compareTo(t.getResourceBo().getPlanEndTime()) > 0) { return true; } } return false; }) .penalize("Start delay conflict", HardSoftScore.ONE_SOFT, (t) -> { Duration duration = Duration.between(t.getResourceBo().getPlanEndTime(), t.getPlanStartTime()); return (int) duration.toMinutes(); } ); } /** * 工序间尽量减少等待时间 * * @param constraintFactory * @return */ private Constraint delayConflict(ConstraintFactory constraintFactory) { return constraintFactory.from(Task.class) .filter(t -> { if (t.getPredecessorOfRouting() != null && t.getPlanStartTime() != null) { if ((t.getPlanStartTime().compareTo(t.getPredecessorOfRouting().getPlanEndTime())) > 0) { return true; } } return false; }) .penalize("Delay conflict", HardSoftScore.ONE_SOFT, (t) -> { Duration duration = Duration.between(t.getPredecessorOfRouting().getPlanEndTime(), t.getPlanStartTime()); return (int) duration.toMinutes(); }); } /** * 工序、资源能力必须匹配 * * @param constraintFactory * @return */ private Constraint capabilityConflict(ConstraintFactory constraintFactory) { return constraintFactory.from(Task.class) .filter(t -> { if (t.getResourceBo() == null) { return false; } if (CollUtil.isEmpty(t.getResourceBo().getCapabilityIds())) { return true; } else { return !t.getResourceBo().getCapabilityIds().containsAll(t.getCapabilityIds()); } }) .penalize("Capability conflict", HardSoftScore.ofHard(10)); } /** * 任务不能重合 * * @param constraintFactory * @return */ private Constraint timeOverlapConflict(ConstraintFactory constraintFactory) { return constraintFactory.from(Task.class) .join(Task.class) .filter((t1, t2) -> ApsConstraintHelper.taskOverlap(t1, t2)) .penalize("Time conflict", HardSoftScore.ONE_HARD); } }