Skip to content

Commit

Permalink
Added getting reverse (incoming) edges, for consideration for directe…
Browse files Browse the repository at this point in the history
…d edges in heuristics (when searching back from a goal...)
  • Loading branch information
J-morag committed Nov 30, 2021
1 parent d7e6c57 commit 06c9574
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 30 deletions.
3 changes: 1 addition & 2 deletions src/main/java/BasicCBS/Instances/Maps/GraphMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import BasicCBS.Instances.Maps.Coordinates.I_Coordinate;

import java.util.*;
import java.util.function.Consumer;

/**
* Represents a {@link I_Map map} as an abstract graph. This implementation can, in principle, support any domain -
Expand Down Expand Up @@ -59,7 +58,7 @@ public I_Map getSubmapWithout(Collection<? extends I_Location> mapLocations) {
if(!mapLocations.contains(originalVertex)){
GraphMapVertex newVertex = vertexMappings.get(coor);
List<GraphMapVertex> neighbors = new ArrayList<>();
for (I_Location neighbor : originalVertex.neighbors) {
for (I_Location neighbor : originalVertex.outgoingEdges) {
if (! mapLocations.contains(neighbor)){
// getting the neighbor from the new vertices, not the original ones.
neighbors.add(vertexMappings.get(neighbor.getCoordinate()));
Expand Down
94 changes: 83 additions & 11 deletions src/main/java/BasicCBS/Instances/Maps/GraphMapVertex.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package BasicCBS.Instances.Maps;

import BasicCBS.Instances.Maps.Coordinates.I_Coordinate;
import org.apache.commons.collections4.list.UnmodifiableList;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* A single cell in a {@link GraphMap}. Represents a unique location in the graph.
* A single cell(/vertex) in a {@link GraphMap}. Represents a unique location in the graph.
* Immutable beyond first initialization (First with a constructor, and then with {@link #setNeighbors(GraphMapVertex[])}.
*/
public class GraphMapVertex implements I_Location {
Expand All @@ -20,23 +23,62 @@ public class GraphMapVertex implements I_Location {
* The type of the cell. The type could determine whether or not an agent can traverse or occupy a cell.
*/
public final Enum_MapCellType cellType;
public List<I_Location> neighbors;
public List<I_Location> outgoingEdges;
private List<I_Location> incomingEdges = new ArrayList<>();
/**
* weights for the edges connecting this location to its neighbors. indexed uniformly with {@link #outgoingEdges}.
* If weights were not provided, contains a uniform edge cost of 1.
*/
public List<Integer> outgoingEdgeWeights;
/**
* weights for the edges connecting neighbors to this location. indexed uniformly with {@link #outgoingEdges}.
* If weights were not provided, contains a uniform edge cost of 1.
*/
public List<Integer> incomingEdgeWeights = new ArrayList<>();

public final I_Coordinate coordinate;

GraphMapVertex(Enum_MapCellType cellType, I_Coordinate coordinate) {
this.cellType = cellType;
this.coordinate = coordinate;
this.neighbors = null;
this.outgoingEdges = null;
}

/**
* Sets the cell's neighbors. All cells in the array should logically be non null.
* Used during graph construction. Only the first call to this method on an instance affects the instance.
* @param neighbors the cell's neighbors.
* Also sets this as a reverse edge on each of the neighbors.
* @param outgoingEdges the cell's neighbors.
* @throws NullPointerException if an element is null or the given array is null.
*/
void setNeighbors(GraphMapVertex[] neighbors) {
this.neighbors = (this.neighbors == null ? List.of(neighbors) : this.neighbors);
void setNeighbors(GraphMapVertex[] outgoingEdges) {
Integer[] edgeWeights = new Integer[outgoingEdges.length];
Arrays.fill(edgeWeights, 1);
setNeighbors(outgoingEdges, edgeWeights);
}

/**
* Sets the cell's neighbors. All cells in the array should logically be non null.
* Used during graph construction. Only the first call to this method on an instance affects the instance.
* Also sets this as a reverse edge on each of the neighbors.
* Also sets weights for the edges to the neighbors.
* @param outgoingEdges the cell's neighbors. must be indexed uniformly with edgeWeights.
* @param edgeWeights weights of the connections to the neighbors. must be indexed uniformly with neighbors.
* @throws NullPointerException if an element is null or the given array is null.
*/
void setNeighbors(GraphMapVertex[] outgoingEdges, Integer[] edgeWeights) {
// unmodifiable list
if (outgoingEdges.length != edgeWeights.length){
throw new IllegalArgumentException("neighbors and edgeWeights must be indexed uniformly");
}
this.outgoingEdges = (this.outgoingEdges == null ? List.of(outgoingEdges) : this.outgoingEdges);
this.outgoingEdgeWeights = (this.outgoingEdgeWeights == null ? List.of(edgeWeights) : this.outgoingEdgeWeights);
// set reverse edges
for (int i = 0; i < outgoingEdges.length; i++) {
GraphMapVertex neighbor = outgoingEdges[i];
neighbor.incomingEdges.add(this);
neighbor.incomingEdgeWeights.add(edgeWeights[i]);
}
}

/**
Expand Down Expand Up @@ -64,20 +106,50 @@ public I_Coordinate getCoordinate() {
* @return an UnmodifiableList of this cell's neighbors.
*/
@Override
public List<I_Location> getNeighbors() {
return this.neighbors;
public List<I_Location> outgoingEdges() {
return this.outgoingEdges;
}

/**
* {@inheritDoc}
* Also locks the internal list of incoming agents from further modification.
* @return {@inheritDoc}
*/
@Override
public List<I_Location> incomingEdges() {
if (! (this.incomingEdges instanceof UnmodifiableList) ){
this.incomingEdges = List.of(this.incomingEdges.toArray(I_Location[]::new));
}
return this.incomingEdges;
}

/**
* Returns an UnmodifiableList of the weights of this cell's edges.
* The amount of neighbors varies by map and connectivity.
* Runs in O(1).
* Indexed uniformly with the list of neighbors returned by {@link #outgoingEdges()}.
* @return an UnmodifiableList of the weights of this cell's edges.
*/
@Override
public List<Integer> getOutgoingEdgesWeights() {
return this.outgoingEdgeWeights;
}

@Override
public List<Integer> getIncomingEdgesWeights() {
return null;
}

/**
* Returns true iff other is contained in {@link #neighbors}. In particular, returns false if other==this.
* Returns true iff other is contained in {@link #outgoingEdges}. In particular, returns false if other==this.
* @param other another {@link I_Location}.
* @return true iff other is contained in {@link #neighbors}.
* @return true iff other is contained in {@link #outgoingEdges}.
*/
@Override
public boolean isNeighbor(I_Location other) {
boolean result = false;
for (I_Location neighbor :
neighbors) {
outgoingEdges) {
result = result || (neighbor.equals(other));
}
return result;
Expand Down
27 changes: 24 additions & 3 deletions src/main/java/BasicCBS/Instances/Maps/I_Location.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,39 @@ public interface I_Location {
Enum_MapCellType getType();

/**
* Returns an array that contains references to this cell's neighbors. Should not include this.
* Returns an array that contains references to locations directly reachable from this. Should not include this.
* The amount of neighbors varies by map and connectivity.
* @return an array that contains references to this cell's neighbors. Should not include this.
* @return an array that contains references to locations directly reachable from this. Should not include this.
*/
List<I_Location> getNeighbors();
List<I_Location> outgoingEdges();

/**
* Returns an array of locations from which this location is directly reachable. Should not include this.
* The amount of neighbors varies by map and connectivity.
* @return an array of locations from which this location is directly reachable. Should not include this.
*/
List<I_Location> incomingEdges();

/**
* returns the cell's coordinate.
* @return the cell's coordinate.
*/
I_Coordinate getCoordinate();

/**
* Get weights of the connections to this cell's neighbors.
* Should be uniformly indexed with the return value of {@link #outgoingEdges()}.
* @return weights of the connections to this cell's neighbors.
*/
List<Integer> getOutgoingEdgesWeights();

/**
* Get weights of the connections from this cell's neighbors.
* Should be uniformly indexed with the return value of {@link #incomingEdges()}.
* @return weights of the connections from this cell's neighbors.
*/
List<Integer> getIncomingEdgesWeights();

/**
* Return true iff other is a neighbor of this.
* @param other another {@link I_Location}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ public void addTargetToHeuristic(I_Location target) {
Map<I_Location, Integer> mapForAgent = new HashMap<>();
this.distanceDictionaries.put(target, mapForAgent);

//distance of a graphMapCell from itself
//distance of a vertex from itself
this.distanceDictionaries.get(target).put(target, 0);

//all the neighbors of a graphMapCell
List<I_Location> neighbors = target.getNeighbors();
// reverse edges, moving back from the target, traversing against the direction of the edges
List<I_Location> neighbors = target.incomingEdges();
LinkedList<I_Location> queue = new LinkedList<>(neighbors);

int distance = 1;
Expand All @@ -79,8 +79,8 @@ public void addTargetToHeuristic(I_Location target) {
if (!(this.distanceDictionaries.get(target).containsKey(i_location))) {
this.distanceDictionaries.get(target).put(i_location, distance);

//add all the neighbors of the current graphMapCell to the queue
List<I_Location> neighborsCell = i_location.getNeighbors();
// traversing edges in reverse back from current vertex
List<I_Location> neighborsCell = i_location.incomingEdges();
queue.addAll(neighborsCell);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ protected boolean initOpen() {
else { // the existing plan is empty (no existing plan)

I_Location sourceCell = map.getMapCell(this.sourceCoor);
// can move to neighboring cells or stay put
List<I_Location> neighborCellsIncludingCurrent = new ArrayList<>(sourceCell.getNeighbors());
// can move to neighboring locations or stay put
List<I_Location> neighborCellsIncludingCurrent = new ArrayList<>(sourceCell.outgoingEdges());
neighborCellsIncludingCurrent.add(sourceCell);

for (I_Location destination: neighborCellsIncludingCurrent) {
Expand Down Expand Up @@ -300,7 +300,7 @@ private float calcH() {
public void expand() {
expandedNodes++;
// can move to neighboring cells or stay put
List<I_Location> neighborCellsIncludingCurrent = new ArrayList<>(this.move.currLocation.getNeighbors());
List<I_Location> neighborCellsIncludingCurrent = new ArrayList<>(this.move.currLocation.outgoingEdges());
neighborCellsIncludingCurrent.add(this.move.currLocation);

for (I_Location destination: neighborCellsIncludingCurrent){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import BasicCBS.Solvers.ConstraintsAndConflicts.CorridorConflict;
import BasicCBS.Solvers.ConstraintsAndConflicts.SwappingConflict;
import BasicCBS.Solvers.Move;
import BasicCBS.Solvers.SingleAgentPlan;

import java.util.HashSet;
import java.util.Objects;
Expand Down Expand Up @@ -123,8 +122,8 @@ private I_Location exploreCorridorOneDirection(HashSet<I_Location> corridorVerti
// might add an existing vertex but it's fine since this is a set.
corridorVertices.add(someDirNeighbor);
// get the neighbor of the current neighbor that is not the anchor (so it is in the right direction)
I_Location newNeighbour = someDirNeighbor.getNeighbors().get(0).equals(anchor) ? someDirNeighbor.getNeighbors().get(1)
: someDirNeighbor.getNeighbors().get(0);
I_Location newNeighbour = someDirNeighbor.outgoingEdges().get(0).equals(anchor) ? someDirNeighbor.outgoingEdges().get(1)
: someDirNeighbor.outgoingEdges().get(0);
anchor = someDirNeighbor;
someDirNeighbor = newNeighbour;
}
Expand All @@ -138,7 +137,7 @@ private boolean equalsSourceOrTarget(I_Location location, Agent agent){
}

private boolean isDegree2(I_Location location){
return location.getNeighbors().size() == 2;
return location.outgoingEdges().size() == 2;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public void addParents(List<MDDSearchNode> parents) {
public List<I_Location> getNeighborLocations(){
// can move to neighboring cells or stay put
I_Location currLocation = this.location;
List<I_Location> neighborCellsIncludingCurrent = new ArrayList<>(currLocation.getNeighbors());
List<I_Location> neighborCellsIncludingCurrent = new ArrayList<>(currLocation.outgoingEdges());
neighborCellsIncludingCurrent.add(currLocation); //staying in the same location is possible
return neighborCellsIncludingCurrent;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/BasicCBS/Solvers/NoStateTimeSearches.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private static boolean basicSearch(I_Location goal, I_Location source, Queue<I_L
while(!open.isEmpty()){
I_Location location = open.remove();
visited.add(location);
for (I_Location neighbour: location.getNeighbors()) {
for (I_Location neighbour: location.outgoingEdges()) {
// must compare coordinates since these locations might come from different copies of the map and thus won't be equal
if(neighbour.getCoordinate().equals(goal.getCoordinate())){
// found (reachable)
Expand Down

0 comments on commit 06c9574

Please sign in to comment.