/** * */ package eu.quanticol.carma.examples.bikesharing; import org.apache.commons.math3.random.RandomGenerator; import org.cmg.ml.sam.sim.SimulationEnvironment; import org.cmg.ml.sam.sim.sampling.Measure; import org.cmg.ml.sam.sim.sampling.SamplingCollection; import org.cmg.ml.sam.sim.sampling.StatisticSampling; import eu.quanticol.carma.simulator.CarmaComponent; import eu.quanticol.carma.simulator.CarmaSequentialProcess; import eu.quanticol.carma.simulator.CarmaStore; import eu.quanticol.carma.simulator.CarmaSystem; /** * @author loreti * */ public class BikeSharing extends CarmaSystem { public static final int ZONES = 4; public static final int TAKE_BIKE = 0; public static final int RETURN_BIKE = 1; public static final int MOVE = 2; public static final int STOP = 3; public static final int RESTART = 4; public static final double MOVE_RATE = 0.1; public static final double STOP_RATE = 0.1; public static final double RESTART_RATE = 1.0; public static final double TAKE_BIKE_RATE = 1.0; public static final double RETURN_BIKE_RATE = 1.0; public static final int PEDESTRIAN = 0; public static final int BIKER = 1; public BikeSharing(int bikers, int pedestrians , int parking_stations , int bikes , int slots ) { super(); for( int i=0 ; i<bikers ; i++ ) { CarmaComponent c = getBiker( i%ZONES ); addComponent( c ); } for( int i=0 ; i<pedestrians ; i++ ) { CarmaComponent c = getPedestrian( i%ZONES ); addComponent( c ); } for( int i=0 ; i<ZONES ; i++ ) { for( int j=0 ; j<parking_stations ; j++ ) { addComponent(getParkingStation(i, bikes, slots)); } } } private CarmaComponent getBiker( int zone ) { CarmaComponent c = new CarmaComponent(); c.set("zone", zone ); c.addAgent( new CarmaSequentialProcess(c, BikeSharingDefinitions.UserProcess , "Biker" ) ); c.set( "status" , BikeSharing.BIKER ); return c; } private CarmaComponent getPedestrian( int zone ) { CarmaComponent c = new CarmaComponent(); c.set("zone", zone ); c.addAgent( new CarmaSequentialProcess(c, BikeSharingDefinitions.UserProcess , "Pedestrian" ) ); c.set( "status" , BikeSharing.PEDESTRIAN ); return c; } private CarmaComponent getParkingStation( int zone , int bikes , int slots ) { CarmaComponent c = new CarmaComponent(); c.set("zone", zone ); c.set("slots", slots); c.set("bikes", bikes); c.addAgent(new CarmaSequentialProcess(c, BikeSharingDefinitions.ParkingProcess) ); return c; } @Override public double broadcastProbability(CarmaStore sender, CarmaStore receiver, int action) { return 1.0; //Broadcast input is always received } @Override public double unicastProbability(CarmaStore sender, CarmaStore receiver, int action) { return 1.0; //Input are always received } @Override public double broadcastRate(CarmaStore sender, int action) { if (action == MOVE) { return MOVE_RATE; } if (action == STOP) { return STOP_RATE; } if (action == RESTART) { return RESTART_RATE; } return 0.0; //In this scenario broadcast is not used. } @Override public double unicastRate(CarmaStore sender, int action) { if (action == TAKE_BIKE) { return TAKE_BIKE_RATE; } if (action == RETURN_BIKE) { return RETURN_BIKE_RATE; } return 0; } @Override public void broadcastUpdate(RandomGenerator r , CarmaStore sender, int action, Object value) { } @Override public void unicastUpdate(RandomGenerator r , CarmaStore sender, CarmaStore receiver , int action, Object value ) { } public double averageAvailableBikes(int zone) { double toReturn = 0.0; double count = 0.0; for (CarmaComponent caspaComponent : collective) { Integer cZone = caspaComponent.get("zone", Integer.class); Integer nBikes = caspaComponent.get("bikes", Integer.class); if ((cZone != null)&&(nBikes != null)&&(cZone.intValue()==zone)) { count += 1.0; toReturn += nBikes.intValue(); } } if (count == 0.0) { return 0.0; } return toReturn/count; } public double maxAvailableBikes(int zone) { int toReturn = 0; for (CarmaComponent caspaComponent : collective) { Integer cZone = caspaComponent.get("zone", Integer.class); Integer nBikes = caspaComponent.get("bikes", Integer.class); if ((cZone != null)&&(nBikes != null)&&(cZone.intValue()==zone)) { if (nBikes.intValue()>toReturn) { toReturn = nBikes.intValue(); } } } return toReturn; } public double minAvailableBikes(int zone) { int toReturn = Integer.MAX_VALUE; for (CarmaComponent caspaComponent : collective) { Integer cZone = caspaComponent.get("zone", Integer.class); Integer nBikes = caspaComponent.get("bikes", Integer.class); if ((cZone != null)&&(nBikes != null)&&(cZone.intValue()==zone)) { if (nBikes.intValue()<toReturn) { toReturn = nBikes.intValue(); } } } return toReturn; } public static void main( String[] argv ) { SimulationEnvironment<CarmaSystem> system = new SimulationEnvironment<CarmaSystem>( new BikeSharingFactory(0,160,4,0,10) ); StatisticSampling<CarmaSystem> minBikes = new StatisticSampling<CarmaSystem>(101, 1.0, new MinAvailableBikes(0) ); StatisticSampling<CarmaSystem> maxBikes = new StatisticSampling<CarmaSystem>(101, 1.0, new MaxAvailableBikes(0) ); StatisticSampling<CarmaSystem> averageBikes = new StatisticSampling<CarmaSystem>(101, 1.0, new AverageAvailableBikes(0) ); system.setSampling( new SamplingCollection<CarmaSystem>( minBikes , maxBikes , averageBikes ) ); system.simulate(200,100); minBikes.printTimeSeries(System.out); maxBikes.printTimeSeries(System.out); averageBikes.printTimeSeries(System.out); } public static class MinAvailableBikes implements Measure<CarmaSystem> { private int zone; public MinAvailableBikes( int zone ) { this.zone = zone; } @Override public double measure(CarmaSystem t) { int toReturn = Integer.MAX_VALUE; for (CarmaComponent caspaComponent : t.getCollective()) { Integer cZone = caspaComponent.get("zone", Integer.class); Integer nBikes = caspaComponent.get("bikes", Integer.class); if ((cZone != null)&&(nBikes != null)&&(cZone.intValue()==zone)) { if (nBikes.intValue()<toReturn) { toReturn = nBikes.intValue(); } } } return toReturn; } @Override public String getName() { return "Min Bikes"; } } public static class MaxAvailableBikes implements Measure<CarmaSystem> { private int zone; public MaxAvailableBikes( int zone ) { this.zone = zone; } @Override public double measure(CarmaSystem t) { int toReturn = 0; for (CarmaComponent caspaComponent : t.getCollective()) { Integer cZone = caspaComponent.get("zone", Integer.class); Integer nBikes = caspaComponent.get("bikes", Integer.class); if ((cZone != null)&&(nBikes != null)&&(cZone.intValue()==zone)) { if (nBikes.intValue()>toReturn) { toReturn = nBikes.intValue(); } } } return toReturn; } @Override public String getName() { return "MX Bikes"; } } public static class AverageAvailableBikes implements Measure<CarmaSystem> { private int zone; public AverageAvailableBikes( int zone ) { this.zone = zone; } @Override public double measure(CarmaSystem t) { double toReturn = 0.0; double count = 0.0; for (CarmaComponent caspaComponent : t.getCollective()) { Integer cZone = caspaComponent.get("zone", Integer.class); Integer nBikes = caspaComponent.get("bikes", Integer.class); if ((cZone != null)&&(nBikes != null)&&(cZone.intValue()==zone)) { count += 1.0; toReturn += nBikes.intValue(); } } if (count == 0.0) { return 0.0; } return toReturn/count; } @Override public String getName() { return "MX Bikes"; } } // protected EvaluationContext copy_context = new EvaluationContext() { // // @Override // public double getRate(CaspaStore store, int action, boolean isBroadcast) { // Integer zone = store.get("zone", Integer.class); // if (zone == null) { // return 0; // } // double bikers = 1+getBikersAt( zone ); // double pedestrians = 1+getPedestriansAt( zone ); // switch (action) { // case MOVE: // return (1-(pedestrians/(bikers+pedestrians)))*MOVE_RATE; // case STOP: // return (pedestrians/(bikers+pedestrians))*STOP_RATE; // default: // return 0; // } // } // // @Override // public double getProbability(CaspaStore src, CaspaStore trg, int action, // boolean isBroadcast) { // return 1.0; // } // // }; // // protected EvaluationContext escape_context = new EvaluationContext() { // // @Override // public double getRate(CaspaStore store, int action, boolean isBroadcast) { // Integer zone = store.get("zone", Integer.class); // if (zone == null) { // return 0; // } // double bikers = 1+getBikersAt( zone ); // double pedestrians = 1+getPedestriansAt( zone ); // switch (action) { // case MOVE: // return (pedestrians/(bikers+pedestrians))*MOVE_RATE; // case STOP: // return (bikers/(bikers+pedestrians))*STOP_RATE; // default: // return 0; // } // } // // @Override // public double getProbability(CaspaStore src, CaspaStore trg, int action, // boolean isBroadcast) { // return 1.0; // } // // }; // // protected EvaluationContext random_context = new EvaluationContext() { // // @Override // public double getRate(CaspaStore store, int action, boolean isBroadcast) { // switch (action) { // case MOVE: // return MOVE_RATE; // case STOP: // return STOP_RATE; // default: // return 0; // } // } // // @Override // public double getProbability(CaspaStore src, CaspaStore trg, int action, // boolean isBroadcast) { // return 1.0; // } // // }; // // @Override // protected EvaluationContext getEvaluationContext(CaspaStore store) { // return copy_context; //// return escape_context; //// return random_context; // } protected int getBikersAt(Integer zone) { int toReturn = 0; for (CarmaComponent caspaComponent : collective) { if (zone.equals(caspaComponent.get("zone", Integer.class))) { Integer status = caspaComponent.get("status", Integer.class); if ((status != null)&&(status == BikeSharing.BIKER)) { toReturn++; } } } return toReturn; } protected int getPedestriansAt(Integer zone) { int toReturn = 0; for (CarmaComponent caspaComponent : collective) { if (zone.equals(caspaComponent.get("zone", Integer.class))) { Integer status = caspaComponent.get("status", Integer.class); if ((status != null)&&(status == BikeSharing.PEDESTRIAN)) { toReturn++; } } } return toReturn; } }