/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * 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.optaplanner.examples.meetingscheduling.persistence; import java.io.File; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.optaplanner.examples.common.app.LoggingMain; import org.optaplanner.examples.common.persistence.AbstractSolutionImporter; import org.optaplanner.examples.common.persistence.SolutionDao; import org.optaplanner.examples.common.persistence.StringDataGenerator; import org.optaplanner.examples.meetingscheduling.domain.Attendance; import org.optaplanner.examples.meetingscheduling.domain.Day; import org.optaplanner.examples.meetingscheduling.domain.Meeting; import org.optaplanner.examples.meetingscheduling.domain.MeetingAssignment; import org.optaplanner.examples.meetingscheduling.domain.MeetingSchedule; import org.optaplanner.examples.meetingscheduling.domain.Person; import org.optaplanner.examples.meetingscheduling.domain.PreferredAttendance; import org.optaplanner.examples.meetingscheduling.domain.RequiredAttendance; import org.optaplanner.examples.meetingscheduling.domain.Room; import org.optaplanner.examples.meetingscheduling.domain.TimeGrain; public class MeetingSchedulingGenerator extends LoggingMain { public static void main(String[] args) { MeetingSchedulingGenerator generator = new MeetingSchedulingGenerator(); generator.writeMeetingSchedule(50, 5); generator.writeMeetingSchedule(100, 5); // generator.writeMeetingSchedule(200, 5); // generator.writeMeetingSchedule(400, 5); // generator.writeMeetingSchedule(800, 5); } private final StringDataGenerator topicGenerator = new StringDataGenerator() .addPart(true, 0, "Strategize", "Fast track", "Cross sell", "Profitize", "Transform", "Engage", "Downsize", "Ramp up", "On board", "Reinvigorate") .addPart(false, 1, "data driven", "sales driven", "compelling", "reusable", "negotiated", "sustainable", "laser-focused", "flexible", "real-time", "targeted") .addPart(true, 1, "B2B", "e-business", "virtualization", "multitasking", "one stop shop", "braindumps", "data mining", "policies", "synergies", "user experience") .addPart(false, 3, "in a nutshell", "in practice", "for dummies", "in action", "recipes", "on the web", "for decision makers", "on the whiteboard", "out of the box", "in the new economy"); private final int[] durationInGrainsOptions = { 1, // 15 mins 2, // 30 mins 3, // 45 mins 4, // 1 hour 6, // 90 mins 8, // 2 hours 16, // 4 hours }; private final int[] personsPerMeetingOptions = { 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 20, 30, }; private final int[] startingMinuteOfDayOptions = { 8 * 60, // 08:00 8 * 60 + 15, // 08:15 8 * 60 + 30, // 08:30 8 * 60 + 45, // 08:45 9 * 60, // 09:00 9 * 60 + 15, // 09:15 9 * 60 + 30, // 09:30 9 * 60 + 45, // 09:45 10 * 60, // 10:00 10 * 60 + 15, // 10:15 10 * 60 + 30, // 10:30 10 * 60 + 45, // 10:45 11 * 60, // 11:00 11 * 60 + 15, // 11:15 11 * 60 + 30, // 11:30 11 * 60 + 45, // 11:45 13 * 60, // 13:00 13 * 60 + 15, // 13:15 13 * 60 + 30, // 13:30 13 * 60 + 45, // 13:45 14 * 60, // 14:00 14 * 60 + 15, // 14:15 14 * 60 + 30, // 14:30 14 * 60 + 45, // 14:45 15 * 60, // 15:00 15 * 60 + 15, // 15:15 15 * 60 + 30, // 15:30 15 * 60 + 45, // 15:45 16 * 60, // 16:00 16 * 60 + 15, // 16:15 16 * 60 + 30, // 16:30 16 * 60 + 45, // 16:45 17 * 60, // 17:00 17 * 60 + 15, // 17:15 17 * 60 + 30, // 17:30 17 * 60 + 45, // 17:45 }; private final StringDataGenerator fullNameGenerator = StringDataGenerator.buildFullNames(); protected final SolutionDao solutionDao; protected final File outputDir; protected Random random; public MeetingSchedulingGenerator() { solutionDao = new MeetingSchedulingDao(); outputDir = new File(solutionDao.getDataDir(), "unsolved"); } private void writeMeetingSchedule(int meetingListSize, int roomListSize) { int timeGrainListSize = meetingListSize * durationInGrainsOptions[durationInGrainsOptions.length - 1] / roomListSize; String fileName = determineFileName(meetingListSize, timeGrainListSize, roomListSize); File outputFile = new File(outputDir, fileName + ".xml"); MeetingSchedule meetingSchedule = createMeetingSchedule(fileName, meetingListSize, timeGrainListSize, roomListSize); solutionDao.writeSolution(meetingSchedule, outputFile); } private String determineFileName(int meetingListSize, int timeGrainListSize, int roomListSize) { return meetingListSize + "meetings-" + timeGrainListSize + "timegrains-" + roomListSize + "rooms"; } public MeetingSchedule createMeetingSchedule(String fileName, int meetingListSize, int timeGrainListSize, int roomListSize) { random = new Random(37); MeetingSchedule meetingSchedule = new MeetingSchedule(); meetingSchedule.setId(0L); createMeetingListAndAttendanceList(meetingSchedule, meetingListSize); createTimeGrainList(meetingSchedule, timeGrainListSize); createRoomList(meetingSchedule, roomListSize); createPersonList(meetingSchedule); linkAttendanceListToPersons(meetingSchedule); createMeetingAssignmentList(meetingSchedule); BigInteger possibleSolutionSize = BigInteger.valueOf((long) timeGrainListSize * roomListSize) .pow(meetingSchedule.getMeetingAssignmentList().size()); logger.info("MeetingSchedule {} has {} meetings, {} timeGrains and {} rooms with a search space of {}.", fileName, meetingListSize, timeGrainListSize, roomListSize, AbstractSolutionImporter.getFlooredPossibleSolutionSize(possibleSolutionSize)); return meetingSchedule; } private void createMeetingListAndAttendanceList(MeetingSchedule meetingSchedule, int meetingListSize) { List<Meeting> meetingList = new ArrayList<>(meetingListSize); List<Attendance> globalAttendanceList = new ArrayList<>(); long attendanceId = 0L; topicGenerator.predictMaximumSizeAndReset(meetingListSize); for (int i = 0; i < meetingListSize; i++) { Meeting meeting = new Meeting(); meeting.setId((long) i); String topic = topicGenerator.generateNextValue(); meeting.setTopic(topic); int durationInGrains = durationInGrainsOptions[random.nextInt(durationInGrainsOptions.length)]; meeting.setDurationInGrains(durationInGrains); int attendanceListSize = personsPerMeetingOptions[random.nextInt(personsPerMeetingOptions.length)]; int requiredAttendanceListSize = Math.max(2, random.nextInt(attendanceListSize + 1)); List<RequiredAttendance> requiredAttendanceList = new ArrayList<>(requiredAttendanceListSize); for (int j = 0; j < requiredAttendanceListSize; j++) { RequiredAttendance attendance = new RequiredAttendance(); attendance.setId(attendanceId); attendanceId++; attendance.setMeeting(meeting); // person is filled in later requiredAttendanceList.add(attendance); globalAttendanceList.add(attendance); } meeting.setRequiredAttendanceList(requiredAttendanceList); int preferredAttendanceListSize = attendanceListSize - requiredAttendanceListSize; List<PreferredAttendance> preferredAttendanceList = new ArrayList<>(preferredAttendanceListSize); for (int j = 0; j < preferredAttendanceListSize; j++) { PreferredAttendance attendance = new PreferredAttendance(); attendance.setId(attendanceId); attendanceId++; attendance.setMeeting(meeting); // person is filled in later preferredAttendanceList.add(attendance); globalAttendanceList.add(attendance); } meeting.setPreferredAttendanceList(preferredAttendanceList); logger.trace("Created meeting with topic ({}), durationInGrains ({})," + " requiredAttendanceListSize ({}), preferredAttendanceListSize ({}).", topic, durationInGrains, requiredAttendanceListSize, preferredAttendanceListSize); meetingList.add(meeting); } meetingSchedule.setMeetingList(meetingList); meetingSchedule.setAttendanceList(globalAttendanceList); } private void createTimeGrainList(MeetingSchedule meetingSchedule, int timeGrainListSize) { List<Day> dayList = new ArrayList<>(timeGrainListSize); long dayId = 0; Day day = null; List<TimeGrain> timeGrainList = new ArrayList<>(timeGrainListSize); for (int i = 0; i < timeGrainListSize; i++) { TimeGrain timeGrain = new TimeGrain(); timeGrain.setId((long) i); int grainIndex = i; timeGrain.setGrainIndex(grainIndex); int dayOfYear = (i / startingMinuteOfDayOptions.length) + 1; if (day == null || day.getDayOfYear() != dayOfYear) { day = new Day(); day.setId(dayId); day.setDayOfYear(dayOfYear); dayId++; dayList.add(day); } timeGrain.setDay(day); int startingMinuteOfDay = startingMinuteOfDayOptions[i % startingMinuteOfDayOptions.length]; timeGrain.setStartingMinuteOfDay(startingMinuteOfDay); logger.trace("Created timeGrain with grainIndex ({}), dayOfYear ({}), startingMinuteOfDay ({}).", grainIndex, dayOfYear, startingMinuteOfDay); timeGrainList.add(timeGrain); } meetingSchedule.setDayList(dayList); meetingSchedule.setTimeGrainList(timeGrainList); } private void createRoomList(MeetingSchedule meetingSchedule, int roomListSize) { List<Room> roomList = new ArrayList<>(roomListSize); for (int i = 0; i < roomListSize; i++) { Room room = new Room(); room.setId((long) i); int roomsPerFloor = 20; String name = "R " + ((i / roomsPerFloor * 100) + (i % roomsPerFloor) + 1); room.setName(name); int capacityOptionsSubsetSize = personsPerMeetingOptions.length * 3 / 4; int capacity = personsPerMeetingOptions[personsPerMeetingOptions.length - (i % capacityOptionsSubsetSize) - 1]; room.setCapacity(capacity); logger.trace("Created room with name ({}), capacity ({}).", name, capacity); roomList.add(room); } meetingSchedule.setRoomList(roomList); } private void createPersonList(MeetingSchedule meetingSchedule) { int attendanceListSize = 0; for (Meeting meeting : meetingSchedule.getMeetingList()) { attendanceListSize += meeting.getRequiredAttendanceList().size() + meeting.getPreferredAttendanceList().size(); } int personListSize = attendanceListSize * meetingSchedule.getRoomList().size() * 3 / (4 * meetingSchedule.getMeetingList().size()); List<Person> personList = new ArrayList<>(personListSize); fullNameGenerator.predictMaximumSizeAndReset(personListSize); for (int i = 0; i < personListSize; i++) { Person person = new Person(); person.setId((long) i); String fullName = fullNameGenerator.generateNextValue(); person.setFullName(fullName); logger.trace("Created person with fullName ({}).", fullName); personList.add(person); } meetingSchedule.setPersonList(personList); } private void linkAttendanceListToPersons(MeetingSchedule meetingSchedule) { for (Meeting meeting : meetingSchedule.getMeetingList()) { List<Person> availablePersonList = new ArrayList<>(meetingSchedule.getPersonList()); int attendanceListSize = meeting.getRequiredAttendanceList().size() + meeting.getPreferredAttendanceList().size(); if (availablePersonList.size() < attendanceListSize) { throw new IllegalStateException("The availablePersonList size (" + availablePersonList.size() + ") is less than the attendanceListSize (" + attendanceListSize + ")."); } for (RequiredAttendance requiredAttendance : meeting.getRequiredAttendanceList()) { requiredAttendance.setPerson(availablePersonList.remove(random.nextInt(availablePersonList.size()))); } for (PreferredAttendance preferredAttendance : meeting.getPreferredAttendanceList()) { preferredAttendance.setPerson(availablePersonList.remove(random.nextInt(availablePersonList.size()))); } } } private void createMeetingAssignmentList(MeetingSchedule meetingSchedule) { List<Meeting> meetingList = meetingSchedule.getMeetingList(); List<MeetingAssignment> meetingAssignmentList = new ArrayList<>(meetingList.size()); for (Meeting meeting : meetingList) { MeetingAssignment meetingAssignment = new MeetingAssignment(); meetingAssignment.setId(meeting.getId()); meetingAssignment.setMeeting(meeting); meetingAssignmentList.add(meetingAssignment); } meetingSchedule.setMeetingAssignmentList(meetingAssignmentList); } }