How to move JUNG nodes(vertices) by changing their location in the code and not by mouse? - jung

I am implementing an interface for creating graph nodes and connecting them using JUNG.
I want to create some nodes that can move from one existing node to another node using the edge between two nodes as their path (It will be used for showing some Data Packets being transferred between nodes that are like Hosts).
There is some information on the internet about how to make the JUNG nodes(vertices) movable by mouse but there is no info about moving them by modifying values in the code.
Even if there is someway for moving the nodes is it possible and efficient to move the node between nodes using the edge between them as the moving path in JUNG library?
Any suggestions would be appreciated.

You can forcibly move a vertex with the setLocation method of the layout. I have built something that is quite similar to your request. It produces a vertex that moves from vertex A to vertex B in a direct line. If your edges are straight then it might work:
import java.awt.geom.Point2D;
import edu.uci.ics.jung.algorithms.layout.AbstractLayout;
import edu.uci.ics.jung.algorithms.util.IterativeProcess;
import edu.uci.ics.jung.visualization.VisualizationViewer;
public class VertexCollider extends IterativeProcess {
private static final String COLLIDER = "Collider";
private AbstractLayout<String, Number> layout;
private VisualizationViewer<String, Number> vv;
private Point2D startLocation;
private Point2D endLocation;
private Double moveX;
private Double moveY;
public VertexCollider(AbstractLayout<String, Number> layout, VisualizationViewer<String, Number> vv, String vertexA, String vertexB) {
this.layout = layout;
this.vv = vv;
startLocation = layout.transform(vertexA);
endLocation = layout.transform(vertexB);
}
public void initialize() {
setPrecision(Double.MAX_VALUE);
layout.getGraph().addVertex(COLLIDER);
layout.setLocation(COLLIDER, startLocation);
moveX = (endLocation.getX() - startLocation.getX()) / getMaximumIterations();
moveY = (endLocation.getY() - startLocation.getY()) / getMaximumIterations();
}
#Override
public void step() {
layout.setLocation(COLLIDER, layout.getX(COLLIDER) + moveX, layout.getY(COLLIDER) + moveY);
vv.repaint();
setPrecision(Math.max(Math.abs(endLocation.getX() - layout.transform(COLLIDER).getX()),
Math.abs(endLocation.getY() - layout.transform(COLLIDER).getY())));
if (hasConverged()){
layout.getGraph().removeVertex(COLLIDER);
}
}
}
You could instantiate this for example with this code:
VertexCollider vtxCol = new VertexCollider(layout, vv, "nameOfVertexA", "nameOfVertexB");
vtxCol.setMaximumIterations(100);
vtxCol.setDesiredPrecision(1);
vtxCol.initialize();
Animator animator = new Animator(vtxCol);
animator.start();
Painting straight edges:
Code Example

Related

classify new image on trained custom model in deeplearning4j (convolutional network)

Im new to deeplearning4J. I already experimented with its word2vec functionality and everything was fine. But now I am little bit confused regarding image classification. I was playing with this example:
https://github.com/deeplearning4j/dl4j-examples/blob/master/dl4j-examples/src/main/java/org/deeplearning4j/examples/convolution/AnimalsClassification.java
I changed the "save" flag to true and my model is stored into model.bin file.
Now comes the problematic part (I am sorry if this sounds as silly question, maybe I am missing something really obvious here)
I created separate class called AnimalClassifier and its purpose is to load model from model.bin file, restore neural network from it and then classify single image using restored network. For this single image I created "temp" folder -> dl4j-examples/src/main/resources/animals/temp/ where I put picture of polar bear that was previously used in training process in AnimalsClassification.java (I wanted to be sure that image would be classified correctly - therefore I reused picture from "bear" folder).
This my code trying to classify polar bear:
protected static int height = 100;
protected static int width = 100;
protected static int channels = 3;
protected static int numExamples = 1;
protected static int numLabels = 1;
protected static int batchSize = 10;
protected static long seed = 42;
protected static Random rng = new Random(seed);
protected static int listenerFreq = 1;
protected static int iterations = 1;
protected static int epochs = 7;
protected static double splitTrainTest = 0.8;
protected static int nCores = 2;
protected static boolean save = true;
protected static String modelType = "AlexNet"; //
public static void main(String[] args) throws Exception {
String basePath = FilenameUtils.concat(System.getProperty("user.dir"), "dl4j-examples/src/main/resources/");
MultiLayerNetwork multiLayerNetwork = ModelSerializer.restoreMultiLayerNetwork(basePath + "model.bin", true);
ParentPathLabelGenerator labelMaker = new ParentPathLabelGenerator();
File mainPath = new File(System.getProperty("user.dir"), "dl4j-examples/src/main/resources/animals/temp/");
FileSplit fileSplit = new FileSplit(mainPath, NativeImageLoader.ALLOWED_FORMATS, rng);
BalancedPathFilter pathFilter = new BalancedPathFilter(rng, labelMaker, numExamples, numLabels, batchSize);
InputSplit[] inputSplit = fileSplit.sample(pathFilter, 1);
InputSplit analysedData = inputSplit[0];
ImageRecordReader recordReader = new ImageRecordReader(height, width, channels);
recordReader.initialize(analysedData);
DataSetIterator dataIter = new RecordReaderDataSetIterator(recordReader, batchSize, 0, 4);
while (dataIter.hasNext()) {
DataSet testDataSet = dataIter.next();
String expectedResult = testDataSet.getLabelName(0);
List<String> predict = multiLayerNetwork.predict(testDataSet);
String modelResult = predict.get(0);
System.out.println("\nFor example that is labeled " + expectedResult + " the model predicted " + modelResult + "\n\n");
}
}
After running this, I get error:
java.lang.UnsupportedOperationException
at org.datavec.api.writable.ArrayWritable.toInt(ArrayWritable.java:47)
at org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator.getDataSet(RecordReaderDataSetIterator.java:275)
at org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator.next(RecordReaderDataSetIterator.java:186)
at org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator.next(RecordReaderDataSetIterator.java:389)
at org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator.next(RecordReaderDataSetIterator.java:52)
at org.deeplearning4j.examples.convolution.AnimalClassifier.main(AnimalClassifier.java:66)
Disconnected from the target VM, address: '127.0.0.1:63967', transport: 'socket'
Exception in thread "main" java.lang.IllegalStateException: Label names are not defined on this dataset. Add label names in order to use getLabelName with an id.
at org.nd4j.linalg.dataset.DataSet.getLabelName(DataSet.java:1106)
at org.deeplearning4j.examples.convolution.AnimalClassifier.main(AnimalClassifier.java:68)
I can see there is a method public void setLabels(INDArray labels) in MultiLayerNetwork.java but I don't get how to use (especially when it takes as argument INDArray).
I am also confused why I have to specify number of possible labels in constructor of RecordReaderDataSetIterator. I would expect that model already knows which labels to use (should not it use labels that were used during training automatically?). I guess, maybe I am loading the picture in completely wrong way...
So to summarize, I would like to achieve simply following:
restore network from model (this is working)
load image to be classified (also working)
classify this image using the same labels that were used during training (bear, deer, duck, turtle) (tricky part)
Thank you in advance for your help or any hints !
So summarizing your multiple questions here:
A record for images is 2 entries in a collection. The second 1 is the label. The label index is relative to the kind of record you pass in.
The second part of your question:
Multiple entries can be apart of a dataset. The list refers to a label for an item at a particular row in the minibatch.

connecting vertices in jung by edges results in another extra vertex being created

I am implementing an interface for taking commands for creating , connecting and coloring vertices in JUNG when I want to connect two already existing vertices JUNG connects to vertices and creates an extra vertex , why?
Here is my code for connect method:
public class Connect extends Command {
private CommandMaster cm;
private BehGraphUndirected behGraph;
private static int edgenumber=0;
#Override
public Object run(BehGraphUndirected behGraph, VisualizationImageServer panel, InterpretMaster interpretMaster, String... args) {
System.out.print("connect Runs\n");
this.cm = new CommandMaster();
this.behGraph = behGraph;
if(cm.exists(args[0]))
{
//got to another command
}else
{
switch (args[0]) {
case "edge":
this.createEdge(args[1] , args[2]);
break;
}
}
interpretMaster.refreshAndRepaint();
return null;
}
public void createEdge(String nodeName1 , String nodeName2)
{
this.behGraph.addEdge(edgenumber++,nodeName1, nodeName2);
System.out.println(this.behGraph.getVertexCount());
System.out.println("edge between: "+nodeName1+" and "+ nodeName2+" added");
}
And it's the create method just in case you want to know the way I implemented the code:
package interpreter.command;
import GraphHandling.BehGraphUndirected;
import edu.uci.ics.jung.visualization.VisualizationImageServer;
import interpreter.Command;
import interpreter.CommandMaster;
import interpreter.InterpretMaster;
/**
*
* #author Administrator
*/
public class Create extends Command{
private CommandMaster cm;
private BehGraphUndirected behGraph;
#Override
public Object run(BehGraphUndirected behGraph, VisualizationImageServer panel, InterpretMaster interpretMaster, String... args) {
System.out.print("create Runs \n");
this.cm = new CommandMaster();
this.behGraph = behGraph;
if(cm.exists(args[0]))
{
//got to another command
}else
{
switch (args[0]) {
case "node":
this.createNode(args[1]);
break;
case "label":
this.createLabel(args[1]);
break;
}
}
interpretMaster.refreshAndRepaint();
return null;
}
public void createNode(String nodeName)
{
this.behGraph.addVertex(nodeName);
System.out.print("vertex: "+nodeName+" added");
}
private void createLabel(String string) {
}
class str
{
int i;
long j;
}
}
Graph images before and after connecting two nodes:
and Here is my BehGraphUndirected class:
package GraphHandling;
import edu.uci.ics.jung.graph.UndirectedSparseGraph;
import java.util.LinkedList;
/**
*
* #author Administrator
*/
public class BehGraphUndirected extends UndirectedSparseGraph{
private final LinkedList<Node> nodeList;
public BehGraphUndirected()
{
this.nodeList = new LinkedList<>();
}
public void addNode(Node newNode)
{
this.nodeList.add(newNode);
}
}
You should look at what BehGraphUndirected is doing; it's not a JUNG class or interface.
What is the name of the vertex that's being created, and how does that relate to what's being passed to the create method?
I have compiled and tested your code , The Jung library seems working right and It extinguishes the different nodes by the different object that was given to it It seems you have some other problem , Like a problem in processing the input strings that are used as objects that create nodes.

ActivePivot leaf level aggregation and Analysis dimension

lets say I have an ActivePivot cube with facts containing just Value, and Currency.
lets say my cube has Currency as a regular dimension.
We fill the cube with facts that have many currencies.
We have a forex service that takes the currency and reference currency to get a rate.
Now, Value.SUM doesn't make any sense, we are adding up values with different currencies, so we want to have a post processor that can convert all values to a reference currency, say, USD, then sum them, so we write a post processor that extends ADynamicAggregationPostProcessor, specify Currency as a leaf level dimension, and use the forex service to do the conversion, and we are happy.
But, lets say we don't want to convert just to USD, we want to convert to 10 different currencies and see the results next to each other on the screen.
So we create an Analysis dimension, say ReferenceCurrency, with 10 members.
My question is: how can I alter the above post processor to handle the Analysis dimension? The plain vanilla ADynamicAggregationPostProcessor does not handle Analysis dimensions, only the default member is visible to this post processor. Other post processors that handle Analysis dimensions, like DefaultAggregatePostProcessor do not have a means for specifying leaf levels, so I cannot get the aggregates by Currency, and so cannot do the forex conversion. How can I have my cake and eat it too?
It looks like you want to use two advanced features of ActivePivot at the same time (Analysis dimensions to expose several outcomes of the same aggregate, and dynamic aggregation to aggregate amounts expressed in different currencies).
Separately each one is fairly easy to setup through configuration and a few lines of code to inject. But to interleave both you will need to understand the internals of post processor evaluation, and inject business logic at the right places.
Here is an example based on ActivePivot 4.3.3. It has been written in the open-source Sandbox Application so that you can run it quickly before adapting it to your own project.
First we need a simple analysis dimension to hold the possible reference currencies:
package com.quartetfs.pivot.sandbox.postprocessor.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import com.quartetfs.biz.pivot.cube.hierarchy.axis.impl.AAnalysisDimension;
import com.quartetfs.fwk.QuartetExtendedPluginValue;
/**
*
* An analysis dimension bearing the
* list of possible reference currencies.
*
* #author Quartet FS
*
*/
#QuartetExtendedPluginValue(interfaceName = "com.quartetfs.biz.pivot.cube.hierarchy.IDimension", key = ReferenceCurrencyDimension.TYPE)
public class ReferenceCurrencyDimension extends AAnalysisDimension {
/** serialVersionUID */
private static final long serialVersionUID = 42706811331081328L;
/** Default reference currency */
public static final String DEFAULT_CURRENCY = "EUR";
/** Static list of non-default possible reference currencies */
public static final List<Object[]> CURRENCIES;
static {
List<Object[]> currencies = new ArrayList<Object[]>();
currencies.add(new Object[] {"USD"});
currencies.add(new Object[] {"GBP"});
currencies.add(new Object[] {"JPY"});
CURRENCIES = Collections.unmodifiableList(currencies);
}
/** Plugin type */
public static final String TYPE = "REF_CCY";
/** Constructor */
public ReferenceCurrencyDimension(String name, int ordinal, Properties properties, Set<String> measureGroups) {
super(name, ordinal, properties, measureGroups);
}
#Override
public Object getDefaultDiscriminator(int levelOrdinal) { return DEFAULT_CURRENCY; }
#Override
public Collection<Object[]> buildDiscriminatorPaths() { return CURRENCIES; }
#Override
public int getLevelsCount() { return 1; }
#Override
public String getLevelName(int levelOrdinal) {
return levelOrdinal == 0 ? "Currency" : super.getLevelName(levelOrdinal);
}
#Override
public String getType() { return TYPE; }
}
Then the post processor itself, a customized dynamic aggregation post processor modified to handle the analysis dimension and output the same aggregate multiple times, one time per reference currency.
package com.quartetfs.pivot.sandbox.postprocessor.impl;
import java.util.List;
import java.util.Properties;
import com.quartetfs.biz.pivot.IActivePivot;
import com.quartetfs.biz.pivot.ILocation;
import com.quartetfs.biz.pivot.ILocationPattern;
import com.quartetfs.biz.pivot.aggfun.IAggregationFunction;
import com.quartetfs.biz.pivot.cellset.ICellSet;
import com.quartetfs.biz.pivot.cube.hierarchy.IDimension;
import com.quartetfs.biz.pivot.cube.hierarchy.axis.IAxisMember;
import com.quartetfs.biz.pivot.impl.Location;
import com.quartetfs.biz.pivot.postprocessing.impl.ADynamicAggregationPostProcessor;
import com.quartetfs.biz.pivot.postprocessing.impl.ADynamicAggregationProcedure;
import com.quartetfs.biz.pivot.query.IQueryCache;
import com.quartetfs.biz.pivot.query.aggregates.IAggregatesRetriever;
import com.quartetfs.biz.pivot.query.aggregates.RetrievalException;
import com.quartetfs.fwk.QuartetException;
import com.quartetfs.fwk.QuartetExtendedPluginValue;
import com.quartetfs.pivot.sandbox.service.impl.ForexService;
import com.quartetfs.tech.type.IDataType;
import com.quartetfs.tech.type.impl.DoubleDataType;
/**
* Forex post processor with two features:
* <ul>
* <li>Dynamically aggregates amounts in their native currencies into reference currency
* <li>Applies several reference currencies, exploded along an analysis dimension.
* </ul>
*
* #author Quartet FS
*/
#QuartetExtendedPluginValue(interfaceName = "com.quartetfs.biz.pivot.postprocessing.IPostProcessor", key = ForexPostProcessor.TYPE)
public class ForexPostProcessor extends ADynamicAggregationPostProcessor<Double> {
/** serialVersionUID */
private static final long serialVersionUID = 15874126988574L;
/** post processor plugin type */
public final static String TYPE = "FOREX";
/** Post processor return type */
private static final IDataType<Double> DATA_TYPE = new DoubleDataType();
/** Ordinal of the native currency dimension */
protected int nativeCurrencyDimensionOrdinal;
/** Ordinal of the native currency level */
protected int nativeCurrencyLevelOrdinal;
/** Ordinal of the reference currencies dimension */
protected int referenceCurrenciesOrdinal;
/** forex service*/
private ForexService forexService;
/** constructor */
public ForexPostProcessor(String name, IActivePivot pivot) {
super(name, pivot);
}
/** Don't forget to inject the Forex service into the post processor */
public void setForexService(ForexService forexService) {
this.forexService = forexService;
}
/** post processor initialization */
#Override
public void init(Properties properties) throws QuartetException {
super.init(properties);
nativeCurrencyDimensionOrdinal = leafLevelsOrdinals.get(0)[0];
nativeCurrencyLevelOrdinal = leafLevelsOrdinals.get(0)[1];
IDimension referenceCurrenciesDimension = getDimension("ReferenceCurrencies");
referenceCurrenciesOrdinal = referenceCurrenciesDimension.getOrdinal();
}
/**
* Handling of the analysis dimension:<br>
* Before retrieving leaves, wildcard the reference currencies dimension.
*/
protected ICellSet retrieveLeaves(ILocation location, IAggregatesRetriever retriever) throws RetrievalException {
ILocation baseLocation = location;
if(location.getLevelDepth(referenceCurrenciesOrdinal-1) > 0) {
Object[][] array = location.arrayCopy();
array[referenceCurrenciesOrdinal-1][0] = null; // wildcard
baseLocation = new Location(array);
}
return super.retrieveLeaves(baseLocation, retriever);
}
/**
* Perform the evaluation of the post processor on a leaf (as defined in the properties).
* Here the leaf level is the UnderlierCurrency level in the Underlyings dimension .
*/
#Override
protected Double doLeafEvaluation(ILocation leafLocation, Object[] underlyingMeasures) throws QuartetException {
// Extract the native and reference currencies from the evaluated location
String currency = (String) leafLocation.getCoordinate(nativeCurrencyDimensionOrdinal-1, nativeCurrencyLevelOrdinal);
String refCurrency = (String) leafLocation.getCoordinate(referenceCurrenciesOrdinal-1, 0);
// Retrieve the measure in the native currency
double nativeAmount = (Double) underlyingMeasures[0];
// If currency is reference currency or measureNative is equal to 0.0 no need to convert
if ((currency.equals(refCurrency)) || (nativeAmount == .0) ) return nativeAmount;
// Retrieve the rate and rely on the IQueryCache
// in order to retrieve the same rate for the same currency for our query
IQueryCache queryCache = pivot.getContext().get(IQueryCache.class);
Double rate = (Double) queryCache.get(currency + "_" + refCurrency);
if(rate == null) {
Double rateRetrieved = forexService.retrieveQuotation(currency, refCurrency);
Double rateCached = (Double) queryCache.putIfAbsent(currency + "_" + refCurrency, rateRetrieved);
rate = rateCached == null ? rateRetrieved : rateCached;
}
// Compute equivalent in reference currency
return rate == null ? nativeAmount : nativeAmount * rate;
}
#Override
protected IDataType<Double> getDataType() { return DATA_TYPE; }
/** #return the type of this post processor, within the post processor extended plugin. */
#Override
public String getType() { return TYPE; }
/**
* #return our own custom dynamic aggregation procedure,
* so that we can inject our business logic.
*/
protected DynamicAggregationProcedure createProcedure(ICellSet cellSet, IAggregationFunction aggregationFunction, ILocationPattern pattern) {
return new DynamicAggregationProcedure(cellSet, aggregationFunction, pattern);
}
/**
* Custom dynamic aggregation procedure.<br>
* When the procedure is executed over a leaf location,
* we produce several aggregates instead of only one:
* one aggregate for each of the visible reference currencies.
*/
protected class DynamicAggregationProcedure extends ADynamicAggregationProcedure<Double> {
protected DynamicAggregationProcedure(ICellSet cellSet, IAggregationFunction aggregationFunction, ILocationPattern pattern) {
super(ForexPostProcessor.this, aggregationFunction, cellSet, pattern);
}
/**
* Execute the procedure over one row of the leaf cell set.
* We compute one aggregate for each of the reference currencies.
*/
#Override
public boolean execute(ILocation location, int rowId, Object[] measures) {
if(location.getLevelDepth(referenceCurrenciesOrdinal-1) > 0) {
// Lookup the visible reference currencies
IDimension referenceCurrenciesDimension = pivot.getDimensions().get(referenceCurrenciesOrdinal);
List<IAxisMember> referenceCurrencies = (List<IAxisMember>) referenceCurrenciesDimension.retrieveMembers(0);
for(IAxisMember member : referenceCurrencies) {
Object[][] array = location.arrayCopy();
array[referenceCurrenciesOrdinal-1][0] = member.getDiscriminator();
ILocation loc = new Location(array);
super.execute(loc, rowId, measures);
}
return true;
} else {
return super.execute(location, rowId, measures);
}
}
#Override
protected Double doLeafEvaluation(ILocation location, Object[] measures) throws QuartetException {
return ForexPostProcessor.this.doLeafEvaluation(location, measures);
}
}
}
In the description of your cube, the analysis dimension and the post processor would be exposed like this:
...
<dimension name="ReferenceCurrencies" pluginKey="REF_CCY" />
...
<measure name="cross" isIntrospectionMeasure="false">
<postProcessor pluginKey="FOREX">
<properties>
<entry key="id" value="pv.SUM" />
<entry key="underlyingMeasures" value="pv.SUM" />
<entry key="leafLevels" value="UnderlierCurrency#Underlyings" />
</properties>
</postProcessor>
</measure>
...
Analysis Dimensions brings so much complexity they should be considered apart of the others features of your cube. One way to handle your issue is then:
Add a first measure expanding properly along the analysis dimension. In your case, it will simply copy the underlying measure along ReferenceCurrency, optionally doing the FX conversion. This measure may be used as underlying of several measures.
Add a second measure, based on usual dynamic aggregation. This second implementation is very simple as it does not know there is an analysis dimension.

Implementation of BFS, DFS and Dijkstra

Is it true that the implementation of BFS, DFS and Dijkstra are almost the same, except that BFS uses queue, DFS uses stack, while Dijkstra uses min priority queue?
More precisely. Can we use the following code for all of BFS, DFS, and Dijkstra, with Q being a queue for BFS, and a stack for DFS, and a min priority queue for Dijkstra? Thanks!
Init d[]=Inf; // distance from the node s
Init c[]='w'; // color of nodes: 'w':undiscovered, 'g':discovered, 'b':fully explored
Init p[]=null; // previous node in the path
c[s]='g';
d[s]=0;
Q.push(s);
while(!Q.empty()) {
u = Q.front();
Q.pop();
for v in adj[u] {
if(c(v)=='w') {
c[v]='g';
if(d[u]+w(u,v)<d[v]) {
d[v]=d[u]+w(u,v);
p[v]=u;
}
Q.push(v);
}
}
c[u]='b';
}
Yes
Let's say we have this graph, and want to find the shortest distances starting at A:
Here is a simple NodeCollection interface that allows for the operations needed for the traversal:
interface NodeCollection<E> {
void offer(E node);
E extract();
boolean isEmpty();
}
And the implementations for queue, stack and priority queue. Note that this interface and classes don't really need to be generic:
static class NodeQueue<E> implements NodeCollection<E> {
private final Queue<E> queue = new LinkedList<E>();
#Override public void offer(E node) { queue.offer(node); }
#Override public E extract() { return queue.poll(); }
#Override public boolean isEmpty() { return queue.isEmpty(); }
}
static class NodeStack<E> implements NodeCollection<E> {
private final Stack<E> stack = new Stack<E>();
#Override public void offer(E node) { stack.push(node); }
#Override public E extract() { return stack.pop(); }
#Override public boolean isEmpty() { return stack.isEmpty(); }
}
static class NodePriorityQueue<E> implements NodeCollection<E> {
private final PriorityQueue<E> pq = new PriorityQueue<E>();
#Override public void offer(E node) { pq.add(node); }
#Override public E extract() { return pq.poll(); }
#Override public boolean isEmpty() { return pq.isEmpty(); }
}
Note that for PriorityQueue to work as expected, the Node class needs to provide a compareTo(Node) method:
static class Node implements Comparable<Node> {
final String name;
Map<Node, Integer> neighbors;
int dist = Integer.MAX_VALUE;
Node prev = null;
char color = 'w';
Node(String name) {
this.name = name;
this.neighbors = Maps.newHashMap();
}
#Override public int compareTo(Node o) {
return ComparisonChain.start().compare(this.dist, o.dist).result();
}
}
Now here's the Graph class. Note that the traverse method takes a NodeCollection instance, which will be used for storing nodes during the traversal.
static class Graph {
Map<String, Node> nodes = Maps.newHashMap();
void addEdge(String fromName, String toName, int weight) {
Node from = getOrCreate(fromName);
Node to = getOrCreate(toName);
from.neighbors.put(to, weight);
to.neighbors.put(from, weight);
}
Node getOrCreate(String name) {
if (!nodes.containsKey(name)) {
nodes.put(name, new Node(name));
}
return nodes.get(name);
}
/**
* Traverses this graph starting at the given node and returns a map of shortest paths from the start node to
* every node.
*
* #param startName start node
* #return shortest path for each node in the graph
*/
public Map<String, Integer> traverse(String startName, NodeCollection<Node> collection) {
assert collection.isEmpty();
resetNodes();
Node start = getOrCreate(startName);
start.dist = 0;
collection.offer(start);
while (!collection.isEmpty()) {
Node curr = collection.extract();
curr.color = 'g';
for (Node neighbor : curr.neighbors.keySet()) {
if (neighbor.color == 'w') {
int thisPathDistance = curr.dist + curr.neighbors.get(neighbor);
if (thisPathDistance < neighbor.dist) {
neighbor.dist = thisPathDistance;
neighbor.prev = curr;
}
collection.offer(neighbor);
}
}
curr.color = 'b';
}
Map<String, Integer> shortestDists = Maps.newTreeMap();
for (Node node : nodes.values()) {
shortestDists.put(node.name, node.dist);
}
return shortestDists;
}
private void resetNodes() {
for (Node node : nodes.values()) {
node.dist = Integer.MAX_VALUE;
node.prev = null;
node.color = 'w';
}
}
}
Finally here's the main method, which traverses the same graph 3 times, once with each of the NodeCollection types:
private static Graph initGraph() {
Graph graph = new Graph();
graph.addEdge("A", "B", 2);
graph.addEdge("B", "C", 2);
graph.addEdge("C", "D", 2);
graph.addEdge("D", "E", 2);
graph.addEdge("E", "F", 2);
graph.addEdge("F", "L", 2);
graph.addEdge("A", "G", 10);
graph.addEdge("G", "H", 10);
graph.addEdge("H", "I", 10);
graph.addEdge("I", "J", 10);
graph.addEdge("J", "K", 10);
graph.addEdge("K", "L", 10);
return graph;
}
public static void main(String[] args) {
Graph graph = initGraph();
System.out.println("Queue (BFS):\n" + graph.traverse("A", new NodeQueue<Node>()));
System.out.println("Stack (DFS):\n" + graph.traverse("A", new NodeStack<Node>()));
System.out.println("PriorityQueue (Dijkstra):\n" + graph.traverse("A", new NodePriorityQueue<Node>()));
}
And the results!
Queue (BFS):
{A=0, B=2, C=4, D=6, E=8, F=10, G=10, H=20, I=30, J=40, K=22, L=12}
Stack (DFS):
{A=0, B=2, C=4, D=66, E=64, F=62, G=10, H=20, I=30, J=40, K=50, L=60}
PriorityQueue (Dijkstra):
{A=0, B=2, C=4, D=6, E=8, F=10, G=10, H=20, I=30, J=32, K=22, L=12}
Note that DFS will sometimes take the top branch first, yielding different but symmetric results.
Here's what the results look like this on the graph:
On the matter of BFS vs. DFS: yes and no, but more "no" than "yes".
If all you care about is the forward traversal order, i.e. the order in which the algorithm discovers the new vertices of the graph, then yes: you can take the classic BFS algorithm, replace the FIFO queue with LIFO stack, and you will get pseudo-DFS algorithm.
However, I call it pseudo-DFS algorithm because it is not really the same as the classic DFS.
The DFS algorithm obtained that way will indeed generate genuine DFS vertex discovery order. However, it will still be different from the classic DFS in some other regadrs. You can find the description of the classic DFS in any book on algorithms (or Wikipedia) and you will see that the structure of the algorithm is notably different from BFS. It is done that way for a reason. The classic DFS offers some additional benefits besides producing the proper DFS vertex discovery order. These additional benefits include
Lower peak memory consumption. In classic DFS implementation the stack size at each moment in time equals the length of the path from the search origin to the current vertex. In pseudo-DFS the stack size at each moment in time equals the sum of the degrees of all vertices from the search origin to the current vertex. This means that the peak memory consumption of pseudo-DFS algorithm will potentially be considerably higher.
For an extreme example, consider a "snowflake" graph consisting of a single vertex in the center directly connected to a 1000 vertices surrounding it. A classic DFS will traverse this graph with maximum stack depth of 1. Meanwhile, a pseudo-DFS will start by pushing all 1000 vertices into the stack (in BFS fashion), resulting in peak stack depth of 1000. That's quite a difference.
Backtracking. A classic DFS algorithm is a genuine recursive algorithm. As a recursive algorithm in addition to the forward traversal order (i.e. vertex discovery order), it also provides you with backward traversal order (backtracking). In the classic DFS you visit each vertex multiple times: first time when you discover it for the very first time, then when you return back from one of its descendant vertices to proceed to the next descendant vertex, and finally for the very last time when you have processed all of its descendants. Many DFS-based algorithms are build on catching and handling these visits. For example, topological sorting algorithm is classic DFS that outputs the vertices in the order of their last DFS visit. The pseudo-DFS algorithm, as I said above, only provides you with clear access to the first event (vertex discovery), but does not register any backtracking events.
Yes this is true. A lot of useful algorithms have similar patterns. For instance, for graph eigenvectors, the Power Iteration algorithm, if you change the starting vector, and the orthogonalizing vector, you get a whole family of useful, but related algorithms. In that case, it's called ABS projection.
In this case they are all built on the "incremental addition"-to-a-tree primitive. It's just how we choose that edge / vertex to add determines the type of tree and hence the type of navigation.

actionscript circle entire drawing moves why?

package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
public class helloworld extends Sprite {
public static var x:int = 0;
public static var y:int = 0;
public function helloworld() {
graphics.lineStyle(1, 0, 1);
stage.focus = this;
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
}
private function onKeyDown(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.DOWN)
{
y++;
graphics.moveTo(x,y);
graphics.drawCircle(x, y, 10);
}
if (event.keyCode == Keyboard.RIGHT)
{
x++;
graphics.moveTo(x,y);
graphics.drawCircle(x, y, 10);
}
}
}
The circles that are drawn first also move. How can I stop it from doing that?
You think you're using your public static x & y values, but actually you're using the Sprite's built in x and y properties which control its location on the stage. When you use y++ and x++ it moves the entire sprite down/right.
You should either make sure you're always calling helloworld.x && helloworld.y (bad idea, easy to forget).
OR
You should not use variables named x and y. Try: circleX and circleY or something that is more descriptive of what you're using it for.

Resources