package iamrescue.agent.firebrigade; import iamrescue.agent.AbstractIAMAgent; import iamrescue.belief.IAMWorldModel; import java.util.Collection; import java.util.Map; import java.util.Set; import javolution.util.FastMap; import javolution.util.FastSet; import org.apache.commons.collections15.BidiMap; import rescuecore2.standard.entities.Building; import rescuecore2.standard.entities.Civilian; import rescuecore2.standard.entities.Refuge; import rescuecore2.standard.entities.StandardEntity; import rescuecore2.standard.entities.StandardEntityURN; import rescuecore2.standard.entities.StandardPropertyURN; import rescuecore2.worldmodel.Entity; import rescuecore2.worldmodel.EntityListener; import rescuecore2.worldmodel.Property; import rescuecore2.worldmodel.WorldModel; import rescuecore2.worldmodel.WorldModelListener; import rescuecore2.worldmodel.properties.EntityRefProperty; import cern.colt.matrix.impl.SparseDoubleMatrix1D; import cern.colt.matrix.impl.SparseDoubleMatrix2D; import cern.colt.matrix.linalg.Algebra; import edu.uci.ics.jung.algorithms.matrix.GraphMatrixOperations; import edu.uci.ics.jung.algorithms.util.Indexer; import edu.uci.ics.jung.graph.DirectedSparseGraph; public class FastImportanceModel { // 2^T = look ahead private final int T = 3; private IAMWorldModel model; private static final int CIVILIAN_DISTANCE = 150000; // 150m // private SparseDoubleMatrix2D importanceCoefficientMatrix; private double[] importanceCoefficientArray; private double[] contextDependentBuildingImportance; private double[] civilianDependentBuildingImportance; private FastMap<Building, Integer> totalCiviliansAroundBuildingMap; private FastMap<Civilian, FastSet<Building>> totalBuildingsAroundCivilianMap; private BidiMap<Building, Integer> indexer; private SparseDoubleMatrix1D importanceLoss; private boolean doPowerCalc = true; private int totalBuildingsNumber; public FastImportanceModel(IAMWorldModel model, HeatTransferGraph graph) { long start = System.currentTimeMillis(); this.model = model; DirectedSparseGraph<Building, HeatTransferRelation> heatTransferGraph = graph .getHeatTransferGraph(); Map<HeatTransferRelation, Number> edgeWeight = new FastMap<HeatTransferRelation, Number>(); for (HeatTransferRelation relation : heatTransferGraph.getEdges()) { edgeWeight.put(relation, relation.getHeatTransferRate()); } Collection<Building> buildings = heatTransferGraph.getVertices(); totalBuildingsNumber = buildings.size(); indexer = Indexer.create(buildings); /** * initialise the new maps */ totalCiviliansAroundBuildingMap = new FastMap<Building, Integer>(); totalBuildingsAroundCivilianMap = new FastMap<Civilian, FastSet<Building>>(); computeImportanceCoefficientMatrix(heatTransferGraph, edgeWeight); for (Building building : buildings) { /** * update buildings map */ totalCiviliansAroundBuildingMap.put(building, new Integer(0)); } for (StandardEntity entity : model .getEntitiesOfType(StandardEntityURN.CIVILIAN)) { //entity.addEntityListener(new CivilianEntityListener()); /** * update civilians map */ totalBuildingsAroundCivilianMap.put((Civilian) entity, new FastSet<Building>()); } //model.addWorldModelListener(new CivilianAddedListener()); update(); long finish = System.currentTimeMillis(); System.out.println("Building Building Importance Model Took " + (finish - start)); } /** * * * @param edgeWeight * @param heatTransferGraph */ private void computeImportanceCoefficientMatrix( DirectedSparseGraph<Building, HeatTransferRelation> heatTransferGraph, Map<HeatTransferRelation, Number> edgeWeight) { importanceLoss = new SparseDoubleMatrix1D(heatTransferGraph .getVertexCount()); SparseDoubleMatrix2D importanceCoefficientMatrix = GraphMatrixOperations .graphToSparseMatrix(heatTransferGraph, edgeWeight); // Ensure that the columns sum to 1. I.e. "importance" is never lost // during value iteration. Otherwise, the importance transfer // coefficients will all be 0 for (int i = 0; i < importanceCoefficientMatrix.columns(); i++) { double colSum = importanceCoefficientMatrix.viewColumn(i).zSum(); importanceLoss.set(i, colSum); for (int j = 0; j < importanceCoefficientMatrix.rows(); j++) { importanceCoefficientMatrix.set(j, i, importanceCoefficientMatrix.get(j, i) / colSum); } } long start = System.currentTimeMillis(); /** * NO MORE POWER CALCULATION!!! */ if (doPowerCalc) { importanceCoefficientMatrix = (SparseDoubleMatrix2D) new Algebra() .pow(importanceCoefficientMatrix, T); } // scale the matrix to reintroduce importance loss for (int i = 0; i < importanceCoefficientMatrix.rows(); i++) { for (int j = 0; j < importanceCoefficientMatrix.columns(); j++) { importanceCoefficientMatrix.set(i, j, importanceCoefficientMatrix.get(i, j) * importanceLoss.get(j)); } } importanceCoefficientArray = new double[totalBuildingsNumber]; for (int i = 0; i < importanceCoefficientMatrix.rows(); i++) for (int j = 0; j < importanceCoefficientMatrix.columns(); j++) importanceCoefficientArray[i] += importanceCoefficientMatrix .get(i, j); long finish = System.currentTimeMillis(); System.out.println(finish - start); } /** * This method integrates the knowledge about the current position of the * civilians with the importance Matrix * * IT SHOULD BE CALLED AT EVERY TIME-STEP!!! * */ public void update() { contextDependentBuildingImportance = new double[importanceCoefficientArray.length]; AbstractIAMAgent.stopIfInterrupted(); computeCivilianImportanceArray(); for (int i = 0; i < contextDependentBuildingImportance.length; i++) { contextDependentBuildingImportance[i] = importanceCoefficientArray[i] * civilianDependentBuildingImportance[i]; } AbstractIAMAgent.stopIfInterrupted(); } private void computeCivilianImportanceArray() { civilianDependentBuildingImportance = new double[importanceCoefficientArray.length]; int totalCivilians = model .getEntitiesOfType(StandardEntityURN.CIVILIAN).size(); for (Building building : totalCiviliansAroundBuildingMap.keySet()) { int index = indexer.get(building); double civilianNumber = totalCiviliansAroundBuildingMap .get(building); // civilianDependentBuildingImportance[index] = // building.getTotalArea()*((0.1 + civilianNumber )/ (0.1 + // totalCivilians)); civilianDependentBuildingImportance[index] = 100 * ((0.1 + civilianNumber) / (0.1 + totalCivilians)); } } public int getCiviliansAroundBuilding(Building b) { Integer civilians= totalCiviliansAroundBuildingMap.get(b); if (civilians == null) { return 0; } else { return civilians; } } private class CivilianAddedListener implements WorldModelListener<StandardEntity> { @Override public void entityAdded(WorldModel<? extends StandardEntity> model, StandardEntity e) { if (e instanceof Civilian) { totalBuildingsAroundCivilianMap.put((Civilian) e, new FastSet<Building>()); CivilianEntityListener listener = new CivilianEntityListener(); e.addEntityListener(listener); EntityRefProperty positionProperty = ((Civilian) e) .getPositionProperty(); if (positionProperty.isDefined()) { listener.propertyChanged(e, positionProperty, null, positionProperty.getValue()); } } } @Override public void entityRemoved(WorldModel<? extends StandardEntity> model, StandardEntity e) { } } private class CivilianEntityListener implements EntityListener { private Object lastValue = null; @Override public void propertyChanged(Entity e, Property p, Object oldValue, Object newValue) { if (lastValue == newValue) { return; } else { lastValue = null; } Civilian civilian = (Civilian) e; if (p.getURN().equals(StandardPropertyURN.HP.toString())) { if (civilian.isHPDefined()) if (civilian.getHP() == 0) { // civilian has moved // StandardEntity newPosition = // model.getEntity(civilian.getPosition()); // first thing we decrease the value of the buildings // that previously contained the building FastSet<Building> previousBuildings = totalBuildingsAroundCivilianMap .get(civilian); if (previousBuildings != null) { for (Building building : previousBuildings) { int newvalue = totalCiviliansAroundBuildingMap .get(building) - 1; totalCiviliansAroundBuildingMap.put(building, new Integer(newvalue)); } totalBuildingsAroundCivilianMap.remove(civilian); } } } if (p.getURN().equals(StandardPropertyURN.POSITION.toString())) { // civilian has moved boolean needToIncreaseImportance = false; if (p.isDefined()) { StandardEntity newPosition = model.getEntity(civilian .getPosition()); needToIncreaseImportance = (newPosition instanceof Building && !(newPosition instanceof Refuge)); } // first thing we decrease the value of the buildings that // previously contained the building FastSet<Building> previousBuildings = totalBuildingsAroundCivilianMap .get(civilian); if (previousBuildings != null) { for (Building building : previousBuildings) { int newvalue = totalCiviliansAroundBuildingMap .get(building) - 1; totalCiviliansAroundBuildingMap.put(building, new Integer(newvalue)); } } if (needToIncreaseImportance) { // we calculate the new set of buildings within range Collection<StandardEntity> BuildingsInRange = model .getObjectsInRange(civilian, CIVILIAN_DISTANCE); FastSet<Building> newSet = new FastSet<Building>(); for (StandardEntity standardEntity : BuildingsInRange) { if (standardEntity instanceof Building) { Building building = (Building) standardEntity; // we add the element to the new set /* * if (building.isFierynessDefined()) if * (building.getFieryness() <= 3 && * building.getFieryness() >= 1) continue; */ newSet.add(building); // we increment the map of civilians per building int newvalue = totalCiviliansAroundBuildingMap .get(building) + 1; totalCiviliansAroundBuildingMap.put(building, new Integer(newvalue)); } } // we can finally update the map totalBuildingsAroundCivilianMap.put(civilian, newSet); } else { totalBuildingsAroundCivilianMap.remove(civilian); } } } } public Set<Building> getBuildings() { return indexer.keySet(); } public double getContextImportance(Building building) { int buildingIndex = indexer.get(building); return contextDependentBuildingImportance[buildingIndex]; } public double getImportance(Building building) { int buildingIndex = indexer.get(building); return importanceCoefficientArray[buildingIndex]; } }