Commit b890dd07 by chamberone

feat: 算法过滤不满足硬约束数据

1 parent a94dc1ad
......@@ -10,6 +10,8 @@ import com.dituhui.pea.dispatch.pojo.Technician;
import com.dituhui.pea.dispatch.service.BatchService;
import com.dituhui.pea.dispatch.service.ExtractService;
import com.dituhui.pea.dispatch.service.SolveService;
import com.dituhui.pea.dispatch.utils.DispatchSolutionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore;
......@@ -45,8 +47,8 @@ public class PrepareController {
private SolverManager<DispatchSolution, UUID> solverManager;
private Solver<DispatchSolution> solver;
private SolverFactory<DispatchSolution> solverFactory;
public PrepareController() {
......@@ -55,7 +57,7 @@ public class PrepareController {
solverConfig.withConstraintProviderClass(DispatchConstraintProvider.class);
solverConfig.withTerminationSpentLimit(Duration.ofSeconds(60 * 5));
SolverFactory<DispatchSolution> solverFactory = SolverFactory.create(solverConfig);
solverFactory = SolverFactory.create(solverConfig);
solver = solverFactory.buildSolver();
solverManager = SolverManager.create(solverConfig, new SolverManagerConfig());
}
......@@ -99,6 +101,7 @@ public class PrepareController {
}
DispatchSolution solution = solver.solve(problem);
DispatchSolutionUtils.removeHardConstraintCustomer(solution, solverFactory);
solveService.saveSolutionWrp(solution);
extractService.extractDispatchToOrder(groupId, batchNo, false);
......
......@@ -226,7 +226,7 @@ public class DataUtils {
String[] temps = line.split(",");
for (int j = 0; j < temps.length; j++) {
// 秒转分钟
pathTimeMatrix[i][j] = (long) (Math.round(Float.parseFloat(temps[j]) / 60));
pathTimeMatrix[i][j] = (long) (Math.round(Float.parseFloat(temps[j]) ));
}
}
for (int i = 0; i < pathTimeMatrix.length; i++) {
......
......@@ -8,6 +8,7 @@ import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
......@@ -79,20 +80,41 @@ public class DispatchSolutionUtils {
endPath = startPath + previousCustomer.getLocation().getPathTimeTo(customer.getLocation());
}
System.out.printf(" 预约单%s(%s) 预约时间窗[%s=>%s] 路上时间[%s=>%s] 早到等待时间[%s=>%s] 派工时间[%s=>%s] 迟到时间[%s=>%s]%n",
customer.getId(), customer.getCode(),
// 预约时间窗
printTime(customer.getStartTime()), printTime(customer.getEndTime()),
// 路上时间
printTime(startPath), printTime(endPath),
// 早到等待时间
customer.getArrivalTime() < customer.getStartTime() ? printTime(endPath) : "",
customer.getArrivalTime() < customer.getStartTime() ? printTime(customer.getStartTime()) : "",
// 派工时间
printTime(customer.getArrivalTime()), printTime(customer.getDepartureTime()),
// 迟到时间
customer.getArrivalTime() > customer.getEndTime() ? printTime(customer.getEndTime()) : "",
customer.getArrivalTime() > customer.getEndTime() ? printTime(customer.getArrivalTime()) : "");
if (customer.getArrivalTime() > customer.getEndTime()) {
// 迟到
System.err.printf(
" 预约单%s(%s) 预约时间窗[%s=>%s] 路上时间[%s=>%s] 早到等待时间[%s=>%s] 派工时间[%s=>%s] 迟到时间[%s=>%s]%n",
customer.getId(), customer.getCode(),
// 预约时间窗
printTime(customer.getStartTime()), printTime(customer.getEndTime()),
// 路上时间
printTime(startPath), printTime(endPath),
// 早到等待时间
customer.getArrivalTime() < customer.getStartTime() ? printTime(endPath) : "",
customer.getArrivalTime() < customer.getStartTime() ? printTime(customer.getStartTime())
: "",
// 派工时间
printTime(customer.getArrivalTime()), printTime(customer.getDepartureTime()),
// 迟到时间
printTime(customer.getEndTime()), printTime(customer.getArrivalTime()));
} else {
System.out.printf(
" 预约单%s(%s) 预约时间窗[%s=>%s] 路上时间[%s=>%s] 早到等待时间[%s=>%s] 派工时间[%s=>%s] 迟到时间[%s=>%s]%n",
customer.getId(), customer.getCode(),
// 预约时间窗
printTime(customer.getStartTime()), printTime(customer.getEndTime()),
// 路上时间
printTime(startPath), printTime(endPath),
// 早到等待时间
customer.getArrivalTime() < customer.getStartTime() ? printTime(endPath) : "",
customer.getArrivalTime() < customer.getStartTime() ? printTime(customer.getStartTime())
: "",
// 派工时间
printTime(customer.getArrivalTime()), printTime(customer.getDepartureTime()),
// 迟到时间
"", "");
}
}
});
}
......@@ -241,9 +263,9 @@ public class DispatchSolutionUtils {
* 打印详细约束得分
*
* @param solution
* @param solverFactory
*/
public static void explainSolutionConstraintDetail(DispatchSolution solution) {
DefaultSolverFactory<DispatchSolution> solverFactory = getSolverFactory();
public static void explainSolutionConstraintDetail(DispatchSolution solution, DefaultSolverFactory<DispatchSolution> solverFactory) {
// Obtain a ScoreExplanation object for the best solution
// Using score calculation outside the Solver
// https://www.optaplanner.org/docs/optaplanner/latest/score-calculation/score-calculation.html
......@@ -322,4 +344,107 @@ public class DispatchSolutionUtils {
exporter.write(solution, new File(fileName));
}
/**
* 移除hard约束元素订单
*
* @param solution
* @param solverFactory
*/
public static void removeHardConstraintCustomer(DispatchSolution solution,
SolverFactory<DispatchSolution> solverFactory) {
SolutionManager<DispatchSolution, HardSoftLongScore> scoreManager = SolutionManager.create(solverFactory);
ScoreExplanation<DispatchSolution, HardSoftLongScore> scoreExplanation = scoreManager.explain(solution);
Map<String, ConstraintMatchTotal<HardSoftLongScore>> constraintMatchTotalMap = scoreExplanation
.getConstraintMatchTotalMap();
constraintMatchTotalMap.forEach((key, value) -> {
if (!value.getScore().isFeasible()) {
// 违反硬约束
System.err.printf("%s 匹配%s次 hard得分:%s%n", value.getConstraintName(), value.getConstraintMatchCount(),
value.getScore().hardScore());
value.getConstraintMatchSet().stream().sorted(comparing(ConstraintMatch::getScore))
.forEach(constraintMatch -> {
String text = "";
switch (ConstraintNameEnum.valueOf(value.getConstraintName())) {
case skillMatch:
case customerTimeWindowsMatch:
for (Object indictedObject : constraintMatch.getIndictedObjectList()) {
// 违反硬约束对象,根据具体约束返回不同类型对象
if (indictedObject instanceof Customer) {
Customer customer = (Customer) indictedObject;
text += customer.getCode() + ",";
// 更新shadow变量
updateShadowVariable(customer);
// 移除技术员
customer.getTechnician().getCustomerList().remove(customer);
}
}
System.out.printf(" 预约单(%s)违反约束,扣分%s%n", text,
constraintMatch.getScore().toShortString());
break;
default:
break;
}
});
}
});
}
private static void updateShadowVariable(Customer sourceCustomer) {
if (sourceCustomer.getTechnician() == null) {
if (sourceCustomer.getArrivalTime() != null) {
sourceCustomer.setArrivalTime(null);
}
return;
}
// 移除当前订单引用
Customer previousCustomer = sourceCustomer.getPreviousCustomer();
Customer nextCustomer = sourceCustomer.getNextCustomer();
if (previousCustomer == null) {
// 当前订单是第一个订单
if(null != nextCustomer) {
nextCustomer.setPreviousCustomer(null);
}
}
if (nextCustomer == null) {
// 当前订单是最后一个订单
if(null != previousCustomer) {
previousCustomer.setNextCustomer(null);
}
}
if (previousCustomer != null && null != nextCustomer) {
previousCustomer.setNextCustomer(nextCustomer);
nextCustomer.setPreviousCustomer(previousCustomer);
}
// 前一个的离开时间
Integer departureTime;
if (previousCustomer == null) {
departureTime = (sourceCustomer.getTechnician().getDepot()).getStartTime();
} else {
departureTime = previousCustomer.getDepartureTime();
}
if (nextCustomer != null) {
// 更新后续订单
Customer shadowCustomer = nextCustomer;
Integer arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
while (shadowCustomer != null && !Objects.equals(shadowCustomer.getArrivalTime(), arrivalTime)) {
shadowCustomer.setArrivalTime(arrivalTime);
departureTime = shadowCustomer.getDepartureTime();
shadowCustomer = shadowCustomer.getNextCustomer();
arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
}
}
}
private static Integer calculateArrivalTime(Customer customer, Integer previousDepartureTime) {
if (customer == null || previousDepartureTime == null) {
return null;
}
return previousDepartureTime + customer.getPathTimeFromPreviousStandstill();
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!