From 7a5a5b1bc08c37d68d5a1d9142abad9808727643 Mon Sep 17 00:00:00 2001 From: blk14 Date: Fri, 4 Jun 2021 19:34:07 +0300 Subject: [PATCH 01/10] dynamic routing, malicious behavior, voting system --- src/application/ApplicationType.java | 4 +- src/application/ApplicationUtils.java | 10 +- .../dynamic_routing/CarDynamicRoutingApp.java | 184 ++++++++++++ .../TrafficLightDynamicRoutingApp.java | 278 ++++++++++++++++++ .../dynamic_routing/VotingStreetCostData.java | 221 ++++++++++++++ .../VotingStreetCostDataTest.java | 226 ++++++++++++++ src/controller/network/NetworkWiFi.java | 94 +++++- src/controller/newengine/EngineUtils.java | 68 ++++- .../newengine/SimulationEngine.java | 53 +++- src/downloader/DownloadCore.java | 11 +- src/downloader/Downloader.java | 6 +- src/gui/TrafficLightView.java | 5 + src/model/DynamicRoutes.java | 167 +++++++++++ src/model/GeoCar.java | 273 ++++++++++++++++- src/model/GeoCarRoute.java | 17 +- src/model/OSMgraph/Way.java | 1 + src/model/mobility/MobilityEngine.java | 128 ++++++-- src/model/network/Message.java | 13 +- src/model/network/MessageType.java | 6 +- src/model/network/SourceType.java | 6 + src/model/parameters/Globals.java | 27 +- .../personality/MaliciousPersonality.java | 80 +++++ src/model/personality/PersonalityTypes.java | 8 + src/utils/StreetsCostSharing.java | 267 +++++++++++++++++ src/utils/StreetsCostSharingMalicious.java | 77 +++++ 25 files changed, 2156 insertions(+), 74 deletions(-) create mode 100644 src/application/dynamic_routing/CarDynamicRoutingApp.java create mode 100644 src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java create mode 100644 src/application/dynamic_routing/VotingStreetCostData.java create mode 100644 src/application/dynamic_routing/VotingStreetCostDataTest.java create mode 100644 src/model/DynamicRoutes.java create mode 100644 src/model/network/SourceType.java create mode 100644 src/model/personality/MaliciousPersonality.java create mode 100644 src/model/personality/PersonalityTypes.java create mode 100644 src/utils/StreetsCostSharing.java create mode 100644 src/utils/StreetsCostSharingMalicious.java diff --git a/src/application/ApplicationType.java b/src/application/ApplicationType.java index 32cc6ac..fe1f48e 100644 --- a/src/application/ApplicationType.java +++ b/src/application/ApplicationType.java @@ -8,5 +8,7 @@ public enum ApplicationType { ROUTING_APP, // the smart Navigator application STREET_VISITS_APP, // application that records the streets visit count TRAFFIC_LIGHT_CONTROL_APP, - SYNCHRONIZE_INTERSECTIONS_APP // app that syncronize traffic lights in multiple intersections + SYNCHRONIZE_INTERSECTIONS_APP, // app that syncronize traffic lights in multiple intersections + TRAFFIC_LIGHT_ROUTING_APP, + CAR_ROUTING_APP } diff --git a/src/application/ApplicationUtils.java b/src/application/ApplicationUtils.java index 59e5297..ac9e17a 100644 --- a/src/application/ApplicationUtils.java +++ b/src/application/ApplicationUtils.java @@ -2,6 +2,8 @@ import java.util.Vector; +import application.dynamic_routing.CarDynamicRoutingApp; +import application.dynamic_routing.TrafficLightDynamicRoutingApp; import controller.engine.EngineSimulation; import controller.newengine.SimulationEngine; import application.multipleIntersections.SynchronizeIntersectionsApplication; @@ -38,6 +40,9 @@ public static Application activateApplicationCar( ApplicationType type, GeoCar c return EngineSimulation.getInstance() != null ? new TileApplicationCar(car) : null; case STREET_VISITS_APP: return SimulationEngine.getInstance() != null ? new StreetVisitsApplication(car) : null; + + case CAR_ROUTING_APP: + return SimulationEngine.getInstance() != null ? new CarDynamicRoutingApp(true, car, ApplicationType.CAR_ROUTING_APP) : null; default: return null; } @@ -54,6 +59,9 @@ public static Application activateApplicationTrafficLight( ApplicationType type, switch (type) { case TRAFFIC_LIGHT_CONTROL_APP: return SimulationEngine.getInstance() != null ? new ApplicationTrafficLightControl(trafficLight) : null; + + case TRAFFIC_LIGHT_ROUTING_APP: + return SimulationEngine.getInstance() != null ? new TrafficLightDynamicRoutingApp(true, trafficLight) : null; default: return null; } @@ -94,7 +102,7 @@ public static Application activateApplicationServer( ApplicationType type, GeoSe } /** - * @param netInterfaces - String with active Applications + * @param //(netInterfaces) - String with active Applications */ public static void parseApplications(String activeApplications) { String activeApps[] = activeApplications.split(","); diff --git a/src/application/dynamic_routing/CarDynamicRoutingApp.java b/src/application/dynamic_routing/CarDynamicRoutingApp.java new file mode 100644 index 0000000..9f371e5 --- /dev/null +++ b/src/application/dynamic_routing/CarDynamicRoutingApp.java @@ -0,0 +1,184 @@ +package application.dynamic_routing; + +import application.Application; +import application.ApplicationType; +import controller.network.NetworkInterface; +import controller.network.NetworkType; +import model.GeoCar; +import model.mobility.MobilityEngine; +import model.network.Message; +import model.network.MessageType; +import model.parameters.Globals; +import utils.StreetsCostSharing; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +public class CarDynamicRoutingApp extends Application { + + private boolean isActive; + private GeoCar car; + private ApplicationType type; + private MobilityEngine mobilityEngine; + + public CarDynamicRoutingApp(boolean isActive, GeoCar car, ApplicationType type) { + this.isActive = isActive; + this.car = car; + this.type = type; + this.mobilityEngine = MobilityEngine.getInstance(); + } + + @Override + public boolean getStatus() { + return false; + } + + @Override + public String run() { + NetworkInterface net = car.getNetworkInterface(NetworkType.Net_WiFi); + net.processOutputQueue(); + return ""; + } + + @Override + public String stop() { + return null; + } + + @Override + public String getInfoApp() { + return null; + } + + @Override + public Object getData() { + return null; + } + + @Override + public ApplicationType getType() { + return type; + } + + + public void sendOutdatedDataToTrafficLight(HashMap outdated, long destinationTrafficLightId) { + NetworkInterface networkInterface = this.car.getNetworkInterface(NetworkType.Net_WiFi); + Message message = new Message(this.car.getId(), destinationTrafficLightId, outdated.clone(), + MessageType.OUTDATED_COSTS, ApplicationType.TRAFFIC_LIGHT_ROUTING_APP); + networkInterface.putMessage(message); + } + + + public void sendOutdatedDataToCar(HashMap outdated, long neighbourCarId) { + NetworkInterface networkInterface = this.car.getNetworkInterface(NetworkType.Net_WiFi); + Message message = new Message(this.car.getId(), neighbourCarId, outdated.clone(), + MessageType.OUTDATED_COSTS, ApplicationType.CAR_ROUTING_APP); + networkInterface.putMessage(message); + } + + + public boolean isOutdated(double oldCost, double updateCost, long currentWayId, VotingStreetCostData votingStreetCostData) { + boolean returnValue = true; + + /* if the cost itself is new for the car's KB*/ + if (Math.abs(oldCost - updateCost) > + (oldCost * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { + returnValue = false; + } + + /*if the cost does not have any new stamp cases: + * has new stamps -> not outdated + * does not have -> is outdated + * it is a new cost to share -> not outdated*/ + + if (returnValue && Globals.useVotingSystem) { + if (this.car.getStreetsCostSharing().getStreetUpdates().containsKey(currentWayId)) { + boolean hasNewStamps = this.car.getStreetsCostSharing().getStreetUpdates() + .get(currentWayId).hasNewStamps(votingStreetCostData); + returnValue = !hasNewStamps; + } else { + returnValue = false; + } + } + + return returnValue; + } + + + /* this function has the role to iterate through the reported costs and to + * split them in valid data or outdated data (outdated data is useful only + * in CARS communication context)*/ + private ArrayList> updatesPreProcessing(Message m) { + HashMap updates; + HashMap validUpdates = new HashMap(); + HashMap outdatedUpdates = new HashMap(); + Iterator itr; + + updates = (HashMap) m.getData(); + itr = updates.keySet().iterator(); + long currentWayId; + double oldCost, updateCost; + + while (itr.hasNext()) { + currentWayId = itr.next(); + oldCost = car.getStreetsCostSharing().getWayCost(mobilityEngine.getWay(currentWayId)); + updateCost = updates.get(currentWayId).streetCost; + + /*check outdated*/ + if (!isOutdated(oldCost, updateCost, currentWayId, updates.get(currentWayId))) { + + car.getStreetsCostSharing().updateWayCost(currentWayId, updates.get(currentWayId)); + + /*validUpdates will be useful when I'll add the validation policy*/ + validUpdates.put(currentWayId, updates.get(currentWayId)); + + } else { + outdatedUpdates.put(currentWayId, updates.get(currentWayId)); + } + } + ArrayList> aux = new ArrayList>(); + aux.add(validUpdates); + aux.add(outdatedUpdates); + return aux; + } + + + @Override + public void process(Message m) { + ArrayList> aux; + HashMap outdated; + + switch (m.getType()) { + case TRAFFIC_LIGHT_INFORMS: + + aux = updatesPreProcessing(m); + outdated = aux.get(1); + + /*if there is some outdated data, inform the traffic light*/ + if (!outdated.isEmpty()) { + sendOutdatedDataToTrafficLight(outdated, m.getSourceId()); + } + + break; + + case CAR_INFORMS: + /*some other car informs current car*/ + + aux = updatesPreProcessing(m); + outdated = aux.get(1); + + if (!outdated.isEmpty()) { + sendOutdatedDataToCar(outdated, m.getSourceId()); + } + break; + + case OUTDATED_COSTS: + + HashMap outdatedUpdates = (HashMap) m.getData(); + this.car.getStreetsCostSharing().removeOutdatedInfo(outdatedUpdates); + + break; + } + } +} diff --git a/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java b/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java new file mode 100644 index 0000000..12aff85 --- /dev/null +++ b/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java @@ -0,0 +1,278 @@ +package application.dynamic_routing; + +import application.Application; +import application.ApplicationType; +import controller.network.NetworkInterface; +import controller.network.NetworkType; +import controller.network.NetworkWiFi; +import model.GeoTrafficLightMaster; +import model.OSMgraph.Node; +import model.OSMgraph.Way; +import model.mobility.MobilityEngine; +import model.network.Message; +import model.network.MessageType; +import utils.StreetsCostSharing; +import utils.tracestool.Utils; + + +import java.util.*; + +public class TrafficLightDynamicRoutingApp extends Application { + private boolean isActive; + private GeoTrafficLightMaster trafficLightMaster; + private ApplicationType type; + private MobilityEngine mobilityEngine; + private HashMap streetGraphCost; + private HashMap streetUpdatesToCars; + private HashMap closestTrafficLightsMap; + private NetworkWiFi networkInterface; + + public static final int NORTH_INDEX = 0; + public static final int SOUTH_INDEX = 1; + public static final int EAST_INDEX = 2; + public static final int WEST_INDEX = 3; + + + + public TrafficLightDynamicRoutingApp(boolean isActive, GeoTrafficLightMaster trafficLightMaster) { + this.isActive = isActive; + this.trafficLightMaster = trafficLightMaster; + mobilityEngine = MobilityEngine.getInstance(); + type = ApplicationType.TRAFFIC_LIGHT_ROUTING_APP; + streetGraphCost = new HashMap(); + + /*this structure has the role to keep track of the latest updates*/ + streetUpdatesToCars = new HashMap(); + } + + public void postConstructInit() { + networkInterface = (NetworkWiFi) trafficLightMaster.getNetworkInterface(NetworkType.Net_WiFi); + closestTrafficLightsMap = networkInterface.discoverClosestTrafficLightsGeographic(); + } + + + public double getWayCost(Way way) { + double streetCost; + + if (!streetGraphCost.containsKey(way.id)) { + Node firstNode = way.nodes.firstElement(); + Node lastNode = way.nodes.lastElement(); + + double streetLength = Utils.getRealDistanceAB(way, firstNode.id, lastNode.id); + streetCost = streetLength / (way.getMaximumSpeed() - 3); + streetGraphCost.put(way.id, streetCost); + + } else { + streetCost = streetGraphCost.get(way.id); + } + return streetCost; + } + + @Override + public boolean getStatus() { + return isActive; + } + +// this function is called periodically from Simulation Engine (to send the messages from outputQueue) + @Override + public String run() { + NetworkInterface net = trafficLightMaster.getNetworkInterface(NetworkType.Net_WiFi); + net.processOutputQueue(); + return ""; + } + + @Override + public String stop() { + return null; + } + + @Override + public String getInfoApp() { + return null; + } + + @Override + public Object getData() { + return null; + } + + @Override + public ApplicationType getType() { + return type; + } + + private void sendUpdatesToCar(long destinationCarId) { + Message message = new Message(this.trafficLightMaster.getId(), destinationCarId, this.streetUpdatesToCars.clone(), + MessageType.TRAFFIC_LIGHT_INFORMS, ApplicationType.CAR_ROUTING_APP); + + this.networkInterface.putMessage(message); + } + + + private void spreadUpdatesToNeighbours(HashMap validUpdates, long sourceId){ + + Iterator it = closestTrafficLightsMap.entrySet().iterator(); + long neighbourTrafficLightId; + int neighbourDirection; + Random rand = new Random(); + int stepOver1 = rand.nextInt(closestTrafficLightsMap.size()); + int stepOver2 = rand.nextInt(closestTrafficLightsMap.size()); + + if (stepOver1 == stepOver2) { + stepOver2 = (stepOver1 + 1) % closestTrafficLightsMap.size(); + } + + if (closestTrafficLightsMap.size() < 4) { + stepOver2 = -1; + } + + int i = -1; + int sents = 0; + while (it.hasNext()) { + i++; + Map.Entry pair = (Map.Entry) it.next(); + neighbourDirection = (int) pair.getKey(); + neighbourTrafficLightId = ((NetworkInterface) pair.getValue()).getOwner().getId(); + + if (neighbourTrafficLightId == sourceId) { + continue; + } + +// if (i == stepOver1 || i == stepOver2) { +// continue; +// } + + /** to reduce the cpu consumption uncomment it, and comment the ones above*/ + if (i != stepOver1) continue; + + Message message = new Message(this.trafficLightMaster.getId(), neighbourTrafficLightId, + validUpdates.clone(), MessageType.TRAFFIC_LIGHT_INFORMS, ApplicationType.TRAFFIC_LIGHT_ROUTING_APP); + message.setMessageDirection(neighbourDirection); + sents++; + + this.networkInterface.putMessage(message); + + } + } + + private void sendBackOutdatedUpdates(HashMap outdatedUpdates, + long destinationId) { + Message message = new Message(this.trafficLightMaster.getId(), destinationId, outdatedUpdates.clone(), + MessageType.OUTDATED_COSTS, ApplicationType.CAR_ROUTING_APP); + this.networkInterface.putMessage(message); + } + + + /* this function has the role to iterate through the reported costs and to + * split them in valid data or outdated data (outdated data is useful only + * in CARS communication context*/ + private ArrayList> updatesPreProcessing(Message m) { + HashMap updates; + HashMap validUpdates = new HashMap(); + HashMap outdatedUpdates = new HashMap(); + Iterator itr; + + updates = (HashMap) m.getData(); + itr = updates.keySet().iterator(); + long currentWayId; + double oldCost, updateCost; + + while (itr.hasNext()) { + currentWayId = itr.next(); + oldCost = getWayCost(mobilityEngine.getWay(currentWayId)); + updateCost = updates.get(currentWayId).getStreetCost(); + + /*check if that cost is new and update, otherwise report it as outdated*/ + if (Math.abs(oldCost - updateCost) > + (oldCost * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { + streetGraphCost.put(currentWayId, updateCost); + + /*validUpdates will be useful when I'll add the validation policy*/ + validUpdates.put(currentWayId, updates.get(currentWayId)); + + /*put the news in the structure responsible for sharing with the cars*/ + streetUpdatesToCars.put(currentWayId, updates.get(currentWayId)); + } else { + /* inform the car that this message is outdated, so put the data into a map to be sent*/ + if (m.getType() == MessageType.CAR_INFORMS) + outdatedUpdates.put(currentWayId, updates.get(currentWayId)); + } + } + ArrayList> aux = new ArrayList>(); + aux.add(validUpdates); + aux.add(outdatedUpdates); + return aux; + } + + + @Override + public void process(Message m) { + HashMap validUpdates; + HashMap outdatedUpdates; + ArrayList> aux; + Iterator itr; + + switch (m.getType()) { + case CAR_INFORMS: + + /* send back some updates*/ + if (!this.streetUpdatesToCars.isEmpty()) { + sendUpdatesToCar(m.getSourceId()); + } + + aux = updatesPreProcessing(m); + validUpdates = aux.get(0); + outdatedUpdates = aux.get(1); + + /* spread this update to the neighbours (traffic lights) and inform the car about outdated data*/ + if (!validUpdates.isEmpty()) { + spreadUpdatesToNeighbours(validUpdates, m.getSourceId()); + } + + if (!outdatedUpdates.isEmpty()) { + sendBackOutdatedUpdates(outdatedUpdates, m.getSourceId()); + } + break; + + case TRAFFIC_LIGHT_INFORMS: + + aux = updatesPreProcessing(m); + validUpdates = aux.get(0); + + /*it's not necessary to send outdated data because the traffic lights spread + * the message only to the closest neighbours. If the message is outdated, + * the current traffic light does not spread it anymore... + * */ + if (!validUpdates.isEmpty()) { + spreadUpdatesToNeighbours(validUpdates, m.getSourceId()); + } + + break; + + /* this type of message is only received from cars*/ + case OUTDATED_COSTS: + + /* remove outdated updates*/ + outdatedUpdates = (HashMap) m.getData(); + itr = outdatedUpdates.keySet().iterator(); + long currentWayId; + double currentUpdateCost; + double outdatedCost; + + while (itr.hasNext()) { + currentWayId = itr.next(); + currentUpdateCost = streetUpdatesToCars.get(currentWayId).getStreetCost(); + outdatedCost = outdatedUpdates.get(currentWayId).getStreetCost(); + + /*check if the currentUpdateCost has been modified before receiving this update + * regarding outdated cost. So, if the difference between this 2 costs is smaller than THRESHOLD, + * there has been an update over this cost so it is not outdated anymore*/ + if (Math.abs(currentUpdateCost - outdatedCost) < + (currentUpdateCost * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { + streetUpdatesToCars.remove(currentWayId); + } + } + break; + } + } +} diff --git a/src/application/dynamic_routing/VotingStreetCostData.java b/src/application/dynamic_routing/VotingStreetCostData.java new file mode 100644 index 0000000..62ea99b --- /dev/null +++ b/src/application/dynamic_routing/VotingStreetCostData.java @@ -0,0 +1,221 @@ +package application.dynamic_routing; + +import utils.StreetsCostSharing; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + + +public class VotingStreetCostData { + double streetCost; + boolean firstVotingSession; + + /*each cost should be stamped by multiple entities before taking it into consideration + * there could be multiple costs reported for the same street, so we need + * to keep track of each cost ant its stamps in order to make the best updated decision*/ + HashMap> costVotingMap; + + public int UPPER_DYNAMIC_VOTING_THRESHOLD = 2; + public int LOWER_DYNAMIC_VOTING_THRESHOLD = 2; + + public HashMap> getCostVotingMap() { + return costVotingMap; + } + + public void setCostVotingMap(HashMap> costVotingMap) { + this.costVotingMap = costVotingMap; + } + + public VotingStreetCostData(double cost, long discovererStamp) { + this.costVotingMap = new HashMap>(); + HashSet stamps = new HashSet(); + stamps.add(discovererStamp); + this.costVotingMap.put(cost, stamps); + this.streetCost = cost; + this.firstVotingSession = true; + } + + public double getStreetCost() { + return streetCost; + } + + public void setStreetCost(double streetCost) { + this.streetCost = streetCost; + } + + /** make sure to add a stamp to the correct cost + * if a similar cost is not found, create another slot*/ + public void addDiscovererStamp(double cost, Long stamp) { + HashSet stamps; + Iterator it = costVotingMap.keySet().iterator(); + + while(it.hasNext()) { + double currentCost = it.next(); + + if (VotingStreetCostData.isTheSameStreetCost(currentCost, cost)) { + stamps = costVotingMap.get(currentCost); + stamps.add(stamp); + return; + } + } + stamps = new HashSet(); + stamps.add(stamp); + costVotingMap.put(cost, stamps); + } + + public boolean isValidated(double cost, int votingThreshold) { + + if (costVotingMap.get(cost).size() >= votingThreshold) { + return true; + } + return false; + } + + + public static boolean isTheSameStreetCost(double c1, double c2) { + if (Math.abs(c1 - c2) < + (c1 * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { + return true; + } + return false; + } + + + /** this method is useful in CarDynamicRoutingApp, at outdated checking. It returns + * if there are new stamps in the param object for a specific cost*/ + public boolean hasNewStamps(VotingStreetCostData votingStreetCostData) { + double paramCost = votingStreetCostData.getStreetCost(); + double costReference = -1; + boolean hasTheCost = false; + Iterator costIt = this.costVotingMap.keySet().iterator(); + + /*check if the cost exists*/ + while (costIt.hasNext()) { + double currentCost = costIt.next(); + + if (VotingStreetCostData.isTheSameStreetCost(currentCost, paramCost)) { + hasTheCost = true; + /*keep the value of the current cost to refer the cost in the current Object + * it could be slightly different*/ + costReference = currentCost; + break; + } + } + + if (!hasTheCost) return false; + + Iterator it = votingStreetCostData.getCostVotingMap().get(paramCost).iterator(); + long currentStamp; + + /*check each stamp*/ + while (it.hasNext()) { + currentStamp = it.next(); + + if (!this.costVotingMap.get(costReference).contains(currentStamp)) { + return true; + } + } + return false; + } + + /** add new costs with stamps, or add new stamps to the existing costs*/ + public void addNewStamps(VotingStreetCostData votingStreetCostData) { + Iterator costIterator = votingStreetCostData.getCostVotingMap().keySet().iterator(); + + while (costIterator.hasNext()) { + double currentCost = costIterator.next(); + + Iterator stampIterator = votingStreetCostData.getCostVotingMap().get(currentCost).iterator(); + long currentStamp; + + /*if the cost is not present into the Map, add the cost and its stamps from the param object*/ + if (!this.costVotingMap.containsKey(currentCost)) { + costVotingMap.put(currentCost, votingStreetCostData.getCostVotingMap().get(currentCost)); + } else { + /*iterate through stamps and add the new ones*/ + while (stampIterator.hasNext()) { + currentStamp = stampIterator.next(); + + if (!this.costVotingMap.get(currentCost).contains(currentStamp)) { + this.costVotingMap.get(currentCost).add(currentStamp); + } + } + } + + } + } + + /* check if there is a cost in the voting session that is over the threshold + * there are 2 cases: + * - an increased report + * - an decreased report + * The threshold is dynamically changed depending on the report type*/ + public boolean isStreetCostUpdated() { + Iterator costIterator = this.costVotingMap.keySet().iterator(); + + while (costIterator.hasNext()) { + double currentCost = costIterator.next(); + + if (currentCost == this.streetCost && !firstVotingSession) { + continue; + } + + /*first voting session*/ + if (this.firstVotingSession) { + if (this.costVotingMap.get(currentCost).size() >= UPPER_DYNAMIC_VOTING_THRESHOLD) { + this.streetCost = currentCost; + firstVotingSession = false; + return true; + } + + } else if (currentCost > streetCost) { + /*increased cost -> UPPER_THRESHOLD*/ + if (this.costVotingMap.get(currentCost).size() >= UPPER_DYNAMIC_VOTING_THRESHOLD) { + this.streetCost = currentCost; + + /*if another session wants to increase the cost more, it has to overwhelm a bigger threshold*/ + if (UPPER_DYNAMIC_VOTING_THRESHOLD < StreetsCostSharing.MAX_DYNAMIC_VOTING_THRESHOLD) + UPPER_DYNAMIC_VOTING_THRESHOLD += 1; + return true; + } + } else { + /*decreased cost -> LOWER_THRESHOLD*/ + if (this.costVotingMap.get(currentCost).size() >= LOWER_DYNAMIC_VOTING_THRESHOLD) { + this.streetCost = currentCost; + + if (LOWER_DYNAMIC_VOTING_THRESHOLD > StreetsCostSharing.MIN_DYNAMIC_VOTING_THRESHOLD) + LOWER_DYNAMIC_VOTING_THRESHOLD -= 1; + return true; + } + } + } + return false; + } + + /* after a decision is making, there is no point in keeping the costs + * that was not voted*/ + public void clearVoteSession() { + this.costVotingMap.entrySet().removeIf(e -> e.getKey() != this.streetCost); + } + + + public void printVoteSession() { + Iterator costIterator = this.costVotingMap.keySet().iterator(); + System.out.println("VOTE SESSION"); + while (costIterator.hasNext()) { + double currentCost = costIterator.next(); + System.out.println("[" + currentCost + "] " + this.costVotingMap.get(currentCost).toString()); + } + } + + @Override + public String toString() { + return "VotingStreetCostData{" + + "streetCost=" + streetCost + + ", costVotingMap=" + costVotingMap.toString() + + ", UPPER_DYNAMIC_VOTING_THRESHOLD=" + UPPER_DYNAMIC_VOTING_THRESHOLD + + ", LOWER_DYNAMIC_VOTING_THRESHOLD=" + LOWER_DYNAMIC_VOTING_THRESHOLD + + '}'; + } +} diff --git a/src/application/dynamic_routing/VotingStreetCostDataTest.java b/src/application/dynamic_routing/VotingStreetCostDataTest.java new file mode 100644 index 0000000..ea130fc --- /dev/null +++ b/src/application/dynamic_routing/VotingStreetCostDataTest.java @@ -0,0 +1,226 @@ +package application.dynamic_routing; + + +import java.util.HashMap; + +public class VotingStreetCostDataTest { + VotingStreetCostData votingStreetCostData; + HashMap myMap = new HashMap(); + + public void idTheSameCostTest() { + System.out.println("---- IS THE SAME COST TEST.. ----"); + // Considering Threshold = 0.2 + if (VotingStreetCostData.isTheSameStreetCost(9, 10)) { + System.out.println("PASS"); + } else { + System.out.println("FAIL"); + } + + if (VotingStreetCostData.isTheSameStreetCost(7, 10)) { + System.out.println("FAIL"); + } else { + System.out.println("PASS"); + } + System.out.println(); + } + + public void addNewCostsTest() { + System.out.println("---- ADD NEW COSTS TEST... ----"); + System.out.println("ADDING 22 and 14.5"); + votingStreetCostData = new VotingStreetCostData(22, 1); + votingStreetCostData.addDiscovererStamp(10, (long) 5); + votingStreetCostData.printVoteSession(); + if (!votingStreetCostData.isStreetCostUpdated()) { + System.out.println("[PASS]: Not updated because there are not enough votes"); + } else { + System.out.println("[FAIL]: at update 1"); + } + + System.out.println("ADDING 15"); + votingStreetCostData.addDiscovererStamp(11, (long) 4); + votingStreetCostData.addDiscovererStamp(11, (long) 4); + + if (votingStreetCostData.isStreetCostUpdated()) { + System.out.println("[PASS]: updated because there ARE enough votes"); + } else { + System.out.println("[FAIL]: at update 2"); + } + + if (VotingStreetCostData.isTheSameStreetCost(votingStreetCostData.getStreetCost(), 11)) { + System.out.println("[PASS]: Current cost correct = " + votingStreetCostData.getStreetCost()); + } else { + System.out.println("[Fail]: wrong cost " + votingStreetCostData.getStreetCost()); + } + + System.out.println("ADDING 21 and 23"); + votingStreetCostData.addDiscovererStamp(21, (long) 2); + votingStreetCostData.addDiscovererStamp(23, (long) 3); + + + if (votingStreetCostData.isStreetCostUpdated()) { + System.out.println("[PASS]: updated because there ARE enough votes"); + } else { + System.out.println("[FAIL]: at update 2"); + } + + if (VotingStreetCostData.isTheSameStreetCost(votingStreetCostData.getStreetCost(), 21)) { + System.out.println("[PASS]: Current cost correct = " + votingStreetCostData.getStreetCost()); + } else { + System.out.println("[Fail]: wrong cost " + votingStreetCostData.getStreetCost()); + } + + if (votingStreetCostData.getCostVotingMap().size() == 2) { + System.out.println("[PASS]: Number of costs is correct"); + } else { + System.out.println("[FAIL]: WRONG: " + votingStreetCostData.getCostVotingMap().size() + " costs instead of 2"); + } + System.out.println(); + System.out.println("SHOULD HAVE 3 VOTES for 22 AND 2 VOTES FOR 11"); + votingStreetCostData.printVoteSession(); + System.out.println(); + this.votingStreetCostData.clearVoteSession(); + } + + public void hasNewStampsTest() { + System.out.println("---- HAS NEW STAMPS TEST... ----"); + VotingStreetCostData votingStreetCostDataAux = new VotingStreetCostData(50, 10); + + if (this.votingStreetCostData.hasNewStamps(votingStreetCostDataAux)) { + System.out.println("[FAIL]"); + } else { + System.out.println("[PASS]"); + } + votingStreetCostData.addDiscovererStamp(15, (long) 4); + + votingStreetCostDataAux.addDiscovererStamp(14.5, (long) 14); + votingStreetCostDataAux.addDiscovererStamp(15, (long) 15); + + /*update the the street cost after the last votes*/ + votingStreetCostDataAux.isStreetCostUpdated(); + + if (this.votingStreetCostData.hasNewStamps(votingStreetCostDataAux)) { + System.out.println("[PASS]"); + } else { + System.out.println("[FAIL]"); + } + votingStreetCostData.clearVoteSession(); + System.out.println(); + } + + public void addNewStampsTest() { + System.out.println("---- ADD NEW STAMPS TEST ...---"); + votingStreetCostData.getCostVotingMap().clear(); + this.votingStreetCostData.addDiscovererStamp(15, (long) 4); + this.votingStreetCostData.addDiscovererStamp(16, (long) 3); + this.votingStreetCostData.addDiscovererStamp(15, (long) 2); + this.votingStreetCostData.addDiscovererStamp(50, (long) 12); + this.votingStreetCostData.addDiscovererStamp(90, (long) 11); + + VotingStreetCostData votingStreetCostDataAux = new VotingStreetCostData(50, 10); + votingStreetCostDataAux.addDiscovererStamp(15, (long) 1); + // cost discovered by the same car + votingStreetCostDataAux.addDiscovererStamp(15, (long) 2); + votingStreetCostDataAux.addDiscovererStamp(15, (long) 23); + votingStreetCostDataAux.addDiscovererStamp(51, (long) 24); + votingStreetCostDataAux.addDiscovererStamp(48, (long) 21); + + this.votingStreetCostData.addNewStamps(votingStreetCostDataAux); + + if (votingStreetCostData.getCostVotingMap().size() == 3) { + System.out.println("[PASS]: Number of costs is correct"); + } else { + System.out.println("[FAIL]: WRONG: " + votingStreetCostData.getCostVotingMap().size() + " costs instead of 3"); + } + + votingStreetCostData.printVoteSession(); + votingStreetCostData.isStreetCostUpdated(); + votingStreetCostData.clearVoteSession(); + System.out.println("Voted cost is: " + votingStreetCostData.getStreetCost()); + votingStreetCostData.printVoteSession(); + System.out.println(); + } + + public void testSomething() { + VotingStreetCostData votingStreetCostData = new VotingStreetCostData(50, 10); + myMap.put((long)1, votingStreetCostData); + VotingStreetCostData v = myMap.get((long)1); + v.addDiscovererStamp(20, (long)11); + + myMap.get((long)1).printVoteSession(); + + } + + public void testIsStreetCostUpdated() { + System.out.println("---- IS STREET COST UPDATED... ----"); + + VotingStreetCostData votingStreetCostData = new VotingStreetCostData(50, 10); + VotingStreetCostData votingStreetCostDataAux = new VotingStreetCostData(50, 10); + + votingStreetCostDataAux.addDiscovererStamp(48, (long)11); + votingStreetCostDataAux.addDiscovererStamp(48, (long)12); + votingStreetCostDataAux.addDiscovererStamp(49, (long)13); + + if (votingStreetCostData.isStreetCostUpdated()) { + System.out.println("[FAIL]"); + } else { + System.out.println("[PASS]"); + } + + votingStreetCostData.addNewStamps(votingStreetCostDataAux); + + if (votingStreetCostData.isStreetCostUpdated()) { + System.out.println("[PASS]"); + } else { + System.out.println("[FAIL]"); + } + + if (votingStreetCostData.UPPER_DYNAMIC_VOTING_THRESHOLD == 2) { + System.out.println("PASS"); + } else { + System.out.println("FAIL"); + } + votingStreetCostData.clearVoteSession(); + if (votingStreetCostData.isStreetCostUpdated()) { + System.out.println("[FAIL]"); + } else { + System.out.println("[PASS]"); + } + + votingStreetCostDataAux.getCostVotingMap().clear(); + votingStreetCostDataAux.addDiscovererStamp(90, (long)111); + votingStreetCostData.addNewStamps(votingStreetCostDataAux); + + if (votingStreetCostData.isStreetCostUpdated()) { + System.out.println("[FAIL]"); + } else { + System.out.println("[PASS]"); + } + System.out.println("Voted cost is: " + votingStreetCostData.getStreetCost()); + + votingStreetCostDataAux.addDiscovererStamp(92, (long)113); + + votingStreetCostData.addNewStamps(votingStreetCostDataAux); + votingStreetCostData.printVoteSession(); + if (votingStreetCostData.isStreetCostUpdated()) { + System.out.println("[PASS]"); + } else { + System.out.println("[FAIL]"); + } + System.out.println("Voted cost is: " + votingStreetCostData.getStreetCost()); + + if (votingStreetCostData.UPPER_DYNAMIC_VOTING_THRESHOLD == 3) { + System.out.println("PASS"); + } else { + System.out.println("FAIL"); + } + } + + public static void main(String[] args) { + VotingStreetCostDataTest votingStreetCostDataTest = new VotingStreetCostDataTest(); + votingStreetCostDataTest.idTheSameCostTest(); + votingStreetCostDataTest.addNewCostsTest(); + votingStreetCostDataTest.hasNewStampsTest(); + votingStreetCostDataTest.addNewStampsTest(); + votingStreetCostDataTest.testIsStreetCostUpdated(); + } +} diff --git a/src/controller/network/NetworkWiFi.java b/src/controller/network/NetworkWiFi.java index fdb00e8..fbea082 100644 --- a/src/controller/network/NetworkWiFi.java +++ b/src/controller/network/NetworkWiFi.java @@ -1,8 +1,8 @@ package controller.network; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import application.dynamic_routing.TrafficLightDynamicRoutingApp; import model.Entity; import model.GeoCar; import model.GeoServer; @@ -98,7 +98,95 @@ public NetworkInterface discoverClosestServer() { return serverInRange.getNetworkInterface(this.getType()); } - + + private boolean trafficLightDiffers(GeoTrafficLightMaster current, GeoTrafficLightMaster tl1, GeoTrafficLightMaster tl2, GeoTrafficLightMaster tl3) { + if (current != tl1 && current != tl2 && current != tl3) + return true; + return false; + } + + + /* this function discovers the closest neighbour from each geographic direction (N S E W)*/ + public HashMap discoverClosestTrafficLightsGeographic() { + Entity owner = getOwner(); + ArrayList mtl = (ArrayList) owner.getMasterTrafficLights(); + + GeoTrafficLightMaster mtlSouth = null; + GeoTrafficLightMaster mtlNorth = null; + GeoTrafficLightMaster mtlEast = null; + GeoTrafficLightMaster mtlWest = null; + + double maxDistSouth = Double.MAX_VALUE; + double maxDistNorth = Double.MAX_VALUE; + double maxDistEast = Double.MAX_VALUE; + double maxDistWest = Double.MAX_VALUE; + double dist = 0; + + for (int i = 0; i < mtl.size(); i++) { + GeoTrafficLightMaster currentTrafficLight = mtl.get(i); + dist = Utils.distance(owner.getCurrentPos().lat, owner.getCurrentPos().lon, + currentTrafficLight.getCurrentPos().lat, currentTrafficLight.getCurrentPos().lon); + + // NORTH case + if (currentTrafficLight.getCurrentPos().lon < owner.getCurrentPos().lon) { + if (dist < maxDistNorth && dist < RoutingApplicationParameters.distMax + && currentTrafficLight.getId() != owner.getId() + && trafficLightDiffers(currentTrafficLight, mtlSouth, mtlEast, mtlWest)) { + maxDistNorth = dist; + mtlNorth = currentTrafficLight; + } + } + + // SOUTH case + if (currentTrafficLight.getCurrentPos().lon > owner.getCurrentPos().lon) { + if (dist < maxDistSouth && dist < RoutingApplicationParameters.distMax + && currentTrafficLight.getId() != owner.getId() + && trafficLightDiffers(currentTrafficLight, mtlNorth, mtlEast, mtlWest)) { + maxDistSouth = dist; + mtlSouth = currentTrafficLight; + } + } + + // EAST case + if (currentTrafficLight.getCurrentPos().lat > owner.getCurrentPos().lat) { + if (dist < maxDistEast && dist < RoutingApplicationParameters.distMax + && currentTrafficLight.getId() != owner.getId() + && trafficLightDiffers(currentTrafficLight, mtlSouth, mtlNorth, mtlWest)) { + maxDistEast = dist; + mtlEast = currentTrafficLight; + } + } + + // WEST case + if (currentTrafficLight.getCurrentPos().lat < owner.getCurrentPos().lat) { + if (dist < maxDistWest && dist < RoutingApplicationParameters.distMax + && currentTrafficLight.getId() != owner.getId() + && trafficLightDiffers(currentTrafficLight, mtlSouth, mtlEast, mtlNorth)) { + maxDistWest = dist; + mtlWest = currentTrafficLight; + } + } + + } + + HashMap ret = new HashMap(); + if (maxDistNorth < RoutingApplicationParameters.distMax && mtlNorth != null) { + ret.put(TrafficLightDynamicRoutingApp.NORTH_INDEX, mtlNorth.getNetworkInterface(this.getType())); + } + if (maxDistSouth < RoutingApplicationParameters.distMax && mtlSouth != null) { + ret.put(TrafficLightDynamicRoutingApp.SOUTH_INDEX, mtlSouth.getNetworkInterface(this.getType())); + } + if (maxDistEast < RoutingApplicationParameters.distMax && mtlEast != null) { + ret.put(TrafficLightDynamicRoutingApp.EAST_INDEX, mtlEast.getNetworkInterface(this.getType())); + } + if (maxDistWest < RoutingApplicationParameters.distMax && mtlWest != null) { + ret.put(TrafficLightDynamicRoutingApp.WEST_INDEX, mtlWest.getNetworkInterface(this.getType())); + } + + return ret; + } + + public List discoverClosestsTrafficLightMasters() { Entity owner = getOwner(); ArrayList mtl = (ArrayList) owner.getMasterTrafficLights(); diff --git a/src/controller/newengine/EngineUtils.java b/src/controller/newengine/EngineUtils.java index 4d0fff9..9022d96 100644 --- a/src/controller/newengine/EngineUtils.java +++ b/src/controller/newengine/EngineUtils.java @@ -1,5 +1,6 @@ package controller.newengine; +import application.dynamic_routing.CarDynamicRoutingApp; import gui.TrafficLightView; import gui.Viewer; @@ -15,16 +16,8 @@ import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.TreeMap; -import java.util.Vector; import java.util.logging.Logger; import application.Application; @@ -44,6 +37,7 @@ import model.mobility.MobilityEngine; import model.parameters.Globals; import model.parameters.MapConfig; +import model.personality.PersonalityTypes; import utils.ComputeAverageSpeeds; import utils.ComputeStreetVisits; import utils.SphericalMercator; @@ -58,6 +52,16 @@ * Class used to read the servers and the cars from files * */ + +class GeoCarComparator implements Comparator { + + @Override + public int compare(GeoCar o1, GeoCar o2) { + return (int) (o2.getRouteIncreasedCostPercentage() - o1.getRouteIncreasedCostPercentage()); + } +} + + public final class EngineUtils { /** Logger used by this class */ @@ -69,6 +73,9 @@ public final class EngineUtils { /* Server info */ static double latEdge = 0d, lonEdge = 0d; static long rows = 0, cols = 0; + +// this queue is useful to choose which car is next for route dynamic update + public static PriorityQueue carsQueue = new PriorityQueue<>(new GeoCarComparator()); private EngineUtils() {} @@ -89,6 +96,8 @@ static TreeMap getCars(String carListFilename, Viewer viewer, Mobil BufferedReader br = new BufferedReader(new InputStreamReader(fstream)); String line; + int malicious_index = 0; + /* Read data about traces */ while ((line = br.readLine()) != null) { /* If the simulation requires just a fraction of the cars @@ -106,11 +115,22 @@ static TreeMap getCars(String carListFilename, Viewer viewer, Mobil st.nextToken(); /* routes = Utils.readCarTraces(path); - + GeoCar car = new GeoCar(count); car.setRoutes(routes); +// added +// car.setSameEndPointToAllRoutes(); + + if (malicious_index < Globals.maliciousCars) { + malicious_index++; + car.setPersonalityType(Globals.maliciousPersonalityType); + } + + if (count == 183) System.out.println("read +"); @@ -120,11 +140,17 @@ static TreeMap getCars(String carListFilename, Viewer viewer, Mobil NetworkInterface netInterface = NetworkUtils.activateNetworkInterface(type, car); car.addNetworkInterface(netInterface); } - + + /*add car's routing app*/ + if (Globals.costSharingApps) { + Globals.activeApplications.add(ApplicationType.CAR_ROUTING_APP); + } + /* Create each application which is defined */ for( ApplicationType type : Globals.activeApplications ) { Application app = ApplicationUtils.activateApplicationCar(type, car); + if( app == null ) { logger.info(" Failed to create application with type " + type); @@ -136,6 +162,7 @@ static TreeMap getCars(String carListFilename, Viewer viewer, Mobil viewer.addCar(car); cars.put(car.getId(), car); count++; + } br.close(); } catch (IOException ex) { @@ -147,7 +174,7 @@ static TreeMap getCars(String carListFilename, Viewer viewer, Mobil ex.printStackTrace(); } } - System.out.println("cars" + cars.size()); + System.out.println("cars " + cars.size()); return cars; } @@ -351,6 +378,18 @@ private static void addTrafficLightApps(GeoTrafficLightMaster master) { else master.addApplication( app ); } + + if (Globals.costSharingApps) { + type = ApplicationType.TRAFFIC_LIGHT_ROUTING_APP; + app = ApplicationUtils.activateApplicationTrafficLight(type, master); + if( app == null ) + { + logger.info(" Failed to create application with type " + type); + } + else { + master.addApplication(app); + } + } } /*** @@ -363,7 +402,6 @@ private static TreeMap readExistingTrafficLights( FileInputStream fstream = null; TreeMap trafficLights = new TreeMap(); - try { fstream = new FileInputStream(file); BufferedReader br = new BufferedReader(new InputStreamReader(fstream)); @@ -441,7 +479,7 @@ private static TreeMap readExistingTrafficLights( ex.printStackTrace(); } } - System.out.println(trafficLights.size()); + System.out.println("nr of tl: " + trafficLights.size()); return trafficLights; } @@ -455,7 +493,7 @@ private static TreeMap readExistingTrafficLights( */ private static TreeMap readTrafficLights( String inFile, String outFile, Viewer viewer, MobilityEngine mobilityEngine) { - + FileInputStream fstream = null; TreeMap trafficLights = new TreeMap(); //if traffic lights were not loaded before, read them from the config diff --git a/src/controller/newengine/SimulationEngine.java b/src/controller/newengine/SimulationEngine.java index fe35e3b..1580a29 100644 --- a/src/controller/newengine/SimulationEngine.java +++ b/src/controller/newengine/SimulationEngine.java @@ -1,5 +1,6 @@ package controller.newengine; +import application.dynamic_routing.TrafficLightDynamicRoutingApp; import gui.View; import gui.Viewer; @@ -24,16 +25,13 @@ import model.parameters.MapConfig; import model.parameters.MapConfiguration; import model.threadpool.ThreadPool; -import model.threadpool.tasks.CarApplicationsRun; -import model.threadpool.tasks.CarMove; -import model.threadpool.tasks.CarPrepareMove; -import model.threadpool.tasks.ServerApplicationsRun; -import model.threadpool.tasks.TrafficLightApplicationsRun; -import model.threadpool.tasks.TrafficLightChangeColor; +import model.threadpool.tasks.*; import controller.engine.EngineInterface; import controller.network.NetworkType; +import utils.StreetsCostSharing; - /** + +/** * Class used to represent the brain of the simulator. * It reads the data for cars and servers applies the designated applications to be run on them. * Runs the simulation steps for each time frame (see the Runnable hidden object) @@ -57,7 +55,7 @@ public class SimulationEngine implements EngineInterface { public TreeMap entities; /** Graphic interface visualizer */ - private Viewer viewer; + public Viewer viewer; /** Thread Pool reference */ private ThreadPool threadPool; @@ -68,9 +66,13 @@ public class SimulationEngine implements EngineInterface { /** Simulation time */ private long time = 0; + private int MAX_CARS_UPDATE_ROUTE = 10; + private static final SimulationEngine _instance = new SimulationEngine(); private static Object lock = null; + public static boolean oneMessage = true; + /** * Constructor is called just once, so all initializations are safe to be done here... */ @@ -100,15 +102,28 @@ public static SimulationEngine getInstance() { } public void setUp() { - + entities.putAll(EngineUtils.getCars(getMapConfig().getTracesListFilename(), viewer, mobilityEngine) ); entities.putAll(EngineUtils.getServers(getMapConfig().getAccessPointsFilename(), viewer, mobilityEngine) ); if (Globals.useTrafficLights || Globals.useDynamicTrafficLights) { entities.putAll(EngineUtils.getTrafficLights(getMapConfig().getTrafficLightsFilename(), getMapConfig().getTrafficLightsLoaded(), viewer, mobilityEngine)); } + + /* the applications are added to the traffic lights in EngineUtils. + * Just need to call "postConstructInit" after all of the traffic lights are + * generated*/ + if (Globals.dynamicRoutes && Globals.costSharingApps) { + for (Entity e : entities.values()) { + if (e instanceof GeoTrafficLightMaster) { + TrafficLightDynamicRoutingApp app = (TrafficLightDynamicRoutingApp)e. + getApplication(ApplicationType.TRAFFIC_LIGHT_ROUTING_APP); + app.postConstructInit(); + } + } + } - if (Globals.activeApplications.contains(ApplicationType.ROUTING_APP)) { + if (Globals.activeApplications.contains(ApplicationType.ROUTING_APP) && !Globals.dynamicRoutes) { for (Entity e : entities.values()) { if (e instanceof GeoServer) { EngineUtils.addApplicationToServer((GeoServer) e); @@ -157,6 +172,21 @@ public void run() { } +// select the cars for route update. All cars are stored in a queue for equal chances + if (time % 3 == 0 && Globals.dynamicRoutes) { + if (EngineUtils.carsQueue.size() > 0) { + GeoCar currentCar = EngineUtils.carsQueue.poll(); + currentCar.setTurnToUpdateRoute(true); + currentCar.setAppointedForRouteRecalculation(false); + currentCar.setRouteIncreasedCost(0); + } + } + + if (time % 100 == 0 && Globals.maliciousCars > 0) { + System.out.println("TIME: " + time + " Malicious costs: " + StreetsCostSharing.counterMaliciousCosts + " Real: " + StreetsCostSharing.counterRealCosts); + } + + threadPool.waitForThreadPoolProcessing(); for (Entity e : entities.values()) { @@ -188,8 +218,9 @@ public void run() { viewer.updateCarPositions(); viewer.updateTrafficLightsColors(); viewer.setTime("" + time); + - if( (time + 2)% RoutingApplicationParameters.SamplingInterval == 0) + if( (time + 5)% RoutingApplicationParameters.SamplingInterval == 0) { System.out.println("WRITTING ROUTES TIME TO FILES!"); for (Entity e : entities.values()) { diff --git a/src/downloader/DownloadCore.java b/src/downloader/DownloadCore.java index 7d32b0c..0063e46 100644 --- a/src/downloader/DownloadCore.java +++ b/src/downloader/DownloadCore.java @@ -174,8 +174,9 @@ public void execute(String city) { String traces = curDir.getAbsolutePath(); parseConfigFile(); - - if (city.equalsIgnoreCase("rome")) { + System.out.println("aiis: " + t.getAbsolutePath()); + + if (city.equalsIgnoreCase("src/configurations/simulator/rome")) { String archive = t.getAbsolutePath() + File.separator + "rome.zip"; if (mode.equalsIgnoreCase("D")) { @@ -186,7 +187,9 @@ public void execute(String city) { unZipIt(archive, traces); - } else if (city.equalsIgnoreCase("beijing")) { + } else if (city.equalsIgnoreCase("src/configurations/simulator/beijing")) { + System.out.println("sunt aucisals " + city); + String archive = t.getAbsolutePath() + File.separator + "beijing.zip"; if (mode.equalsIgnoreCase("D")) { @@ -197,7 +200,7 @@ public void execute(String city) { unZipIt(archive, traces); - } else if (city.equalsIgnoreCase("sanfrancisco")) { + } else if (city.equalsIgnoreCase("src/configurations/simulator/sanfrancisco")) { String archive = t.getAbsolutePath() + File.separator + "sanfrancisco.zip"; if (mode.equalsIgnoreCase("D")) { diff --git a/src/downloader/Downloader.java b/src/downloader/Downloader.java index 5102813..7ff18f8 100644 --- a/src/downloader/Downloader.java +++ b/src/downloader/Downloader.java @@ -38,7 +38,7 @@ private void extractCity(String propFile) { city = propF[0]; } - + public void downloadTraces(String propFile) { // Extract the city name @@ -48,8 +48,8 @@ public void downloadTraces(String propFile) { System.out.println("Trace files exist - Skipping DOWNLOAD STEP"); } else { System.out.println("Trace files don't exist - Starting DOWNLOAD STEP"); - DownloadCore core = new DownloadCore(); - core.execute(this.city); +// DownloadCore core = new DownloadCore(); +// core.execute(this.city); } } diff --git a/src/gui/TrafficLightView.java b/src/gui/TrafficLightView.java index f0ffa98..27be899 100644 --- a/src/gui/TrafficLightView.java +++ b/src/gui/TrafficLightView.java @@ -77,6 +77,11 @@ public void run() { }); } + + public void messageAlert() { + Color c = this.getColor(); + setColor(Color.blue); + } public void changeColor() { if (trafficLightColor == Color.red) { diff --git a/src/model/DynamicRoutes.java b/src/model/DynamicRoutes.java new file mode 100644 index 0000000..992d814 --- /dev/null +++ b/src/model/DynamicRoutes.java @@ -0,0 +1,167 @@ +package model; + +import model.OSMgraph.Node; +import model.OSMgraph.Way; +import model.mobility.MobilityEngine; +import utils.StreetsCostSharing; +import utils.Pair; +import utils.tracestool.Utils; + +import java.util.*; + +public class DynamicRoutes { + public TreeMap streetsGraph; + MobilityEngine mobilityEngine; + StreetsCostSharing streetsCostSharing; + + DynamicRoutes(StreetsCostSharing dr_utils) { + mobilityEngine = MobilityEngine.getInstance(); + streetsGraph = mobilityEngine.streetsGraph; + streetsCostSharing = dr_utils; + } + + + public Pair, HashSet> findPath(Node startNode, Node stopNode) { + List intersectionsList = new ArrayList(); + TreeMap,Node> path = new TreeMap,Node>(); + TreeMap,Double> distance = new TreeMap,Double>(); + HashSet wayIdsSet = new HashSet(); + + /*checks for startNode and stopNode correctness. + + * if case, try to correct them by considering the closest nodes*/ + + int ok = 1; + if( startNode.id != -1 ) { + Way sW = streetsGraph.get(startNode.wayId); + if(sW != null && sW.neighs.get(startNode.id) != null ) { + startNode = sW.getNode(startNode.id); + } else { + ok = 0; + } + + } else { + ok = 0; + } + if (ok == 0) { + startNode = Utils.getClosestJointFromCrtPosition( + streetsGraph, startNode.wayId, + streetsGraph.get(startNode.wayId).getClosestNode( startNode.lat, startNode.lon) + ); + } + + ok = 1; + if( stopNode.id != -1 ) { + Way sW = streetsGraph.get(stopNode.wayId); + if(sW != null && sW.neighs.get(stopNode.id) != null ) { + stopNode = sW.getNode(stopNode.id); + } else { + ok = 0; + } + + } else { + ok = 0; + } + if (ok == 0) { + stopNode = Utils.getClosestJointFromCrtPosition( + streetsGraph, stopNode.wayId, + streetsGraph.get(stopNode.wayId).getClosestNode( stopNode.lat, stopNode.lon) + ); + } + + if( startNode == null || stopNode == null ) { + return null; + } + + /* start the path finding algorithm*/ + + Pair currentPair = new Pair(startNode.id, startNode.wayId); + LinkedList> q = new LinkedList>(); + Node currentNode, jointNode; + Way currentWay; + Vector> neighs = new Vector>(); + HashMap parents = new HashMap(); + double currentDistance, parentDistance; + + q.addLast(currentPair); + distance.put(currentPair, (double) 0); + + /*explore the graph in a bfs manner*/ + ok = 1; + while(!q.isEmpty()) { + if (currentPair.getFirst() == stopNode.id && currentPair.getSecond() == stopNode.wayId) { + break; + } + currentWay = streetsGraph.get(currentPair.getSecond()); + currentNode = currentWay.getNode(currentPair.getFirst()); + +// make sure that startNode has the same way id with what I am looking for at the backpropagation +// through parents list + if (ok == 1) { + startNode = currentNode; + ok = 0; + } + +// intersection's neighbours + neighs = Utils.getDirectLinkedJointsFromCrtPosition(streetsGraph, currentNode); + + for( Pair entry : neighs ) { + jointNode = streetsGraph.get(entry.getSecond()).getNode(entry.getFirst()); + currentWay = streetsGraph.get(currentNode.wayId); + if( !q.contains(entry) ) + { + + /*calculate the distance between current and next node. + * add the distance from the source. + * the cost is measured in seconds*/ + boolean isDistanceUpdated = false; + parentDistance = distance.get(currentPair); + currentDistance = parentDistance + streetsCostSharing.getWayCost(currentWay); + + /*the nodes are explored in 2 scenarios: + * - the node has not been visited before + * - it has been visited, but there is a time improvement in reaching that node + * otherwise, the node will not be explored */ + + if (distance.containsKey(entry)) { + + if (currentDistance < distance.get(entry)) { + distance.put(entry, currentDistance); + isDistanceUpdated = true; + } + + } else { + distance.put(entry, currentDistance); + isDistanceUpdated = true; + } + + if (isDistanceUpdated) { + q.addLast(new Pair(jointNode.id, jointNode.wayId)); + parents.put(jointNode, currentNode); + } + } + } + currentPair = q.poll(); + } + + // build the new path + try { + + currentNode = streetsGraph.get(currentPair.getSecond()).getNode(currentPair.getFirst()); + + while (currentNode.id != -1 && currentNode.id != startNode.id) { + + intersectionsList.add(0, parents.get(currentNode)); + currentNode = parents.get(currentNode); + wayIdsSet.add(currentNode.wayId); + } + + } catch (Exception e) { + System.out.println(e.getMessage()); + } + + return new Pair<>(intersectionsList, wayIdsSet); + + } + + +} diff --git a/src/model/GeoCar.java b/src/model/GeoCar.java index 3d4b237..630ccbd 100644 --- a/src/model/GeoCar.java +++ b/src/model/GeoCar.java @@ -4,26 +4,26 @@ import java.awt.Color; import java.io.FileNotFoundException; import java.io.PrintWriter; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; +import java.util.*; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; import controller.network.NetworkInterface; import controller.network.NetworkType; import controller.network.NetworkWiFi; +import controller.newengine.EngineUtils; import controller.newengine.SimulationEngine; import model.OSMgraph.Node; +import model.OSMgraph.Way; import model.mobility.MobilityEngine; import model.network.Message; import model.network.MessageType; import model.parameters.Globals; import model.personality.Personality; +import model.personality.PersonalityTypes; import model.personality.RegularPersonality; -import utils.ComputeAverageFuelConsumption; -import utils.Pair; -import utils.TraceParsingTool; +import utils.*; import utils.tracestool.Utils; import application.Application; import application.ApplicationType; @@ -70,8 +70,13 @@ public class GeoCar extends Entity { /** Used to count the number of times the car has stayed still */ private int still = 0; + private boolean ableToUpdate = true; + private boolean stoppedAtTrafficLight = false; + + private boolean appointedForRouteRecalculation = false; + /** * List of nodes between current position and next position. The list is sorted * from the current position towards next position. @@ -83,10 +88,54 @@ public class GeoCar extends Entity { /** The car in front of this car. Is updated at every iteration */ private Pair elementAhead = null; + public static int ROUTE_CHECK_TIMESTAMP = 10; + private boolean turnToUpdateRoute = false; + /** Route length in time information */ StringBuffer routesTime = new StringBuffer(); // StringBuffer tracesTime = new StringBuffer(); + /** reference to algorithms for dynamic routes, useful for routes updating */ + StreetsCostSharing streetsCostSharing; + + public StreetsCostSharing getStreetsCostSharing() { + return streetsCostSharing; + } + + public void setStreetsCostSharing(StreetsCostSharing streetsCostSharing) { + this.streetsCostSharing = streetsCostSharing; + } + + DynamicRoutes dynamicRoutes; + + private PersonalityTypes personalityType = PersonalityTypes.REGULAR; + + + public PersonalityTypes getPersonalityType() { + return personalityType; + } + public boolean isAppointedForRouteRecalculation() { + return appointedForRouteRecalculation; + } + + public void setAppointedForRouteRecalculation(boolean appointedForRouteRecalculation) { + this.appointedForRouteRecalculation = appointedForRouteRecalculation; + } + + public void setPersonalityType(PersonalityTypes personalityType) { + this.personalityType = personalityType; + this.streetsCostSharing = new StreetsCostSharingMalicious(this); + } + + /** Street costs related elements (to update the costs dynamically)*/ + private Way currentWay; + private Node startingNode; + private long wayStartTime; + private HashMap costSharedCars; + private HashSet costSharedTrafficLight; + private double entireRouteCost = 0; + public static double ROUTE_UPDATE_THRESHOLD = 0.1; + public GeoCar(int id) { this(id, new RegularPersonality()); } @@ -98,6 +147,10 @@ public GeoCar(int id, Personality driver) { this.setCurrentPos(null); this.setNextPos(null); this.beginNewRoute = true; + costSharedCars = new HashMap(); + costSharedTrafficLight = new HashSet(); + streetsCostSharing = new StreetsCostSharing(this); + dynamicRoutes = new DynamicRoutes(streetsCostSharing); } public void setSpeed(double speed) { @@ -286,6 +339,10 @@ public void updateSpeedTrafficLightAhead() { long wayId = this.getCurrentPos().wayId; int direction = -this.getCurrentPos().direction; + /*if there is a traffic light ahead, share the costs updates with it*/ + if (Globals.costSharingApps && distance < 25) + sendUpdatesToTrafficLight(trafficLightInFront); + /* The car is close to the traffic light and the traffic light is red -> stop */ if (distance < 25 && trafficLightInFront.getTrafficLightColor(wayId, direction) == Color.red && !isStoppedAtTrafficLight()) { @@ -295,6 +352,7 @@ public void updateSpeedTrafficLightAhead() { setStopppedAtTrafficLight(true); if (Globals.useTrafficLights || Globals.useDynamicTrafficLights) sendDataToTrafficLight(trafficLightInFront, wayId, direction, this.getCurrentPos()); + } else { /* @@ -314,7 +372,7 @@ && isStoppedAtTrafficLight()) { } /*** - * Sends a message via WiFi to the master trafic light in front to notify it + * Sends a message via WiFi to the master traffic light in front to notify it * about it's presence. The master traffic light will put the car to the * corresponding waiting queue. * @@ -382,11 +440,167 @@ public Double getCongestionDegree(Double AVGspeed, Double maxSpeed) { return g; } + private int ok = 1; + +/** task that calls findPath method from dynamicRoutes. + this task is sent to executor service */ + Callable, HashSet>> updateRouteTask = new Callable, HashSet>>() { + + @Override + public Pair, HashSet> call() throws Exception { + + return dynamicRoutes.findPath(getCurrentRoute().getIntersectionList().get(0), + getCurrentRoute().getIntersectionList().get(getCurrentRoute().getIntersectionList().size() - 1)); + } + }; + + private ExecutorService executor = Executors.newCachedThreadPool(); + + private boolean updatedRoute = false; + + /** function called when it's current car's turn to find a new path. + * add the task to the thread pool. + * update the intersectionList and wayIdsSet*/ + public void updateGeoCarRoute() { + + Future, HashSet>> future = executor.submit(updateRouteTask); + + try { + Pair, HashSet> updateResult = future.get(200, TimeUnit.MILLISECONDS); + + this.getCurrentRoute().setIntersectionList(updateResult.getFirst()); + this.getCurrentRoute().setWayIdsSet(updateResult.getSecond()); + this.updatedRoute = true; + + } catch (Exception e) { + // handle other exceptions + } finally { + future.cancel(true); + } + + } + + + public void setRouteIncreasedCost(double routeIncreasedCost) { + this.routeIncreasedCost = routeIncreasedCost; + } + + private double routeIncreasedCost = 0; + + public double getRouteIncreasedCostPercentage() { + return routeIncreasedCostPercentage; + } + + private double routeIncreasedCostPercentage = 0; + + + /** this method has the role to appoint the car for route recalculation + * it is called from streetsCostSharing.updateWayCost when a way within + * this car's route is updated (has a different cost)*/ + + public void appointForRouteRecalculation(double increasedWayCost) { + routeIncreasedCost += increasedWayCost; + routeIncreasedCostPercentage = (routeIncreasedCost * 100) / entireRouteCost; + + if (!this.appointedForRouteRecalculation + && routeIncreasedCost > this.entireRouteCost * GeoCar.ROUTE_UPDATE_THRESHOLD) { + + EngineUtils.carsQueue.add(this); + this.appointedForRouteRecalculation = true; + } + } + + public void setTurnToUpdateRoute(boolean t) { + this.turnToUpdateRoute = t; + } + + + /** method for street change detection. + * When a car change the current street, it will calculate the new discovered cost for the old current street + * and it will start a new timer for the new current street*/ + + public void updateCostRelatedElements() { + + if (currentWay.id != getCurrentRoute().getIntersectionList().get(0).wayId) { + // get the finish node of the current way + Node finishNode = this.currentWay.getClosestNode(this.getCurrentPos().lat, this.getCurrentPos().lon); + streetsCostSharing.discoverNewWayCost(currentWay, startingNode, finishNode, this.wayStartTime, SimulationEngine.getInstance().getSimulationTime()); + + /*delete the way that has been traveled from the set (otherwise, risk to appoint for route recalc based + on your own report for a street that you passed) */ + getCurrentRoute().getWayIdsSet().remove(currentWay.id); + + this.currentWay = mobility.streetsGraph.get(getCurrentRoute().getIntersectionList().get(0).wayId); + this.wayStartTime = SimulationEngine.getInstance().getSimulationTime(); + + this.startingNode = this.currentWay.getClosestNode(this.getCurrentPos().lat, this.getCurrentPos().lon); + } + } + + + public void sendUpdatesToTrafficLight(GeoTrafficLightMaster trafficLightMaster) { + + if (this.getStreetsCostSharing().getStreetUpdates().isEmpty() || + costSharedTrafficLight.contains(trafficLightMaster.getId())) { + return; + } + + NetworkInterface networkInterface = this.getNetworkInterface(NetworkType.Net_WiFi); + + NetworkInterface discoveredTrafficLightMaster = ((NetworkWiFi) networkInterface).discoverTrafficLight(trafficLightMaster); + Message message = new Message(this.getId(), discoveredTrafficLightMaster.getOwner().getId(), this.streetsCostSharing.getStreetUpdates().clone(), + MessageType.CAR_INFORMS, ApplicationType.TRAFFIC_LIGHT_ROUTING_APP); + networkInterface.putMessage(message); + + costSharedTrafficLight.add(trafficLightMaster.getId()); + } + + + public void sendUpdatesToCar(GeoCar neighbourCar) { + NetworkInterface networkInterface = this.getNetworkInterface(NetworkType.Net_WiFi); + + Message message = new Message(this.getId(), neighbourCar.getId(), this.streetsCostSharing.getStreetUpdates().clone(), + MessageType.CAR_INFORMS, ApplicationType.CAR_ROUTING_APP); + networkInterface.putMessage(message); + } + + public void checkForNeighboursForCostSharing() { + /*Get neighbours for cars' cost sharing + * check if there was already an exchange of messages with that car*/ + GeoCar carOnOppositeSide = mobility.getCarOnOppositeSide(this); + + if (carOnOppositeSide != null + && !costSharedCars.containsKey(carOnOppositeSide.getId())) { + costSharedCars.put(carOnOppositeSide.getId(), carOnOppositeSide); + sendUpdatesToCar(carOnOppositeSide); + } + + Pair elemAheadAux = new Pair<>(elementAhead.getFirst(), elementAhead.getSecond()); + GeoCar carAhead = null; + if (elemAheadAux != null && elemAheadAux.getFirst()!= null && elemAheadAux.getFirst() instanceof GeoCar + && !costSharedCars.containsKey(elemAheadAux.getFirst().getId()) + && elemAheadAux.getSecond() < NetworkWiFi.maxWifiRange / 10000) { + costSharedCars.put(elemAheadAux.getFirst().getId(), (GeoCar) elemAheadAux.getFirst()); + carAhead = (GeoCar) elementAhead.getFirst(); + sendUpdatesToCar(carAhead); + } + } + + + /** * Prepares the next position the car will go to. This must be called after the * updateSpeed method. */ public MapPoint getNextPosition() { + +/* this boolean is set to "true" in SimulationEngine (following a fair strategy, + each car has its chance for route recalculation) */ + if (turnToUpdateRoute && Globals.dynamicRoutes) { + updateGeoCarRoute(); + this.turnToUpdateRoute = false; + } + GeoCarRoute route = this.routes.get(0); MapPoint newPos = null; nodesToMoveOver = new LinkedList(); @@ -398,6 +612,7 @@ public MapPoint getNextPosition() { if (stoppedAtTrafficLight) { hasMoved.set(true); +// System.out.println("return current position"); return this.getCurrentPos(); } @@ -411,7 +626,9 @@ public MapPoint getNextPosition() { double avgFuelConsumption = ComputeAverageFuelConsumption.computeAverageFuelConsumption(routeFuelFromStart, timei); routesTime.append((routes_idx++) + " " + timei + " " + avgSpeed + " " + avgFuelConsumption + System.lineSeparator()); +// System.out.println("Reached destination: " + "id: " + this.getId() + " avgSpeed: " + avgSpeed); } +// System.out.println("null from 1 if"); return null; } @@ -419,6 +636,9 @@ public MapPoint getNextPosition() { Node prevNode = null; Node nextNode = mobility.getSegmentByIndex(this.getCurrentPos()); int newDirection = this.getCurrentPos().direction; + +// System.out.println("Intersection List size: " + route.getIntersectionList().size()); +// System.out.println("id: " + nextNode.id + " way id: " + nextNode.wayId); while (it.hasNext()) { prevNode = nextNode; nextNode = it.next(); @@ -430,6 +650,7 @@ public MapPoint getNextPosition() { * TODO(mariana): e ceva gresit cu ruta asta, returnam null ca apoi sa i se faca * skip */ +// System.out.println("null from mariana if"); return null; } @@ -492,7 +713,12 @@ public MapPoint getNextPosition() { double avgFuelConsumption = ComputeAverageFuelConsumption.computeAverageFuelConsumption(routeFuelFromStart, timei); routesTime.append((routes_idx++) + " " + timei + " " + avgSpeed + " " + avgFuelConsumption + System.lineSeparator()); +// System.out.println("Reached destination: " + "id: " + this.getId() + " avgSpeed: " + avgSpeed); +// if (updatedRoute) System.out.println("Cu update BAA"); + + } +// System.out.println("null from reached dest last if"); return null; } @@ -503,6 +729,7 @@ public MapPoint getNextPosition() { * Prepare next Move for this car object. */ public void prepareMove() { +// System.out.println(this.getId() + " oe way: " + this.getCurrentPos().wayId); try { /** @@ -515,7 +742,6 @@ public void prepareMove() { return; } if (this.getCurrentPos() == null) { - // System.out.println("begin new route"); setBeginNewRoute(true); initRoute(); return; @@ -523,6 +749,9 @@ public void prepareMove() { elementAhead = mobility.getElementAhead(this, driver.getInfluenceDistance(speed)); + if (Globals.costSharingApps && streetsCostSharing.getStreetUpdates().size() > 0) + checkForNeighboursForCostSharing(); + oldSpeed = speed; updateSpeed(); @@ -531,11 +760,16 @@ public void prepareMove() { nextPos = getNextPosition(); this.setBeginNewRoute(false); + /* + aicisa imi da nextPosition null why ????? + */ +// if (nextPos == null) System.out.println("Problema din prepare move"); mobility.queueNextMove(this.getId(), nextPos); hasMoved.set(false); } catch (RuntimeException e) { /** Something was wrong with the route, so it's better to start a new one. */ +// System.out.println(e + " " + e.getStackTrace()[0].getLineNumber()); setBeginNewRoute(true); // long timei = SimulationEngine.getInstance().getSimulationTime() - // routeStartTime; @@ -584,6 +818,7 @@ public void move() { return; } if (newPosition == this.getCurrentPos()) { + if (still > 200) { /* we've stayed too much time in the same place */ resetRoute(); @@ -611,10 +846,16 @@ public void move() { mobility.removeQueuedCar(oldNextPos, this.getId()); this.setCurrentPos(newPosition); mobility.addCar(this); + +// update the elements before dropping relevant data + if (Globals.dynamicRoutes) + updateCostRelatedElements(); + finishMove(); } } catch (RuntimeException e) { /** Something was wrong with the route, so it's better to start a new one. */ + setBeginNewRoute(true); initRoute(); return; @@ -688,11 +929,19 @@ public void initStartPosition() { // tracesTime.append("< " + start.lat + " " + start.lon + " " + end.lat + " " + // end.lon + " " + (start.timestamp.getTime() - end.timestamp.getTime()) / 1000 // + "\n"); + + /* set the way of the first joint Node and set starting time in order to + start current way cost*/ + currentWay = mobility.streetsGraph.get(first.wayId); + + this.startingNode = mobility.getSegmentByIndex(route.getStartPoint()); + this.wayStartTime = SimulationEngine.getInstance().getSimulationTime(); } public void printRouteData(String filename) { try { String city = SimulationEngine.getInstance().getMapConfig().getCity(); + System.out.println("SE SCRIEEE!!!!!!!!!!!!!!!!!! " + filename); city += "/"; if (Globals.useTrafficLights) @@ -719,6 +968,9 @@ public void printRouteData(String filename) { } public void initRoute() { + updatedRoute = false; + costSharedTrafficLight.clear(); + try { if (isBeginNewRoute()) { resetRoute(); @@ -759,11 +1011,15 @@ public void initRoute() { this.routes.add(route); } hasMoved.set(true); + + entireRouteCost = this.streetsCostSharing.calculateEntireRouteCost(this.getCurrentRoute().getWayIdsSet()); + } catch (RuntimeException e) { this.setCurrentPos(null); this.routes.remove(0); hasMoved.set(true); } + } /** @@ -786,6 +1042,7 @@ public void resetRoute() { * Destroy the next position. */ public void finishMove() { + nodesToMoveOver = null; nextPos = null; } diff --git a/src/model/GeoCarRoute.java b/src/model/GeoCarRoute.java index 0214632..ce0f590 100644 --- a/src/model/GeoCarRoute.java +++ b/src/model/GeoCarRoute.java @@ -2,6 +2,7 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import model.OSMgraph.Node; @@ -13,12 +14,26 @@ public class GeoCarRoute implements Serializable{ private MapPoint endPoint; private List intersectionList; private List originalintersectionList; - + private HashSet wayIdsSet; + + public HashSet getWayIdsSet() { + return wayIdsSet; + } + + public void setWayIdsSet(HashSet wayIdsSet) { + this.wayIdsSet = wayIdsSet; + } + public GeoCarRoute(MapPoint start, MapPoint end, List intersections) { startPoint = start; endPoint = end; intersectionList = intersections; originalintersectionList = new ArrayList(intersections); + + this.wayIdsSet = new HashSet(); + for (int i = 0; i < intersectionList.size(); i++) { + wayIdsSet.add(intersectionList.get(i).wayId); + } } public MapPoint getStartPoint() { diff --git a/src/model/OSMgraph/Way.java b/src/model/OSMgraph/Way.java index 6b7947e..8c24d6a 100644 --- a/src/model/OSMgraph/Way.java +++ b/src/model/OSMgraph/Way.java @@ -74,6 +74,7 @@ public Way(long id) { max_long = -360; } + /** It is oneway or not */ public void setDirection(boolean val) { oneway = val; diff --git a/src/model/mobility/MobilityEngine.java b/src/model/mobility/MobilityEngine.java index d558849..9412cb4 100644 --- a/src/model/mobility/MobilityEngine.java +++ b/src/model/mobility/MobilityEngine.java @@ -1,5 +1,6 @@ package model.mobility; +import java.awt.*; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; @@ -11,6 +12,8 @@ import application.routing.RoutingApplicationData.RoutingApplicationState; import application.routing.RoutingApplicationParameters; import application.routing.RoutingRoadCost; +import controller.network.NetworkWiFi; +import gui.CarView; import model.Entity; import model.GeoCar; import model.GeoCarRoute; @@ -388,7 +391,13 @@ public int getSegmentForPointNotOnSegment(MapPoint point) { else return way.getNodeIndex(around.getSecond().id); } - public static void initDataDijkstraQ( TreeMap graph, Node startNode, TreeMap,Node> path, TreeMap,Double> distance, int depthMax ){ + + /* + this function explores the graph in a BFS manner and adds into the "path" TreeMap + the nodes that could be visited, but being constrained by a maximum depth + Path has pairs of (wayId, nodeId) as keys and Nodes as values (nodes with default value - Node(-1, -1, -1)) + */ + public static void initDataDijkstraQ( TreeMap graph, Node startNode, TreeMap,Node> path, TreeMap,Double> distance, int depthMax ){ int level = 0; LinkedList> q = new LinkedList>(); @@ -482,7 +491,8 @@ public void initDataDijkstra( TreeMap streetsGraph, Node startNode, T initDataDijkstra(streetsGraph, jointNode, path, distance, depthMax - 1 ); } } - + + /** * FindPath - returns a list with the intersections that have to passed. * @param graph - the street graphs @@ -693,9 +703,87 @@ public boolean isIntersectionAhead(GeoCar car, double distance, Node intersectio } + public GeoCar getCarOnOppositeSide(GeoCar car) { + MapPoint currentPos = car.getCurrentPos(); + GeoCarRoute route = car.getCurrentRoute(); + Way way = streetsGraph.get(currentPos.wayId); + Node currentNode = way.nodes.get(currentPos.segmentIndex); + Entity carOnTheOtherSide; + Long crtCell = currentPos.cellIndex; + int direction, queueNr; + double dist; + Iterator it = route.getIntersectionList().iterator(); + Node next = null; + + if (way.oneway) return null; + + while (it.hasNext()) { + next = it.next(); + dist = TraceParsingTool.distance(currentPos.lat, currentPos.lon, next.lat, next.lon); + + /** check if the next node is still on the same way. + * check if the distance between nodes does not exceed the max wifi range*/ + + if (currentNode.wayId != next.wayId + || dist > NetworkWiFi.maxWifiRange / 10000) { + break; + } + direction = getDirection(currentNode, next); + + /*select the opposite direction.*/ + queueNr = (direction == 1) ? 1 : 0; + + int segmentIndex = way.getNodeIndex(currentNode.id); + + /*segment index remains the same because the segments have the same order + * in both directions*/ + int queueSegmentIndex = (direction == 1) ? + segmentIndex : + way.nodes.size() - 1 - segmentIndex; + + TreeMap segmentQueue = way.streetQueues[queueNr].get(queueSegmentIndex); + + + if (segmentQueue.size() != 0) { + Cell cell = segmentQueue.firstEntry().getValue(); + carOnTheOtherSide = SimulationEngine.getInstance(). + entities.get(cell.trafficEntityId); + if (carOnTheOtherSide.getId() == car.getId()) { + return null; + } + + double distAhead = TraceParsingTool.distance(car.getCurrentPos().lat, car.getCurrentPos().lon, + carOnTheOtherSide.getCurrentPos().lat, carOnTheOtherSide.getCurrentPos().lon); + + if (distAhead > NetworkWiFi.maxWifiRange / 10000) { + return null; + } + + /*uncomment to color the cars which communicates + * make some attributes public before*/ +// if (distAhead > 1000) +// System.out.println("OPPOSITE: " + " car " + car.getId() + " car " + carOnTheOtherSide.getId() + " distance: " + distAhead +// + " NODE DIST "+ TraceParsingTool.distance(next.lat, next.lon, carOnTheOtherSide.getCurrentPos().lat, carOnTheOtherSide.getCurrentPos().lon) + " way: " + way.id); +// +// List carViewList = SimulationEngine.getInstance().viewer.carViewList; +// for (CarView carView : carViewList) { +// if (carView.car.getId() == car.getId()) { +// carView.setColor(Color.BLACK); +// } +// if (carView.car.getId() == carOnTheOtherSide.getId()) { +// carView.setColor(Color.BLACK); +// } +// } + + return (GeoCar) carOnTheOtherSide; + } + } + return null; + } + /** * Returns the car in front of the given car, within a given distance. - * + * * @param car * @param distance * @return null if it's the end of the route @@ -716,22 +804,22 @@ public Pair getElementAhead(GeoCar car, double distance) { if (crtPos.equals(route.getEndPoint())) return null; - + int queueNr = (crtPos.direction == 1) ? 0 : 1; - + Iterator it = route.getIntersectionList().iterator(); Node next = null; while (it.hasNext()) { next = it.next(); - + /* Check if the next node has a traffic light control */ if (next.hasTrafficLightControl()) { elementAhead = SimulationEngine.getInstance().entities.get(next.getTrafficLightId()); distAhead += TraceParsingTool.distance(lat, lon, elementAhead.getCurrentPos().lat, elementAhead.getCurrentPos().lon); - return new Pair(elementAhead, distAhead); + return new Pair(elementAhead, distAhead); } - + if (crt.wayId != next.wayId) { crt = getSegmentById(next.wayId, crt.id); /** @@ -742,52 +830,52 @@ public Pair getElementAhead(GeoCar car, double distance) { return null; } way = streetsGraph.get(crt.wayId); - + /** - * TODO(Cosmin): Check this condition because it + * TODO(Cosmin): Check this condition because it * seems not to work properly due to the fact that * one street can have a joint node in the middle of * the nodes vector. !!! - */ + */ int direction = getDirection(crt, next); queueNr = (direction == 1) ? 0 : 1; - + int segmentIndex = way.getNodeIndex(crt.id); int queueSegmentIndex = (direction == 1) ? segmentIndex : way.nodes.size() - 1 - segmentIndex; - + TreeMap segmentQueue = way.streetQueues[queueNr].get(queueSegmentIndex); - + /* On the first segment, remove cars behind current car */ if (way.id == crtPos.wayId && segmentIndex == crtPos.segmentIndex) { TreeMap aux = new TreeMap(segmentQueue); segmentQueue = new TreeMap(aux.tailMap(crtCell)); segmentQueue.remove(crtCell); } - + if (segmentQueue.size() != 0) { Cell cell = segmentQueue.firstEntry().getValue(); elementAhead = SimulationEngine.getInstance(). - entities.get(cell.trafficEntityId); - + entities.get(cell.trafficEntityId); + distAhead += TraceParsingTool.distance(lat, lon, elementAhead.getCurrentPos().lat, elementAhead.getCurrentPos().lon); return new Pair(elementAhead, distAhead); } - + /* No car on this segment, move to the next one. */ double dist = TraceParsingTool.distance(lat, lon, crt.lat, crt.lon); if (dist > distance) return new Pair(null, null); distance -= dist; distAhead += dist; - + lat = crt.lat; lon = crt.lon; crt = next; } - + return new Pair(null, null); } diff --git a/src/model/network/Message.java b/src/model/network/Message.java index 6651deb..cb02b4c 100644 --- a/src/model/network/Message.java +++ b/src/model/network/Message.java @@ -21,10 +21,18 @@ public class Message extends Header { private ApplicationType appType; private MessageType type; private Integer priority; + + private int messageDirection; private byte[] payload; - - + + public int getMessageDirection() { + return messageDirection; + } + + public void setMessageDirection(int messageDirection) { + this.messageDirection = messageDirection; + } public Message(long sourceId, long destId, Object data, MessageType type, ApplicationType appType) { this.setSourceId(sourceId); @@ -32,6 +40,7 @@ public Message(long sourceId, long destId, Object data, MessageType type, Applic this.setData(data); this.setType(type); this.setAppType(appType); + this.messageDirection = 1; } diff --git a/src/model/network/MessageType.java b/src/model/network/MessageType.java index 4007fdb..28c984a 100644 --- a/src/model/network/MessageType.java +++ b/src/model/network/MessageType.java @@ -17,5 +17,9 @@ public enum MessageType { ADD_WAITING_QUEUE, REMOVE_WAITING_QUEUE, /* Used by SincronizeIntersectionsApplication */ - SYNCHRONIZE_TRAFFIC_LIGHTS + SYNCHRONIZE_TRAFFIC_LIGHTS, + /* Used by Dynamic Routing Apps */ + CAR_INFORMS, + TRAFFIC_LIGHT_INFORMS, + OUTDATED_COSTS } \ No newline at end of file diff --git a/src/model/network/SourceType.java b/src/model/network/SourceType.java new file mode 100644 index 0000000..56dd7f1 --- /dev/null +++ b/src/model/network/SourceType.java @@ -0,0 +1,6 @@ +package model.network; + +public enum SourceType { + CAR, + TRAFFIC_LIGHT +} diff --git a/src/model/parameters/Globals.java b/src/model/parameters/Globals.java index 048fbcf..468ad8b 100644 --- a/src/model/parameters/Globals.java +++ b/src/model/parameters/Globals.java @@ -8,6 +8,7 @@ import com.beust.jcommander.Parameter; import controller.network.NetworkType; import controller.network.NetworkUtils; +import model.personality.PersonalityTypes; /** * Contains command line parameters and static fields that are used in multiple @@ -45,9 +46,27 @@ public class Globals { @Parameter(names = {"--debug"}, description = "The length of a clock tick.") public static int debug = 0; - + + /* Malicious Behavior */ @Parameter(names = {"--carsCount"}, description = "The number of cars simulated.") - public static int carsCount = 150; + public static int carsCount = 500; + + @Parameter(names = {"--maliciousCars"}, description = "the number of malicious cars") + public static int maliciousCars = 0; + + public static PersonalityTypes maliciousPersonalityType = PersonalityTypes.MALICIOUS_RANDOM; + + @Parameter(names = {"--dynamicRoutes"}, description = "The cars change their routes dynamically") + public static boolean dynamicRoutes = false; + + @Parameter(names = {"--CostSharingApps"}, description = "use the apps for streets cost sharing") + public static boolean costSharingApps = false; + + @Parameter(names = {"--votingSystem"}, description = "activate the voting system for cars before route recalculation") + public static boolean useVotingSystem = false; + + + /* ends here*/ @Parameter(names = {"--maxWaitingTime"}, description = "The maximum simulation time a car can wait at a traffic light.") public static int maxWaitingTime = 120; @@ -68,7 +87,7 @@ public class Globals { public static boolean loadGraph = false; @Parameter(names = {"--simulationDays"}, description = "Duration of the simulation in days.") - public static int simulationDays = 7; + public static int simulationDays = 1; @Parameter(names = {"--randomCarsSelect"}, description = "Set the percentage of cars to use in the simulation: 0.0 == none, 1.0 = all.") public static double randomCarsSelect = 1.0; @@ -140,7 +159,7 @@ public class Globals { @Parameter(names = {"--activeApps"}, description = "the accepted values ROUTING,TILES,STREET_VISITS,TRAFFIC_LIGHT_CONTROL." + "Please see ApplicationType for more details\n." + "Multiple applications can be passed using --activeApps=app1,app2,app3,..,appn") - public static String activeApps = "ROUTING,TRAFFIC_LIGHT_CONTROL"; + public static String activeApps = "TRAFFIC_LIGHT_CONTROL"; /* The default application is ROUTING_APP */ public static Vector activeApplications; diff --git a/src/model/personality/MaliciousPersonality.java b/src/model/personality/MaliciousPersonality.java new file mode 100644 index 0000000..564e5ce --- /dev/null +++ b/src/model/personality/MaliciousPersonality.java @@ -0,0 +1,80 @@ +package model.personality; + +import model.OSMgraph.Way; +import model.mobility.MobilityEngine; + +public class MaliciousPersonality implements Personality { + + private double coef2, coef3, coef4, coef5, coef6, coef7, coef8, + coef9, coef10; + + public MaliciousPersonality() { + coef2 = 1.0 - Math.random() * 2; + coef3 = 0.1 - Math.random() * 0.2; + coef4 = 5.0 - Math.random() * 10; + coef5 = 0.1 - Math.random() * 0.2; + coef6 = 1.0 - Math.random() * 2; + coef7 = 1.0 - Math.random() * 2; + coef8 = 1.0 - Math.random() * 2; + coef9 = 1.0 - Math.random() * 2; + coef10 = 0.5 - Math.random(); + } + + @Override + public double getSafetyDistance(double speed) { + if (speed < 10) + return 2.0 * speed + coef2; + return 2.0 * speed + coef4; + } + + @Override + public double getInfluenceDistance(double speed) { + return (5.7 + coef3) * speed + (40.0 + coef4); + } + + @Override + public double getDesiredDistance(double speed) { + if (speed < 10) { + return 5.0; + } + return (0.4 + coef5) * 3.6 * speed + (10.0 + coef6); + } + + @Override + public double getAccelerationFreeDriving() { + return (1.5 + coef7); + } + + @Override + public double getAccelerationMaximumBrake() { + return (-4.0 + coef8); + } + + @Override + public double getIntersectionDeceleration() { + return (-3.0 + coef7); + } + + @Override + public double getWantedSpeed(long id) { + Way way = MobilityEngine.getInstance().getWay(id); + return 0.0; + } + + @Override + public double getWantedSpeedInfluenced(double distanceFromIntersection, + double requiredSpeed) { + if (distanceFromIntersection > 90) + return 100; // speed in km here, should be meters + double ret = requiredSpeed + + (-1.0 / 90.0 * distanceFromIntersection * distanceFromIntersection + 19 / 9 * distanceFromIntersection); + + return ret; + } + + @Override + public double getReactionTimeFreeDriving() { + return (1.6 + coef10); + } +} + diff --git a/src/model/personality/PersonalityTypes.java b/src/model/personality/PersonalityTypes.java new file mode 100644 index 0000000..23c90d2 --- /dev/null +++ b/src/model/personality/PersonalityTypes.java @@ -0,0 +1,8 @@ +package model.personality; + +public enum PersonalityTypes { + REGULAR, + MALICIOUS_RANDOM, + MALICIOUS_INCREASED, + MALICIOUS_DECREASED +} diff --git a/src/utils/StreetsCostSharing.java b/src/utils/StreetsCostSharing.java new file mode 100644 index 0000000..4c91917 --- /dev/null +++ b/src/utils/StreetsCostSharing.java @@ -0,0 +1,267 @@ +package utils; +import application.dynamic_routing.VotingStreetCostData; +import model.GeoCar; +import model.OSMgraph.Way; +import model.OSMgraph.Node; +import model.mobility.MobilityEngine; +import model.parameters.Globals; +import utils.tracestool.Utils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + +/** + * This class has a batch of functions useful for dynamic routes calculations. + * Also, it has a reference to car's hashmap of streets cost (each car + * has its own perspective about the streets costs) + * + */ + +public class StreetsCostSharing { + +// pairs between each way id and its current cost +// each car has its representation + protected HashMap streetGraphCost; + + protected HashMap streetUpdates; + public static int MAX_DYNAMIC_VOTING_THRESHOLD = 7; + public static int MIN_DYNAMIC_VOTING_THRESHOLD = 2; + + // percentage threshold for considering a street cost updated + public static double STREET_COST_UPDATE_THRESHOLD = 0.4; + + /* street update constraints: CAR_MIN_TRACE_ON_STREET - percent + * CAR_MIN_TIME_ON_STREET - timestamps*/ + public static double CAR_MIN_TRACE_ON_STREET = 0.5; + public static double CAR_MIN_TIME_ON_STREET = 10; + + MobilityEngine mobilityEngine; + GeoCar car; + + + public HashMap getStreetUpdates() { + return streetUpdates; + } + + public StreetsCostSharing(GeoCar car){ + this.mobilityEngine = MobilityEngine.getInstance(); + streetGraphCost = new HashMap(); + this.streetUpdates = new HashMap(); + this.car = car; + } + + /* addNewUpdate and removeOutdatedInfo are functions for + * handling the updates regarding streets' costs by adding new costs + * or removing a info that already has been scattered*/ + + public void addNewUpdate(Long wayId, Double cost, Long discovererStamp) { + + if (!this.streetUpdates.containsKey(wayId)) { + this.streetUpdates.put(wayId, new VotingStreetCostData(cost, this.car.getId())); + return; + } + + VotingStreetCostData votingStreetCostData = this.streetUpdates.get(wayId); + votingStreetCostData.addDiscovererStamp(cost, discovererStamp); + } + + /*The network is aware of this street costs. So they can be deleted from the + * sharing package (streetUpdates). + * There is no point in trying to achieve a number of votes for this cost. Given the fact + * that the network is aware of it, the car will receive a valid package in the near future*/ + public void removeOutdatedInfo(HashMap outdatedCosts) { + Iterator itr = outdatedCosts.keySet().iterator(); + long currentWayId; + double currentUpdateCost; + double outdatedCost; + + while (itr.hasNext()) { + currentWayId = itr.next(); + + currentUpdateCost = streetUpdates.get(currentWayId).getStreetCost(); + outdatedCost = outdatedCosts.get(currentWayId).getStreetCost(); + + /*check if the currentUpdateCost has been modified before receiving this update + * regarding outdated cost. So, if the difference between this 2 costs is under THRESHOLD, + * there has been an update over this cost so it is not outdated anymore*/ + if (Math.abs(currentUpdateCost - outdatedCost) < + (currentUpdateCost * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { + streetUpdates.remove(currentWayId); + } + } + } + +/* returns the cost of street if it knows, otherwise calculate*/ + public double getWayCost(Way way) { + double streetCost; + + /*if the car does not know the street cost, take the first and the last node + * of the street. Calculate the distance between them using normal cruising speed.*/ + if (!streetGraphCost.containsKey(way.id)) { + Node firstNode = way.nodes.firstElement(); + Node lastNode = way.nodes.lastElement(); + + double streetLength = Utils.getRealDistanceAB(way, firstNode.id, lastNode.id); + streetCost = streetLength / (way.getMaximumSpeed() - 3); + streetGraphCost.put(way.id, streetCost); + + } else { + streetCost = streetGraphCost.get(way.id); + } + return streetCost; + } + + + /* this function calculates the average street cost considering a car that traveled just a segment + * of the entire street. We cannot assume that the distance traveled by the car is the + * actual street length*/ + public double calculateAverageCost (Way way, Node startingNode, Node finishNode, long wayStartTime, long wayFinishTime) { + Node firstNode = way.nodes.firstElement(); + Node lastNode = way.nodes.lastElement(); + long carTraceTime = wayFinishTime - wayStartTime; + + double streetLength = Utils.getRealDistanceAB(way, firstNode.id, lastNode.id); + +// car's trace on the current street + double carTraceLength = Utils.getRealDistanceAB(way, startingNode.id, finishNode.id); + +// start node is not correct + if (carTraceLength > streetLength) { + return -1; + } + + if (carTraceLength < (StreetsCostSharing.CAR_MIN_TRACE_ON_STREET * streetLength) || + carTraceTime < StreetsCostSharing.CAR_MIN_TIME_ON_STREET) { + return -1; + } + double speed = carTraceLength / carTraceTime; + + if (speed == 0) { + return -1; + } + + return streetLength / speed; + } + + + /* this method is called when a car changes the street. So it is able to generate a report */ + public void discoverNewWayCost(Way way, Node startingNode, Node finishNode, long startTime, long finishTime) { + + double reportedCost = calculateAverageCost(way, startingNode, finishNode, startTime, finishTime); + + if (reportedCost == -1) { + return; + } + + double currentStreetCost = getWayCost(way); + +// use the percentage threshold to validate the new update + if (Math.abs(currentStreetCost - reportedCost) > + (currentStreetCost * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { + streetGraphCost.put(way.id, reportedCost); + + // add this new cost to the "StreetUpdates" in order to inform the next trafficLight + this.addNewUpdate(way.id, reportedCost, this.car.getId()); + } + + } + + public static long counterMaliciousCosts = 0; + public static long counterRealCosts = 0; + + /*function called when a the CarDynamicRoutingApp finds some validUpdates for this car*/ + public void updateWayCost(long wayId, VotingStreetCostData receivedVotingData) { + + /*stamps management*/ + if (Globals.useVotingSystem) { + if (!this.streetUpdates.containsKey(wayId)) { + this.streetUpdates.put(wayId, receivedVotingData); + } else { + + VotingStreetCostData currentVotingData = this.streetUpdates.get(wayId); + currentVotingData.addNewStamps(receivedVotingData); + } + + VotingStreetCostData votingStreetCostData = this.streetUpdates.get(wayId); + if (votingStreetCostData.isStreetCostUpdated()) { + + if (car.getCurrentRoute().getWayIdsSet().contains(wayId)) { + + if (VotingStreetCostData.isTheSameStreetCost(receivedVotingData.getStreetCost(), StreetsCostSharingMalicious.DECREASED_VALUE) + || (VotingStreetCostData.isTheSameStreetCost(receivedVotingData.getStreetCost(), StreetsCostSharingMalicious.INCREASED_VALUE))) { + synchronized (StreetsCostSharing.class) { + counterMaliciousCosts++; + } + } else { + synchronized (StreetsCostSharing.class) { + counterRealCosts++; + } + } + + if (receivedVotingData.getStreetCost() > this.getWayCost(mobilityEngine.getWay(wayId))) { + double oldCost = this.getWayCost(mobilityEngine.getWay(wayId)); + this.streetGraphCost.put(wayId, receivedVotingData.getStreetCost()); + this.streetUpdates.put(wayId, receivedVotingData); + + car.appointForRouteRecalculation( receivedVotingData.getStreetCost() + - oldCost); + } + } + + // clear the voting session and redistribute the new info + votingStreetCostData.clearVoteSession(); + this.streetUpdates.put(wayId, votingStreetCostData); + + /* the cost was voted, so we can add the cost to the KB*/ + this.streetGraphCost.put(wayId, votingStreetCostData.getStreetCost()); + + } else { + /*otherwise, we have to wait until the cost is voted*/ + } + } else { + // do not use voting system + + if (car.getCurrentRoute().getWayIdsSet().contains(wayId)) { + + if (VotingStreetCostData.isTheSameStreetCost(receivedVotingData.getStreetCost(), StreetsCostSharingMalicious.DECREASED_VALUE) + || (VotingStreetCostData.isTheSameStreetCost(receivedVotingData.getStreetCost(), StreetsCostSharingMalicious.INCREASED_VALUE))) { + synchronized (StreetsCostSharing.class) { + counterMaliciousCosts++; + } + } else { + synchronized (StreetsCostSharing.class) { + counterRealCosts++; + } + } + + if (receivedVotingData.getStreetCost() > this.getWayCost(mobilityEngine.getWay(wayId))) { + double oldCost = this.getWayCost(mobilityEngine.getWay(wayId)); + this.streetGraphCost.put(wayId, receivedVotingData.getStreetCost()); + this.streetUpdates.put(wayId, receivedVotingData); + + car.appointForRouteRecalculation( receivedVotingData.getStreetCost() + - oldCost); + } + } else { + this.streetGraphCost.put(wayId, receivedVotingData.getStreetCost()); + this.streetUpdates.put(wayId, receivedVotingData); + } + } + + } + + public double calculateEntireRouteCost(HashSet wayIdsSet) { + Iterator it = wayIdsSet.iterator(); + long currentWayId = 0; + double total = 0; + double currentCost = 0; + + while (it.hasNext()) { + currentWayId = it.next(); + currentCost = this.getWayCost(mobilityEngine.getWay(currentWayId)); + total += currentCost; + } + return total; + } +} diff --git a/src/utils/StreetsCostSharingMalicious.java b/src/utils/StreetsCostSharingMalicious.java new file mode 100644 index 0000000..1798759 --- /dev/null +++ b/src/utils/StreetsCostSharingMalicious.java @@ -0,0 +1,77 @@ +package utils; + +import model.GeoCar; +import model.OSMgraph.Node; +import model.OSMgraph.Way; +import model.mobility.MobilityEngine; + +import java.util.ArrayList; +import java.util.Random; + +public class StreetsCostSharingMalicious extends StreetsCostSharing { + + public static final double INCREASED_VALUE = 4000; + public static final double DECREASED_VALUE = 1; + public static final int REPORT_MULTIPLICATION_FACTOR = 10; + ArrayList wayIdArr; + + public StreetsCostSharingMalicious(GeoCar car) { + + super(car); + wayIdArr = new ArrayList(MobilityEngine.getInstance().streetsGraph.keySet()); + + } + + @Override + public void discoverNewWayCost(Way way, Node startingNode, Node finishNode, long startTime, long finishTime) { + int counter = 0; + Random rand = new Random(); + long wayId; + + switch (super.car.getPersonalityType()) { + case MALICIOUS_RANDOM: + + while (counter < REPORT_MULTIPLICATION_FACTOR) { + int position = rand.nextInt(wayIdArr.size()); + wayId = wayIdArr.get(position); + + if (rand.nextInt(10) % 2 == 0) + super.addNewUpdate(wayId, StreetsCostSharingMalicious.INCREASED_VALUE, super.car.getId()); + else + super.addNewUpdate(wayId, StreetsCostSharingMalicious.DECREASED_VALUE, super.car.getId()); + counter++; + } + + if (rand.nextInt(10) % 2 == 0) { + super.addNewUpdate(way.id, StreetsCostSharingMalicious.INCREASED_VALUE, super.car.getId()); + } else { + super.addNewUpdate(way.id, StreetsCostSharingMalicious.DECREASED_VALUE, super.car.getId()); + } + break; + + case MALICIOUS_INCREASED: + + while (counter < REPORT_MULTIPLICATION_FACTOR) { + int position = rand.nextInt(wayIdArr.size()); + wayId = wayIdArr.get(position); + super.addNewUpdate(wayId, StreetsCostSharingMalicious.INCREASED_VALUE, super.car.getId()); + counter++; + } + super.addNewUpdate(way.id, StreetsCostSharingMalicious.INCREASED_VALUE, super.car.getId()); + break; + + case MALICIOUS_DECREASED: + + while (counter < REPORT_MULTIPLICATION_FACTOR) { + int position = rand.nextInt(wayIdArr.size()); + wayId = wayIdArr.get(position); + super.addNewUpdate(wayId, StreetsCostSharingMalicious.DECREASED_VALUE, super.car.getId()); + counter++; + } + super.addNewUpdate(way.id, StreetsCostSharingMalicious.DECREASED_VALUE, super.car.getId()); + break; + } + + } + +} From e8bfd0b9549441f1ff5606caa7c7f98726a52b94 Mon Sep 17 00:00:00 2001 From: blk14 Date: Fri, 4 Jun 2021 19:47:28 +0300 Subject: [PATCH 02/10] conflincts --- .idea/.gitignore | 8 +++ .idea/.name | 1 + .idea/misc.xml | 6 ++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 6 ++ Sim2Car.iml | 78 ++++++++++++++++++++++++++ src/downloader/DownloadCore.java | 2 - src/downloader/Downloader.java | 4 +- src/model/GeoCar.java | 14 +---- src/model/mobility/MobilityEngine.java | 16 ------ 10 files changed, 111 insertions(+), 32 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 Sim2Car.iml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..7103e4a --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/../../../../../../../../:\Users\bogda\OneDrive\Desktop\forked\sim2car\.idea/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..5e042cc --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Sim2Car \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..6c3d775 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..3b25812 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Sim2Car.iml b/Sim2Car.iml new file mode 100644 index 0000000..ac38aac --- /dev/null +++ b/Sim2Car.iml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/downloader/DownloadCore.java b/src/downloader/DownloadCore.java index 0063e46..d091f00 100644 --- a/src/downloader/DownloadCore.java +++ b/src/downloader/DownloadCore.java @@ -174,7 +174,6 @@ public void execute(String city) { String traces = curDir.getAbsolutePath(); parseConfigFile(); - System.out.println("aiis: " + t.getAbsolutePath()); if (city.equalsIgnoreCase("src/configurations/simulator/rome")) { String archive = t.getAbsolutePath() + File.separator + "rome.zip"; @@ -188,7 +187,6 @@ public void execute(String city) { unZipIt(archive, traces); } else if (city.equalsIgnoreCase("src/configurations/simulator/beijing")) { - System.out.println("sunt aucisals " + city); String archive = t.getAbsolutePath() + File.separator + "beijing.zip"; diff --git a/src/downloader/Downloader.java b/src/downloader/Downloader.java index 7ff18f8..2c87c58 100644 --- a/src/downloader/Downloader.java +++ b/src/downloader/Downloader.java @@ -48,8 +48,8 @@ public void downloadTraces(String propFile) { System.out.println("Trace files exist - Skipping DOWNLOAD STEP"); } else { System.out.println("Trace files don't exist - Starting DOWNLOAD STEP"); -// DownloadCore core = new DownloadCore(); -// core.execute(this.city); + DownloadCore core = new DownloadCore(); + core.execute(this.city); } } diff --git a/src/model/GeoCar.java b/src/model/GeoCar.java index 630ccbd..fffbc8a 100644 --- a/src/model/GeoCar.java +++ b/src/model/GeoCar.java @@ -713,12 +713,8 @@ public MapPoint getNextPosition() { double avgFuelConsumption = ComputeAverageFuelConsumption.computeAverageFuelConsumption(routeFuelFromStart, timei); routesTime.append((routes_idx++) + " " + timei + " " + avgSpeed + " " + avgFuelConsumption + System.lineSeparator()); -// System.out.println("Reached destination: " + "id: " + this.getId() + " avgSpeed: " + avgSpeed); -// if (updatedRoute) System.out.println("Cu update BAA"); - } -// System.out.println("null from reached dest last if"); return null; } @@ -729,7 +725,6 @@ public MapPoint getNextPosition() { * Prepare next Move for this car object. */ public void prepareMove() { -// System.out.println(this.getId() + " oe way: " + this.getCurrentPos().wayId); try { /** @@ -755,21 +750,16 @@ public void prepareMove() { oldSpeed = speed; updateSpeed(); - // System.out.println("speed: " + speed); - // System.out.println("way: " + this.getCurrentPos().wayId); nextPos = getNextPosition(); this.setBeginNewRoute(false); - /* - aicisa imi da nextPosition null why ????? - */ -// if (nextPos == null) System.out.println("Problema din prepare move"); + mobility.queueNextMove(this.getId(), nextPos); hasMoved.set(false); } catch (RuntimeException e) { /** Something was wrong with the route, so it's better to start a new one. */ -// System.out.println(e + " " + e.getStackTrace()[0].getLineNumber()); + setBeginNewRoute(true); // long timei = SimulationEngine.getInstance().getSimulationTime() - // routeStartTime; diff --git a/src/model/mobility/MobilityEngine.java b/src/model/mobility/MobilityEngine.java index 9412cb4..89ea020 100644 --- a/src/model/mobility/MobilityEngine.java +++ b/src/model/mobility/MobilityEngine.java @@ -759,22 +759,6 @@ public GeoCar getCarOnOppositeSide(GeoCar car) { return null; } - /*uncomment to color the cars which communicates - * make some attributes public before*/ -// if (distAhead > 1000) -// System.out.println("OPPOSITE: " + " car " + car.getId() + " car " + carOnTheOtherSide.getId() + " distance: " + distAhead -// + " NODE DIST "+ TraceParsingTool.distance(next.lat, next.lon, carOnTheOtherSide.getCurrentPos().lat, carOnTheOtherSide.getCurrentPos().lon) + " way: " + way.id); -// -// List carViewList = SimulationEngine.getInstance().viewer.carViewList; -// for (CarView carView : carViewList) { -// if (carView.car.getId() == car.getId()) { -// carView.setColor(Color.BLACK); -// } -// if (carView.car.getId() == carOnTheOtherSide.getId()) { -// carView.setColor(Color.BLACK); -// } -// } - return (GeoCar) carOnTheOtherSide; } } From 0fe1ef5467cd59da00507fe7251fa60e3a984ee0 Mon Sep 17 00:00:00 2001 From: blk14 Date: Fri, 4 Jun 2021 19:55:46 +0300 Subject: [PATCH 03/10] modified gitignore --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index ae3c172..049ba02 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,8 @@ /bin/ +/processeddata/ +/rawdata/ +/rome/ +sanfrancisco/ +/beijing/ +/ARCHIVES/ +/.idea/ \ No newline at end of file From f455d63620ae63a577514f62c5496e9ec4a6891a Mon Sep 17 00:00:00 2001 From: blk14 Date: Fri, 4 Jun 2021 20:08:11 +0300 Subject: [PATCH 04/10] refactor - street cost sharing --- .gitignore | 1 - .idea/.gitignore | 8 - .idea/workspace.xml | 54 ++++ .../dynamic_routing/CarDynamicRoutingApp.java | 2 +- .../TrafficLightDynamicRoutingApp.java | 2 +- .../dynamic_routing/VotingStreetCostData.java | 2 +- .../streetCostSharing/StreetsCostSharing.java | 267 ++++++++++++++++++ .../StreetsCostSharingMalicious.java | 77 +++++ .../newengine/SimulationEngine.java | 2 +- src/model/DynamicRoutes.java | 2 +- src/model/GeoCar.java | 2 + 11 files changed, 405 insertions(+), 14 deletions(-) delete mode 100644 .idea/.gitignore create mode 100644 .idea/workspace.xml create mode 100644 src/application/streetCostSharing/StreetsCostSharing.java create mode 100644 src/application/streetCostSharing/StreetsCostSharingMalicious.java diff --git a/.gitignore b/.gitignore index 049ba02..a6bab48 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,3 @@ sanfrancisco/ /beijing/ /ARCHIVES/ -/.idea/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 7103e4a..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Datasource local storage ignored files -/../../../../../../../../:\Users\bogda\OneDrive\Desktop\forked\sim2car\.idea/dataSources/ -/dataSources.local.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..51b8a87 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1622825924998 + + + + + + \ No newline at end of file diff --git a/src/application/dynamic_routing/CarDynamicRoutingApp.java b/src/application/dynamic_routing/CarDynamicRoutingApp.java index 9f371e5..663bab5 100644 --- a/src/application/dynamic_routing/CarDynamicRoutingApp.java +++ b/src/application/dynamic_routing/CarDynamicRoutingApp.java @@ -9,7 +9,7 @@ import model.network.Message; import model.network.MessageType; import model.parameters.Globals; -import utils.StreetsCostSharing; +import application.streetCostSharing.StreetsCostSharing; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java b/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java index 12aff85..4dd9c1d 100644 --- a/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java +++ b/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java @@ -11,7 +11,7 @@ import model.mobility.MobilityEngine; import model.network.Message; import model.network.MessageType; -import utils.StreetsCostSharing; +import application.streetCostSharing.StreetsCostSharing; import utils.tracestool.Utils; diff --git a/src/application/dynamic_routing/VotingStreetCostData.java b/src/application/dynamic_routing/VotingStreetCostData.java index 62ea99b..e1743af 100644 --- a/src/application/dynamic_routing/VotingStreetCostData.java +++ b/src/application/dynamic_routing/VotingStreetCostData.java @@ -1,6 +1,6 @@ package application.dynamic_routing; -import utils.StreetsCostSharing; +import application.streetCostSharing.StreetsCostSharing; import java.util.HashMap; import java.util.HashSet; diff --git a/src/application/streetCostSharing/StreetsCostSharing.java b/src/application/streetCostSharing/StreetsCostSharing.java new file mode 100644 index 0000000..3ec8066 --- /dev/null +++ b/src/application/streetCostSharing/StreetsCostSharing.java @@ -0,0 +1,267 @@ +package application.streetCostSharing; +import application.dynamic_routing.VotingStreetCostData; +import model.GeoCar; +import model.OSMgraph.Way; +import model.OSMgraph.Node; +import model.mobility.MobilityEngine; +import model.parameters.Globals; +import utils.tracestool.Utils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + +/** + * This class has a batch of functions useful for dynamic routes calculations. + * Also, it has a reference to car's hashmap of streets cost (each car + * has its own perspective about the streets costs) + * + */ + +public class StreetsCostSharing { + +// pairs between each way id and its current cost +// each car has its representation + protected HashMap streetGraphCost; + + protected HashMap streetUpdates; + public static int MAX_DYNAMIC_VOTING_THRESHOLD = 7; + public static int MIN_DYNAMIC_VOTING_THRESHOLD = 2; + + // percentage threshold for considering a street cost updated + public static double STREET_COST_UPDATE_THRESHOLD = 0.4; + + /* street update constraints: CAR_MIN_TRACE_ON_STREET - percent + * CAR_MIN_TIME_ON_STREET - timestamps*/ + public static double CAR_MIN_TRACE_ON_STREET = 0.5; + public static double CAR_MIN_TIME_ON_STREET = 10; + + MobilityEngine mobilityEngine; + GeoCar car; + + + public HashMap getStreetUpdates() { + return streetUpdates; + } + + public StreetsCostSharing(GeoCar car){ + this.mobilityEngine = MobilityEngine.getInstance(); + streetGraphCost = new HashMap(); + this.streetUpdates = new HashMap(); + this.car = car; + } + + /* addNewUpdate and removeOutdatedInfo are functions for + * handling the updates regarding streets' costs by adding new costs + * or removing a info that already has been scattered*/ + + public void addNewUpdate(Long wayId, Double cost, Long discovererStamp) { + + if (!this.streetUpdates.containsKey(wayId)) { + this.streetUpdates.put(wayId, new VotingStreetCostData(cost, this.car.getId())); + return; + } + + VotingStreetCostData votingStreetCostData = this.streetUpdates.get(wayId); + votingStreetCostData.addDiscovererStamp(cost, discovererStamp); + } + + /*The network is aware of this street costs. So they can be deleted from the + * sharing package (streetUpdates). + * There is no point in trying to achieve a number of votes for this cost. Given the fact + * that the network is aware of it, the car will receive a valid package in the near future*/ + public void removeOutdatedInfo(HashMap outdatedCosts) { + Iterator itr = outdatedCosts.keySet().iterator(); + long currentWayId; + double currentUpdateCost; + double outdatedCost; + + while (itr.hasNext()) { + currentWayId = itr.next(); + + currentUpdateCost = streetUpdates.get(currentWayId).getStreetCost(); + outdatedCost = outdatedCosts.get(currentWayId).getStreetCost(); + + /*check if the currentUpdateCost has been modified before receiving this update + * regarding outdated cost. So, if the difference between this 2 costs is under THRESHOLD, + * there has been an update over this cost so it is not outdated anymore*/ + if (Math.abs(currentUpdateCost - outdatedCost) < + (currentUpdateCost * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { + streetUpdates.remove(currentWayId); + } + } + } + +/* returns the cost of street if it knows, otherwise calculate*/ + public double getWayCost(Way way) { + double streetCost; + + /*if the car does not know the street cost, take the first and the last node + * of the street. Calculate the distance between them using normal cruising speed.*/ + if (!streetGraphCost.containsKey(way.id)) { + Node firstNode = way.nodes.firstElement(); + Node lastNode = way.nodes.lastElement(); + + double streetLength = Utils.getRealDistanceAB(way, firstNode.id, lastNode.id); + streetCost = streetLength / (way.getMaximumSpeed() - 3); + streetGraphCost.put(way.id, streetCost); + + } else { + streetCost = streetGraphCost.get(way.id); + } + return streetCost; + } + + + /* this function calculates the average street cost considering a car that traveled just a segment + * of the entire street. We cannot assume that the distance traveled by the car is the + * actual street length*/ + public double calculateAverageCost (Way way, Node startingNode, Node finishNode, long wayStartTime, long wayFinishTime) { + Node firstNode = way.nodes.firstElement(); + Node lastNode = way.nodes.lastElement(); + long carTraceTime = wayFinishTime - wayStartTime; + + double streetLength = Utils.getRealDistanceAB(way, firstNode.id, lastNode.id); + +// car's trace on the current street + double carTraceLength = Utils.getRealDistanceAB(way, startingNode.id, finishNode.id); + +// start node is not correct + if (carTraceLength > streetLength) { + return -1; + } + + if (carTraceLength < (StreetsCostSharing.CAR_MIN_TRACE_ON_STREET * streetLength) || + carTraceTime < StreetsCostSharing.CAR_MIN_TIME_ON_STREET) { + return -1; + } + double speed = carTraceLength / carTraceTime; + + if (speed == 0) { + return -1; + } + + return streetLength / speed; + } + + + /* this method is called when a car changes the street. So it is able to generate a report */ + public void discoverNewWayCost(Way way, Node startingNode, Node finishNode, long startTime, long finishTime) { + + double reportedCost = calculateAverageCost(way, startingNode, finishNode, startTime, finishTime); + + if (reportedCost == -1) { + return; + } + + double currentStreetCost = getWayCost(way); + +// use the percentage threshold to validate the new update + if (Math.abs(currentStreetCost - reportedCost) > + (currentStreetCost * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { + streetGraphCost.put(way.id, reportedCost); + + // add this new cost to the "StreetUpdates" in order to inform the next trafficLight + this.addNewUpdate(way.id, reportedCost, this.car.getId()); + } + + } + + public static long counterMaliciousCosts = 0; + public static long counterRealCosts = 0; + + /*function called when a the CarDynamicRoutingApp finds some validUpdates for this car*/ + public void updateWayCost(long wayId, VotingStreetCostData receivedVotingData) { + + /*stamps management*/ + if (Globals.useVotingSystem) { + if (!this.streetUpdates.containsKey(wayId)) { + this.streetUpdates.put(wayId, receivedVotingData); + } else { + + VotingStreetCostData currentVotingData = this.streetUpdates.get(wayId); + currentVotingData.addNewStamps(receivedVotingData); + } + + VotingStreetCostData votingStreetCostData = this.streetUpdates.get(wayId); + if (votingStreetCostData.isStreetCostUpdated()) { + + if (car.getCurrentRoute().getWayIdsSet().contains(wayId)) { + + if (VotingStreetCostData.isTheSameStreetCost(receivedVotingData.getStreetCost(), StreetsCostSharingMalicious.DECREASED_VALUE) + || (VotingStreetCostData.isTheSameStreetCost(receivedVotingData.getStreetCost(), StreetsCostSharingMalicious.INCREASED_VALUE))) { + synchronized (StreetsCostSharing.class) { + counterMaliciousCosts++; + } + } else { + synchronized (StreetsCostSharing.class) { + counterRealCosts++; + } + } + + if (receivedVotingData.getStreetCost() > this.getWayCost(mobilityEngine.getWay(wayId))) { + double oldCost = this.getWayCost(mobilityEngine.getWay(wayId)); + this.streetGraphCost.put(wayId, receivedVotingData.getStreetCost()); + this.streetUpdates.put(wayId, receivedVotingData); + + car.appointForRouteRecalculation( receivedVotingData.getStreetCost() + - oldCost); + } + } + + // clear the voting session and redistribute the new info + votingStreetCostData.clearVoteSession(); + this.streetUpdates.put(wayId, votingStreetCostData); + + /* the cost was voted, so we can add the cost to the KB*/ + this.streetGraphCost.put(wayId, votingStreetCostData.getStreetCost()); + + } else { + /*otherwise, we have to wait until the cost is voted*/ + } + } else { + // do not use voting system + + if (car.getCurrentRoute().getWayIdsSet().contains(wayId)) { + + if (VotingStreetCostData.isTheSameStreetCost(receivedVotingData.getStreetCost(), StreetsCostSharingMalicious.DECREASED_VALUE) + || (VotingStreetCostData.isTheSameStreetCost(receivedVotingData.getStreetCost(), StreetsCostSharingMalicious.INCREASED_VALUE))) { + synchronized (StreetsCostSharing.class) { + counterMaliciousCosts++; + } + } else { + synchronized (StreetsCostSharing.class) { + counterRealCosts++; + } + } + + if (receivedVotingData.getStreetCost() > this.getWayCost(mobilityEngine.getWay(wayId))) { + double oldCost = this.getWayCost(mobilityEngine.getWay(wayId)); + this.streetGraphCost.put(wayId, receivedVotingData.getStreetCost()); + this.streetUpdates.put(wayId, receivedVotingData); + + car.appointForRouteRecalculation( receivedVotingData.getStreetCost() + - oldCost); + } + } else { + this.streetGraphCost.put(wayId, receivedVotingData.getStreetCost()); + this.streetUpdates.put(wayId, receivedVotingData); + } + } + + } + + public double calculateEntireRouteCost(HashSet wayIdsSet) { + Iterator it = wayIdsSet.iterator(); + long currentWayId = 0; + double total = 0; + double currentCost = 0; + + while (it.hasNext()) { + currentWayId = it.next(); + currentCost = this.getWayCost(mobilityEngine.getWay(currentWayId)); + total += currentCost; + } + return total; + } +} diff --git a/src/application/streetCostSharing/StreetsCostSharingMalicious.java b/src/application/streetCostSharing/StreetsCostSharingMalicious.java new file mode 100644 index 0000000..d9d776c --- /dev/null +++ b/src/application/streetCostSharing/StreetsCostSharingMalicious.java @@ -0,0 +1,77 @@ +package application.streetCostSharing; + +import model.GeoCar; +import model.OSMgraph.Node; +import model.OSMgraph.Way; +import model.mobility.MobilityEngine; + +import java.util.ArrayList; +import java.util.Random; + +public class StreetsCostSharingMalicious extends StreetsCostSharing { + + public static final double INCREASED_VALUE = 4000; + public static final double DECREASED_VALUE = 1; + public static final int REPORT_MULTIPLICATION_FACTOR = 10; + ArrayList wayIdArr; + + public StreetsCostSharingMalicious(GeoCar car) { + + super(car); + wayIdArr = new ArrayList(MobilityEngine.getInstance().streetsGraph.keySet()); + + } + + @Override + public void discoverNewWayCost(Way way, Node startingNode, Node finishNode, long startTime, long finishTime) { + int counter = 0; + Random rand = new Random(); + long wayId; + + switch (super.car.getPersonalityType()) { + case MALICIOUS_RANDOM: + + while (counter < REPORT_MULTIPLICATION_FACTOR) { + int position = rand.nextInt(wayIdArr.size()); + wayId = wayIdArr.get(position); + + if (rand.nextInt(10) % 2 == 0) + super.addNewUpdate(wayId, StreetsCostSharingMalicious.INCREASED_VALUE, super.car.getId()); + else + super.addNewUpdate(wayId, StreetsCostSharingMalicious.DECREASED_VALUE, super.car.getId()); + counter++; + } + + if (rand.nextInt(10) % 2 == 0) { + super.addNewUpdate(way.id, StreetsCostSharingMalicious.INCREASED_VALUE, super.car.getId()); + } else { + super.addNewUpdate(way.id, StreetsCostSharingMalicious.DECREASED_VALUE, super.car.getId()); + } + break; + + case MALICIOUS_INCREASED: + + while (counter < REPORT_MULTIPLICATION_FACTOR) { + int position = rand.nextInt(wayIdArr.size()); + wayId = wayIdArr.get(position); + super.addNewUpdate(wayId, StreetsCostSharingMalicious.INCREASED_VALUE, super.car.getId()); + counter++; + } + super.addNewUpdate(way.id, StreetsCostSharingMalicious.INCREASED_VALUE, super.car.getId()); + break; + + case MALICIOUS_DECREASED: + + while (counter < REPORT_MULTIPLICATION_FACTOR) { + int position = rand.nextInt(wayIdArr.size()); + wayId = wayIdArr.get(position); + super.addNewUpdate(wayId, StreetsCostSharingMalicious.DECREASED_VALUE, super.car.getId()); + counter++; + } + super.addNewUpdate(way.id, StreetsCostSharingMalicious.DECREASED_VALUE, super.car.getId()); + break; + } + + } + +} diff --git a/src/controller/newengine/SimulationEngine.java b/src/controller/newengine/SimulationEngine.java index 1580a29..c37c1df 100644 --- a/src/controller/newengine/SimulationEngine.java +++ b/src/controller/newengine/SimulationEngine.java @@ -28,7 +28,7 @@ import model.threadpool.tasks.*; import controller.engine.EngineInterface; import controller.network.NetworkType; -import utils.StreetsCostSharing; +import application.streetCostSharing.StreetsCostSharing; /** diff --git a/src/model/DynamicRoutes.java b/src/model/DynamicRoutes.java index 992d814..f28c969 100644 --- a/src/model/DynamicRoutes.java +++ b/src/model/DynamicRoutes.java @@ -3,7 +3,7 @@ import model.OSMgraph.Node; import model.OSMgraph.Way; import model.mobility.MobilityEngine; -import utils.StreetsCostSharing; +import application.streetCostSharing.StreetsCostSharing; import utils.Pair; import utils.tracestool.Utils; diff --git a/src/model/GeoCar.java b/src/model/GeoCar.java index fffbc8a..d276335 100644 --- a/src/model/GeoCar.java +++ b/src/model/GeoCar.java @@ -9,6 +9,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; +import application.streetCostSharing.StreetsCostSharing; +import application.streetCostSharing.StreetsCostSharingMalicious; import controller.network.NetworkInterface; import controller.network.NetworkType; import controller.network.NetworkWiFi; From 7d58bc595112cfba3f3c119f65b2772aa145e283 Mon Sep 17 00:00:00 2001 From: blk14 Date: Fri, 4 Jun 2021 20:13:03 +0300 Subject: [PATCH 05/10] --- .gitignore | 1 + .idea/.name | 1 - .idea/misc.xml | 6 ----- .idea/modules.xml | 8 ------- .idea/vcs.xml | 6 ----- .idea/workspace.xml | 54 --------------------------------------------- 6 files changed, 1 insertion(+), 75 deletions(-) delete mode 100644 .idea/.name delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/workspace.xml diff --git a/.gitignore b/.gitignore index a6bab48..5025588 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ sanfrancisco/ /beijing/ /ARCHIVES/ +.idea diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 5e042cc..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -Sim2Car \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 6c3d775..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 3b25812..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 51b8a87..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1622825924998 - - - - - - \ No newline at end of file From 1125710365c54751a0a54081223ccf4ecbf4fdd3 Mon Sep 17 00:00:00 2001 From: blk14 Date: Fri, 4 Jun 2021 21:19:17 +0300 Subject: [PATCH 06/10] --- .../TrafficLightDynamicRoutingApp.java | 10 +-- src/model/parameters/Globals.java | 2 +- .../personality/MaliciousPersonality.java | 80 ------------------- 3 files changed, 6 insertions(+), 86 deletions(-) delete mode 100644 src/model/personality/MaliciousPersonality.java diff --git a/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java b/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java index 4dd9c1d..05526fb 100644 --- a/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java +++ b/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java @@ -138,12 +138,12 @@ private void spreadUpdatesToNeighbours(HashMap valid continue; } -// if (i == stepOver1 || i == stepOver2) { -// continue; -// } + if (i == stepOver1 || i == stepOver2) { + continue; + } - /** to reduce the cpu consumption uncomment it, and comment the ones above*/ - if (i != stepOver1) continue; + /** to reduce the cpu consumption uncomment this, and comment the ones above*/ +// if (i != stepOver1) continue; Message message = new Message(this.trafficLightMaster.getId(), neighbourTrafficLightId, validUpdates.clone(), MessageType.TRAFFIC_LIGHT_INFORMS, ApplicationType.TRAFFIC_LIGHT_ROUTING_APP); diff --git a/src/model/parameters/Globals.java b/src/model/parameters/Globals.java index 468ad8b..6d37f2e 100644 --- a/src/model/parameters/Globals.java +++ b/src/model/parameters/Globals.java @@ -49,7 +49,7 @@ public class Globals { /* Malicious Behavior */ @Parameter(names = {"--carsCount"}, description = "The number of cars simulated.") - public static int carsCount = 500; + public static int carsCount = 300; @Parameter(names = {"--maliciousCars"}, description = "the number of malicious cars") public static int maliciousCars = 0; diff --git a/src/model/personality/MaliciousPersonality.java b/src/model/personality/MaliciousPersonality.java deleted file mode 100644 index 564e5ce..0000000 --- a/src/model/personality/MaliciousPersonality.java +++ /dev/null @@ -1,80 +0,0 @@ -package model.personality; - -import model.OSMgraph.Way; -import model.mobility.MobilityEngine; - -public class MaliciousPersonality implements Personality { - - private double coef2, coef3, coef4, coef5, coef6, coef7, coef8, - coef9, coef10; - - public MaliciousPersonality() { - coef2 = 1.0 - Math.random() * 2; - coef3 = 0.1 - Math.random() * 0.2; - coef4 = 5.0 - Math.random() * 10; - coef5 = 0.1 - Math.random() * 0.2; - coef6 = 1.0 - Math.random() * 2; - coef7 = 1.0 - Math.random() * 2; - coef8 = 1.0 - Math.random() * 2; - coef9 = 1.0 - Math.random() * 2; - coef10 = 0.5 - Math.random(); - } - - @Override - public double getSafetyDistance(double speed) { - if (speed < 10) - return 2.0 * speed + coef2; - return 2.0 * speed + coef4; - } - - @Override - public double getInfluenceDistance(double speed) { - return (5.7 + coef3) * speed + (40.0 + coef4); - } - - @Override - public double getDesiredDistance(double speed) { - if (speed < 10) { - return 5.0; - } - return (0.4 + coef5) * 3.6 * speed + (10.0 + coef6); - } - - @Override - public double getAccelerationFreeDriving() { - return (1.5 + coef7); - } - - @Override - public double getAccelerationMaximumBrake() { - return (-4.0 + coef8); - } - - @Override - public double getIntersectionDeceleration() { - return (-3.0 + coef7); - } - - @Override - public double getWantedSpeed(long id) { - Way way = MobilityEngine.getInstance().getWay(id); - return 0.0; - } - - @Override - public double getWantedSpeedInfluenced(double distanceFromIntersection, - double requiredSpeed) { - if (distanceFromIntersection > 90) - return 100; // speed in km here, should be meters - double ret = requiredSpeed - + (-1.0 / 90.0 * distanceFromIntersection * distanceFromIntersection + 19 / 9 * distanceFromIntersection); - - return ret; - } - - @Override - public double getReactionTimeFreeDriving() { - return (1.6 + coef10); - } -} - From b0d3ea8028f1466928a7f8da50bed289ea6904b4 Mon Sep 17 00:00:00 2001 From: blk14 Date: Sat, 12 Jun 2021 22:23:02 +0300 Subject: [PATCH 07/10] '' --- .../dynamic_routing/CarDynamicRoutingApp.java | 4 +--- .../TrafficLightDynamicRoutingApp.java | 4 +--- .../dynamic_routing/VotingStreetCostData.java | 12 ++++++------ .../streetCostSharing/StreetsCostSharing.java | 5 +++-- src/model/GeoCar.java | 2 +- src/model/parameters/Globals.java | 4 +--- 6 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/application/dynamic_routing/CarDynamicRoutingApp.java b/src/application/dynamic_routing/CarDynamicRoutingApp.java index 663bab5..43b7758 100644 --- a/src/application/dynamic_routing/CarDynamicRoutingApp.java +++ b/src/application/dynamic_routing/CarDynamicRoutingApp.java @@ -107,7 +107,7 @@ public boolean isOutdated(double oldCost, double updateCost, long currentWayId, /* this function has the role to iterate through the reported costs and to - * split them in valid data or outdated data (outdated data is useful only + * split them into valid data or outdated data (outdated data is useful only * in CARS communication context)*/ private ArrayList> updatesPreProcessing(Message m) { HashMap updates; @@ -129,8 +129,6 @@ private ArrayList> updatesPreProcessing(Mess if (!isOutdated(oldCost, updateCost, currentWayId, updates.get(currentWayId))) { car.getStreetsCostSharing().updateWayCost(currentWayId, updates.get(currentWayId)); - - /*validUpdates will be useful when I'll add the validation policy*/ validUpdates.put(currentWayId, updates.get(currentWayId)); } else { diff --git a/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java b/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java index 05526fb..b50804c 100644 --- a/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java +++ b/src/application/dynamic_routing/TrafficLightDynamicRoutingApp.java @@ -164,7 +164,7 @@ private void sendBackOutdatedUpdates(HashMap outdate /* this function has the role to iterate through the reported costs and to - * split them in valid data or outdated data (outdated data is useful only + * split them into valid data or outdated data (outdated data is useful only * in CARS communication context*/ private ArrayList> updatesPreProcessing(Message m) { HashMap updates; @@ -186,8 +186,6 @@ private ArrayList> updatesPreProcessing(Mess if (Math.abs(oldCost - updateCost) > (oldCost * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { streetGraphCost.put(currentWayId, updateCost); - - /*validUpdates will be useful when I'll add the validation policy*/ validUpdates.put(currentWayId, updates.get(currentWayId)); /*put the news in the structure responsible for sharing with the cars*/ diff --git a/src/application/dynamic_routing/VotingStreetCostData.java b/src/application/dynamic_routing/VotingStreetCostData.java index e1743af..55dad18 100644 --- a/src/application/dynamic_routing/VotingStreetCostData.java +++ b/src/application/dynamic_routing/VotingStreetCostData.java @@ -11,7 +11,7 @@ public class VotingStreetCostData { double streetCost; boolean firstVotingSession; - /*each cost should be stamped by multiple entities before taking it into consideration + /*each cost should be stamped by multiple entities before taking it into consideration. * there could be multiple costs reported for the same street, so we need * to keep track of each cost ant its stamps in order to make the best updated decision*/ HashMap> costVotingMap; @@ -129,7 +129,7 @@ public void addNewStamps(VotingStreetCostData votingStreetCostData) { Iterator stampIterator = votingStreetCostData.getCostVotingMap().get(currentCost).iterator(); long currentStamp; - /*if the cost is not present into the Map, add the cost and its stamps from the param object*/ + /*if the cost is not present into the Map, add the cost and its stamps from params*/ if (!this.costVotingMap.containsKey(currentCost)) { costVotingMap.put(currentCost, votingStreetCostData.getCostVotingMap().get(currentCost)); } else { @@ -146,10 +146,10 @@ public void addNewStamps(VotingStreetCostData votingStreetCostData) { } } - /* check if there is a cost in the voting session that is over the threshold + /* check if there is a cost in the voting session that is greater than the threshold * there are 2 cases: * - an increased report - * - an decreased report + * - a decreased report * The threshold is dynamically changed depending on the report type*/ public boolean isStreetCostUpdated() { Iterator costIterator = this.costVotingMap.keySet().iterator(); @@ -193,8 +193,8 @@ public boolean isStreetCostUpdated() { return false; } - /* after a decision is making, there is no point in keeping the costs - * that was not voted*/ + /* after a decision is made, there is no point in keeping the costs + * that were not voted*/ public void clearVoteSession() { this.costVotingMap.entrySet().removeIf(e -> e.getKey() != this.streetCost); } diff --git a/src/application/streetCostSharing/StreetsCostSharing.java b/src/application/streetCostSharing/StreetsCostSharing.java index 3ec8066..faab9c2 100644 --- a/src/application/streetCostSharing/StreetsCostSharing.java +++ b/src/application/streetCostSharing/StreetsCostSharing.java @@ -83,7 +83,7 @@ public void removeOutdatedInfo(HashMap outdatedCosts outdatedCost = outdatedCosts.get(currentWayId).getStreetCost(); /*check if the currentUpdateCost has been modified before receiving this update - * regarding outdated cost. So, if the difference between this 2 costs is under THRESHOLD, + * regarding outdated cost. So, if the difference between this 2 costs smaller than the THRESHOLD, * there has been an update over this cost so it is not outdated anymore*/ if (Math.abs(currentUpdateCost - outdatedCost) < (currentUpdateCost * StreetsCostSharing.STREET_COST_UPDATE_THRESHOLD)) { @@ -217,7 +217,8 @@ public void updateWayCost(long wayId, VotingStreetCostData receivedVotingData) { this.streetGraphCost.put(wayId, votingStreetCostData.getStreetCost()); } else { - /*otherwise, we have to wait until the cost is voted*/ + /*otherwise, we have to wait until the cost is voted. + * the new votes are added to the KB in the first if statement*/ } } else { // do not use voting system diff --git a/src/model/GeoCar.java b/src/model/GeoCar.java index d276335..b47d916 100644 --- a/src/model/GeoCar.java +++ b/src/model/GeoCar.java @@ -497,7 +497,7 @@ public double getRouteIncreasedCostPercentage() { /** this method has the role to appoint the car for route recalculation - * it is called from streetsCostSharing.updateWayCost when a way within + * it is called from streetsCostSharing.updateWayCost when a street within * this car's route is updated (has a different cost)*/ public void appointForRouteRecalculation(double increasedWayCost) { diff --git a/src/model/parameters/Globals.java b/src/model/parameters/Globals.java index 6d37f2e..0df4782 100644 --- a/src/model/parameters/Globals.java +++ b/src/model/parameters/Globals.java @@ -64,9 +64,7 @@ public class Globals { @Parameter(names = {"--votingSystem"}, description = "activate the voting system for cars before route recalculation") public static boolean useVotingSystem = false; - - - /* ends here*/ + /* end MB*/ @Parameter(names = {"--maxWaitingTime"}, description = "The maximum simulation time a car can wait at a traffic light.") public static int maxWaitingTime = 120; From f6d6f7f520a7a9fae1cb7588c36dc497d33871ee Mon Sep 17 00:00:00 2001 From: blk14 Date: Sun, 13 Jun 2021 18:02:03 +0300 Subject: [PATCH 08/10] dynamic voting threshold --- .../dynamic_routing/VotingStreetCostData.java | 20 +++++++++---------- .../VotingStreetCostDataTest.java | 4 ++-- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/application/dynamic_routing/VotingStreetCostData.java b/src/application/dynamic_routing/VotingStreetCostData.java index 55dad18..5eeb2ad 100644 --- a/src/application/dynamic_routing/VotingStreetCostData.java +++ b/src/application/dynamic_routing/VotingStreetCostData.java @@ -16,8 +16,7 @@ public class VotingStreetCostData { * to keep track of each cost ant its stamps in order to make the best updated decision*/ HashMap> costVotingMap; - public int UPPER_DYNAMIC_VOTING_THRESHOLD = 2; - public int LOWER_DYNAMIC_VOTING_THRESHOLD = 2; + public int DYNAMIC_VOTING_THRESHOLD = 2; public HashMap> getCostVotingMap() { return costVotingMap; @@ -163,7 +162,7 @@ public boolean isStreetCostUpdated() { /*first voting session*/ if (this.firstVotingSession) { - if (this.costVotingMap.get(currentCost).size() >= UPPER_DYNAMIC_VOTING_THRESHOLD) { + if (this.costVotingMap.get(currentCost).size() >= DYNAMIC_VOTING_THRESHOLD) { this.streetCost = currentCost; firstVotingSession = false; return true; @@ -171,21 +170,21 @@ public boolean isStreetCostUpdated() { } else if (currentCost > streetCost) { /*increased cost -> UPPER_THRESHOLD*/ - if (this.costVotingMap.get(currentCost).size() >= UPPER_DYNAMIC_VOTING_THRESHOLD) { + if (this.costVotingMap.get(currentCost).size() >= DYNAMIC_VOTING_THRESHOLD) { this.streetCost = currentCost; /*if another session wants to increase the cost more, it has to overwhelm a bigger threshold*/ - if (UPPER_DYNAMIC_VOTING_THRESHOLD < StreetsCostSharing.MAX_DYNAMIC_VOTING_THRESHOLD) - UPPER_DYNAMIC_VOTING_THRESHOLD += 1; + if (DYNAMIC_VOTING_THRESHOLD < StreetsCostSharing.MAX_DYNAMIC_VOTING_THRESHOLD) + DYNAMIC_VOTING_THRESHOLD += 1; return true; } } else { /*decreased cost -> LOWER_THRESHOLD*/ - if (this.costVotingMap.get(currentCost).size() >= LOWER_DYNAMIC_VOTING_THRESHOLD) { + if (this.costVotingMap.get(currentCost).size() >= DYNAMIC_VOTING_THRESHOLD) { this.streetCost = currentCost; - if (LOWER_DYNAMIC_VOTING_THRESHOLD > StreetsCostSharing.MIN_DYNAMIC_VOTING_THRESHOLD) - LOWER_DYNAMIC_VOTING_THRESHOLD -= 1; + if (DYNAMIC_VOTING_THRESHOLD > StreetsCostSharing.MIN_DYNAMIC_VOTING_THRESHOLD) + DYNAMIC_VOTING_THRESHOLD -= 1; return true; } } @@ -214,8 +213,7 @@ public String toString() { return "VotingStreetCostData{" + "streetCost=" + streetCost + ", costVotingMap=" + costVotingMap.toString() + - ", UPPER_DYNAMIC_VOTING_THRESHOLD=" + UPPER_DYNAMIC_VOTING_THRESHOLD + - ", LOWER_DYNAMIC_VOTING_THRESHOLD=" + LOWER_DYNAMIC_VOTING_THRESHOLD + + ", UPPER_DYNAMIC_VOTING_THRESHOLD=" + DYNAMIC_VOTING_THRESHOLD + '}'; } } diff --git a/src/application/dynamic_routing/VotingStreetCostDataTest.java b/src/application/dynamic_routing/VotingStreetCostDataTest.java index ea130fc..e54c89a 100644 --- a/src/application/dynamic_routing/VotingStreetCostDataTest.java +++ b/src/application/dynamic_routing/VotingStreetCostDataTest.java @@ -174,7 +174,7 @@ public void testIsStreetCostUpdated() { System.out.println("[FAIL]"); } - if (votingStreetCostData.UPPER_DYNAMIC_VOTING_THRESHOLD == 2) { + if (votingStreetCostData.DYNAMIC_VOTING_THRESHOLD == 2) { System.out.println("PASS"); } else { System.out.println("FAIL"); @@ -208,7 +208,7 @@ public void testIsStreetCostUpdated() { } System.out.println("Voted cost is: " + votingStreetCostData.getStreetCost()); - if (votingStreetCostData.UPPER_DYNAMIC_VOTING_THRESHOLD == 3) { + if (votingStreetCostData.DYNAMIC_VOTING_THRESHOLD == 3) { System.out.println("PASS"); } else { System.out.println("FAIL"); From 9a17e26403e777c06e74e2f47c758c51989b1d86 Mon Sep 17 00:00:00 2001 From: blk14 Date: Fri, 2 Jul 2021 15:01:23 +0300 Subject: [PATCH 09/10] voting sessions, collect the stamps from 2 similar costs --- .../dynamic_routing/VotingStreetCostData.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/application/dynamic_routing/VotingStreetCostData.java b/src/application/dynamic_routing/VotingStreetCostData.java index 5eeb2ad..df47b52 100644 --- a/src/application/dynamic_routing/VotingStreetCostData.java +++ b/src/application/dynamic_routing/VotingStreetCostData.java @@ -118,9 +118,11 @@ public boolean hasNewStamps(VotingStreetCostData votingStreetCostData) { return false; } + /** add new costs with stamps, or add new stamps to the existing costs*/ public void addNewStamps(VotingStreetCostData votingStreetCostData) { Iterator costIterator = votingStreetCostData.getCostVotingMap().keySet().iterator(); + Iterator currentSessionCostIterator = this.costVotingMap.keySet().iterator(); while (costIterator.hasNext()) { double currentCost = costIterator.next(); @@ -128,20 +130,24 @@ public void addNewStamps(VotingStreetCostData votingStreetCostData) { Iterator stampIterator = votingStreetCostData.getCostVotingMap().get(currentCost).iterator(); long currentStamp; - /*if the cost is not present into the Map, add the cost and its stamps from params*/ - if (!this.costVotingMap.containsKey(currentCost)) { - costVotingMap.put(currentCost, votingStreetCostData.getCostVotingMap().get(currentCost)); - } else { - /*iterate through stamps and add the new ones*/ - while (stampIterator.hasNext()) { - currentStamp = stampIterator.next(); - - if (!this.costVotingMap.get(currentCost).contains(currentStamp)) { - this.costVotingMap.get(currentCost).add(currentStamp); + /*if the cost is not present into the Map, add the cost and its stamps from the param object*/ + while (currentSessionCostIterator.hasNext()) { + double votedCost = currentSessionCostIterator.next(); + if (VotingStreetCostData.isTheSameStreetCost(votedCost, currentCost)) { + /*iterate through stamps and add the new ones*/ + while (stampIterator.hasNext()) { + currentStamp = stampIterator.next(); + + if (!this.costVotingMap.get(votedCost).contains(currentStamp)) { + this.costVotingMap.get(votedCost).add(currentStamp); + } } + return; } } + /*if the cost not found in the session, add all stamps*/ + costVotingMap.put(currentCost, votingStreetCostData.getCostVotingMap().get(currentCost)); } } From cb0e9f817a26e4230a98efb67c42cb78ae74229c Mon Sep 17 00:00:00 2001 From: blk14 Date: Mon, 5 Jul 2021 16:11:11 +0300 Subject: [PATCH 10/10] voting sessions merge tested --- .../dynamic_routing/VotingStreetCostData.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/application/dynamic_routing/VotingStreetCostData.java b/src/application/dynamic_routing/VotingStreetCostData.java index df47b52..79731c0 100644 --- a/src/application/dynamic_routing/VotingStreetCostData.java +++ b/src/application/dynamic_routing/VotingStreetCostData.java @@ -122,18 +122,22 @@ public boolean hasNewStamps(VotingStreetCostData votingStreetCostData) { /** add new costs with stamps, or add new stamps to the existing costs*/ public void addNewStamps(VotingStreetCostData votingStreetCostData) { Iterator costIterator = votingStreetCostData.getCostVotingMap().keySet().iterator(); - Iterator currentSessionCostIterator = this.costVotingMap.keySet().iterator(); + Iterator currentSessionCostIterator; while (costIterator.hasNext()) { double currentCost = costIterator.next(); + currentSessionCostIterator = this.costVotingMap.keySet().iterator(); Iterator stampIterator = votingStreetCostData.getCostVotingMap().get(currentCost).iterator(); long currentStamp; + HashSet added = new HashSet(); /*if the cost is not present into the Map, add the cost and its stamps from the param object*/ while (currentSessionCostIterator.hasNext()) { double votedCost = currentSessionCostIterator.next(); if (VotingStreetCostData.isTheSameStreetCost(votedCost, currentCost)) { + added.add(currentCost); + /*iterate through stamps and add the new ones*/ while (stampIterator.hasNext()) { currentStamp = stampIterator.next(); @@ -142,10 +146,9 @@ public void addNewStamps(VotingStreetCostData votingStreetCostData) { this.costVotingMap.get(votedCost).add(currentStamp); } } - return; } } - + if (added.contains(currentCost)) continue; /*if the cost not found in the session, add all stamps*/ costVotingMap.put(currentCost, votingStreetCostData.getCostVotingMap().get(currentCost)); }