All Downloads are FREE. Search and download functionalities are using the official Maven repository.

slib.graph.algo.validator.dag.ValidatorDAG Maven / Gradle / Ivy

/* 
 *  Copyright or © or Copr. Ecole des Mines d'Alès (2012-2014) 
 *  
 *  This software is a computer program whose purpose is to provide 
 *  several functionalities for the processing of semantic data 
 *  sources such as ontologies or text corpora.
 *  
 *  This software is governed by the CeCILL  license under French law and
 *  abiding by the rules of distribution of free software.  You can  use, 
 *  modify and/ or redistribute the software under the terms of the CeCILL
 *  license as circulated by CEA, CNRS and INRIA at the following URL
 *  "http://www.cecill.info". 
 * 
 *  As a counterpart to the access to the source code and  rights to copy,
 *  modify and redistribute granted by the license, users are provided only
 *  with a limited warranty  and the software's author,  the holder of the
 *  economic rights,  and the successive licensors  have only  limited
 *  liability. 

 *  In this respect, the user's attention is drawn to the risks associated
 *  with loading,  using,  modifying and/or developing or reproducing the
 *  software by the user in light of its specific status of free software,
 *  that may mean  that it is complicated to manipulate,  and  that  also
 *  therefore means  that it is reserved for developers  and  experienced
 *  professionals having in-depth computer knowledge. Users are therefore
 *  encouraged to load and test the software's suitability as regards their
 *  requirements in conditions enabling the security of their systems and/or 
 *  data to be ensured and,  more generally, to use and operate it in the 
 *  same conditions as regards security. 
 * 
 *  The fact that you are presently reading this means that you have had
 *  knowledge of the CeCILL license and that you accept its terms.
 */
package slib.graph.algo.validator.dag;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.openrdf.model.URI;
import org.openrdf.model.vocabulary.RDFS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import slib.graph.algo.accessor.GraphAccessor;
import slib.graph.algo.utils.Color;
import slib.graph.model.graph.G;
import slib.graph.model.graph.elements.E;
import slib.graph.model.graph.utils.Direction;
import slib.graph.model.graph.utils.WalkConstraint;
import slib.graph.utils.WalkConstraintGeneric;
import slib.graph.utils.WalkConstraintUtils;
import slib.utils.ex.SLIB_Ex_Critic;
import slib.utils.impl.SetUtils;

/**
 * Used to validate if a graph is directed and acyclic (DAG)
 *
 * @author Sébastien Harispe 
 */
public class ValidatorDAG {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    G graph;
    WalkConstraint wc;
    HashMap verticesColors;
    boolean valid;
    E lastEdge;
    Path currentPath;

    /*---------------------------------------------------------------------*
     *  Algorithm
     *---------------------------------------------------------------------*/
    /**
     *
     * @param graph
     * @param startingURIs
     * @param wc
     * @return true if the graph is a DAG
     * @throws SLIB_Ex_Critic
     */
    public boolean isDag(G graph, Set startingURIs, WalkConstraint wc) throws SLIB_Ex_Critic {

        this.wc = wc;

        this.graph = graph;
        this.verticesColors = new HashMap();
        valid = true;

        logger.debug("Cheking DAG property of : " + graph.getURI());
        logger.debug("WalkConstraint                  : " + wc);


        if (startingURIs == null || startingURIs.isEmpty()) {
            return false;
        }

        logger.debug("starting nodes          : " + startingURIs.size());

        if (startingURIs.size() < 10) {
            logger.debug("starting vertices : " + startingURIs);
        }

        currentPath = new Path();

        for (URI rootUri : startingURIs) {

            if (!graph.containsVertex(rootUri)) {
                throw new SLIB_Ex_Critic("Vertex '" + rootUri + "' not found in " + graph.getURI());
            }

            if (valid) {
                performDFS(rootUri);
            }
        }

        logger.info("isDag : " + valid);
        if (!valid) {

            logger.info("current path :" + currentPath.toString());
            logger.info("Cycle detected adding : " + lastEdge + " to path");
        }
        return valid;
    }

    private void performDFS(URI v) {

        if (!valid) {
            return;
        }

        if (!verticesColors.containsKey(v)) {

            verticesColors.put(v, Color.ORANGE);


            Set edges = graph.getE(v, wc);


            for (E e : edges) {



                if (!valid) {
                    return;
                }

                URI target = e.getTarget();

                if (target.equals(v)) { // IN
                    target = e.getSource();
                }

                if (verticesColors.get(target) != Color.RED) {
                    currentPath.addEdge(e);
                    lastEdge = e;
                    performDFS(target);
                }

            }
            if (!valid) {
                return;
            }
            currentPath.removeLastEdge();
            verticesColors.put(v, Color.RED);

        } else if (verticesColors.get(v) == Color.ORANGE) {
            valid = false;
        }
    }

    /*---------------------------------------------------------------------*
     *  Utils
     *---------------------------------------------------------------------*/
    /**
     * Check if the underlying graph defined by the edges of the given edge
     * types and build using a traversal starting from the given root node is a
     * DAG. shortcut of {@link ValidatorDAG#isDag(G, WalkConstraint)} only
     * considering the given set of edge types
     *
     * @param graph the graph on which the evaluation has to be made
     * @param rootURI
     * @param wc
     * @return true if the the (underlying) graph reduction is a DAG
     * @throws SLIB_Ex_Critic
     *
     */
    public boolean isDag(G graph, URI rootURI, WalkConstraint wc) throws SLIB_Ex_Critic {
        return isDag(graph, SetUtils.buildSet(rootURI), wc);
    }

    /**
     *
     * @param graph
     * @return true if the graph contains a taxonomic graph.
     * @throws SLIB_Ex_Critic
     */
    public boolean containsTaxonomicDag(G graph) throws SLIB_Ex_Critic {
        WalkConstraint wct = new WalkConstraintGeneric(RDFS.SUBCLASSOF, Direction.IN);
        return isDag(graph, wct);
    }

    /**
     * Check if the underlying graph defined by given {@link WalkConstraint} is
     * a DAG. shortcut of {@link ValidatorDAG#isDag(G, WalkConstraint)}
     * considering the given edge types and the root vertices according to the
     * inverse of the specified edge types as root (see
     * {@link ValidatorDAG#getDAGRoots(G, WalkConstraint)})
     *
     * @param graph the graph on which the evaluation has to be made
     * @param wc
     * @return true if the the (underlying) graph reduction is a DAG
     *
     * @throws SLIB_Ex_Critic
     */
    public boolean isDag(G graph, WalkConstraint wc) throws SLIB_Ex_Critic {

        logger.debug("Check DAG property of the graph " + graph.getURI() + " considering the walkconstraint " + wc);
        Set startingNodes = getDAGRoots(graph, WalkConstraintUtils.getInverse(wc, false));

        logger.info("Starting process from " + startingNodes.size() + " vertices");
        if(graph.getE().isEmpty()){
            logger.info("No edge");
        }
        else if (startingNodes.isEmpty()) // No root No Dag
        {
            logger.debug("No roots have been detected...");
            logger.debug("DAG = false");
            return false;
        }
        else if(!isDag(graph, startingNodes, wc)){
            return false;
        }
        return true;
    }

    /**
     * Root vertices (terminal vertices) are those of type CLASS which respect
     * the following restrictions :
  • must not contains an edges of * the given types and direction
* * Do not check if the graph is a DAG * * @param g the graph on which the root vertices need to be retrieve * @param wc * @return The set of vertices matching the predefined conditions */ public Set getDAGRoots(G g, WalkConstraint wc) { Set classes = GraphAccessor.getClasses(g); Set roots = new HashSet(); for (URI v : classes) { if (g.getV(v, wc).isEmpty()) { roots.add(v); } } return roots; } /** * Check if the given graph contains a underlying taxonomic graph with a * unique root. * * @param g the graph on which the test is performed * @return true if the graph contains a unique underlying rooted taxonomic * graph * * @throws SLIB_Ex_Critic */ public boolean containsTaxonomicDagWithUniqueRoot(G g) throws SLIB_Ex_Critic { WalkConstraintGeneric wc = new WalkConstraintGeneric(RDFS.SUBCLASSOF, Direction.OUT); Set roots = getDAGRoots(g, wc); logger.info("Number of roots " + roots.size()); logger.debug("Root(s): " + roots); if (roots.size() == 1) { isDag(g, roots.iterator().next(), new WalkConstraintGeneric(RDFS.SUBCLASSOF, Direction.IN)); } else { valid = false; } logger.debug("isRootedTaxonomicDag (" + roots.size() + " root(s)) valid " + valid); return valid; } /** * Return the unique vertex rooting the underlying taxonomic graph. Do not * check if the taxonomic graph is a DAG but throw an error if the taxonomic * graph contains multiple roots. * * @param g the graph * @return the unique vertex which roots the taxonomic graph * * @throws SLIB_Ex_Critic if the underlying taxonomic graph of the * given graph contains multiple roots. * */ public URI getUniqueTaxonomicRoot(G g) throws SLIB_Ex_Critic { WalkConstraintGeneric wcTax = new WalkConstraintGeneric(RDFS.SUBCLASSOF, Direction.OUT); Set roots = getDAGRoots(g, wcTax); if (roots.size() != 1) { throw new SLIB_Ex_Critic("Multiple roots detected in the underlying taxonomic graph of graph " + g.getURI()); } return roots.iterator().next(); } /** * Return the vertices which root the taxonomic graph. * * @param g * @return the vertices which can be considered as a root, i.e. all the * vertices which are not subsumed by an other vertex through a taxonomic * relationship. */ public Set getTaxonomicRoots(G g) { return getDAGRoots(g, new WalkConstraintGeneric(RDFS.SUBCLASSOF, Direction.OUT)); } /** * Test if the given URI corresponds to a root of the graph build according * to the specified edge types. * * @param g the graph to consider * @param rootURI the URI to test * @param wc the edge type to consider only OUT direction is considered * @return true if the graph defined by the specified constraint is rooted * by the given URI */ public boolean containsRootedDagRoot(G g, URI rootURI, WalkConstraint wc) { for (URI v : getDAGRoots(g, wc)) { if (v.equals(rootURI)) { return true; } } return false; } /** * @param g * @param root * @return true if the graph contains a taxonomic graph which is rooted by a * unique vertex. * @throws SLIB_Ex_Critic */ public boolean isUniqueRootedTaxonomicDag(G g, URI root) throws SLIB_Ex_Critic { WalkConstraint wc = new WalkConstraintGeneric(RDFS.SUBCLASSOF, Direction.IN); return isUniqueRootedDagRoot(g, root, wc); } /** * Do not check if the graph is a DAG * * @param g * @param root * @param wc * @return true if the graph is a DAG and rooted by a unique vertex. * @throws SLIB_Ex_Critic */ public boolean isUniqueRootedDagRoot(G g, URI root, WalkConstraint wc) throws SLIB_Ex_Critic { if (isDag(g, wc)) { Set roots = getDAGRoots(g, WalkConstraintUtils.getInverse(wc, false)); logger.debug("roots: " + roots); if (roots.size() == 1 && roots.iterator().next().equals(root)) { return true; } } return false; } /** * * @return the last edge which has been processed during the treatment. */ public E getLastEdge() { return lastEdge; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy