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);
|
}
|
|
|
}
|