Package edu.ucla.sspace.graph.isomorphism

Source Code of edu.ucla.sspace.graph.isomorphism.AbstractIsomorphismTester

/*
* Copyright 2011 David Jurgens
*
* This file is part of the S-Space package and is covered under the terms and
* conditions therein.
*
* The S-Space package is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation and distributed hereunder to you.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND NO REPRESENTATIONS OR WARRANTIES,
* EXPRESS OR IMPLIED ARE MADE.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, WE MAKE
* NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- ABILITY OR FITNESS FOR ANY
* PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE OR DOCUMENTATION
* WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER
* RIGHTS.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package edu.ucla.sspace.graph.isomorphism;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import edu.ucla.sspace.graph.*; // FIX

import edu.ucla.sspace.util.Pair;

import gnu.trove.TDecorators;
import gnu.trove.map.TIntIntMap;
import gnu.trove.map.hash.TIntIntHashMap;

import static edu.ucla.sspace.graph.isomorphism.State.NULL_NODE;


/**
* An abstraction of an {@link IsomorphismTester} that relies on
* algorithm-specific {@link State} implementations to check for edge and vertex
* contraints when performing isomorphism testing. 
*
* <p> This class is a an adaptation of parts of the VFLib library.
*/
public abstract class AbstractIsomorphismTester implements IsomorphismTester {

    /**
     * {@inheritDoc}
     */
    public boolean areIsomorphic(Graph<? extends Edge> g1,
                                 Graph<? extends Edge> g2) {
        Graph<? extends Edge> g1mapped = remap(g1, null);
        Graph<? extends Edge> g2mapped = remap(g2, null);
        State state = makeInitialState(g1mapped, g2mapped);
        return match(state);
    }

    /**
     * {@inheritDoc}
     */
    public Map<Integer,Integer> findIsomorphism(Graph<? extends Edge> g1,
                                                Graph<? extends Edge> g2) {
        // Since the user has asked to find the mapping itself, we'll need to
        // keep track of how the vertices are remapped.  Note that if the graphs
        // are already in canonical order, then these maps will be empty.
        TIntIntHashMap g1vMap = new TIntIntHashMap(g1.order());
        TIntIntHashMap g2vMap = new TIntIntHashMap(g2.order());

        // Remap the graphs so that the vertices are contiguous, filling in a
        // backwards mapping so we can recover the isomorphism later.
        Graph<? extends Edge> g1mapped = remap(g1, g1vMap);
        Graph<? extends Edge> g2mapped = remap(g2, g2vMap);
        State state = makeInitialState(g1mapped, g2mapped);

        Map<Integer,Integer> isoMapping = new HashMap<Integer,Integer>();
        // If we mapped the vertices, we have to unmap the vertices in order
        // to identify the isometric pairs.
        if (match(state, isoMapping)) {
            // Create a new isometric map that will contain the unmapped
            // mappings
            TIntIntMap fixedIsoMapping = new TIntIntHashMap(isoMapping.size());
            for (Map.Entry<Integer,Integer> e : isoMapping.entrySet()) {
                int v1 = e.getKey();
                v1 = (g1vMap.isEmpty()) ? v1 : g1vMap.get(v1);
                int v2 = e.getValue();
                v2 = (g2vMap.isEmpty()) ? v2 : g2vMap.get(v2);
                fixedIsoMapping.put(v1, v2);
            }
            return TDecorators.wrap(fixedIsoMapping);
        }
        else
            return Collections.<Integer,Integer>emptyMap();
    }

    /**
     * Creates an empty {@link State} for mapping the vertices of {@code g1} to
     * {@code g2}.
     */
    protected abstract State makeInitialState(Graph<? extends Edge> g1,
                                              Graph<? extends Edge> g2);

    /**
     * Returns {@code true} if the graphs being matched by this state are
     * isomorphic.
     */
    private boolean match(State s) {
        if (s.isGoal())
            return true;       

        if (s.isDead())
            return false;

        int n1 = NULL_NODE, n2 = NULL_NODE;
        Pair<Integer> next = null;
        boolean found = false;
        while (!found && (next = s.nextPair(n1, n2)) != null) {
            n1 = next.x;
            n2 = next.y;
            if (s.isFeasiblePair(n1, n2)) {
                State copy = s.copy();
                copy.addPair(n1, n2);
                found = match(copy);
                // If we found a match, then don't bother backtracking as it
                // would be wasted effort.
                if (!found)
                    copy.backTrack();
            }
        }
        return found;
    }

    /**
     * Returns {@code true} if the graphs being matched by this state are
     * isomorphic.
     */
    private boolean match(State s, Map<Integer,Integer> isoMap) {
        if (s.isGoal())
            return true;       

        if (s.isDead())
            return false;

        int n1 = NULL_NODE, n2 = NULL_NODE;
        Pair<Integer> next = null;
        boolean found = false;
        while (!found && (next = s.nextPair(n1, n2)) != null) {
            n1 = next.x;
            n2 = next.y;
            if (s.isFeasiblePair(n1, n2)) {
                State copy = s.copy();
                copy.addPair(n1, n2);
                found = match(copy, isoMap);
                // If we found a mapping, fill the vertex mapping state
                if (found)
                    isoMap.putAll(copy.getVertexMapping());
                // Otherwise, back track and try again
                else
                    copy.backTrack();
            }
        }
        return found;
    }

    /**
     * Remaps the graph's vertices so that they are in a contiguous range from 0
     * to {@code g.order()}-1.  If the graph's vertices are already contiguous,
     * returns the original graph.
     *
     * @param rvMap an optional parameter for a map that is filled with the
     *        reverse mapping from the vertex indices in the return map to the
     *        indices of {@code g}
     */
    private <E extends Edge> Graph<E> remap(Graph<E> g, TIntIntHashMap rvMap) {
        int order = g.order();
        boolean isContiguous = true;
        for (int i : g.vertices()) {
            if (i >= order) {
                isContiguous = false;
                break;
            }
        }
        if (isContiguous)
            return g;       

        // Map the vertices to a contiguous range
        TIntIntMap vMap = new TIntIntHashMap(g.order());
        int j = 0;
        for (int i : g.vertices()) {
            vMap.put(i, j++);
        }
       
        if (rvMap != null) {
            // Assumes a stable iteration ordering of the vertices, which is
            // potentially unsafe... However, this avoids putting a redundant
            // null check in the prior loop.
            int k = 0;
            for (int i : g.vertices()) {
                rvMap.put(k++, i);
            }
        }
       
        Graph<E> copy = g.copy(Collections.<Integer>emptySet());
        for (int i = 0; i < order; ++i)
            copy.add(i);
        for (E e : g.edges())
            copy.add(e.<E>clone(vMap.get(e.from()), vMap.get(e.to())));
       
        return copy;
    }   
}
TOP

Related Classes of edu.ucla.sspace.graph.isomorphism.AbstractIsomorphismTester

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.