package cz.agents.agentpolis.darptestbed.siminfrastructure.request.generator.support;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.primitives.Doubles;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import cz.agents.agentpolis.darptestbed.global.Utils;
import cz.agents.agentpolis.darptestbed.siminfrastructure.planner.init.TestbedPlannerModuleFactory;
import cz.agents.agentpolis.darptestbed.siminfrastructure.request.GPS;
import cz.agents.agentpolis.darptestbed.siminfrastructure.request.TimeWindow;
import cz.agents.agentpolis.darptestbed.siminfrastructure.request.generator.LenientRequestGenerator;
import cz.agents.agentpolis.darptestbed.simmodel.environment.TestbedEnvironmentModul;
import cz.agents.agentpolis.darptestbed.simulator.initializator.osm.NearestNodeInitModuleFactory;
import cz.agents.agentpolis.darptestbed.simulator.initializator.osm.NodeExtendedFunction;
import cz.agents.agentpolis.darptestbed.simulator.initializator.osm.init.TestbedMapInit;
import cz.agents.agentpolis.simmodel.environment.AgentPolisEnvironmentModule;
import cz.agents.agentpolis.simmodel.environment.model.citymodel.transportnetwork.EGraphType;
import cz.agents.agentpolis.simulator.creator.initializator.InitModuleFactory;
import cz.agents.agentpolis.simulator.creator.initializator.impl.MapData;
import cz.agents.agentpolis.simulator.importer.osm.OsmDataGetter;
import cz.agents.agentpolis.simulator.importer.osm.util.OSMBoundsUtil;
import cz.agents.agentpolis.simulator.vehiclemodel.init.VehicleDataModelModulFactory;
import cz.agents.agentpolis.utils.config.ConfigReader;
import cz.agents.alite.common.event.EventProcessor;
import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.math3.distribution.AbstractRealDistribution;
import org.apache.commons.math3.random.EmpiricalDistribution;
import org.apache.commons.math3.random.Well19937c;
import org.apache.log4j.Logger;
import org.joda.time.Duration;
import org.openstreetmap.osm.data.coordinates.Bounds;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
public class LenientPassengerGenerator implements PassengerGenerator {
private final static Logger LOGGER = Logger.getLogger(LenientPassengerGenerator.class);
private final static long HOUR23 = Duration.standardHours(23).getMillis();
private final static long HOUR23_30MIN = Duration.standardMinutes(23 * 60 + 30).getMillis();
private final static long HOUR24 = Duration.standardDays(1).getMillis();
private final static long TIME_WINDOW_RANGE = Duration.standardMinutes(30).getMillis();
private final static long CALL_TIME_BEFORE_REQUEST_FROM_TIME = Duration.standardHours(1).getMillis();
private final static long REQUEST_DURATION_TIME = Duration.standardHours(2).getMillis();
private final AbstractRealDistribution dayDistribution;
private final Random random;
private final GPSPositionGenerator generator;
private final Utils utils;
private final String benchmarkDir;
private final NodeExtendedFunction nearestNodeFinder;
private final List<Long> sampleNodesList;
private MapData osmDTO;
private final long averageDrivingTimeBetweenSamples;
private final long AVERAGE_PASSENGER_LOAD = 3;
private final float PERCENTAGE_OF_ALL_NODES_USED_FOR_SAMPLES = 0.01f;
private final double DEFAULT_SPEED = 30;
public static AbstractRealDistribution createDayMockDistribution(final int seed) {
final EmpiricalDistribution dayDistributionMock = new EmpiricalDistribution(new Well19937c(seed));
int[] demandsOverDay = new int[]{/* 0 */9,/* 1 */6,/* 2 */6,
/* 3 */6,/* 4 */7,/* 5 */12,/* 6 */25,/* 7 */37,/* 8 */49,
/* 9 */38,/* 10 */30,/* 11 */30,/* 12 */30,/* 13 */30,/* 14 */31,
/* 15 */36,/* 16 */45,/* 17 */41,/* 18 */31,/* 19 */27,/* 20 */25,/* 21 */22,/* 22 */18,/* 23 */11};
List<Double> dayHourDistribution = Lists.newArrayList();
int day = 0;
for (int demand : demandsOverDay) {
double hourInMillis = Duration.standardHours(day).getMillis();
for (int i = 0; i < demand; i++) {
dayHourDistribution.add(hourInMillis);
}
day++;
}
dayDistributionMock.load(Doubles.toArray(dayHourDistribution));
return dayDistributionMock;
}
public LenientPassengerGenerator(AbstractRealDistribution dayDistribution, Random random,
LenientRequestGenerator generator, String osmFileName, String benchmarkDir) {
super();
this.dayDistribution = dayDistribution;
this.random = random;
this.benchmarkDir = benchmarkDir;
this.generator = createGPSPositionGenerator(new File(osmFileName), generator.getPositionGeneratorFactory());
Injector injector = createInjector(this.benchmarkDir, new File(osmFileName));
this.utils = injector.getInstance(Utils.class);
this.nearestNodeFinder = injector.getInstance(NodeExtendedFunction.class);
// this.sampleNodesList = null;
// this.averageDrivingTimeBetweenSamples = 0;
this.sampleNodesList = generateSamples();
this.averageDrivingTimeBetweenSamples = calculateAverageDrivingTimeBetweenSamples();
}
private long calculateAverageDrivingTimeBetweenSamples() {
double averageDrivingTime = 0d;
LOGGER.debug("Starting calculateAverageDrivingTimeBetweenSamples.");
int counter = 1;
for (long position : sampleNodesList) {
Long drivingTime = getMultipliedAverageDrivingTimeFromSamples(position, 0.5f);
if (drivingTime == null)
continue;
averageDrivingTime = averageDrivingTime / (counter + 1) * counter + drivingTime / (counter + 1);
++counter;
// LOGGER.debug("Finished #" + counter + " node in mutual distance average: " +
// position + " " + averageDrivingTime);
}
return (long) averageDrivingTime;
}
private List<Long> generateSamples() {
int sampleCount = (int) (osmDTO.graphByType.get(EGraphType.HIGHWAY).getAllNodes().size() *
PERCENTAGE_OF_ALL_NODES_USED_FOR_SAMPLES);
List<Long> samples = new ArrayList<>();
// LOGGER.debug("Generating " + sampleCount + " samples ...");
for (int i = 0; i < sampleCount; ++i) {
// LOGGER.debug("Generating sample #" + i);
GPS position = generator.generateGPSPosition();
samples.add(nearestNodeFinder.getNearestNodeByNodeId(position.longitude, position.latitude));
}
return samples;
}
private long getMultipliedAverageDrivingTimeFromSamples(long originNode, float coef) {
double averageDrivingTime = 0d;
int counter = 1;
for (long position : sampleNodesList) {
Long drivingTime = utils.computeDrivingTime(originNode, position, DEFAULT_SPEED);
if (drivingTime == null)
continue;
averageDrivingTime = averageDrivingTime / (counter + 1) * counter + drivingTime / (counter + 1);
++counter;
// if (counter % (int) (sampleNodesList.size() * 0.2f) == 0)
// LOGGER.debug("Finished #" + counter + " node in distance from a single node average: " + position +
// averageDrivingTime);
}
return (long) (averageDrivingTime * coef);
}
@Override
public Set<String> generateAdditionalRequirements() {
return Sets.newHashSet(AdditionalRequirementsVehicleEquipment.WHEELCHAIR_SUPPORT.additionalRequirements);
}
@Override
public RequestTimeInfo generateRequestTimeInfo() {
throw new NotImplementedException();
}
@Override
public RequestTimeInfo generateRequestTimeInfo(GPS fromGPS, GPS toGPS) {
// return new RequestTimeInfo(1, new TimeWindow(1, 86400000 - 1), new TimeWindow(1, 86400000 - 1));
// time should be driving time + driving to time as 1.3 from E(dist(fromGPS, sample)) +
// time it would take the vehicle to deliver served passengers with the average path length of
// the average of distance between samples
long fromNode = nearestNodeFinder.getNearestNodeByNodeId(fromGPS.longitude, fromGPS.latitude);
long toNode = nearestNodeFinder.getNearestNodeByNodeId(toGPS.longitude, toGPS.latitude);
Long drivingTime = this.utils.computeDrivingTime(fromNode, toNode, DEFAULT_SPEED);
if (drivingTime == null) {
return new RequestTimeInfo(0, new TimeWindow(0, 0), new TimeWindow(0, 0));
}
double drivingToPassengerTime = getMultipliedAverageDrivingTimeFromSamples(fromNode, 1.3f); // think 80% of 2*E(dist)
double timeToFinishDrivingNPassengers = (double) (averageDrivingTimeBetweenSamples) * AVERAGE_PASSENGER_LOAD;
long fromTimeMin = (long) dayDistribution.sample();
long fromTimeMax = Math.min(fromTimeMin + generateTime(TIME_WINDOW_RANGE), HOUR23_30MIN);
long toTimeMin = (long)
((fromTimeMax + drivingTime + drivingToPassengerTime + timeToFinishDrivingNPassengers) *
(0.975d + Math.random() * 0.05d));
long requestCallTimeInDayRange = Math.max(fromTimeMin - generateTime(CALL_TIME_BEFORE_REQUEST_FROM_TIME),
1);
checkArgument(fromTimeMin >= 0 && fromTimeMin <= HOUR23,
"The distribution generated value, which is outof range 0 - " + HOUR23);
if (requestCallTimeInDayRange < 0) {
requestCallTimeInDayRange = 0;
}
long toTimeMax = toTimeMin + generateTime(TIME_WINDOW_RANGE);
fromTimeMin = Math.min(Math.max(fromTimeMin, 1), HOUR23);
fromTimeMax = Math.max(Math.min(fromTimeMax, 86400000 - 1), HOUR23_30MIN);
toTimeMin = Math.min(Math.max(toTimeMin, 1), HOUR23);
toTimeMax = Math.max(Math.min(toTimeMax, 86400000 - 1), HOUR23_30MIN);
return new RequestTimeInfo(requestCallTimeInDayRange, new TimeWindow(fromTimeMin, fromTimeMax), new TimeWindow(
toTimeMin, toTimeMax));
}
@Override
public RequestTimeInfo generateRequestTimeInfo(long fromNode, long toNode) {
// return new RequestTimeInfo(1, new TimeWindow(1, 86400000 - 1), new TimeWindow(1, 86400000 - 1));
// time should be driving time + driving to time as 1.3 from E(dist(fromGPS, sample)) +
// time it would take the vehicle to deliver served passengers with the average path length of
// the average of distance between samples
Long drivingTime = this.utils.computeDrivingTime(fromNode, toNode, DEFAULT_SPEED);
if (drivingTime == null) {
return new RequestTimeInfo(0, new TimeWindow(0, 0), new TimeWindow(0, 0));
}
double drivingToPassengerTime = getMultipliedAverageDrivingTimeFromSamples(fromNode, 1.3f); // think 80% of 2*E(dist)
double timeToFinishDrivingNPassengers = (double) (averageDrivingTimeBetweenSamples) * AVERAGE_PASSENGER_LOAD;
long fromTimeMin = (long) dayDistribution.sample();
long fromTimeMax = Math.min(fromTimeMin + generateTime(TIME_WINDOW_RANGE), HOUR23_30MIN);
long toTimeMin = (long)
((fromTimeMax + drivingTime + drivingToPassengerTime + timeToFinishDrivingNPassengers) *
(0.975d + Math.random() * 0.05d));
long requestCallTimeInDayRange = Math.max(fromTimeMin - generateTime(CALL_TIME_BEFORE_REQUEST_FROM_TIME),
1);
checkArgument(fromTimeMin >= 0 && fromTimeMin <= HOUR23,
"The distribution generated value, which is outof range 0 - " + HOUR23);
if (requestCallTimeInDayRange < 0) {
requestCallTimeInDayRange = 0;
}
long toTimeMax = toTimeMin + generateTime(TIME_WINDOW_RANGE);
fromTimeMin = Math.min(Math.max(fromTimeMin, 1), HOUR23);
fromTimeMax = Math.max(Math.min(fromTimeMax, 86400000 - 1), HOUR23_30MIN);
toTimeMin = Math.min(Math.max(toTimeMin, 1), HOUR23);
toTimeMax = Math.max(Math.min(toTimeMax, 86400000 - 1), HOUR23_30MIN);
return new RequestTimeInfo(requestCallTimeInDayRange, new TimeWindow(fromTimeMin, fromTimeMax), new TimeWindow(
toTimeMin, toTimeMax));
}
private long generateTime(long time) {
return (long) (random.nextDouble() * time);
}
protected GPSPositionGenerator createGPSPositionGenerator(File osmMap, GPSPositionGeneratorFactory positionGeneratorFactory) {
OsmDataGetter osmDataGetter = OsmDataGetter.createOsmDataGetter(osmMap);
Bounds bounds = OSMBoundsUtil.computeBoundsOfSimulationWorld(osmDataGetter);
double maxLon = bounds.getMax().lon();
double minLon = bounds.getMin().lon();
double maxLat = bounds.getMax().lat();
double minLat = bounds.getMin().lat();
return positionGeneratorFactory.createGPSPositionGenerator(minLon, minLat, maxLon, maxLat);
}
protected Injector createInjector(String benchmarkDir, File osmMap) {
try {
Injector injector = Guice.createInjector();
// select the benchmark directory
File experiment = new File(benchmarkDir);
ConfigReader scenario = ConfigReader.initConfigReader(new File(experiment, "config/scenario.groovy").toURL());
// extract the filenames from scenario.groovy config file
int epsg = scenario.getIntegerValueFromConfig("epsg");
String vehicledatamodelPath = scenario.getStringValueFromConfig("vehicledatamodelPath");
TestbedMapInit mapInitFactory = new TestbedMapInit(epsg);
osmDTO = mapInitFactory.initMap(osmMap, injector);
EventProcessor eventProcessor = new EventProcessor();
injector = injector.createChildInjector(new AgentPolisEnvironmentModule(
eventProcessor, new Random(4),
osmDTO.graphByType, osmDTO.nodesFromAllGraphs));
List<InitModuleFactory> initModuleFactories = new ArrayList<>();
initModuleFactories.add(new VehicleDataModelModulFactory(new File(vehicledatamodelPath)));
initModuleFactories.add(new NearestNodeInitModuleFactory(epsg));
initModuleFactories.add(new TestbedPlannerModuleFactory());
injector = injector.createChildInjector(new TestbedEnvironmentModul(eventProcessor));
// add agents into the environment
// List<AgentInitFactory> agentInits = new ArrayList<>();
// agentInits.add(new DriverForBenchmarkInitFactory(new File(driverPopulationPath)));
for (InitModuleFactory initFactory : initModuleFactories) {
AbstractModule module = initFactory.injectModule(injector);
injector = injector.createChildInjector(module);
}
// initModuleFactories.add(new DispatchingAndTimersInitFactory());
// initialize the dispatching and timers
return injector;
} catch (Exception e) {
System.out.println(e.toString());
return null;
}
}
}