All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.rinde.rinsim.pdptw.common.StatsTracker Maven / Gradle / Ivy

There is a newer version: 4.4.6
Show newest version
/*
 * Copyright (C) 2011-2016 Rinde van Lon, iMinds-DistriNet, KU Leuven
 *
 * 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 com.github.rinde.rinsim.pdptw.common;

import static com.github.rinde.rinsim.core.model.pdp.PDPModel.PDPModelEventType.END_DELIVERY;
import static com.github.rinde.rinsim.core.model.pdp.PDPModel.PDPModelEventType.END_PICKUP;
import static com.github.rinde.rinsim.core.model.pdp.PDPModel.PDPModelEventType.NEW_PARCEL;
import static com.github.rinde.rinsim.core.model.pdp.PDPModel.PDPModelEventType.NEW_VEHICLE;
import static com.github.rinde.rinsim.core.model.pdp.PDPModel.PDPModelEventType.START_DELIVERY;
import static com.github.rinde.rinsim.core.model.pdp.PDPModel.PDPModelEventType.START_PICKUP;
import static com.github.rinde.rinsim.core.model.road.GenericRoadModel.RoadEventType.MOVE;
import static com.github.rinde.rinsim.core.model.time.Clock.ClockEventType.STARTED;
import static com.github.rinde.rinsim.core.model.time.Clock.ClockEventType.STOPPED;
import static com.github.rinde.rinsim.scenario.ScenarioController.EventType.SCENARIO_EVENT;
import static com.github.rinde.rinsim.scenario.ScenarioController.EventType.SCENARIO_FINISHED;
import static com.github.rinde.rinsim.scenario.ScenarioController.EventType.SCENARIO_STARTED;
import static com.google.common.base.Verify.verify;
import static com.google.common.collect.Maps.newLinkedHashMap;

import java.util.Map;

import com.github.rinde.rinsim.core.model.DependencyProvider;
import com.github.rinde.rinsim.core.model.Model.AbstractModelVoid;
import com.github.rinde.rinsim.core.model.ModelBuilder.AbstractModelBuilder;
import com.github.rinde.rinsim.core.model.pdp.PDPModel;
import com.github.rinde.rinsim.core.model.pdp.PDPModel.PDPModelEventType;
import com.github.rinde.rinsim.core.model.pdp.PDPModelEvent;
import com.github.rinde.rinsim.core.model.pdp.Parcel;
import com.github.rinde.rinsim.core.model.pdp.Vehicle;
import com.github.rinde.rinsim.core.model.road.GenericRoadModel.RoadEventType;
import com.github.rinde.rinsim.core.model.road.MoveEvent;
import com.github.rinde.rinsim.core.model.road.MovingRoadUser;
import com.github.rinde.rinsim.core.model.road.RoadModel;
import com.github.rinde.rinsim.core.model.time.Clock;
import com.github.rinde.rinsim.core.model.time.Clock.ClockEventType;
import com.github.rinde.rinsim.event.Event;
import com.github.rinde.rinsim.event.EventAPI;
import com.github.rinde.rinsim.event.EventDispatcher;
import com.github.rinde.rinsim.event.Listener;
import com.github.rinde.rinsim.geom.Point;
import com.github.rinde.rinsim.scenario.ScenarioController;
import com.github.rinde.rinsim.scenario.ScenarioController.ScenarioEvent;
import com.github.rinde.rinsim.scenario.TimeOutEvent;
import com.google.auto.value.AutoValue;

/**
 * This class tracks statistics in a simulation.
 *
 * 

* Model properties *

    *
  • Provides: {@link StatisticsProvider}.
  • *
  • Dependencies: {@link ScenarioController}, {@link Clock}, * {@link RoadModel}, {@link PDPModel}.
  • *
* @author Rinde van Lon */ public final class StatsTracker extends AbstractModelVoid implements StatisticsProvider { final EventDispatcher eventDispatcher; final TheListener theListener; final Clock clock; final RoadModel roadModel; enum StatisticsEventType { PICKUP_TARDINESS, DELIVERY_TARDINESS, ALL_VEHICLES_AT_DEPOT; } StatsTracker(ScenarioController scenContr, Clock c, RoadModel rm, PDPModel pm) { clock = c; roadModel = rm; eventDispatcher = new EventDispatcher(StatisticsEventType.values()); theListener = new TheListener(); scenContr.getEventAPI().addListener(theListener, SCENARIO_STARTED, SCENARIO_FINISHED, SCENARIO_EVENT); roadModel.getEventAPI().addListener(theListener, MOVE); clock.getEventAPI().addListener(theListener, STARTED, STOPPED); pm.getEventAPI() .addListener(theListener, START_PICKUP, END_PICKUP, START_DELIVERY, END_DELIVERY, NEW_PARCEL, NEW_VEHICLE); } EventAPI getEventAPI() { return eventDispatcher.getPublicEventAPI(); } /** * @return A {@link StatisticsDTO} with the current simulation stats. */ @Override public StatisticsDTO getStatistics() { final int vehicleBack = theListener.lastArrivalTimeAtDepot.size(); long overTime = 0; if (theListener.simFinish) { for (final Long time : theListener.lastArrivalTimeAtDepot.values()) { if (time - theListener.scenarioEndTime > 0) { overTime += time - theListener.scenarioEndTime; } } } long compTime = theListener.computationTime; if (compTime == 0) { compTime = System.currentTimeMillis() - theListener.startTimeReal; } return new StatisticsDTO(theListener.totalDistance, theListener.totalPickups, theListener.totalDeliveries, theListener.totalParcels, theListener.acceptedParcels, theListener.pickupTardiness, theListener.deliveryTardiness, compTime, clock.getCurrentTime(), theListener.simFinish, vehicleBack, overTime, theListener.totalVehicles, theListener.distanceMap.size(), clock.getTimeUnit(), roadModel.getDistanceUnit(), roadModel.getSpeedUnit()); } @Override public U get(Class clazz) { return clazz.cast(this); } /** * @return A new {@link Builder} instance. */ public static Builder builder() { return new AutoValue_StatsTracker_Builder(); } class TheListener implements Listener { private static final double MOVE_THRESHOLD = 0.0001; // parcels protected int totalParcels; protected int acceptedParcels; // vehicles protected int totalVehicles; protected final Map distanceMap; protected double totalDistance; protected final Map lastArrivalTimeAtDepot; protected int totalPickups; protected int totalDeliveries; protected long pickupTardiness; protected long deliveryTardiness; // simulation protected long startTimeReal; protected long startTimeSim; protected long computationTime; protected long simulationTime; protected boolean simFinish; protected long scenarioEndTime; TheListener() { totalParcels = 0; acceptedParcels = 0; totalVehicles = 0; distanceMap = newLinkedHashMap(); totalDistance = 0d; lastArrivalTimeAtDepot = newLinkedHashMap(); totalPickups = 0; totalDeliveries = 0; pickupTardiness = 0; deliveryTardiness = 0; simFinish = false; } @Override public void handleEvent(Event e) { if (e.getEventType() == ClockEventType.STARTED) { startTimeReal = System.currentTimeMillis(); startTimeSim = clock.getCurrentTime(); computationTime = 0; } else if (e.getEventType() == ClockEventType.STOPPED) { computationTime = System.currentTimeMillis() - startTimeReal; simulationTime = clock.getCurrentTime() - startTimeSim; } else if (e.getEventType() == RoadEventType.MOVE) { verify(e instanceof MoveEvent); final MoveEvent me = (MoveEvent) e; increment((MovingRoadUser) me.roadUser, me.pathProgress.distance() .getValue() .doubleValue()); totalDistance += me.pathProgress.distance().getValue().doubleValue(); // if we are closer than 10 cm to the depot, we say we are 'at' // the depot if (Point.distance(me.roadModel.getPosition(me.roadUser), ((Vehicle) me.roadUser).getStartPosition()) < MOVE_THRESHOLD) { // only override time if the vehicle did actually move if (me.pathProgress.distance().getValue() .doubleValue() > MOVE_THRESHOLD) { lastArrivalTimeAtDepot.put((MovingRoadUser) me.roadUser, clock.getCurrentTime()); if (totalVehicles == lastArrivalTimeAtDepot.size()) { eventDispatcher.dispatchEvent(new Event( StatisticsEventType.ALL_VEHICLES_AT_DEPOT, this)); } } } else { lastArrivalTimeAtDepot.remove(me.roadUser); } } else if (e.getEventType() == PDPModelEventType.START_PICKUP) { verify(e instanceof PDPModelEvent); final PDPModelEvent pme = (PDPModelEvent) e; final Parcel p = pme.parcel; final Vehicle v = pme.vehicle; assert p != null; assert v != null; final long latestBeginTime = p.getPickupTimeWindow().end() - p.getPickupDuration(); if (pme.time > latestBeginTime) { final long tardiness = pme.time - latestBeginTime; pickupTardiness += tardiness; eventDispatcher.dispatchEvent(new StatisticsEvent( StatisticsEventType.PICKUP_TARDINESS, this, p, v, tardiness, pme.time)); } } else if (e.getEventType() == PDPModelEventType.END_PICKUP) { totalPickups++; } else if (e.getEventType() == PDPModelEventType.START_DELIVERY) { final PDPModelEvent pme = (PDPModelEvent) e; final Parcel p = pme.parcel; final Vehicle v = pme.vehicle; assert p != null; assert v != null; final long latestBeginTime = p.getDeliveryTimeWindow().end() - p.getDeliveryDuration(); if (pme.time > latestBeginTime) { final long tardiness = pme.time - latestBeginTime; deliveryTardiness += tardiness; eventDispatcher.dispatchEvent(new StatisticsEvent( StatisticsEventType.DELIVERY_TARDINESS, this, p, v, tardiness, pme.time)); } } else if (e.getEventType() == PDPModelEventType.END_DELIVERY) { totalDeliveries++; } else if (e.getEventType() == SCENARIO_EVENT) { final ScenarioEvent se = (ScenarioEvent) e; if (se.getTimedEvent() instanceof AddParcelEvent) { totalParcels++; } else if (se.getTimedEvent() instanceof AddVehicleEvent) { totalVehicles++; } else if (se.getTimedEvent() instanceof TimeOutEvent) { simFinish = true; scenarioEndTime = se.getTimedEvent().getTime(); } } else if (e.getEventType() == NEW_PARCEL) { // pdp model event acceptedParcels++; } else if (e.getEventType() == NEW_VEHICLE) { verify(e instanceof PDPModelEvent); final PDPModelEvent ev = (PDPModelEvent) e; lastArrivalTimeAtDepot.put(ev.vehicle, clock.getCurrentTime()); } else { // currently not handling fall throughs } } protected void increment(MovingRoadUser mru, double num) { if (!distanceMap.containsKey(mru)) { distanceMap.put(mru, num); } else { distanceMap.put(mru, distanceMap.get(mru) + num); } } } static class StatisticsEvent extends Event { final Parcel parcel; final Vehicle vehicle; final long tardiness; final long time; StatisticsEvent(Enum type, Object pIssuer, Parcel p, Vehicle v, long tar, long tim) { super(type, pIssuer); parcel = p; vehicle = v; tardiness = tar; time = tim; } } /** * Builder for creating {@link StatsTracker} instance. * @author Rinde van Lon */ @AutoValue public abstract static class Builder extends AbstractModelBuilder { Builder() { setDependencies(ScenarioController.class, Clock.class, RoadModel.class, PDPModel.class); setProvidingTypes(StatisticsProvider.class); } @Override public StatsTracker build(DependencyProvider dependencyProvider) { final ScenarioController ctrl = dependencyProvider .get(ScenarioController.class); final Clock clck = dependencyProvider.get(Clock.class); final RoadModel rm = dependencyProvider.get(RoadModel.class); final PDPModel pm = dependencyProvider.get(PDPModel.class); return new StatsTracker(ctrl, clck, rm, pm); } } }