Я не вижу корректного обновления назначений смены, хотя все остальные элементы (шаблоны) обновляются, включая запросы. Я работаю с 14-дневным списком смен для 12 сотрудников.11 должны работать 9 дней в две недели 1 должны работать 5 дней в две недели.(104 смены).Может ли кто-нибудь увидеть что-то явно не так с моим кодом и / или подходом.К вашему сведению, я испробовал все разные методы взвешивания.
Я реализовал решение с балансировкой нагрузки на примере тенниса.Это прекрасно работает для всех сотрудников, работающих полный рабочий день в 9 смен (108 смен).Все элементы обновляются правильно.Запрос, нежелательные шаблоны и т. Д. И продвигается хорошо.Сохранение всех шаблонов, запросов и требований к смене
private void advancePlanningWindowStart() {
logger.info("Advancing planningWindowStart.");
if (solutionBusiness.isSolving()) {
JOptionPane.showMessageDialog(this.getTopLevelAncestor(),
"The GUI does not support this action yet during solving.\nOptaPlanner itself does support it.\n"
+ "\nTerminate solving first and try again.",
"Unsupported in GUI", JOptionPane.INFORMATION_MESSAGE);
return;
}
doProblemFactChange(scoreDirector -> {
NurseRoster nurseRoster = scoreDirector.getWorkingSolution();
NurseRosterParametrization nurseRosterParametrization = nurseRoster
.getNurseRosterParametrization();
List<ShiftDate> shiftDateList = nurseRoster.getShiftDateList();
Shift oldLastShift = nurseRoster.getShiftList()
.get(nurseRoster.getShiftList().size() - 1);
long shiftId = oldLastShift.getId() + 1L;
int shiftIndex = oldLastShift.getIndex() + 1;
ShiftDate oldLastShiftDate = shiftDateList
.get(shiftDateList.size() - 1);
long shiftDateId = (oldLastShiftDate.getId() + 1L);
int shiftDayIndex = (oldLastShiftDate.getDayIndex() + 1);
scoreDirector
.beforeProblemPropertyChanged(nurseRosterParametrization);
// Update to get the first day along with adding 14 days to the run
LocalDate startDate = (oldLastShiftDate.getDate().plusDays(1));
LocalDate endDate = (oldLastShiftDate.getDate().plusDays(14));
int maxDayIndex = Math.toIntExact(DAYS.between(startDate, endDate));
int shiftDateSize = maxDayIndex + 1;
List<ShiftDate> newshiftdateList = new ArrayList<>(shiftDateSize);
shiftDateMap = new HashMap<>(shiftDateSize);
LocalDate date = startDate;
for (int i = 0; i < shiftDateSize; i++) {
ShiftDate shiftDate = new ShiftDate();
shiftDate.setId(shiftDateId);
shiftDate.setDayIndex(shiftDayIndex);
shiftDate.setDate(date);
shiftDate.setShiftList(new ArrayList<>());
shiftDateMap.put(date, shiftDate);
shiftDateId++;
shiftDayIndex++;
date = date.plusDays(1);
nurseRoster.getShiftDateList().add(shiftDate);
newshiftdateList.add(shiftDate);
scoreDirector.afterProblemFactAdded(shiftDate);
}
List<Skill> skillList;
List<Skill> skillElementList = (List<Skill>) nurseRoster
.getSkillList();
skillList = new ArrayList<>(skillElementList.size());
skillMap = new HashMap<>(skillElementList.size());
for (Skill element : skillElementList) {
Skill skill = new Skill();
long skillid = element.getId();
skill.setId(skillid);
skill.setCode(element.getCode());
Skill skillnew = scoreDirector.lookUpWorkingObject(skill);
skillList.add(skillnew);
if (skillMap.containsKey(skillnew.getCode())) {
throw new IllegalArgumentException(
"There are 2 skills with the same code ("
+ skill.getCode() + ").");
}
skillMap.put(skillnew.getCode(), skillnew);
}
List<Contract> contractElementList = (List<Contract>) nurseRoster
.getContractList();
List<Contract> contractList = new ArrayList<>(
contractElementList.size());
contractMap = new HashMap<>(contractElementList.size());
for (Contract element : contractElementList) {
Contract contract = new Contract();
long Id = element.getId();
contract.setId(Id);
contract.setCode(element.getCode());
contract.setDescription(element.getDescription());
WeekendDefinition weekend = element.getWeekendDefinition();
contract.setWeekendDefinition(weekend);
contract.setContractLineList(new ArrayList<ContractLine>());
Contract contractnew = scoreDirector
.lookUpWorkingObject(contract);
contractMap.put(contractnew.getCode(), contractnew);
contractList.add(contractnew);
}
List<Employee> employeeElementList = (List<Employee>) nurseRoster
.getEmployeeList();
Employee oldLastEmployee = nurseRoster.getEmployeeList()
.get(nurseRoster.getEmployeeList().size() - 1);
long empId = oldLastEmployee.getId() + 1L;
List<Employee> employeeList = new ArrayList<>(
employeeElementList.size());
employeeMap = new HashMap<>(employeeElementList.size());
for (Employee element : employeeElementList) {
Employee employee = new Employee();
String name = element.getName();
String code = element.getCode();
employee.setId(empId);
empId++;
Contract c = scoreDirector
.lookUpWorkingObject(element.getContract());
employee.setCode(code);
employee.setContract(c);
employee.setName(name);
employeeList.add(employee);
employeeMap.put(employee.getName(), employee);
scoreDirector.afterProblemFactAdded(employee);
}
List<ShiftTypeSkillRequirement> coverRequirementElementList = (List<ShiftTypeSkillRequirement>) nurseRoster
.getShiftTypeSkillRequirementList();
List<ShiftType> shiftTypeElementList = (List<ShiftType>) nurseRoster
.getShiftTypeList();
List<ShiftType> shiftTypeList = new ArrayList<>(
shiftTypeElementList.size());
shiftTypeMap = new HashMap<>(shiftTypeElementList.size());
int index = 0;
long shiftTypeSkillRequirementId = 0L;
List<ShiftTypeSkillRequirement> shiftTypeSkillRequirementList = new ArrayList<>(
shiftTypeElementList.size() * 2);
for (ShiftType shiftelement : shiftTypeElementList) {
ShiftType shiftType = new ShiftType();
long Id = shiftelement.getId();
shiftType.setId(Id);
shiftType.setCode(shiftelement.getCode());
shiftType.setIndex(index);
String startTimeString = shiftelement.getStartTimeString();
shiftType.setStartTimeString(startTimeString);
String endTimeString = shiftelement.getEndTimeString();
shiftType.setEndTimeString(endTimeString);
shiftType
.setNight(startTimeString.compareTo(endTimeString) > 0);
shiftType.setDescription(shiftelement.getDescription());
ShiftType shiftTypenew = scoreDirector
.lookUpWorkingObject(shiftType);
for (ShiftTypeSkillRequirement skillElement : coverRequirementElementList) {
ShiftTypeSkillRequirement shiftTypeSkillRequirement = new ShiftTypeSkillRequirement();
shiftTypeSkillRequirement
.setId(shiftTypeSkillRequirementId);
ShiftType shiftTypen = scoreDirector
.lookUpWorkingObject(shiftType);
shiftTypeSkillRequirement.setShiftType(shiftTypen);
Skill skill = skillMap
.get(skillElement.getSkill().getCode());
Skill skillnew = scoreDirector.lookUpWorkingObject(skill);
if (skillnew == null) {
throw new IllegalArgumentException("The skill ("
+ skillElement.getSkill().getCode()
+ ") of shiftType (" + shiftType.getCode()
+ ") does not exist.");
}
shiftTypeSkillRequirement.setSkill(skillnew);
shiftTypeSkillRequirementList
.add(shiftTypeSkillRequirement);
shiftTypeSkillRequirementId++;
}
shiftTypeList.add(shiftTypenew);
if (shiftTypeMap.containsKey(shiftTypenew.getCode())) {
throw new IllegalArgumentException(
"There are 2 shiftTypes with the same code ("
+ shiftTypenew.getCode() + ").");
}
shiftTypeMap.put(shiftTypenew.getCode(), shiftTypenew);
index++;
}
nurseRoster.setShiftTypeList(shiftTypeList);
nurseRoster.setShiftTypeSkillRequirementList(
shiftTypeSkillRequirementList);
int shiftListSize = shiftDateMap.size() * shiftTypeList.size();
List<Shift> shiftList1 = new ArrayList<>(shiftListSize);
dateAndShiftTypeToShiftMap = new HashMap<>(shiftListSize);
dayOfWeekAndShiftTypeToShiftListMap = new HashMap<>(
7 * shiftTypeList.size());
for (ShiftDate shiftDate : newshiftdateList) {
for (ShiftType shiftType : shiftTypeList) {
Shift shift = new Shift();
shift.setId(shiftId);
shift.setShiftDate(shiftDate);
shiftDate.getShiftList().add(shift);
ShiftType type = scoreDirector
.lookUpWorkingObject(shiftType);
shift.setShiftType(type);
shift.setIndex(shiftIndex);
shift.setRequiredEmployeeSize(0); // Filled in later
shiftList1.add(shift);
dateAndShiftTypeToShiftMap.put(
Pair.of(shiftDate.getDate(), type.getCode()),
shift);
addShiftToDayOfWeekAndShiftTypeToShiftListMap(shiftDate,
type, shift);
shiftId++;
shiftIndex++;
nurseRoster.getShiftList().add(shift);
scoreDirector.afterProblemFactAdded(shift);
}
}
List<DayOffRequest> dayOffRequestList;
List<DayOffDate> dayOffElementList = rosterService.listDayOffDate();
dayOffRequestList = new ArrayList<>(dayOffElementList.size());
long id = 0L;
for (DayOffDate element : dayOffElementList) {
DayOffRequest dayOffRequest = new DayOffRequest();
dayOffRequest.setId(id);
id++;
int weight = element.getWeight();
LocalDate shiftDate = element.getDate();
ShiftDate dateoff = shiftDateMap.get(shiftDate);
Employee employee = element.getEmployee();
Employee workingEmployee = scoreDirector
.lookUpWorkingObject(employee);
dayOffRequest.setWeight(weight);
dayOffRequest.setEmployee(workingEmployee);
dayOffRequest.setShiftDate(dateoff);
dayOffRequestList.add(dayOffRequest);
workingEmployee.getDayOffRequestMap().put(dateoff,
dayOffRequest);
nurseRoster.getDayOffRequestList().add(dayOffRequest);
}
List<DayOnRequest> dayOnRequestList;
List<DayOnDate> dayOnElementList1 = rosterService.listDayOnDate();
long onid = 0L;
dayOnRequestList = new ArrayList<>(dayOnElementList1.size());
for (DayOnDate element : dayOnElementList1) {
DayOnRequest dayOnRequest = new DayOnRequest();
int weight = element.getWeight();
LocalDate localshiftDate = element.getDate();
ShiftDate dateon = shiftDateMap.get(localshiftDate);
Employee employee = element.getEmployee();
Employee workingEmployee = scoreDirector
.lookUpWorkingObject(employee);
dayOnRequest.setId(onid);
onid++;
dayOnRequest.setWeight(weight);
dayOnRequest.setEmployee(workingEmployee);
dayOnRequest.setShiftDate(dateon);
dayOnRequestList.add(dayOnRequest);
workingEmployee.getDayOnRequestMap().put(dateon, dayOnRequest);
nurseRoster.getDayOnRequestList().add(dayOnRequest);
}
List<ShiftOffRequest> shiftOffRequestList;
List<ShiftOffDate> shiftOffElementList = (List<ShiftOffDate>) rosterService
.listShiftOffDate();
shiftOffRequestList = new ArrayList<>(shiftOffElementList.size());
for (ShiftOffDate element : shiftOffElementList) {
ShiftOffRequest shiftOffRequest = new ShiftOffRequest();
long ShiftonId = element.getId();
int weight = element.getWeight();
Employee employee = element.getEmployee();
Employee workingEmployee = scoreDirector
.lookUpWorkingObject(employee);
LocalDate date1 = element.getDate();
String shiftcode = element.getShiftType().getCode();
Shift shift = dateAndShiftTypeToShiftMap
.get(Pair.of(date1, shiftcode));
shiftOffRequest.setId(ShiftonId);
shiftOffRequest.setEmployee(workingEmployee);
shiftOffRequest.setShift(shift);
shiftOffRequest.setWeight(weight);
shiftOffRequestList.add(shiftOffRequest);
workingEmployee.getShiftOffRequestMap().put(shift,
shiftOffRequest);
nurseRoster.setShiftOffRequestList(shiftOffRequestList);
}
List<ShiftOnRequest> shiftOnRequestList;
List<ShiftOnDate> shiftOnElementList = (List<ShiftOnDate>) rosterService
.listShiftOnDate();
shiftOnRequestList = new ArrayList<>(shiftOnElementList.size());
for (ShiftOnDate element : shiftOnElementList) {
ShiftOnRequest shiftOnRequest = new ShiftOnRequest();
long ShiftonId = element.getId();
int weight = element.getWeight();
Employee employee = element.getEmployee();
Employee workingEmployee = scoreDirector
.lookUpWorkingObject(employee);
LocalDate date1 = element.getDate();
String shiftcode = element.getShiftType().getCode();
Shift shift = dateAndShiftTypeToShiftMap
.get(Pair.of(date1, shiftcode));
shiftOnRequest.setId(ShiftonId);
shiftOnRequest.setEmployee(workingEmployee);
shiftOnRequest.setShift(shift);
shiftOnRequest.setWeight(weight);
shiftOnRequestList.add(shiftOnRequest);
workingEmployee.getShiftOnRequestMap().put(shift,
shiftOnRequest);
nurseRoster.setShiftOnRequestList(shiftOnRequestList);
}
List<CoverRequirements> coverRequirementElementList1 = (List<CoverRequirements>) rosterService
.listCoverRequirements();
for (CoverRequirements element : coverRequirementElementList1) {
String type = element.getShiftType().getCode();
ShiftType shiftTypen = shiftTypeMap.get(type);
DayOfWeek day = element.getDayOfWeek();
int req = element.getRequiredEmployeesize();
Pair<DayOfWeek, ShiftType> key = Pair.of(day, shiftTypen);
List<Shift> shiftList = dayOfWeekAndShiftTypeToShiftListMap
.get(key);
for (Shift shift : shiftList) {
shift.setRequiredEmployeeSize(
shift.getRequiredEmployeeSize() + req);
}
}
List<ShiftAssignment> shiftAssignmentList = new ArrayList<>(
shiftList1.size());
long shiftAssignmentId = nurseRoster.getShiftAssignmentList()
.get(nurseRoster.getShiftAssignmentList().size() - 1)
.getId() + 1L;
for (Shift shift : shiftList1) {
for (int i = 0; i < shift.getRequiredEmployeeSize(); i++) {
ShiftAssignment newShiftAssignment = new ShiftAssignment();
newShiftAssignment.setId(shiftAssignmentId);
shiftAssignmentId++;
newShiftAssignment.setShift(shift);
newShiftAssignment.setIndexInShift(i);
shiftAssignmentList.add(newShiftAssignment);
nurseRoster.getShiftAssignmentList()
.add(newShiftAssignment);
scoreDirector.afterEntityAdded(newShiftAssignment);
}
}
// This should move the planning window
nurseRosterParametrization
.setFirstShiftDate(newshiftdateList.get(0));
nurseRosterParametrization.setLastShiftDate(
newshiftdateList.get(newshiftdateList.size() - 1));
nurseRosterParametrization
.setPlanningWindowStart(newshiftdateList.get(0));
nurseRoster
.setNurseRosterParametrization(nurseRosterParametrization);
scoreDirector
.afterProblemPropertyChanged(nurseRosterParametrization);
// scoreDirector.triggerVariableListeners();
}, true);
}
private void addShiftToDayOfWeekAndShiftTypeToShiftListMap(ShiftDate shiftDate, ShiftType shiftType, Shift shift) {
Pair<DayOfWeek, ShiftType> key = Pair.of(shiftDate.getDayOfWeek(), shiftType);
List<Shift> dayOfWeekAndShiftTypeToShiftList = dayOfWeekAndShiftTypeToShiftListMap.computeIfAbsent(key,
k -> new ArrayList<>((shiftDateMap.size() + 6) / 7));
dayOfWeekAndShiftTypeToShiftList.add(shift);
}
Ниже приведен небольшой отладочный фрагмент с полным подтверждением, показывающий отсутствие ошибок: шаг (122), затраченное время (102920), счет (0hard / 1342soft), новый лучший результат(0hard / 1342soft), количество принятых / выбранных ходов (800/884), выбранный ход (2019-07-20 / E {Reece Bamford} <-> 2019-07-20 / D {David Hemmings}).17: 53: 37.746 [l-3-thread-2] DEBUG LS шаг (123), потраченное время (103652), оценка (0hard / 1342soft), лучший результат (0hard / 1342soft), количество принятых / выбранных ходов (800 /874), выбранный ход ([[2019-07-23 / D, 2019-07-24 / E, 2019-07-25 / E] {? -> Алана Джилл}, [2019-07-23 / E, 2019-07-24 / E, 2019-07-25 / E, 2019-07-26 / E, 2019-07-27 / D, 2019-07-28 / E] {? -> Дэвид Хеммингс}]).17: 53: 38.513 [l-3-thread-2] DEBUG LS шаг (124), потраченное время (104419), оценка (0hard / 1342soft), лучший результат (0hard / 1342soft), количество принятых / выбранных ходов (800 /887), выбранный ход ([[2019-07-15 / N] {? -> Софи Дривс}, [2019-07-15 / N] {? -> Рис Бэмфорд}]).17: 53: 39.337 [l-3-thread-2] DEBUG LS шаг (125), затраченное время (105243), оценка (0hard / 1342soft), лучший результат (0hard / 1342soft), количество принятых / выбранных ходов (800 /925), выбранный ход (2019-07-22 / E {Энтони Фан} <-> 2019-07-22 / D {Майкл С}).17: 53: 40.121 [l-3-thread-2] DEBUG LS шаг (126), затраченное время (106027), оценка (0hard / 1342soft), лучший результат (0hard / 1342soft), количество принятых / выбранных ходов (800 /943), выбранный ход (2019-07-15 / L {Дэвид Хеммингс -> Клейтон Флетчер}).17: 53: 40.972 [l-3-thread-2] DEBUG LS шаг (127), затраченное время (106878), оценка (0hard / 1342soft), лучший результат (0hard / 1342soft), количество принятых / выбранных ходов (800 /932), выбранный ход (2019-07-22 / E {Sophie Dreves} <-> 2019-07-22 / L {Karen Ahrens}).17: 53: 41.815 [l-3-thread-2] DEBUG LS шаг (128), потраченное время (107721), оценка (0hard / 1342soft), лучший результат (0hard / 1342soft), количество принятых / выбранных ходов (800 /932), выбранный ход ([[2019-07-21 / E, 2019-07-22 / E, 2019-07-23 / D, 2019-07-24 / L, 2019-07-25 / D, 2019-07-26 / E] {? -> Michael C}, [2019-07-21 / D, 2019-07-22 / E, 2019-07-23 / E, 2019-07-24 / L, 2019-07-25 / L, 2019-07-26 / N] {? -> Карен Аренс}]).17: 53: 42.635 [l-3-thread-2] DEBUG LS шаг (129), потраченное время (108541), оценка (0hard / 1342soft), лучший результат (0hard / 1342soft), количество принятых / выбранных ходов (800 /950), выбранный ход ([[2019-07-19 / D, 2019-07-20 / E, 2019-07-21 / L] {? -> Джемма Невин}, [2019-07-19 / D, 2019-07-20 / L] {? -> Дэвид Хеммингс}]).17: 53: 43.481 [l-3-thread-2] DEBUG LS шаг (130), затраченное время (109387), счет (0hard / 1343soft), новый лучший результат (0hard / 1343soft), количество принятых / выбранных ходов (800/ 950), выбранный ход ([[2019-07-15 / D, 2019-07-16 / E, 2019-07-17 / E, 2019-07-18 / E, 2019-07-19 / E] {? -> Дэвид Хеммингс}, [2019-07-16 / N] {? -> Изабелла}, [2019-07-19 / D, 2019-07-20 / L] {? -> Изабелла}]).17: 53: 44.290 [l-3-thread-2] DEBUG LS шаг (131), потраченное время (110196), оценка (0hard / 1343soft), лучший результат (0hard / 1343soft), количество принятых / выбранных ходов (800 /944), выбранный ход (2019-07-28 / E {Дэвид Хеммингс} <-> 2019-07-28 / L {Энтони Фан}).17: 53: 45.053 [l-3-thread-2] DEBUG LS шаг (132), потраченное время (110959), оценка (0hard / 1343soft), лучший результат (0hard / 1343soft), количество принятых / выбранных ходов (800 /919), выбранный ход ([[2019-07-15 / L, 2019-07-16 / L, 2019-07-17 / N] {? -> Lisa Coull}, [2019-07-15 / L, 2019-07-16 / L, 2019-07-17 / N] {? -> Clayton Fletcher}]).17: 53: 45.857 [l-3-thread-2] DEBUG LS шаг (133), затраченное время (111763), счет (0hard / 1343soft), лучший результат (0hard / 1343soft), количество принятых / выбранных ходов (800 /936), выбранный ход (2019-07-19 / N {Энтони Фан} <-> 2019-07-19 / N {Софи Дривс}).17: 53: 46.638 [l-3-thread-2] DEBUG LS шаг (134), затраченное время (112544), счет (0hard / 1343soft), лучший результат (0hard / 1343soft), количество принятых / выбранных ходов (800 /952), выбранный ход (2019-07-23 / E {David Hemmings} <-> 2019-07-23 / D {Alana Gill}).17: 53: 47.437 [l-3-thread-2] DEBUG LS шаг (135), потраченное время (113343), оценка (0hard / 1343soft), лучший результат (0hard / 1343soft), количество принятых / выбранных ходов (800 /926), выбранный ход ([[2019-07-15 / N] {? -> Софи Дривс}, [2019-07-15 / N] {? -> Рис Бэмфорд}]).17: 53: 48.253 [l-3-thread-2] DEBUG LS шаг (136), затраченное время (114159), оценка (0hard / 1343soft), лучший результат (0hard / 1343soft), количество принятых / выбранных ходов (800 /963), выбранный ход ([[2019-07-27 / E, 2019-07-28 / E] {? -> Изабелла}, [2019-07-27 / N, 2019-07-28 / N] {?-> Софи Древес}]).17: 53: 49.035 [l-3-thread-2] DEBUG LS шаг (137), затраченное время (114941), счет (0hard / 1343soft), лучший результат (0hard / 1343soft), количество принятых / выбранных ходов (800 /964), выбранный ход (2019-07-17 / N {Lisa Coull} <-> 2019-07-17 / N {Клейтон Флетчер}).