org.drools.planner.examples.pas.persistence.PatientAdmissionScheduleSolutionImporter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of drools-planner-examples Show documentation
Show all versions of drools-planner-examples Show documentation
Drools Planner optimizes automated planning by combining metaheuristic search algorithms with rule
engine powered score calculation. This is the drools-planner-examples module which contains examples on how to use
Drools Planner.
/*
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.planner.examples.pas.persistence;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Collections;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.drools.planner.core.solution.Solution;
import org.drools.planner.examples.common.domain.PersistableIdComparator;
import org.drools.planner.examples.common.persistence.AbstractTxtSolutionImporter;
import org.drools.planner.examples.pas.domain.AdmissionPart;
import org.drools.planner.examples.pas.domain.Bed;
import org.drools.planner.examples.pas.domain.BedDesignation;
import org.drools.planner.examples.pas.domain.Department;
import org.drools.planner.examples.pas.domain.DepartmentSpecialism;
import org.drools.planner.examples.pas.domain.Equipment;
import org.drools.planner.examples.pas.domain.Gender;
import org.drools.planner.examples.pas.domain.GenderLimitation;
import org.drools.planner.examples.pas.domain.Night;
import org.drools.planner.examples.pas.domain.Patient;
import org.drools.planner.examples.pas.domain.PatientAdmissionSchedule;
import org.drools.planner.examples.pas.domain.PreferredPatientEquipment;
import org.drools.planner.examples.pas.domain.RequiredPatientEquipment;
import org.drools.planner.examples.pas.domain.Room;
import org.drools.planner.examples.pas.domain.RoomEquipment;
import org.drools.planner.examples.pas.domain.RoomSpecialism;
import org.drools.planner.examples.pas.domain.Specialism;
public class PatientAdmissionScheduleSolutionImporter extends AbstractTxtSolutionImporter {
public static void main(String[] args) {
new PatientAdmissionScheduleSolutionImporter().convertAll();
}
public PatientAdmissionScheduleSolutionImporter() {
super(new PatientAdmissionScheduleDaoImpl());
}
public TxtInputBuilder createTxtInputBuilder() {
return new PatientAdmissionScheduleInputBuilder();
}
public class PatientAdmissionScheduleInputBuilder extends TxtInputBuilder {
private PatientAdmissionSchedule patientAdmissionSchedule;
private int specialismListSize;
private int departmentListSize;
private int equipmentListSize;
private int roomListSize;
private int bedListSize;
private int nightListSize;
private int patientListSize;
private Map idToSpecialismMap = null;
private Map idToDepartmentMap = null;
private Map indexToEquipmentMap = null;
private Map idToRoomMap = null;
private Map indexToNightMap = null;
public Solution readSolution() throws IOException {
patientAdmissionSchedule = new PatientAdmissionSchedule();
patientAdmissionSchedule.setId(0L);
readSizes();
readEmptyLine();
readEmptyLine();
readSpecialismList();
readEmptyLine();
readDepartmentListAndDepartmentSpecialismList();
readEmptyLine();
readEquipmentList();
readEmptyLine();
readRoomListAndRoomSpecialismListAndRoomEquipmentList();
readEmptyLine();
readBedList();
readEmptyLine();
generateNightList();
readPatientListAndAdmissionPartListAndRequiredPatientEquipmentListAndPreferredPatientEquipmentList();
readEmptyLine();
readConstantLine("END.");
createBedDesignationList();
// TODO not all nights are planned, only the "planning horizon" nights are planned
logger.info("PatientAdmissionSchedule with {} specialisms, {} equipments, {} departments, {} rooms, "
+ "{} beds, {} nights, {} patients and {} admissions.",
new Object[]{patientAdmissionSchedule.getSpecialismList().size(),
patientAdmissionSchedule.getEquipmentList().size(),
patientAdmissionSchedule.getDepartmentList().size(),
patientAdmissionSchedule.getRoomList().size(),
patientAdmissionSchedule.getBedList().size(),
patientAdmissionSchedule.getNightList().size(),
patientAdmissionSchedule.getPatientList().size(),
patientAdmissionSchedule.getAdmissionPartList().size()});
BigInteger possibleSolutionSize = BigInteger.valueOf(patientAdmissionSchedule.getBedList().size()).pow(
patientAdmissionSchedule.getAdmissionPartList().size());
String flooredPossibleSolutionSize = "10^" + (possibleSolutionSize.toString().length() - 1);
logger.info("PatientAdmissionSchedule with flooredPossibleSolutionSize ({}) and possibleSolutionSize ({}).",
flooredPossibleSolutionSize, possibleSolutionSize);
return patientAdmissionSchedule;
}
private void readSizes() throws IOException {
readConstantLine("ARTICLE BENCHMARK DATA SET");
roomListSize = readIntegerValue("Rooms:");
equipmentListSize = readIntegerValue("Roomproperties:");
bedListSize = readIntegerValue("Beds:");
departmentListSize = readIntegerValue("Departments:");
specialismListSize = readIntegerValue("Specialisms:");
patientListSize = readIntegerValue("Patients:");
nightListSize = readIntegerValue("Planning horizon:");
}
private void readSpecialismList() throws IOException {
readConstantLine("SPECIALISMS:");
List specialismList = new ArrayList(specialismListSize);
idToSpecialismMap = new HashMap(specialismListSize);
for (int i = 0; i < specialismListSize; i++) {
String line = bufferedReader.readLine();
String[] lineTokens = splitBySpace(line, 2);
Specialism specialism = new Specialism();
specialism.setId(Long.parseLong(lineTokens[0]));
specialism.setName(lineTokens[1]);
specialismList.add(specialism);
idToSpecialismMap.put(specialism.getId(), specialism);
}
patientAdmissionSchedule.setSpecialismList(specialismList);
}
private void readDepartmentListAndDepartmentSpecialismList() throws IOException {
readConstantLine("DEPARTMENTS:");
List departmentList = new ArrayList(departmentListSize);
idToDepartmentMap = new HashMap(departmentListSize);
List departmentSpecialismList = new ArrayList(
departmentListSize * 5);
long departmentSpecialismId = 0L;
for (int i = 0; i < departmentListSize; i++) {
String line = bufferedReader.readLine();
String[] lineTokens = splitByPipelineAndTrim(line, 2);
String[] departmentTokens = splitBySpace(lineTokens[0], 4);
Department department = new Department();
department.setId(Long.parseLong(departmentTokens[0]));
department.setName(departmentTokens[1]);
int minimumAge = Integer.parseInt(departmentTokens[2]);
if (minimumAge != 0) {
department.setMinimumAge(Integer.valueOf(minimumAge));
}
int maximumAge = Integer.parseInt(departmentTokens[3]);
if (maximumAge != 0) {
department.setMaximumAge(Integer.valueOf(maximumAge));
}
departmentList.add(department);
idToDepartmentMap.put(department.getId(), department);
String[] departmentSpecialismTokens = splitBySpace(lineTokens[1]);
if (departmentSpecialismTokens.length % 2 != 0) {
throw new IllegalArgumentException("Read line (" + line
+ ") is expected to contain even number of tokens (" + departmentSpecialismTokens.length
+ ") after 1st pipeline (|) separated by a space ( ).");
}
for (int j = 0; j < departmentSpecialismTokens.length; j += 2) {
long specialismId = Long.parseLong(departmentSpecialismTokens[j + 1]);
if (specialismId != 0) {
DepartmentSpecialism departmentSpecialism = new DepartmentSpecialism();
departmentSpecialism.setId(departmentSpecialismId);
departmentSpecialism.setDepartment(department);
departmentSpecialism.setPriority(Integer.parseInt(departmentSpecialismTokens[j]));
Specialism specialism = idToSpecialismMap.get(specialismId);
if (specialism == null) {
throw new IllegalArgumentException("Read line (" + line
+ ") has a non existing specialismId (" + specialismId + ").");
}
departmentSpecialism.setSpecialism(specialism);
departmentSpecialismList.add(departmentSpecialism);
departmentSpecialismId++;
}
}
}
Collections.sort(departmentList, new PersistableIdComparator());
patientAdmissionSchedule.setDepartmentList(departmentList);
patientAdmissionSchedule.setDepartmentSpecialismList(departmentSpecialismList);
}
private void readEquipmentList() throws IOException {
readConstantLine("ROOMPROPERTIES:");
List equipmentList = new ArrayList(equipmentListSize);
indexToEquipmentMap = new HashMap(equipmentListSize);
for (int i = 0; i < equipmentListSize; i++) {
String line = bufferedReader.readLine();
String[] lineTokens = splitBySpace(line, 2);
Equipment equipment = new Equipment();
equipment.setId(Long.parseLong(lineTokens[0]));
equipment.setName(lineTokens[1]);
equipmentList.add(equipment);
indexToEquipmentMap.put(i, equipment);
}
patientAdmissionSchedule.setEquipmentList(equipmentList);
}
private void readRoomListAndRoomSpecialismListAndRoomEquipmentList() throws IOException {
readConstantLine("ROOMS:");
List roomList = new ArrayList(roomListSize);
idToRoomMap = new HashMap(roomListSize);
List roomSpecialismList = new ArrayList(roomListSize * 5);
List roomEquipmentList = new ArrayList(roomListSize * 2);
long roomSpecialismId = 0L;
long roomEquipmentId = 0L;
for (int i = 0; i < roomListSize; i++) {
String line = bufferedReader.readLine();
String[] lineTokens = splitByPipelineAndTrim(line, 6);
String[] roomTokens = splitBySpace(lineTokens[0], 2);
Room room = new Room();
room.setId(Long.parseLong(roomTokens[0]));
room.setName(roomTokens[1]);
room.setCapacity(Integer.parseInt(lineTokens[1]));
room.setDepartment(idToDepartmentMap.get(
Long.parseLong(lineTokens[2])));
room.setGenderLimitation(GenderLimitation.valueOfCode(lineTokens[3]));
roomList.add(room);
idToRoomMap.put(room.getId(), room);
String[] roomSpecialismTokens = splitBySpace(lineTokens[4]);
if (roomSpecialismTokens.length % 2 != 0) {
throw new IllegalArgumentException("Read line (" + line
+ ") is expected to contain even number of tokens (" + roomSpecialismTokens.length
+ ") after 4th pipeline (|) separated by a space ( ).");
}
List roomSpecialismListOfRoom = new ArrayList(roomSpecialismTokens.length / 2);
for (int j = 0; j < roomSpecialismTokens.length; j += 2) {
int priority = Integer.parseInt(roomSpecialismTokens[j]);
long specialismId = Long.parseLong(roomSpecialismTokens[j + 1]);
if (specialismId != 0) {
RoomSpecialism roomSpecialism = new RoomSpecialism();
roomSpecialism.setId(roomSpecialismId);
roomSpecialism.setRoom(room);
Specialism specialism = idToSpecialismMap.get(specialismId);
if (specialism == null) {
throw new IllegalArgumentException("Read line (" + line
+ ") has a non existing specialismId (" + specialismId + ").");
}
roomSpecialism.setSpecialism(specialism);
roomSpecialism.setPriority(priority);
roomSpecialismListOfRoom.add(roomSpecialism);
roomSpecialismList.add(roomSpecialism);
roomSpecialismId++;
}
}
room.setRoomSpecialismList(roomSpecialismListOfRoom);
List roomEquipmentListOfRoom = new ArrayList(equipmentListSize);
String[] roomEquipmentTokens = splitBySpace(lineTokens[5]);
if (roomEquipmentTokens.length != equipmentListSize) {
throw new IllegalArgumentException("Read line (" + line
+ ") is expected to contain equal number of tokens (" + roomEquipmentTokens.length
+ ") as equipmentListSize (" + equipmentListSize + ") after 5th pipeline (|).");
}
for (int j = 0; j < roomEquipmentTokens.length; j++) {
int hasEquipment = Integer.parseInt(roomEquipmentTokens[j]);
if (hasEquipment == 1) {
RoomEquipment roomEquipment = new RoomEquipment();
roomEquipment.setId(roomEquipmentId);
roomEquipment.setRoom(room);
roomEquipment.setEquipment(indexToEquipmentMap.get(j));
roomEquipmentListOfRoom.add(roomEquipment);
roomEquipmentList.add(roomEquipment);
roomEquipmentId++;
} else if (hasEquipment != 0) {
throw new IllegalArgumentException("Read line (" + line
+ ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
}
}
room.setRoomEquipmentList(roomEquipmentListOfRoom);
}
Collections.sort(roomList, new Comparator() {
public int compare(Room a, Room b) {
return new CompareToBuilder()
.append(a.getDepartment().getId(), b.getDepartment().getId())
.append(a.getId(), b.getId())
.toComparison();
}
});
patientAdmissionSchedule.setRoomList(roomList);
patientAdmissionSchedule.setRoomSpecialismList(roomSpecialismList);
patientAdmissionSchedule.setRoomEquipmentList(roomEquipmentList);
}
private void readBedList() throws IOException {
readConstantLine("BEDS:");
List bedList = new ArrayList(bedListSize);
Map roomToLastIndexInRoomMap = new HashMap(roomListSize);
for (int i = 0; i < bedListSize; i++) {
String line = bufferedReader.readLine();
String[] lineTokens = splitBySpace(line, 2);
Bed bed = new Bed();
bed.setId(Long.parseLong(lineTokens[0]));
Room room = idToRoomMap.get(Long.parseLong(lineTokens[1]));
bed.setRoom(room);
Integer indexInRoom = roomToLastIndexInRoomMap.get(room);
if (indexInRoom == null) {
indexInRoom = 0;
} else {
indexInRoom++;
}
bed.setIndexInRoom(indexInRoom);
roomToLastIndexInRoomMap.put(room, indexInRoom);
bedList.add(bed);
}
Collections.sort(bedList, new Comparator() {
public int compare(Bed a, Bed b) {
return new CompareToBuilder()
.append(a.getRoom().getDepartment().getId(), b.getRoom().getDepartment().getId())
.append(a.getRoom().getId(), b.getRoom().getId())
.append(a.getIndexInRoom(), b.getIndexInRoom())
.append(a.getId(), b.getId())
.toComparison();
}
});
patientAdmissionSchedule.setBedList(bedList);
}
private void generateNightList() {
List nightList = new ArrayList(nightListSize);
indexToNightMap = new HashMap(nightListSize);
long nightId = 0L;
for (int i = 0; i < nightListSize; i++) {
Night night = new Night();
night.setId(nightId);
night.setIndex(i);
nightList.add(night);
indexToNightMap.put(i, night);
nightId++;
}
patientAdmissionSchedule.setNightList(nightList);
}
private void readPatientListAndAdmissionPartListAndRequiredPatientEquipmentListAndPreferredPatientEquipmentList() throws IOException {
readConstantLine("PATIENTS:");
List patientList = new ArrayList(patientListSize);
List admissionPartList = new ArrayList(patientListSize);
List requiredPatientEquipmentList = new ArrayList(patientListSize * equipmentListSize);
List preferredPatientEquipmentList = new ArrayList(patientListSize * equipmentListSize);
long admissionPartId = 0L;
long requiredPatientEquipmentId = 0L;
long preferredPatientEquipmentId = 0L;
for (int i = 0; i < patientListSize; i++) {
String line = bufferedReader.readLine();
String[] lineTokens = splitByPipelineAndTrim(line, 6);
String[] nightTokens = splitBySpace(lineTokens[1], 2);
int firstNightIndex = Integer.parseInt(nightTokens[0]);
int lastNightIndex = Integer.parseInt(nightTokens[1]);
int patientNightListSize = lastNightIndex - firstNightIndex;
// A patient with no nights in the planning horizon or no nights at all is ignored
if (firstNightIndex >= nightListSize || patientNightListSize == 0) {
continue;
}
String[] patientTokens = splitBySpace(lineTokens[0], 4);
Patient patient = new Patient();
patient.setId(Long.parseLong(patientTokens[0]));
patient.setName(patientTokens[1]);
patient.setAge(Integer.parseInt(patientTokens[2]));
patient.setGender(Gender.valueOfCode(patientTokens[3]));
int preferredMaximumRoomCapacity = Integer.parseInt(lineTokens[3]);
patient.setPreferredMaximumRoomCapacity(preferredMaximumRoomCapacity == 0
? null : preferredMaximumRoomCapacity);
patientList.add(patient);
String[] admissionPartTokens = splitBySpace(lineTokens[2]);
int patientAdmissionPartListSize = Integer.parseInt(admissionPartTokens[0]);
if (admissionPartTokens.length != ((patientAdmissionPartListSize * 2) + 1)) {
throw new IllegalArgumentException("Read line (" + line
+ ") is expected to contain " + ((patientAdmissionPartListSize * 2) + 1)
+ " number of tokens after 2th pipeline (|).");
}
int nextFirstNightIndex = firstNightIndex;
for (int j = 1; j < admissionPartTokens.length; j += 2) {
long specialismId = Long.parseLong(admissionPartTokens[j]);
int admissionPartNightListSize = Integer.parseInt(admissionPartTokens[j + 1]);
if (nextFirstNightIndex >= nightListSize || admissionPartNightListSize == 0) {
nextFirstNightIndex += admissionPartNightListSize;
continue;
}
AdmissionPart admissionPart = new AdmissionPart();
admissionPart.setId(admissionPartId);
admissionPart.setPatient(patient);
Specialism specialism = (specialismId == 0) ? null : idToSpecialismMap.get(specialismId);
if (specialism == null) {
throw new IllegalArgumentException("Read line (" + line
+ ") has a non existing specialismId (" + specialismId + ").");
}
admissionPart.setSpecialism(specialism);
int admissionPartFirstNightIndex = nextFirstNightIndex;
Night admissionPartFirstNight = indexToNightMap.get(admissionPartFirstNightIndex);
if (admissionPartFirstNight == null) {
throw new IllegalStateException(
"The admissionPartFirstNight was not found for admissionPartFirstNightIndex("
+ admissionPartFirstNightIndex + ").");
}
admissionPart.setFirstNight(admissionPartFirstNight);
int admissionPartLastNightIndex = nextFirstNightIndex + admissionPartNightListSize - 1;
// TODO Instead of ensureEnoughNights(lastNightIndex);
// the official score function ignores any broken constraints after the planning horizon
if (admissionPartLastNightIndex >= nightListSize) {
admissionPartLastNightIndex = nightListSize - 1;
}
Night admissionPartLastNight = indexToNightMap.get(admissionPartLastNightIndex);
if (admissionPartLastNight == null) {
throw new IllegalStateException(
"The admissionPartLastNight was not found for admissionPartLastNightIndex("
+ admissionPartLastNightIndex + ").");
}
admissionPart.setLastNight(admissionPartLastNight);
admissionPartList.add(admissionPart);
admissionPartId++;
nextFirstNightIndex += admissionPartNightListSize;
}
int admissionPartNightListSizeSum = nextFirstNightIndex - firstNightIndex;
if (patientNightListSize != admissionPartNightListSizeSum) {
throw new IllegalArgumentException("Read line (" + line
+ ") has patientNightListSize (" + patientNightListSize
+ ") different from admissionPartNightListSizeSum(" + admissionPartNightListSizeSum + ")");
}
String[] requiredPatientEquipmentTokens = splitBySpace(lineTokens[4]);
if (requiredPatientEquipmentTokens.length != equipmentListSize) {
throw new IllegalArgumentException("Read line (" + line
+ ") is expected to contain equal number of tokens ("
+ requiredPatientEquipmentTokens.length
+ ") as equipmentListSize (" + equipmentListSize + ") after 4th pipeline (|).");
}
List requiredPatientEquipmentOfPatientList
= new ArrayList(equipmentListSize);
for (int j = 0; j < requiredPatientEquipmentTokens.length; j++) {
int hasEquipment = Integer.parseInt(requiredPatientEquipmentTokens[j]);
if (hasEquipment == 1) {
RequiredPatientEquipment requiredPatientEquipment = new RequiredPatientEquipment();
requiredPatientEquipment.setId(requiredPatientEquipmentId);
requiredPatientEquipment.setPatient(patient);
requiredPatientEquipment.setEquipment(indexToEquipmentMap.get(j));
requiredPatientEquipmentOfPatientList.add(requiredPatientEquipment);
requiredPatientEquipmentList.add(requiredPatientEquipment);
requiredPatientEquipmentId++;
} else if (hasEquipment != 0) {
throw new IllegalArgumentException("Read line (" + line
+ ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
}
}
patient.setRequiredPatientEquipmentList(requiredPatientEquipmentOfPatientList);
String[] preferredPatientEquipmentTokens = splitBySpace(lineTokens[5]);
if (preferredPatientEquipmentTokens.length != equipmentListSize) {
throw new IllegalArgumentException("Read line (" + line
+ ") is expected to contain equal number of tokens ("
+ preferredPatientEquipmentTokens.length
+ ") as equipmentListSize (" + equipmentListSize + ") after 5th pipeline (|).");
}
List preferredPatientEquipmentOfPatientList
= new ArrayList(equipmentListSize);
for (int j = 0; j < preferredPatientEquipmentTokens.length; j++) {
int hasEquipment = Integer.parseInt(preferredPatientEquipmentTokens[j]);
if (hasEquipment == 1) {
boolean alreadyRequired = (Integer.parseInt(requiredPatientEquipmentTokens[j]) == 1);
// Official spec: if equipment is required
// then a duplicate preffered constraint should be ignored
if (!alreadyRequired) {
PreferredPatientEquipment preferredPatientEquipment = new PreferredPatientEquipment();
preferredPatientEquipment.setId(preferredPatientEquipmentId);
preferredPatientEquipment.setPatient(patient);
preferredPatientEquipment.setEquipment(indexToEquipmentMap.get(j));
preferredPatientEquipmentOfPatientList.add(preferredPatientEquipment);
preferredPatientEquipmentList.add(preferredPatientEquipment);
preferredPatientEquipmentId++;
}
} else if (hasEquipment != 0) {
throw new IllegalArgumentException("Read line (" + line
+ ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
}
}
patient.setPreferredPatientEquipmentList(preferredPatientEquipmentOfPatientList);
}
patientAdmissionSchedule.setPatientList(patientList);
patientAdmissionSchedule.setAdmissionPartList(admissionPartList);
patientAdmissionSchedule.setRequiredPatientEquipmentList(requiredPatientEquipmentList);
patientAdmissionSchedule.setPreferredPatientEquipmentList(preferredPatientEquipmentList);
}
// /**
// * hack to make sure there are enough nights
// * @param lastNightIndex >= 0
// */
// private void ensureEnoughNights(int lastNightIndex) {
// List nightList = patientAdmissionSchedule.getNightList();
// if (lastNightIndex >= nightList.size()) {
// long nightId = nightList.size();
// for (int j = nightList.size(); j <= lastNightIndex; j++) {
// Night night = new Night();
// night.setId(nightId);
// night.setIndex(j);
// nightList.add(night);
// indexToNightMap.put(j, night);
// nightId++;
// }
// }
// }
private void createBedDesignationList() {
List admissionPartList = patientAdmissionSchedule.getAdmissionPartList();
List bedDesignationList = new ArrayList(admissionPartList.size());
long id = 0L;
for (AdmissionPart admissionPart : admissionPartList) {
BedDesignation bedDesignation = new BedDesignation();
bedDesignation.setId(id);
id++;
bedDesignation.setAdmissionPart(admissionPart);
// Notice that we leave the PlanningVariable properties on null
bedDesignationList.add(bedDesignation);
}
patientAdmissionSchedule.setBedDesignationList(bedDesignationList);
}
}
}