/*
* 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.coachshuttlegathering.persistence;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FilenameUtils;
import org.optaplanner.examples.coachshuttlegathering.domain.Bus;
import org.optaplanner.examples.coachshuttlegathering.domain.BusHub;
import org.optaplanner.examples.coachshuttlegathering.domain.BusStop;
import org.optaplanner.examples.coachshuttlegathering.domain.Coach;
import org.optaplanner.examples.coachshuttlegathering.domain.CoachShuttleGatheringSolution;
import org.optaplanner.examples.coachshuttlegathering.domain.Shuttle;
import org.optaplanner.examples.coachshuttlegathering.domain.location.RoadLocation;
import org.optaplanner.examples.coachshuttlegathering.domain.location.RoadLocationArc;
import org.optaplanner.examples.common.persistence.AbstractTxtSolutionImporter;
public class CoachShuttleGatheringImporter extends AbstractTxtSolutionImporter<CoachShuttleGatheringSolution> {
public static void main(String[] args) {
CoachShuttleGatheringImporter importer = new CoachShuttleGatheringImporter();
importer.convert("example", "demo01.xml");
}
public CoachShuttleGatheringImporter() {
super(new CoachShuttleGatheringDao());
}
public CoachShuttleGatheringImporter(boolean withoutDao) {
super(withoutDao);
}
@Override
public boolean isInputFileDirectory() {
return true;
}
@Override
public String getInputFileSuffix() {
throw new IllegalStateException("The inputFile is a directory, so there is no suffix.");
}
@Override
public TxtInputBuilder<CoachShuttleGatheringSolution> createTxtInputBuilder() {
return new CoachShuttleGatheringInputBuilder();
}
@Override
public CoachShuttleGatheringSolution readSolution(File inputFile) {
// TODO Bridging hack because InputBuilder is designed for a single File.
File instanceFile = new File(inputFile, "Busstops.csv");
return super.readSolution(instanceFile);
}
public static class CoachShuttleGatheringInputBuilder extends TxtInputBuilder {
private CoachShuttleGatheringSolution solution;
private Map<List<Double>, RoadLocation> latLongToLocationMap;
private long busOrStopOrHubId;
@Override
public CoachShuttleGatheringSolution readSolution() throws IOException {
solution = new CoachShuttleGatheringSolution();
solution.setId(0L);
readLocationList();
busOrStopOrHubId = 0L;
readBusList();
readBusStopList();
int busListSize = solution.getCoachList().size() + solution.getShuttleList().size();
int base = solution.getStopList().size() + solution.getShuttleList().size();
BigInteger possibleSolutionSize = factorial(base + busListSize - 1).divide(factorial(busListSize - 1));
logger.info("CoachShuttleGathering {} has {} road locations, {} coaches, {} shuttles and {} bus stops"
+ " with a search space of {}.",
getInputId(),
solution.getLocationList().size(),
solution.getCoachList().size(),
solution.getShuttleList().size(),
solution.getStopList().size(),
getFlooredPossibleSolutionSize(possibleSolutionSize));
return solution;
}
@Override
public String getInputId() {
return FilenameUtils.getBaseName(inputFile.getParentFile().getPath());
}
private void readLocationList() throws IOException {
File file = new File(inputFile.getParentFile(), "DistanceTimesCoordinates.csv");
latLongToLocationMap = new HashMap<>();
List<RoadLocation> locationList = new ArrayList<>();
long locationId = 0L;
try (BufferedReader subBufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
subBufferedReader.readLine(); // Ignore first line (comment)
for (String line = subBufferedReader.readLine(); line != null; line = subBufferedReader.readLine()) {
if (line.isEmpty()) {
continue;
}
String[] lineTokens = splitBySemicolonSeparatedValue(line, 2);
RoadLocation location = new RoadLocation();
location.setId(locationId);
locationId++;
location.setLatitude(Double.parseDouble(lineTokens[0]));
location.setLongitude(Double.parseDouble(lineTokens[1]));
locationList.add(location);
latLongToLocationMap.put(Arrays.asList(location.getLatitude(), location.getLongitude()), location);
}
} catch (IOException e) {
throw new IllegalArgumentException("Could not read the file (" + file.getName() + ").", e);
}
solution.setLocationList(locationList);
for (RoadLocation sourceLocation : locationList) {
LinkedHashMap<RoadLocation, RoadLocationArc> travelDistanceMap = new LinkedHashMap<>(locationList.size());
for (RoadLocation targetLocation : locationList) {
travelDistanceMap.put(targetLocation, new RoadLocationArc());
}
sourceLocation.setTravelDistanceMap(travelDistanceMap);
}
readLocationDistancesCoaches();
readLocationDistancesShuttles();
}
private void readLocationDistancesCoaches() throws IOException {
List<RoadLocation> locationList = solution.getLocationList();
int locationListSize = locationList.size();
File file = new File(inputFile.getParentFile(), "DistanceTimesData_COACHES.csv");
int locationListIndex = 0;
try (BufferedReader subBufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
subBufferedReader.readLine(); // Ignore first line (comment)
for (String line = subBufferedReader.readLine(); line != null; line = subBufferedReader.readLine()) {
if (line.isEmpty()) {
continue;
}
RoadLocation sourceLocation = locationList.get(locationListIndex);
locationListIndex++;
String[] lineTokens = splitBySemicolonSeparatedValue(line, locationListSize * 2);
for (int i = 0; i < locationListSize; i++) {
RoadLocation targetLocation = locationList.get(i);
RoadLocationArc locationArc = sourceLocation.getTravelDistanceMap().get(targetLocation);
locationArc.setCoachDistance(Integer.parseInt(lineTokens[i * 2]));
locationArc.setCoachDuration(Integer.parseInt(lineTokens[i * 2 + 1]));
}
}
} catch (IOException e) {
throw new IllegalArgumentException("Could not read the file (" + file.getName() + ").", e);
}
}
private void readLocationDistancesShuttles() throws IOException {
List<RoadLocation> locationList = solution.getLocationList();
int locationListSize = locationList.size();
File file = new File(inputFile.getParentFile(), "DistanceTimesData_SHUTTLES.csv");
int locationListIndex = 0;
try (BufferedReader subBufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
subBufferedReader.readLine(); // Ignore first line (comment)
for (String line = subBufferedReader.readLine(); line != null; line = subBufferedReader.readLine()) {
if (line.isEmpty()) {
continue;
}
RoadLocation sourceLocation = locationList.get(locationListIndex);
locationListIndex++;
String[] lineTokens = splitBySemicolonSeparatedValue(line, locationListSize * 2);
for (int i = 0; i < locationListSize; i++) {
RoadLocation targetLocation = locationList.get(i);
RoadLocationArc locationArc = sourceLocation.getTravelDistanceMap().get(targetLocation);
locationArc.setShuttleDistance(Integer.parseInt(lineTokens[i * 2]));
locationArc.setShuttleDuration(Integer.parseInt(lineTokens[i * 2 + 1]));
}
}
} catch (IOException e) {
throw new IllegalArgumentException("Could not read the file (" + file.getName() + ").", e);
}
}
private void readBusList() throws IOException {
File file = new File(inputFile.getParentFile(), "Fleet.csv");
List<Coach> coachList = new ArrayList<>();
List<Shuttle> shuttleList = new ArrayList<>();
try (BufferedReader subBufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
subBufferedReader.readLine(); // Ignore first line (comment)
for (String line = subBufferedReader.readLine(); line != null; line = subBufferedReader.readLine()) {
if (line.isEmpty()) {
continue;
}
String[] lineTokens = splitBySemicolonSeparatedValue(line, 8);
Bus bus;
String busType = lineTokens[0];
String name = lineTokens[1];
if (busType.equalsIgnoreCase("COACH")) {
bus = new Coach();
coachList.add((Coach) bus);
} else if (busType.equalsIgnoreCase("SHUTTLE")) {
bus = new Shuttle();
shuttleList.add((Shuttle) bus);
} else {
throw new IllegalArgumentException("The fleet vehicle with name (" + name
+ ") has an unsupported type (" + busType + ").");
}
bus.setId(busOrStopOrHubId);
busOrStopOrHubId++;
bus.setName(name);
bus.setCapacity(Integer.parseInt(lineTokens[2]));
int stopLimit = Integer.parseInt(lineTokens[3]);
if (bus instanceof Coach) {
((Coach) bus).setStopLimit(stopLimit);
} else {
if (stopLimit != -1) {
throw new IllegalArgumentException("The shuttle with name (" + name
+ ") has an unsupported stopLimit (" + stopLimit + ").");
}
}
bus.setMileageCost(Integer.parseInt(lineTokens[4]));
int setupCost = Integer.parseInt(lineTokens[5]);
if (bus instanceof Coach) {
if (setupCost != 0) {
throw new IllegalArgumentException("The coach with name (" + name
+ ") has an unsupported setupCost (" + setupCost + ").");
}
} else {
((Shuttle) bus).setSetupCost(setupCost);
}
double latitude = Double.parseDouble(lineTokens[6]);
double longitude = Double.parseDouble(lineTokens[7]);
RoadLocation location = latLongToLocationMap.get(Arrays.asList(latitude, longitude));
if (location == null) {
throw new IllegalArgumentException("The fleet vehicle with name (" + name
+ ") has a coordinate (" + latitude + ", " + longitude
+ ") which is not in the coordinates file.");
}
bus.setDepartureLocation(location);
}
} catch (IOException e) {
throw new IllegalArgumentException("Could not read the file (" + file.getName() + ").", e);
}
solution.setCoachList(coachList);
solution.setShuttleList(shuttleList);
}
private void readBusStopList() throws IOException {
List<BusStop> busStopList = new ArrayList<>();
bufferedReader.readLine(); // Ignore first line (comment)
for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) {
if (line.isEmpty()) {
continue;
}
String[] lineTokens = splitBySemicolonSeparatedValue(line, 8);
String busStopType = lineTokens[0];
String name = lineTokens[1];
if (busStopType.equalsIgnoreCase("HUB")) {
if (solution.getHub() != null) {
throw new IllegalArgumentException("The hub with name (" + name
+ ") is not the only hub (" + solution.getHub().getName() + ").");
}
BusHub hub = new BusHub();
hub.setId(busOrStopOrHubId);
busOrStopOrHubId++;
hub.setName(name);
// Ignore lineTokens[2] and lineTokens[3]
double latitude = Double.parseDouble(lineTokens[4]);
double longitude = Double.parseDouble(lineTokens[5]);
RoadLocation location = latLongToLocationMap.get(Arrays.asList(latitude, longitude));
if (location == null) {
throw new IllegalArgumentException("The bus stop with name (" + name
+ ") has a coordinate (" + latitude + ", " + longitude
+ ") which is not in the coordinates file.");
}
hub.setLocation(location);
int passengerQuantity = Integer.parseInt(lineTokens[6]);
if (passengerQuantity != 0) {
throw new IllegalArgumentException("The hub with name (" + name
+ ") has an unsupported passengerQuantity (" + passengerQuantity + ").");
}
int transportTimeLimit = Integer.parseInt(lineTokens[7]);
if (transportTimeLimit != 0) {
throw new IllegalArgumentException("The hub with name (" + name
+ ") has an unsupported transportTimeLimit (" + transportTimeLimit + ").");
}
for (Coach coach : solution.getCoachList()) {
coach.setDestination(hub);
}
ArrayList<Shuttle> transferShuttleList = new ArrayList<>(solution.getShuttleList().size());
for (Shuttle shuttle : solution.getShuttleList()) {
// TODO Use a fixed value Construction Heuristic to initialize the destination variable
shuttle.setDestination(hub);
transferShuttleList.add(shuttle);
}
hub.setTransferShuttleList(transferShuttleList);
solution.setHub(hub);
} else if (busStopType.equalsIgnoreCase("BUSSTOP")) {
BusStop busStop = new BusStop();
busStop.setId(busOrStopOrHubId);
busOrStopOrHubId++;
busStop.setName(name);
// Ignore lineTokens[2] and lineTokens[3]
double latitude = Double.parseDouble(lineTokens[4]);
double longitude = Double.parseDouble(lineTokens[5]);
RoadLocation location = latLongToLocationMap.get(Arrays.asList(latitude, longitude));
if (location == null) {
throw new IllegalArgumentException("The bus stop with name (" + name
+ ") has a coordinate (" + latitude + ", " + longitude
+ ") which is not in the coordinates file.");
}
busStop.setLocation(location);
busStop.setPassengerQuantity(Integer.parseInt(lineTokens[6]));
busStop.setTransportTimeLimit(Integer.parseInt(lineTokens[7]));
// Trade memory for performance (might not be desired if it is too memory hungry)
busStop.setTransferShuttleList(new ArrayList<>(solution.getShuttleList().size()));
busStopList.add(busStop);
} else {
throw new IllegalArgumentException("The bus stop with name (" + name
+ ") has an unsupported type (" + busStopType + ").");
}
}
solution.setStopList(busStopList);
}
}
}