edu.uci.ics.jung.algorithms.layout.ISOMLayout.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.algorithms.layout.ISOMLayout.java

Source

/*
* Copyright (c) 2003, the JUNG Project and the Regents of the University
* of California
* All rights reserved.
*
* This software is open-source under the BSD license; see either
* "license.txt" or
* http://jung.sourceforge.net/license.txt for a description.
*/
package edu.uci.ics.jung.algorithms.layout;

import edu.uci.ics.jung.algorithms.layout.util.RandomLocationTransformer;
import edu.uci.ics.jung.algorithms.util.IterativeContext;
import edu.uci.ics.jung.graph.Graph;

import org.apache.commons.collections15.Factory;
import org.apache.commons.collections15.map.LazyMap;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Implements a self-organizing map layout algorithm, based on Meyer's
 * self-organizing graph methods.
 *
 * @author Yan Biao Boey
 */
public class ISOMLayout<V, E> extends AbstractLayout<V, E> implements IterativeContext {

    Map<V, ISOMVertexData> isomVertexData = LazyMap.decorate(new HashMap<V, ISOMVertexData>(),
            new Factory<ISOMVertexData>() {
                public ISOMVertexData create() {
                    return new ISOMVertexData();
                }
            });

    private int maxEpoch;
    private int epoch;

    private int radiusConstantTime;
    private int radius;
    private int minRadius;

    private double adaption;
    private double initialAdaption;
    private double minAdaption;

    protected GraphElementAccessor<V, E> elementAccessor = new RadiusGraphElementAccessor<V, E>();

    private double coolingFactor;

    private List<V> queue = new ArrayList<V>();
    private String status = null;

    /**
     * Returns the current number of epochs and execution status, as a string.
     */
    public String getStatus() {
        return status;
    }

    /**
     * Creates an <code>ISOMLayout</code> instance for the specified graph <code>g</code>.
     * @param g
     */
    public ISOMLayout(Graph<V, E> g) {
        super(g);
    }

    public void initialize() {

        setInitializer(new RandomLocationTransformer<V>(getSize()));
        maxEpoch = 2000;
        epoch = 1;

        radiusConstantTime = 100;
        radius = 5;
        minRadius = 1;

        initialAdaption = 90.0D / 100.0D;
        adaption = initialAdaption;
        minAdaption = 0;

        //factor = 0; //Will be set later on
        coolingFactor = 2;

        //temperature = 0.03;
        //initialJumpRadius = 100;
        //jumpRadius = initialJumpRadius;

        //delay = 100;
    }

    /**
    * Advances the current positions of the graph elements.
    */
    public void step() {
        status = "epoch: " + epoch + "; ";
        if (epoch < maxEpoch) {
            adjust();
            updateParameters();
            status += " status: running";

        } else {
            status += "adaption: " + adaption + "; ";
            status += "status: done";
            //         done = true;
        }
    }

    private synchronized void adjust() {
        //Generate random position in graph space
        Point2D tempXYD = new Point2D.Double();

        // creates a new XY data location
        tempXYD.setLocation(10 + Math.random() * getSize().getWidth(), 10 + Math.random() * getSize().getHeight());

        //Get closest vertex to random position
        V winner = elementAccessor.getVertex(this, tempXYD.getX(), tempXYD.getY());

        while (true) {
            try {
                for (V v : getGraph().getVertices()) {
                    ISOMVertexData ivd = getISOMVertexData(v);
                    ivd.distance = 0;
                    ivd.visited = false;
                }
                break;
            } catch (ConcurrentModificationException cme) {
            }
        }
        adjustVertex(winner, tempXYD);
    }

    private synchronized void updateParameters() {
        epoch++;
        double factor = Math.exp(-1 * coolingFactor * (1.0 * epoch / maxEpoch));
        adaption = Math.max(minAdaption, factor * initialAdaption);
        //jumpRadius = (int) factor * jumpRadius;
        //temperature = factor * temperature;
        if ((radius > minRadius) && (epoch % radiusConstantTime == 0)) {
            radius--;
        }
    }

    private synchronized void adjustVertex(V v, Point2D tempXYD) {
        queue.clear();
        ISOMVertexData ivd = getISOMVertexData(v);
        ivd.distance = 0;
        ivd.visited = true;
        queue.add(v);
        V current;

        while (!queue.isEmpty()) {
            current = queue.remove(0);
            ISOMVertexData currData = getISOMVertexData(current);
            Point2D currXYData = transform(current);

            double dx = tempXYD.getX() - currXYData.getX();
            double dy = tempXYD.getY() - currXYData.getY();
            double factor = adaption / Math.pow(2, currData.distance);

            currXYData.setLocation(currXYData.getX() + (factor * dx), currXYData.getY() + (factor * dy));

            if (currData.distance < radius) {
                Collection<V> s = getGraph().getNeighbors(current);
                while (true) {
                    try {
                        for (V child : s) {
                            ISOMVertexData childData = getISOMVertexData(child);
                            if (childData != null && !childData.visited) {
                                childData.visited = true;
                                childData.distance = currData.distance + 1;
                                queue.add(child);
                            }
                        }
                        break;
                    } catch (ConcurrentModificationException cme) {
                    }
                }
            }
        }
    }

    protected ISOMVertexData getISOMVertexData(V v) {
        return isomVertexData.get(v);
    }

    /**
     * This one is an incremental visualization.
     * @return <code>true</code> is the layout algorithm is incremental, <code>false</code> otherwise
     */
    public boolean isIncremental() {
        return true;
    }

    /**
     * Returns <code>true</code> if the vertex positions are no longer being
     * updated.  Currently <code>ISOMLayout</code> stops updating vertex
     * positions after a certain number of iterations have taken place.
     * @return <code>true</code> if the vertex position updates have stopped,
     * <code>false</code> otherwise
     */
    public boolean done() {
        return epoch >= maxEpoch;
    }

    protected static class ISOMVertexData {
        int distance;
        boolean visited;

        protected ISOMVertexData() {
            distance = 0;
            visited = false;
        }
    }

    /**
     * Resets the layout iteration count to 0, which allows the layout algorithm to
     * continue updating vertex positions.
     */
    public void reset() {
        epoch = 0;
    }
}