Commit 42a53b83 by chamberone

feat: 集成算法约束条件

1 parent a75f8659
...@@ -14,10 +14,18 @@ public enum ConstraintNameEnum { ...@@ -14,10 +14,18 @@ public enum ConstraintNameEnum {
*/ */
skillMatch, skillMatch,
/** /**
* 技术员到达时间跟时间窗吻合 * 订单到达时间跟时间窗吻合
*/ */
customerTimeWindowsMatch, customerTimeWindowsMatch,
/** /**
* 技术员不加班
*/
technicianTimeWindowsMatch,
/**
* 技术员订单数量不超过最大值
*/
technicianCapacityMatch,
/**
* 已分配匹配 * 已分配匹配
*/ */
dispatchedMatch, dispatchedMatch,
......
...@@ -19,6 +19,8 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -19,6 +19,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
// 5s/60s: 技能权重4-技能匹配问题0个,时间窗问题14个 // 5s/60s: 技能权重4-技能匹配问题0个,时间窗问题14个
// 10s/300s: 技能权重4-技能匹配问题0个,时间窗问题9个 // 10s/300s: 技能权重4-技能匹配问题0个,时间窗问题9个
customerTimeWindowsMatch(factory), customerTimeWindowsMatch(factory),
technicianTimeWindowsMatch(factory),
technicianCapacityMatch(factory),
skillMatch(factory), skillMatch(factory),
dispatchedMatch(factory), dispatchedMatch(factory),
...@@ -50,6 +52,22 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -50,6 +52,22 @@ public class DispatchConstraintProvider implements ConstraintProvider {
.asConstraint(ConstraintNameEnum.customerTimeWindowsMatch.name()); .asConstraint(ConstraintNameEnum.customerTimeWindowsMatch.name());
} }
protected Constraint technicianTimeWindowsMatch(ConstraintFactory factory) {
return factory.forEach(Technician.class).filter(
// EndTime ==0 表示不起作用
technician -> technician.getEndTime() > 0 && technician.getOffWorkTime() > technician.getEndTime())
.penalizeLong(HardSoftLongScore.ONE_HARD, technician -> 1)
.asConstraint(ConstraintNameEnum.technicianTimeWindowsMatch.name());
}
protected Constraint technicianCapacityMatch(ConstraintFactory factory) {
return factory.forEach(Technician.class).filter(
// MaxCount ==0 表示不起作用
technician -> technician.getMaxCount() > 0 && technician.getCustomerSize() > technician.getMaxCount())
.penalizeLong(HardSoftLongScore.ONE_HARD, technician -> 1)
.asConstraint(ConstraintNameEnum.technicianCapacityMatch.name());
}
protected Constraint dispatchedMatch(ConstraintFactory factory) { protected Constraint dispatchedMatch(ConstraintFactory factory) {
return factory.forEach(Customer.class) return factory.forEach(Customer.class)
.filter(customer -> customer.getDispatchedTechnicianCode() != null .filter(customer -> customer.getDispatchedTechnicianCode() != null
...@@ -120,7 +138,7 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -120,7 +138,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
protected Constraint technicianBalanceSoft(ConstraintFactory factory) { protected Constraint technicianBalanceSoft(ConstraintFactory factory) {
return factory.forEachUniquePair(Technician.class).penalizeLong(HardSoftLongScore.ONE_SOFT, return factory.forEachUniquePair(Technician.class).penalizeLong(HardSoftLongScore.ONE_SOFT,
// 权重需要调节,差距一个相当于多一公里 FIXME 这里应该是时长均衡,不是订单量均衡 // 权重需要调节,差距一个相当于多一公里 FIXME 这里应该是时长均衡,不是订单量均衡
(a, b) -> Math.abs(a.getCustomerSize() - b.getCustomerSize()) * 1000) (a, b) -> Math.abs(a.getCustomerSize() - b.getCustomerSize()) * 4000)
.asConstraint(ConstraintNameEnum.technicianBalanceSoft.name()); .asConstraint(ConstraintNameEnum.technicianBalanceSoft.name());
} }
......
...@@ -14,6 +14,9 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L ...@@ -14,6 +14,9 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
@Query("from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' and (engineerCode is null or engineerCode='' ) ") @Query("from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' and (engineerCode is null or engineerCode='' ) ")
List<DispatchOrder> findNotAssigned(String groupId, String batchNo); List<DispatchOrder> findNotAssigned(String groupId, String batchNo);
// 查看未指派非confirm的,供算法计算
@Query("from DispatchOrder where groupId=?1 and batchNo=?2")
List<DispatchOrder> findAll(String groupId, String batchNo);
// 查看算法指派成功(也有抹掉技术员、时间情况),非confirm状态的 // 查看算法指派成功(也有抹掉技术员、时间情况),非confirm状态的
@Query("from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' ") @Query("from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' ")
......
...@@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.Query; ...@@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List;
import java.util.Optional; import java.util.Optional;
...@@ -13,5 +14,9 @@ public interface OrderInfoRepository extends CrudRepository<OrderInfo, Long> { ...@@ -13,5 +14,9 @@ public interface OrderInfoRepository extends CrudRepository<OrderInfo, Long> {
// @Query(value = "SELECT * FROM order_info WHERE order_id=:orderId ORDER BY dt DESC LIMIT 1",nativeQuery = true) // @Query(value = "SELECT * FROM order_info WHERE order_id=:orderId ORDER BY dt DESC LIMIT 1",nativeQuery = true)
Optional<OrderInfo> findOrderInfoByOrderIdAndDt(String orderId, LocalDate dt); Optional<OrderInfo> findOrderInfoByOrderIdAndDt(String orderId, LocalDate dt);
List<OrderInfo> findByOrderId(String orderId);
List<OrderInfo> findByOrgTeamIdAndDt(String teamId, LocalDate dt);
} }
...@@ -98,7 +98,9 @@ public class SolveServiceImpl implements SolveService { ...@@ -98,7 +98,9 @@ public class SolveServiceImpl implements SolveService {
// customerlist // customerlist
ArrayList<Customer> customerList = new ArrayList<>(); ArrayList<Customer> customerList = new ArrayList<>();
List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findNotAssigned(groupId, batchNo); // 已分配和未分配一起排班,因为已分配会影响整体排班结果
List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findAll(groupId, batchNo);
// List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findNotAssigned(groupId, batchNo);
log.info("组织问题对象, dispatchorder-list, groupId:{}, batchNo:{}, dispatchorder-size:{}", groupId, batchNo, dispatchOrderList.size()); log.info("组织问题对象, dispatchorder-list, groupId:{}, batchNo:{}, dispatchorder-size:{}", groupId, batchNo, dispatchOrderList.size());
......
...@@ -44,7 +44,31 @@ public class DataUtils { ...@@ -44,7 +44,31 @@ public class DataUtils {
Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap(); Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap();
DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, customerIndexXyMap, DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, customerIndexXyMap,
technicianIndexMap, technicianCodeSkillsMap, customerCodeSkillMap, technicianCodePreferredLocationMap, technicianIndexMap, technicianCodeSkillsMap, customerCodeSkillMap, technicianCodePreferredLocationMap,
preferredlocationDistanceMap, customerCodeServiceTimeMap); preferredlocationDistanceMap, customerCodeServiceTimeMap, false);
return problem;
}
/**
* 获取初始化测试数据
* fullDay 是否全天派工
* @return
* @throws UncheckedIOException
* @throws FileNotFoundException
*/
public static DispatchSolution getInitialProblem(boolean fullDay) throws UncheckedIOException, FileNotFoundException {
Map<Integer, String> customerIndexMap = loadCustomerIndex();
Map<Integer, String> customerIndexXyMap = loadCustomerIndexXY();
Map<Integer, String> technicianIndexMap = loadTechnicianIndex();
Map<String, Set<String>> technicianCodeSkillsMap = loadTechnicianCodeSkillsMap();
Map<String, String> customerCodeSkillMap = loadCustomerCodeSkillMap();
// 偏好中心点位置
Map<String, String> technicianCodePreferredLocationMap = loadPreferredlocationMap();
Map<String, Map<String, Long>> preferredlocationDistanceMap = loadPreferredlocationDistanceMap(
technicianCodePreferredLocationMap);
Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap();
DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, customerIndexXyMap,
technicianIndexMap, technicianCodeSkillsMap, customerCodeSkillMap, technicianCodePreferredLocationMap,
preferredlocationDistanceMap, customerCodeServiceTimeMap,fullDay);
return problem; return problem;
} }
...@@ -189,7 +213,7 @@ public class DataUtils { ...@@ -189,7 +213,7 @@ public class DataUtils {
Map<String, Set<String>> technicianCodeSkillsMap, Map<String, String> customerCodeSkillMap, Map<String, Set<String>> technicianCodeSkillsMap, Map<String, String> customerCodeSkillMap,
Map<String, String> technicianCodePreferredLocationMap, Map<String, String> technicianCodePreferredLocationMap,
Map<String, Map<String, Long>> preferredlocationDistanceMap, Map<String, Map<String, Long>> preferredlocationDistanceMap,
Map<String, Integer> customerCodeServiceTimeMap) throws UncheckedIOException, FileNotFoundException { Map<String, Integer> customerCodeServiceTimeMap, boolean fullDay) throws UncheckedIOException, FileNotFoundException {
DispatchSolution vehicleRoutingSolution = new DispatchSolution(); DispatchSolution vehicleRoutingSolution = new DispatchSolution();
// 翻转map // 翻转map
...@@ -290,7 +314,7 @@ public class DataUtils { ...@@ -290,7 +314,7 @@ public class DataUtils {
String[] temps = xyString.split(","); String[] temps = xyString.split(",");
Location preferredlocation = new Location(i + 1, Float.parseFloat(RegExUtils.removeAll(temps[0], "\"")), Location preferredlocation = new Location(i + 1, Float.parseFloat(RegExUtils.removeAll(temps[0], "\"")),
Float.parseFloat(RegExUtils.removeAll(temps[1], "\""))); Float.parseFloat(RegExUtils.removeAll(temps[1], "\"")));
technicianList.add(new Technician(i + 1, technicianIndexMap.get(i + 1), depot, 480, 1080, skills, technicianList.add(new Technician(i + 1, technicianIndexMap.get(i + 1), depot, 480, fullDay ? 1440 : 1080 , skills,
preferredlocationDistanceMap.get(technicianIndexMap.get(i + 1)), preferredlocation)); preferredlocationDistanceMap.get(technicianIndexMap.get(i + 1)), preferredlocation));
} }
......
...@@ -140,9 +140,11 @@ public class DispatchSolutionUtils { ...@@ -140,9 +140,11 @@ public class DispatchSolutionUtils {
// 技术员路线 // 技术员路线
String lines_ = "["; String lines_ = "[";
for (Technician technician : solution.getTechnicianList()) { for (Technician technician : solution.getTechnicianList()) {
lines_ += "\"" + technician.getCustomerList().stream() if (technician.getCustomerList().size() > 0) {
.map(c -> c.getLocation().getX() + "," + c.getLocation().getY()).reduce((a, b) -> a + ";" + b) lines_ += "\"" + technician.getCustomerList().stream()
.get() + "\","; .map(c -> c.getLocation().getX() + "," + c.getLocation().getY())
.reduce((a, b) -> a + ";" + b).get() + "\",";
}
} }
lines_ += "]"; lines_ += "]";
final String lines = lines_; final String lines = lines_;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!