[clean] Apply formatting and add formatter configuration.
This commit is contained in:
committed by
Mikael CAPELLE
parent
2f936d44ec
commit
730cda6426
@@ -19,7 +19,7 @@ public abstract class AbstractAlgorithm<Observer> {
|
||||
|
||||
/**
|
||||
* Create a new algorithm with an empty list of observers.
|
||||
*
|
||||
*
|
||||
* @param data Input data for the algorithm.
|
||||
*/
|
||||
protected AbstractAlgorithm(AbstractInputData data) {
|
||||
@@ -29,7 +29,7 @@ public abstract class AbstractAlgorithm<Observer> {
|
||||
|
||||
/**
|
||||
* Create a new algorithm with the given list of observers.
|
||||
*
|
||||
*
|
||||
* @param data Input data for the algorithm.
|
||||
* @param observers Initial list of observers for the algorithm.
|
||||
*/
|
||||
@@ -40,7 +40,7 @@ public abstract class AbstractAlgorithm<Observer> {
|
||||
|
||||
/**
|
||||
* Add an observer to this algorithm.
|
||||
*
|
||||
*
|
||||
* @param observer Observer to add to this algorithm.
|
||||
*/
|
||||
public void addObserver(Observer observer) {
|
||||
@@ -62,11 +62,9 @@ public abstract class AbstractAlgorithm<Observer> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the algorithm and return the solution.
|
||||
*
|
||||
* This methods internally time the call to doRun() and update the result of the
|
||||
* call with the computed solving time.
|
||||
*
|
||||
* Run the algorithm and return the solution. This methods internally time the call
|
||||
* to doRun() and update the result of the call with the computed solving time.
|
||||
*
|
||||
* @return The solution found by the algorithm (may not be a feasible solution).
|
||||
*/
|
||||
public AbstractSolution run() {
|
||||
@@ -78,9 +76,9 @@ public abstract class AbstractAlgorithm<Observer> {
|
||||
|
||||
/**
|
||||
* Abstract method that should be implemented by child class.
|
||||
*
|
||||
* @return The solution found, must not be null (use an infeasible or unknown
|
||||
* status if necessary).
|
||||
*
|
||||
* @return The solution found, must not be null (use an infeasible or unknown status
|
||||
* if necessary).
|
||||
*/
|
||||
protected abstract AbstractSolution doRun();
|
||||
|
||||
|
@@ -5,16 +5,15 @@ import org.insa.graphs.model.Graph;
|
||||
import org.insa.graphs.model.GraphStatistics;
|
||||
|
||||
/**
|
||||
* Base class for algorithm input data classes. This class contains the basic
|
||||
* data that are required by most graph algorithms, i.e. a graph, a mode (time /
|
||||
* length) and a filter for the arc.
|
||||
*
|
||||
* Base class for algorithm input data classes. This class contains the basic data that
|
||||
* are required by most graph algorithms, i.e. a graph, a mode (time / length) and a
|
||||
* filter for the arc.
|
||||
*/
|
||||
public abstract class AbstractInputData {
|
||||
|
||||
/**
|
||||
* Enum specifying the top mode of the algorithms.
|
||||
*
|
||||
*
|
||||
* @see ArcInspector
|
||||
*/
|
||||
public enum Mode {
|
||||
@@ -29,7 +28,7 @@ public abstract class AbstractInputData {
|
||||
|
||||
/**
|
||||
* Create a new AbstractInputData instance for the given graph, mode and filter.
|
||||
*
|
||||
*
|
||||
* @param graph Graph for this input data.
|
||||
* @param arcInspector Arc inspector for this input data.
|
||||
*/
|
||||
@@ -46,13 +45,11 @@ public abstract class AbstractInputData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the cost associated with the given arc according to the underlying
|
||||
* arc inspector.
|
||||
*
|
||||
* Retrieve the cost associated with the given arc according to the underlying arc
|
||||
* inspector.
|
||||
*
|
||||
* @param arc Arc for which cost should be retrieved.
|
||||
*
|
||||
* @return Cost for the given arc.
|
||||
*
|
||||
* @see ArcInspector
|
||||
*/
|
||||
public double getCost(Arc arc) {
|
||||
@@ -61,7 +58,6 @@ public abstract class AbstractInputData {
|
||||
|
||||
/**
|
||||
* @return Mode associated with this input data.
|
||||
*
|
||||
* @see Mode
|
||||
*/
|
||||
public Mode getMode() {
|
||||
@@ -70,10 +66,10 @@ public abstract class AbstractInputData {
|
||||
|
||||
/**
|
||||
* Retrieve the maximum speed associated with this input data, or
|
||||
* {@link GraphStatistics#NO_MAXIMUM_SPEED} if none is associated. The maximum
|
||||
* speed associated with input data is different from the maximum speed
|
||||
* associated with graph (accessible via {@link Graph#getGraphInformation()}).
|
||||
*
|
||||
* {@link GraphStatistics#NO_MAXIMUM_SPEED} if none is associated. The maximum speed
|
||||
* associated with input data is different from the maximum speed associated with
|
||||
* graph (accessible via {@link Graph#getGraphInformation()}).
|
||||
*
|
||||
* @return The maximum speed for this inspector, or
|
||||
* {@link GraphStatistics#NO_MAXIMUM_SPEED} if none is set.
|
||||
*/
|
||||
@@ -83,11 +79,9 @@ public abstract class AbstractInputData {
|
||||
|
||||
/**
|
||||
* Check if the given arc is allowed for the filter corresponding to this input.
|
||||
*
|
||||
*
|
||||
* @param arc Arc to check.
|
||||
*
|
||||
* @return true if the given arc is allowed.
|
||||
*
|
||||
* @see ArcInspector
|
||||
*/
|
||||
public boolean isAllowed(Arc arc) {
|
||||
|
@@ -3,16 +3,14 @@ package org.insa.graphs.algorithm;
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* Base class for solution classes returned by the algorithm. This class
|
||||
* contains the basic information that any solution should have: status of the
|
||||
* solution (unknown, infeasible, etc.), solving time and the original input
|
||||
* data.
|
||||
* Base class for solution classes returned by the algorithm. This class contains the
|
||||
* basic information that any solution should have: status of the solution (unknown,
|
||||
* infeasible, etc.), solving time and the original input data.
|
||||
*/
|
||||
public abstract class AbstractSolution {
|
||||
|
||||
/**
|
||||
* Possible status for a solution.
|
||||
*
|
||||
*/
|
||||
public enum Status {
|
||||
UNKNOWN, INFEASIBLE, FEASIBLE, OPTIMAL,
|
||||
@@ -29,7 +27,7 @@ public abstract class AbstractSolution {
|
||||
|
||||
/**
|
||||
* Create a new abstract solution with unknown status.
|
||||
*
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
protected AbstractSolution(AbstractInputData data) {
|
||||
@@ -39,7 +37,6 @@ public abstract class AbstractSolution {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @param status
|
||||
*/
|
||||
@@ -71,7 +68,7 @@ public abstract class AbstractSolution {
|
||||
|
||||
/**
|
||||
* Set the solving time of this solution.
|
||||
*
|
||||
*
|
||||
* @param solvingTime Solving time for the solution.
|
||||
*/
|
||||
protected void setSolvingTime(Duration solvingTime) {
|
||||
|
@@ -5,26 +5,23 @@ import org.insa.graphs.model.Arc;
|
||||
import org.insa.graphs.model.GraphStatistics;
|
||||
|
||||
/**
|
||||
* This class can be used to indicate to an algorithm which arcs can be used and
|
||||
* the costs of the usable arcs..
|
||||
*
|
||||
* This class can be used to indicate to an algorithm which arcs can be used and the
|
||||
* costs of the usable arcs..
|
||||
*/
|
||||
public interface ArcInspector {
|
||||
|
||||
/**
|
||||
* Check if the given arc can be used (is allowed).
|
||||
*
|
||||
*
|
||||
* @param arc Arc to check.
|
||||
*
|
||||
* @return true if the given arc is allowed.
|
||||
*/
|
||||
public boolean isAllowed(Arc arc);
|
||||
|
||||
/**
|
||||
* Find the cost of the given arc.
|
||||
*
|
||||
*
|
||||
* @param arc Arc for which the cost should be returned.
|
||||
*
|
||||
* @return Cost of the arc.
|
||||
*/
|
||||
public double getCost(Arc arc);
|
||||
@@ -40,4 +37,4 @@ public interface ArcInspector {
|
||||
*/
|
||||
public Mode getMode();
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -52,9 +52,10 @@ public class ArcInspectorFactory {
|
||||
filters.add(new ArcInspector() {
|
||||
@Override
|
||||
public boolean isAllowed(Arc arc) {
|
||||
return arc.getRoadInformation().getAccessRestrictions()
|
||||
.isAllowedForAny(AccessMode.MOTORCAR, EnumSet.complementOf(EnumSet
|
||||
.of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
|
||||
return arc.getRoadInformation().getAccessRestrictions().isAllowedForAny(
|
||||
AccessMode.MOTORCAR,
|
||||
EnumSet.complementOf(EnumSet.of(AccessRestriction.FORBIDDEN,
|
||||
AccessRestriction.PRIVATE)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,9 +111,10 @@ public class ArcInspectorFactory {
|
||||
filters.add(new ArcInspector() {
|
||||
@Override
|
||||
public boolean isAllowed(Arc arc) {
|
||||
return arc.getRoadInformation().getAccessRestrictions()
|
||||
.isAllowedForAny(AccessMode.MOTORCAR, EnumSet.complementOf(EnumSet
|
||||
.of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
|
||||
return arc.getRoadInformation().getAccessRestrictions().isAllowedForAny(
|
||||
AccessMode.MOTORCAR,
|
||||
EnumSet.complementOf(EnumSet.of(AccessRestriction.FORBIDDEN,
|
||||
AccessRestriction.PRIVATE)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,15 +143,16 @@ public class ArcInspectorFactory {
|
||||
|
||||
@Override
|
||||
public boolean isAllowed(Arc arc) {
|
||||
return arc.getRoadInformation().getAccessRestrictions()
|
||||
.isAllowedForAny(AccessMode.FOOT, EnumSet.complementOf(EnumSet
|
||||
.of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
|
||||
return arc.getRoadInformation().getAccessRestrictions().isAllowedForAny(
|
||||
AccessMode.FOOT,
|
||||
EnumSet.complementOf(EnumSet.of(AccessRestriction.FORBIDDEN,
|
||||
AccessRestriction.PRIVATE)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCost(Arc arc) {
|
||||
return arc.getTravelTime(
|
||||
Math.min(getMaximumSpeed(), arc.getRoadInformation().getMaximumSpeed()));
|
||||
return arc.getTravelTime(Math.min(getMaximumSpeed(),
|
||||
arc.getRoadInformation().getMaximumSpeed()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -2,7 +2,8 @@ package org.insa.graphs.algorithm.carpooling;
|
||||
|
||||
import org.insa.graphs.algorithm.AbstractAlgorithm;
|
||||
|
||||
public abstract class CarPoolingAlgorithm extends AbstractAlgorithm<CarPoolingObserver> {
|
||||
public abstract class CarPoolingAlgorithm
|
||||
extends AbstractAlgorithm<CarPoolingObserver> {
|
||||
|
||||
protected CarPoolingAlgorithm(CarPoolingData data) {
|
||||
super(data);
|
||||
|
@@ -2,11 +2,12 @@ package org.insa.graphs.algorithm.packageswitch;
|
||||
|
||||
import org.insa.graphs.algorithm.AbstractAlgorithm;
|
||||
|
||||
public abstract class PackageSwitchAlgorithm extends AbstractAlgorithm<PackageSwitchObserver> {
|
||||
public abstract class PackageSwitchAlgorithm
|
||||
extends AbstractAlgorithm<PackageSwitchObserver> {
|
||||
|
||||
/**
|
||||
* Create a new PackageSwitchAlgorithm with the given data.
|
||||
*
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
protected PackageSwitchAlgorithm(PackageSwitchData data) {
|
||||
|
@@ -41,8 +41,8 @@ public class BellmanFordAlgorithm extends ShortestPathAlgorithm {
|
||||
boolean found = false;
|
||||
for (int i = 0; !found && i < nbNodes; ++i) {
|
||||
found = true;
|
||||
for (Node node: graph.getNodes()) {
|
||||
for (Arc arc: node.getSuccessors()) {
|
||||
for (Node node : graph.getNodes()) {
|
||||
for (Arc arc : node.getSuccessors()) {
|
||||
|
||||
// Small test to check allowed roads...
|
||||
if (!data.isAllowed(arc)) {
|
||||
@@ -54,14 +54,16 @@ public class BellmanFordAlgorithm extends ShortestPathAlgorithm {
|
||||
double oldDistance = distances[arc.getDestination().getId()];
|
||||
double newDistance = distances[node.getId()] + w;
|
||||
|
||||
if (Double.isInfinite(oldDistance) && Double.isFinite(newDistance)) {
|
||||
if (Double.isInfinite(oldDistance)
|
||||
&& Double.isFinite(newDistance)) {
|
||||
notifyNodeReached(arc.getDestination());
|
||||
}
|
||||
|
||||
// Check if new distances would be better, if so update...
|
||||
if (newDistance < oldDistance) {
|
||||
found = false;
|
||||
distances[arc.getDestination().getId()] = distances[node.getId()] + w;
|
||||
distances[arc.getDestination().getId()] =
|
||||
distances[node.getId()] + w;
|
||||
predecessorArcs[arc.getDestination().getId()] = arc;
|
||||
}
|
||||
}
|
||||
@@ -91,7 +93,8 @@ public class BellmanFordAlgorithm extends ShortestPathAlgorithm {
|
||||
Collections.reverse(arcs);
|
||||
|
||||
// Create the final solution.
|
||||
solution = new ShortestPathSolution(data, Status.OPTIMAL, new Path(graph, arcs));
|
||||
solution = new ShortestPathSolution(data, Status.OPTIMAL,
|
||||
new Path(graph, arcs));
|
||||
}
|
||||
|
||||
return solution;
|
||||
|
@@ -3,7 +3,8 @@ package org.insa.graphs.algorithm.shortestpath;
|
||||
import org.insa.graphs.algorithm.AbstractAlgorithm;
|
||||
import org.insa.graphs.model.Node;
|
||||
|
||||
public abstract class ShortestPathAlgorithm extends AbstractAlgorithm<ShortestPathObserver> {
|
||||
public abstract class ShortestPathAlgorithm
|
||||
extends AbstractAlgorithm<ShortestPathObserver> {
|
||||
|
||||
protected ShortestPathAlgorithm(ShortestPathData data) {
|
||||
super(data);
|
||||
@@ -24,45 +25,45 @@ public abstract class ShortestPathAlgorithm extends AbstractAlgorithm<ShortestPa
|
||||
|
||||
/**
|
||||
* Notify all observers that the origin has been processed.
|
||||
*
|
||||
*
|
||||
* @param node Origin.
|
||||
*/
|
||||
public void notifyOriginProcessed(Node node) {
|
||||
for (ShortestPathObserver obs: getObservers()) {
|
||||
for (ShortestPathObserver obs : getObservers()) {
|
||||
obs.notifyOriginProcessed(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all observers that a node has been reached for the first time.
|
||||
*
|
||||
*
|
||||
* @param node Node that has been reached.
|
||||
*/
|
||||
public void notifyNodeReached(Node node) {
|
||||
for (ShortestPathObserver obs: getObservers()) {
|
||||
for (ShortestPathObserver obs : getObservers()) {
|
||||
obs.notifyNodeReached(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all observers that a node has been marked, i.e. its final value has
|
||||
* been set.
|
||||
*
|
||||
* Notify all observers that a node has been marked, i.e. its final value has been
|
||||
* set.
|
||||
*
|
||||
* @param node Node that has been marked.
|
||||
*/
|
||||
public void notifyNodeMarked(Node node) {
|
||||
for (ShortestPathObserver obs: getObservers()) {
|
||||
for (ShortestPathObserver obs : getObservers()) {
|
||||
obs.notifyNodeMarked(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all observers that the destination has been reached.
|
||||
*
|
||||
*
|
||||
* @param node Destination.
|
||||
*/
|
||||
public void notifyDestinationReached(Node node) {
|
||||
for (ShortestPathObserver obs: getObservers()) {
|
||||
for (ShortestPathObserver obs : getObservers()) {
|
||||
obs.notifyDestinationReached(node);
|
||||
}
|
||||
}
|
||||
|
@@ -12,14 +12,15 @@ public class ShortestPathData extends AbstractInputData {
|
||||
|
||||
/**
|
||||
* Construct a new instance of ShortestPathInputData with the given parameters.
|
||||
*
|
||||
*
|
||||
* @param graph Graph in which the path should be looked for.
|
||||
* @param origin Origin node of the path.
|
||||
* @param destination Destination node of the path.
|
||||
* @param arcInspector Filter for arcs (used to allow only a specific set of
|
||||
* arcs in the graph to be used).
|
||||
* @param arcInspector Filter for arcs (used to allow only a specific set of arcs in
|
||||
* the graph to be used).
|
||||
*/
|
||||
public ShortestPathData(Graph graph, Node origin, Node destination, ArcInspector arcInspector) {
|
||||
public ShortestPathData(Graph graph, Node origin, Node destination,
|
||||
ArcInspector arcInspector) {
|
||||
super(graph, arcInspector);
|
||||
this.origin = origin;
|
||||
this.destination = destination;
|
||||
@@ -41,7 +42,7 @@ public class ShortestPathData extends AbstractInputData {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Shortest-path from #" + origin.getId() + " to #" + destination.getId() + " ["
|
||||
+ this.arcInspector.toString().toLowerCase() + "]";
|
||||
return "Shortest-path from #" + origin.getId() + " to #" + destination.getId()
|
||||
+ " [" + this.arcInspector.toString().toLowerCase() + "]";
|
||||
}
|
||||
}
|
||||
|
@@ -3,35 +3,34 @@ package org.insa.graphs.algorithm.shortestpath;
|
||||
import org.insa.graphs.model.Node;
|
||||
|
||||
public interface ShortestPathObserver {
|
||||
|
||||
/**
|
||||
* Notify the observer that the origin has been processed.
|
||||
*
|
||||
* @param node Origin.
|
||||
*/
|
||||
public void notifyOriginProcessed(Node node);
|
||||
|
||||
/**
|
||||
* Notify the observer that a node has been reached for the first
|
||||
* time.
|
||||
*
|
||||
* @param node Node that has been reached.
|
||||
*/
|
||||
public void notifyNodeReached(Node node);
|
||||
|
||||
/**
|
||||
* Notify the observer that a node has been marked, i.e. its final
|
||||
* value has been set.
|
||||
*
|
||||
* @param node Node that has been marked.
|
||||
*/
|
||||
public void notifyNodeMarked(Node node);
|
||||
|
||||
/**
|
||||
* Notify the observer that the destination has been reached.
|
||||
*
|
||||
* @param node Destination.
|
||||
*/
|
||||
public void notifyDestinationReached(Node node);
|
||||
|
||||
/**
|
||||
* Notify the observer that the origin has been processed.
|
||||
*
|
||||
* @param node Origin.
|
||||
*/
|
||||
public void notifyOriginProcessed(Node node);
|
||||
|
||||
/**
|
||||
* Notify the observer that a node has been reached for the first time.
|
||||
*
|
||||
* @param node Node that has been reached.
|
||||
*/
|
||||
public void notifyNodeReached(Node node);
|
||||
|
||||
/**
|
||||
* Notify the observer that a node has been marked, i.e. its final value has been
|
||||
* set.
|
||||
*
|
||||
* @param node Node that has been marked.
|
||||
*/
|
||||
public void notifyNodeMarked(Node node);
|
||||
|
||||
/**
|
||||
* Notify the observer that the destination has been reached.
|
||||
*
|
||||
* @param node Destination.
|
||||
*/
|
||||
public void notifyDestinationReached(Node node);
|
||||
|
||||
}
|
||||
|
@@ -11,9 +11,8 @@ public class ShortestPathSolution extends AbstractSolution {
|
||||
private final Path path;
|
||||
|
||||
/**
|
||||
* Create a new infeasible shortest-path solution for the given input and
|
||||
* status.
|
||||
*
|
||||
* Create a new infeasible shortest-path solution for the given input and status.
|
||||
*
|
||||
* @param data Original input data for this solution.
|
||||
* @param status Status of the solution (UNKNOWN / INFEASIBLE).
|
||||
*/
|
||||
@@ -24,7 +23,7 @@ public class ShortestPathSolution extends AbstractSolution {
|
||||
|
||||
/**
|
||||
* Create a new shortest-path solution.
|
||||
*
|
||||
*
|
||||
* @param data Original input data for this solution.
|
||||
* @param status Status of the solution (FEASIBLE / OPTIMAL).
|
||||
* @param path Path corresponding to the solution.
|
||||
@@ -51,15 +50,17 @@ public class ShortestPathSolution extends AbstractSolution {
|
||||
String info = null;
|
||||
if (!isFeasible()) {
|
||||
info = String.format("No path found from node #%d to node #%d",
|
||||
getInputData().getOrigin().getId(), getInputData().getDestination().getId());
|
||||
getInputData().getOrigin().getId(),
|
||||
getInputData().getDestination().getId());
|
||||
}
|
||||
else {
|
||||
double cost = 0;
|
||||
for (Arc arc: getPath().getArcs()) {
|
||||
for (Arc arc : getPath().getArcs()) {
|
||||
cost += getInputData().getCost(arc);
|
||||
}
|
||||
info = String.format("Found a path from node #%d to node #%d",
|
||||
getInputData().getOrigin().getId(), getInputData().getDestination().getId());
|
||||
getInputData().getOrigin().getId(),
|
||||
getInputData().getDestination().getId());
|
||||
if (getInputData().getMode() == Mode.LENGTH) {
|
||||
info = String.format("%s, %.4f kilometers", info, cost / 1000.0);
|
||||
}
|
||||
|
@@ -3,11 +3,9 @@ package org.insa.graphs.algorithm.utils;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Implements a binary heap containing elements of type E.
|
||||
* Implements a binary heap containing elements of type E. Note that all comparisons are
|
||||
* based on the compareTo method, hence E must implement Comparable
|
||||
*
|
||||
* Note that all comparisons are based on the compareTo method, hence E must
|
||||
* implement Comparable
|
||||
*
|
||||
* @author Mark Allen Weiss
|
||||
* @author DLB
|
||||
*/
|
||||
@@ -29,7 +27,7 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
||||
|
||||
/**
|
||||
* Construct a copy of the given heap.
|
||||
*
|
||||
*
|
||||
* @param heap Binary heap to copy.
|
||||
*/
|
||||
public BinaryHeap(BinaryHeap<E> heap) {
|
||||
@@ -39,7 +37,7 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
||||
|
||||
/**
|
||||
* Set an element at the given index.
|
||||
*
|
||||
*
|
||||
* @param index Index at which the element should be set.
|
||||
* @param value Element to set.
|
||||
*/
|
||||
@@ -68,15 +66,14 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
||||
|
||||
/**
|
||||
* Internal method to percolate up in the heap.
|
||||
*
|
||||
*
|
||||
* @param index Index at which the percolate begins.
|
||||
*/
|
||||
private void percolateUp(int index) {
|
||||
E x = this.array.get(index);
|
||||
|
||||
for (; index > 0
|
||||
&& x.compareTo(this.array.get(indexParent(index))) < 0; index = indexParent(
|
||||
index)) {
|
||||
for (; index > 0 && x.compareTo(this.array.get(indexParent(index))) < 0; index =
|
||||
indexParent(index)) {
|
||||
E moving_val = this.array.get(indexParent(index));
|
||||
this.arraySet(index, moving_val);
|
||||
}
|
||||
@@ -86,7 +83,7 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
||||
|
||||
/**
|
||||
* Internal method to percolate down in the heap.
|
||||
*
|
||||
*
|
||||
* @param index Index at which the percolate begins.
|
||||
*/
|
||||
private void percolateDown(int index) {
|
||||
@@ -158,7 +155,7 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
||||
|
||||
/**
|
||||
* Creates a multi-lines string representing a sorted view of this binary heap.
|
||||
*
|
||||
*
|
||||
* @return a string containing a sorted view this binary heap.
|
||||
*/
|
||||
public String toStringSorted() {
|
||||
@@ -167,10 +164,9 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
||||
|
||||
/**
|
||||
* Creates a multi-lines string representing a sorted view of this binary heap.
|
||||
*
|
||||
* @param maxElement Maximum number of elements to display. or {@code -1} to
|
||||
* display all the elements.
|
||||
*
|
||||
*
|
||||
* @param maxElement Maximum number of elements to display. or {@code -1} to display
|
||||
* all the elements.
|
||||
* @return a string containing a sorted view this binary heap.
|
||||
*/
|
||||
public String toStringSorted(int maxElement) {
|
||||
@@ -179,7 +175,7 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
||||
|
||||
/**
|
||||
* Creates a multi-lines string representing a tree view of this binary heap.
|
||||
*
|
||||
*
|
||||
* @return a string containing a tree view of this binary heap.
|
||||
*/
|
||||
public String toStringTree() {
|
||||
@@ -188,9 +184,8 @@ public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
|
||||
|
||||
/**
|
||||
* Creates a multi-lines string representing a tree view of this binary heap.
|
||||
*
|
||||
*
|
||||
* @param maxDepth Maximum depth of the tree to display.
|
||||
*
|
||||
* @return a string containing a tree view of this binary heap.
|
||||
*/
|
||||
public String toStringTree(int maxDepth) {
|
||||
|
@@ -7,7 +7,6 @@ public class BinaryHeapFormatter {
|
||||
/**
|
||||
* This class is used by {@link #toStringTree}, and simply contains three string
|
||||
* accumulating. This is an immutable class.
|
||||
*
|
||||
*/
|
||||
private static class Context {
|
||||
|
||||
@@ -22,9 +21,9 @@ public class BinaryHeapFormatter {
|
||||
|
||||
/**
|
||||
* Creaet a new {@code Context}.
|
||||
*
|
||||
* @param acu The accumulated string.
|
||||
* @param margin The current margin.
|
||||
*
|
||||
* @param acu The accumulated string.
|
||||
* @param margin The current margin.
|
||||
* @param lastMargin The last margin used.
|
||||
*/
|
||||
public Context(String acu, String margin, String lastMargin) {
|
||||
@@ -35,9 +34,8 @@ public class BinaryHeapFormatter {
|
||||
|
||||
/**
|
||||
* Creates a new context by appending newlines to this context.
|
||||
*
|
||||
*
|
||||
* @param n Number of newlines to append.
|
||||
*
|
||||
* @return a new context with {@code n} newlines appended.
|
||||
*/
|
||||
public Context appendNewlines(int n) {
|
||||
@@ -45,40 +43,40 @@ public class BinaryHeapFormatter {
|
||||
return this;
|
||||
}
|
||||
else {
|
||||
return (new Context(this.acu + "\n" + this.margin, this.margin, this.lastmargin)
|
||||
.appendNewlines(n - 1));
|
||||
return (new Context(this.acu + "\n" + this.margin, this.margin,
|
||||
this.lastmargin).appendNewlines(n - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new context by appending the given string to this context.
|
||||
*
|
||||
*
|
||||
* @param count Number of spaces to add to the margin, or {@code null} to use
|
||||
* the length of the string.
|
||||
* @param text String to append.
|
||||
*
|
||||
* the length of the string.
|
||||
* @param text String to append.
|
||||
* @return a new context with {@code text} appended.
|
||||
*/
|
||||
public Context appendText(Integer count, String text) {
|
||||
int cnt = (count == null) ? text.length() : count;
|
||||
final String spaces = new String(new char[cnt]).replace('\0', ' ');
|
||||
return new Context(this.acu + text, this.margin + spaces, this.lastmargin + spaces);
|
||||
return new Context(this.acu + text, this.margin + spaces,
|
||||
this.lastmargin + spaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new context by appending a branch to this context.
|
||||
*
|
||||
* @param n Number of spaces to add to the margin, or {@code null} to use
|
||||
* the length of the string.
|
||||
*
|
||||
* @param n Number of spaces to add to the margin, or {@code null} to use the
|
||||
* length of the string.
|
||||
* @param label Name of the branch.
|
||||
*
|
||||
* @return a new context with the branch appended.
|
||||
*/
|
||||
public Context appendBranch(Integer count, String label) {
|
||||
final Context ctxt = this.appendText(count, label);
|
||||
|
||||
if (count == null) {
|
||||
return new Context(ctxt.acu + "_", ctxt.margin + "|", ctxt.margin + " ");
|
||||
return new Context(ctxt.acu + "_", ctxt.margin + "|",
|
||||
ctxt.margin + " ");
|
||||
}
|
||||
else {
|
||||
return new Context(ctxt.acu, ctxt.margin + "|", ctxt.margin + " ")
|
||||
@@ -89,8 +87,8 @@ public class BinaryHeapFormatter {
|
||||
}
|
||||
|
||||
/*
|
||||
* Input : ready to write the current node at the current context position.
|
||||
* Output : the last character of acu is the last character of the current node.
|
||||
* Input : ready to write the current node at the current context position. Output :
|
||||
* the last character of acu is the last character of the current node.
|
||||
*/
|
||||
protected static <E extends Comparable<E>> Context toStringLoop(BinaryHeap<E> heap,
|
||||
Context ctxt, int node, int max_depth) {
|
||||
@@ -122,13 +120,16 @@ public class BinaryHeapFormatter {
|
||||
int child = childs.get(ch);
|
||||
|
||||
if (is_last) {
|
||||
Context ctxt3 = new Context(ctxt2.acu, ctxt2.lastmargin, ctxt2.lastmargin);
|
||||
ctxt2 = new Context(toStringLoop(heap, ctxt3.appendText(null, "___"), child,
|
||||
max_depth - 1).acu, ctxt2.margin, ctxt2.lastmargin);
|
||||
Context ctxt3 =
|
||||
new Context(ctxt2.acu, ctxt2.lastmargin, ctxt2.lastmargin);
|
||||
ctxt2 = new Context(toStringLoop(heap,
|
||||
ctxt3.appendText(null, "___"), child, max_depth - 1).acu,
|
||||
ctxt2.margin, ctxt2.lastmargin);
|
||||
}
|
||||
else {
|
||||
ctxt2 = new Context(toStringLoop(heap, ctxt2.appendText(null, "___"), child,
|
||||
max_depth - 1).acu, ctxt2.margin, ctxt2.lastmargin).appendNewlines(2);
|
||||
ctxt2 = new Context(toStringLoop(heap,
|
||||
ctxt2.appendText(null, "___"), child, max_depth - 1).acu,
|
||||
ctxt2.margin, ctxt2.lastmargin).appendNewlines(2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,28 +138,25 @@ public class BinaryHeapFormatter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multi-lines string representing a tree view of the given binary
|
||||
* heap.
|
||||
*
|
||||
* @param heap The binary heap to display.
|
||||
* Creates a multi-lines string representing a tree view of the given binary heap.
|
||||
*
|
||||
* @param heap The binary heap to display.
|
||||
* @param maxDepth Maximum depth of the tree to display.
|
||||
*
|
||||
* @return a string containing a tree view of the given binary heap.
|
||||
*/
|
||||
public static <E extends Comparable<E>> String toStringTree(BinaryHeap<E> heap, int maxDepth) {
|
||||
public static <E extends Comparable<E>> String toStringTree(BinaryHeap<E> heap,
|
||||
int maxDepth) {
|
||||
final Context init_context = new Context(" ", " ", " ");
|
||||
final Context result = toStringLoop(heap, init_context, 0, maxDepth);
|
||||
return result.acu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multi-lines string representing a sorted view of the given binary
|
||||
* heap.
|
||||
*
|
||||
* @param heap The binary heap to display.
|
||||
* @param maxElement Maximum number of elements to display. or {@code -1} to
|
||||
* display all the elements.
|
||||
*
|
||||
* Creates a multi-lines string representing a sorted view of the given binary heap.
|
||||
*
|
||||
* @param heap The binary heap to display.
|
||||
* @param maxElement Maximum number of elements to display. or {@code -1} to display
|
||||
* all the elements.
|
||||
* @return a string containing a sorted view the given binary heap.
|
||||
*/
|
||||
public static <E extends Comparable<E>> String toStringSorted(BinaryHeap<E> heap,
|
||||
@@ -174,7 +172,8 @@ public class BinaryHeapFormatter {
|
||||
truncate = ", only " + max_elements + " elements are shown";
|
||||
}
|
||||
|
||||
result += "======== Sorted HEAP (size = " + heap.size() + truncate + ") ========\n\n";
|
||||
result += "======== Sorted HEAP (size = " + heap.size() + truncate
|
||||
+ ") ========\n\n";
|
||||
|
||||
while (!copy.isEmpty() && max_elements-- != 0) {
|
||||
result += copy.deleteMin() + "\n";
|
||||
|
@@ -17,7 +17,7 @@ public class BinarySearchTree<E extends Comparable<E>> implements PriorityQueue<
|
||||
|
||||
/**
|
||||
* Create a copy of the given binary search tree.
|
||||
*
|
||||
*
|
||||
* @param bst Binary search tree to copy.
|
||||
*/
|
||||
public BinarySearchTree(BinarySearchTree<E> bst) {
|
||||
|
@@ -3,7 +3,7 @@ package org.insa.graphs.algorithm.utils;
|
||||
public class ElementNotFoundException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@@ -3,14 +3,13 @@ package org.insa.graphs.algorithm.utils;
|
||||
public class EmptyPriorityQueueException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public EmptyPriorityQueueException() {
|
||||
}
|
||||
public EmptyPriorityQueueException() {}
|
||||
|
||||
}
|
||||
|
@@ -1,79 +1,69 @@
|
||||
package org.insa.graphs.algorithm.utils;
|
||||
|
||||
/**
|
||||
* Interface representing a basic priority queue.
|
||||
*
|
||||
* Implementation should enforce the required complexity of each method.
|
||||
*
|
||||
* Interface representing a basic priority queue. Implementation should enforce the
|
||||
* required complexity of each method.
|
||||
*/
|
||||
public interface PriorityQueue<E extends Comparable<E>> {
|
||||
|
||||
/**
|
||||
* Check if the priority queue is empty.
|
||||
*
|
||||
* <p>
|
||||
* <b>Complexity:</b> <i>O(1)</i>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return true if the queue is empty, false otherwise.
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Get the number of elements in this queue.
|
||||
*
|
||||
* <p>
|
||||
* <b>Complexity:</b> <i>O(1)</i>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return Current size (number of elements) of this queue.
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/**
|
||||
* Insert the given element into the queue.
|
||||
*
|
||||
* <p>
|
||||
* <b>Complexity:</b> <i>O(log n)</i>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param x Item to insert.
|
||||
*/
|
||||
public void insert(E x);
|
||||
|
||||
/**
|
||||
* Remove the given element from the priority queue.
|
||||
*
|
||||
* <p>
|
||||
* <b>Complexity:</b> <i>O(log n)</i>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param x Item to remove.
|
||||
*/
|
||||
public void remove(E x) throws ElementNotFoundException;
|
||||
|
||||
/**
|
||||
* Retrieve (but not remove) the smallest item in the queue.
|
||||
*
|
||||
* <p>
|
||||
* <b>Complexity:</b> <i>O(1)</i>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return The smallest item in the queue.
|
||||
*
|
||||
* @throws EmptyPriorityQueueException if this queue is empty.
|
||||
*/
|
||||
public E findMin() throws EmptyPriorityQueueException;
|
||||
|
||||
/**
|
||||
* Remove and return the smallest item from the priority queue.
|
||||
*
|
||||
* <p>
|
||||
* <b>Complexity:</b> <i>O(log n)</i>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return The smallest item in the queue.
|
||||
*
|
||||
* @throws EmptyPriorityQueueException if this queue is empty.
|
||||
*/
|
||||
public E deleteMin() throws EmptyPriorityQueueException;
|
||||
|
@@ -6,25 +6,25 @@ import org.insa.graphs.model.Node;
|
||||
|
||||
public interface WeaklyConnectedComponentObserver {
|
||||
|
||||
/**
|
||||
* Notify that the algorithm is entering a new component.
|
||||
*
|
||||
* @param curNode Starting node for the component.
|
||||
*/
|
||||
public void notifyStartComponent(Node curNode);
|
||||
|
||||
/**
|
||||
* Notify that a new node has been found for the current component.
|
||||
*
|
||||
* @param node New node found for the current component.
|
||||
*/
|
||||
public void notifyNewNodeInComponent(Node node);
|
||||
|
||||
/**
|
||||
* Notify that the algorithm has computed a new component.
|
||||
*
|
||||
* @param nodes List of nodes in the component.
|
||||
*/
|
||||
public void notifyEndComponent(ArrayList<Node> nodes);
|
||||
/**
|
||||
* Notify that the algorithm is entering a new component.
|
||||
*
|
||||
* @param curNode Starting node for the component.
|
||||
*/
|
||||
public void notifyStartComponent(Node curNode);
|
||||
|
||||
/**
|
||||
* Notify that a new node has been found for the current component.
|
||||
*
|
||||
* @param node New node found for the current component.
|
||||
*/
|
||||
public void notifyNewNodeInComponent(Node node);
|
||||
|
||||
/**
|
||||
* Notify that the algorithm has computed a new component.
|
||||
*
|
||||
* @param nodes List of nodes in the component.
|
||||
*/
|
||||
public void notifyEndComponent(ArrayList<Node> nodes);
|
||||
|
||||
}
|
||||
|
@@ -5,32 +5,33 @@ import java.util.ArrayList;
|
||||
|
||||
import org.insa.graphs.model.Node;
|
||||
|
||||
public class WeaklyConnectedComponentTextObserver implements WeaklyConnectedComponentObserver {
|
||||
|
||||
// Number of the current component.
|
||||
private int numComponent = 1;
|
||||
|
||||
// Output stream
|
||||
PrintStream stream;
|
||||
public class WeaklyConnectedComponentTextObserver
|
||||
implements WeaklyConnectedComponentObserver {
|
||||
|
||||
public WeaklyConnectedComponentTextObserver(PrintStream stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
// Number of the current component.
|
||||
private int numComponent = 1;
|
||||
|
||||
@Override
|
||||
public void notifyStartComponent(Node curNode) {
|
||||
stream.print("Entering component #" + numComponent + " from node #" + curNode.getId() + "... ");
|
||||
}
|
||||
// Output stream
|
||||
PrintStream stream;
|
||||
|
||||
@Override
|
||||
public void notifyNewNodeInComponent(Node node) {
|
||||
}
|
||||
public WeaklyConnectedComponentTextObserver(PrintStream stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyEndComponent(ArrayList<Node> nodes) {
|
||||
stream.println(nodes.size() + " nodes found.");
|
||||
stream.flush();
|
||||
numComponent += 1;
|
||||
}
|
||||
@Override
|
||||
public void notifyStartComponent(Node curNode) {
|
||||
stream.print("Entering component #" + numComponent + " from node #"
|
||||
+ curNode.getId() + "... ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNewNodeInComponent(Node node) {}
|
||||
|
||||
@Override
|
||||
public void notifyEndComponent(ArrayList<Node> nodes) {
|
||||
stream.println(nodes.size() + " nodes found.");
|
||||
stream.flush();
|
||||
numComponent += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -34,34 +34,33 @@ public class WeaklyConnectedComponentsAlgorithm
|
||||
|
||||
/**
|
||||
* Notify all observers that the algorithm is entering a new component.
|
||||
*
|
||||
*
|
||||
* @param curNode Starting node for the component.
|
||||
*/
|
||||
protected void notifyStartComponent(Node curNode) {
|
||||
for (WeaklyConnectedComponentObserver obs: getObservers()) {
|
||||
for (WeaklyConnectedComponentObserver obs : getObservers()) {
|
||||
obs.notifyStartComponent(curNode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all observers that a new node has been found for the current
|
||||
* component.
|
||||
*
|
||||
* Notify all observers that a new node has been found for the current component.
|
||||
*
|
||||
* @param node New node found for the current component.
|
||||
*/
|
||||
protected void notifyNewNodeInComponent(Node node) {
|
||||
for (WeaklyConnectedComponentObserver obs: getObservers()) {
|
||||
for (WeaklyConnectedComponentObserver obs : getObservers()) {
|
||||
obs.notifyNewNodeInComponent(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all observers that the algorithm has computed a new component.
|
||||
*
|
||||
*
|
||||
* @param nodes List of nodes in the component.
|
||||
*/
|
||||
protected void notifyEndComponent(ArrayList<Node> nodes) {
|
||||
for (WeaklyConnectedComponentObserver obs: getObservers()) {
|
||||
for (WeaklyConnectedComponentObserver obs : getObservers()) {
|
||||
obs.notifyEndComponent(nodes);
|
||||
}
|
||||
}
|
||||
@@ -77,8 +76,8 @@ public class WeaklyConnectedComponentsAlgorithm
|
||||
res.add(new HashSet<Integer>());
|
||||
}
|
||||
|
||||
for (Node node: getInputData().getGraph().getNodes()) {
|
||||
for (Arc arc: node.getSuccessors()) {
|
||||
for (Node node : getInputData().getGraph().getNodes()) {
|
||||
for (Arc arc : node.getSuccessors()) {
|
||||
res.get(node.getId()).add(arc.getDestination().getId());
|
||||
if (arc.getRoadInformation().isOneWay()) {
|
||||
res.get(arc.getDestination().getId()).add(node.getId());
|
||||
@@ -90,15 +89,15 @@ public class WeaklyConnectedComponentsAlgorithm
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a breadth first search algorithm on the given undirected graph
|
||||
* (adjacency list), starting at node cur, and marking nodes in marked.
|
||||
*
|
||||
* Apply a breadth first search algorithm on the given undirected graph (adjacency
|
||||
* list), starting at node cur, and marking nodes in marked.
|
||||
*
|
||||
* @param marked
|
||||
* @param cur
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected ArrayList<Node> bfs(ArrayList<HashSet<Integer>> ugraph, boolean[] marked, int cur) {
|
||||
protected ArrayList<Node> bfs(ArrayList<HashSet<Integer>> ugraph, boolean[] marked,
|
||||
int cur) {
|
||||
Graph graph = getInputData().getGraph();
|
||||
ArrayList<Node> component = new ArrayList<Node>();
|
||||
|
||||
@@ -118,7 +117,7 @@ public class WeaklyConnectedComponentsAlgorithm
|
||||
// Notify observers
|
||||
notifyNewNodeInComponent(node);
|
||||
|
||||
for (Integer destId: ugraph.get(node.getId())) {
|
||||
for (Integer destId : ugraph.get(node.getId())) {
|
||||
Node dest = graph.get(destId);
|
||||
if (!marked[dest.getId()]) {
|
||||
queue.add(destId);
|
||||
@@ -149,11 +148,11 @@ public class WeaklyConnectedComponentsAlgorithm
|
||||
components.add(this.bfs(ugraph, marked, cur));
|
||||
|
||||
// Find next non-marked
|
||||
for (; cur < marked.length && marked[cur]; ++cur)
|
||||
;
|
||||
for (; cur < marked.length && marked[cur]; ++cur);
|
||||
}
|
||||
|
||||
return new WeaklyConnectedComponentsSolution(getInputData(), Status.OPTIMAL, components);
|
||||
return new WeaklyConnectedComponentsSolution(getInputData(), Status.OPTIMAL,
|
||||
components);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -14,8 +14,8 @@ public class WeaklyConnectedComponentsSolution extends AbstractSolution {
|
||||
super(data);
|
||||
}
|
||||
|
||||
protected WeaklyConnectedComponentsSolution(WeaklyConnectedComponentsData data, Status status,
|
||||
ArrayList<ArrayList<Node>> components) {
|
||||
protected WeaklyConnectedComponentsSolution(WeaklyConnectedComponentsData data,
|
||||
Status status, ArrayList<ArrayList<Node>> components) {
|
||||
super(data, status);
|
||||
this.components = components;
|
||||
}
|
||||
@@ -34,14 +34,14 @@ public class WeaklyConnectedComponentsSolution extends AbstractSolution {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
int nIsolated = 0;
|
||||
int nGt10 = 0;
|
||||
for (ArrayList<Node> component: components) {
|
||||
for (ArrayList<Node> component : components) {
|
||||
if (component.size() == 1) {
|
||||
nIsolated += 1;
|
||||
}
|
||||
@@ -49,8 +49,9 @@ public class WeaklyConnectedComponentsSolution extends AbstractSolution {
|
||||
nGt10 += 1;
|
||||
}
|
||||
}
|
||||
return "Found " + components.size() + " components (" + nGt10 + " with more than 10 nodes, "
|
||||
+ nIsolated + " isolated nodes) in " + getSolvingTime().getSeconds() + " seconds.";
|
||||
return "Found " + components.size() + " components (" + nGt10
|
||||
+ " with more than 10 nodes, " + nIsolated + " isolated nodes) in "
|
||||
+ getSolvingTime().getSeconds() + " seconds.";
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user