0

I have a matrix representing a grid, made with 0s,1s and 2s. There is a 0 when there isn't any element on the grid, a 1 when there is an element that can be moved, and a 2 when it's an element that can't be moved.

For example:

0 0 0 0 2 2 0 0 0 0 
0 0 1 1 2 2 1 1 1 0 
0 0 1 0 0 0 1 0 1 0 
0 0 1 0 0 0 1 1 1 0 
0 0 1 1 1 1 1 0 0 0 
0 0 0 0 1 0 1 0 0 0 
0 0 0 0 1 1 1 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0

I would like to turn this into a Directed graph, with every 1 being a vertex, and edges are links between two vertices. To do this, I want to use the jgrapht library, and I try to use their demo code:

package org.jgrapht.demo;

import java.util.*;

import org.jgrapht.*;
import org.jgrapht.generate.*;
import org.jgrapht.graph.*;
import org.jgrapht.traverse.*;


public final class CompleteGraphDemo
{


    static Graph<Object, DefaultEdge> completeGraph;

    //Number of vertices
    static int size = 10;



    public static void main(String [] args)
    {
        //Create the graph object; it is null at this point
        completeGraph = new SimpleGraph<Object, DefaultEdge>(DefaultEdge.class);

        //Create the CompleteGraphGenerator object
        CompleteGraphGenerator<Object, DefaultEdge> completeGenerator =
            new CompleteGraphGenerator<Object, DefaultEdge>(size);

        //Create the VertexFactory so the generator can create vertices
        VertexFactory<Object> vFactory =
            new ClassBasedVertexFactory<Object>(Object.class);

        //Use the CompleteGraphGenerator object to make completeGraph a
        //complete graph with [size] number of vertices
        completeGenerator.generateGraph(completeGraph, vFactory, null);

        //Now, replace all the vertices with sequential numbers so we can ID
        //them
        Set<Object> vertices = new HashSet<Object>();
        vertices.addAll(completeGraph.vertexSet());
        Integer counter = 0;
        for (Object vertex : vertices) {
            replaceVertex(vertex, (Object) counter++);
        }

        //Print out the graph to be sure it's really complete
        Iterator<Object> iter =
            new DepthFirstIterator<Object, DefaultEdge>(completeGraph);
        Object vertex;
        while (iter.hasNext()) {
            vertex = iter.next();
            System.out.println(
                "Vertex " + vertex.toString() + " is connected to: "
                + completeGraph.edgesOf(vertex).toString());
        }
    }

    public static boolean replaceVertex(Object oldVertex, Object newVertex)
    {
        if ((oldVertex == null) || (newVertex == null)) {
            return false;
        }
        Set<DefaultEdge> relatedEdges = completeGraph.edgesOf(oldVertex);
        completeGraph.addVertex(newVertex);

        Object sourceVertex;
        Object targetVertex;
        for (DefaultEdge e : relatedEdges) {
            sourceVertex = completeGraph.getEdgeSource(e);
            targetVertex = completeGraph.getEdgeTarget(e);
            if (sourceVertex.equals(oldVertex)
                && targetVertex.equals(oldVertex))
            {
                completeGraph.addEdge(newVertex, newVertex);
            } else {
                if (sourceVertex.equals(oldVertex)) {
                    completeGraph.addEdge(newVertex, targetVertex);
                } else {
                    completeGraph.addEdge(sourceVertex, newVertex);
                }
            }
        }
        completeGraph.removeVertex(oldVertex);
        return true;
    }
}

// End CompleteGraphDemo.java

However, this code creates a random Digraph based on the number of vertices declared with size, whereas I need to add the matrix' elements (1s) as vertices, and then use the program to generate the digraph and return the number of cycles (in the matrix above there would be 3 cycles).

I can't figure out how to replace the line:

completeGenerator.generateGraph(completeGraph, vFactory, null);

to take as input the matrix'elements. Does anyone know how to do this ? (I use processing which is based on java)

Graham Slick
  • 6,692
  • 9
  • 51
  • 87

1 Answers1

1

Although it is unclear what you want to do exactly (what happens with the 2s? which edges are connected? is this a complete graph? what does it have to do with the grid?) the answer to your question is to probably not use a ready-made process. Yes, the method in the example creates a complete graph as its name implies, which I am not sure as stated above is what you want.

What you can do though is to process the matrix yourself and use other methods in this library to manually add the vertices and edges such as in one of the examples on the library's home page, (adapted here to make a Directed graph of Strings, and print it)

    DirectedGraph<String, DefaultEdge> g =
        new DefaultDirectedGraph<String, DefaultEdge>(DefaultEdge.class);

    String v1 = "v1";
    String v2 = "v2";
    String v3 = "v3";
    String v4 = "v4";

    // add the vertices
    g.addVertex(v1);
    g.addVertex(v2);
    g.addVertex(v3);
    g.addVertex(v4);

    // add edges to create a circuit
    g.addEdge(v1, v2);
    g.addEdge(v2, v3);
    g.addEdge(v3, v4);
    g.addEdge(v4, v1);


    //Print the edges
    Iterator<String> iter =
        new DepthFirstIterator<String, DefaultEdge>(g);
    String vertex;
    while (iter.hasNext()) {
        vertex = iter.next();
        System.out.println(
            "Vertex " + vertex + " is connected to: "
            + g.edgesOf(vertex));
    }

A side note: Note that in this example, the type of the node is "String". It could be any non-primitive type or a new class. For example I attach below the same code for "Integer"

    DirectedGraph<Integer, DefaultEdge> g =
        new DefaultDirectedGraph<Integer, DefaultEdge>(DefaultEdge.class);

    Integer v1 = 2367;
    Integer v2 = 56799;
    Integer v3 = 78678;
    Integer v4 = 343;

    // add the vertices
    g.addVertex(v1);
    g.addVertex(v2);
    g.addVertex(v3);
    g.addVertex(v4);

    // add edges to create a circuit
    g.addEdge(v1, v2);
    g.addEdge(v2, v3);
    g.addEdge(v3, v4);
    g.addEdge(v4, v1);

    //Print out the graph to be sure it's really complete
    Iterator<Integer> iter =
        new DepthFirstIterator<Integer, DefaultEdge>(g);
    Integer vertex;
    while (iter.hasNext()) {
        vertex = iter.next();
        System.out.println(
            "Vertex " + vertex + " is connected to: "
            + g.edgesOf(vertex));
    }
Petros Koutsolampros
  • 2,790
  • 1
  • 14
  • 20
  • Would this work if I wanted to create Vertices based on a couple of coordinates (rounded to they are Integer) ? I tried DirectedGraph g = new DefaultDirectedGraph(DefaultEdge.class); But I get an error saying that it is the wrong number of arguments for the type DirectedGraph (V,E) – Graham Slick Jul 25 '15 at 01:59
  • No you need to create a class with 2 integers in this case and use the new class, or just use PVector – Petros Koutsolampros Jul 25 '15 at 13:56
  • Will I be able to use the jgrapht's functions if I create a new class ? How should I create it to be able to use DijkstraShortestPath and cycledetector for example ? They both don't take coordinates as parameters. Should I create a class and define a Point object that has 2 int parameters and then do: DirectedGraph< Point, DefaultEdge> g = new DefaultDirectedGraph(DefaultEdge.class); ? – Graham Slick Jul 25 '15 at 16:15
  • 1
    Best answer I can give you: Try a few things and if you get stuck come back and ask another question :) – Petros Koutsolampros Jul 25 '15 at 16:53