001/**
002 * Copyright (C) 2007 - 2016, Jens Lehmann
003 * <p>
004 * This file is part of DL-Learner.
005 * <p>
006 * DL-Learner is free software; you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation; either version 3 of the License, or
009 * (at your option) any later version.
010 * <p>
011 * DL-Learner is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 * <p>
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.dllearner.algorithms.qtl.util.filters;
020
021import org.apache.jena.graph.Node;
022import org.apache.jena.vocabulary.RDF;
023import org.dllearner.algorithms.qtl.QueryTreeUtils;
024import org.dllearner.algorithms.qtl.datastructures.NodeInv;
025import org.dllearner.algorithms.qtl.datastructures.impl.RDFResourceTree;
026import org.dllearner.algorithms.qtl.util.Entailment;
027
028import java.util.Collection;
029import java.util.HashSet;
030import java.util.Set;
031import java.util.SortedSet;
032
033/**
034 * A query tree filter that removes edges whose existence is supposed to be
035 * semantically meaningless from user perspective.
036 *
037 * @author Lorenz Buehmann
038 *
039 */
040public class PredicateExistenceFilter extends AbstractTreeFilter<RDFResourceTree> {
041
042    private Set<Node> existentialMeaninglessProperties = new HashSet<>();
043
044    public PredicateExistenceFilter() {}
045
046    public PredicateExistenceFilter(Set<Node> existentialMeaninglessProperties) {
047        this.existentialMeaninglessProperties = existentialMeaninglessProperties;
048    }
049
050    /**
051     * @param existentialMeaninglessProperties the existential meaningless properties
052     */
053    public void setExistentialMeaninglessProperties(Set<Node> existentialMeaninglessProperties) {
054        this.existentialMeaninglessProperties = existentialMeaninglessProperties;
055    }
056
057    public boolean isMeaningless(Node predicate) {
058        return existentialMeaninglessProperties.contains(predicate);
059    }
060
061    @Override
062    public RDFResourceTree apply(RDFResourceTree tree) {
063        RDFResourceTree newTree = new RDFResourceTree(tree, false);
064
065//        if (tree.isLiteralNode() && !tree.isLiteralValueNode()) {
066//            newTree = new RDFResourceTree(tree.getDatatype());
067//        } else {
068//            newTree = new RDFResourceTree(0);
069//            newTree.setData(tree.getData());
070//        }
071//        newTree.setAnchorVar(tree.getAnchorVar());
072
073        for (Node edge : tree.getEdges()) {
074            // get the label if it's an incoming edge
075            Node edgeLabel = edge instanceof NodeInv ? ((NodeInv) edge).getNode() : edge;
076
077            // properties that are marked as "meaningless"
078            if (isMeaningless(edgeLabel)) {
079                // if the edge is meaningless
080                // 1. process all children
081                for (RDFResourceTree child : tree.getChildren(edge)) {
082                    // add edge if child is resource, literal or a nodes that has to be kept
083                    if (child.isResourceNode() || child.isLiteralValueNode() || nodes2Keep.contains(child.getAnchorVar())) {
084                        RDFResourceTree newChild = apply(child);
085                        newTree.addChild(newChild, edge);
086                    } else {
087                        // else recursive call and then check if there is no more child attached, i.e. it's just a leaf with a variable as label
088                        RDFResourceTree newChild = apply(child);
089                        SortedSet<Node> childEdges = newChild.getEdges();
090                        if (!childEdges.isEmpty() && !(childEdges.size() == 1 && childEdges.contains(RDF.type.asNode()))) {
091                            newTree.addChild(newChild, edge);
092                        }
093                    }
094                }
095            } else {
096                // all other properties
097                for (RDFResourceTree child : tree.getChildren(edge)) {
098                    RDFResourceTree newChild = apply(child);
099                    newTree.addChild(newChild, edge);
100                }
101            }
102        }
103
104        // we have to run the subsumption check one more time to prune the tree
105        QueryTreeUtils.prune(newTree, null, Entailment.RDFS);
106        return newTree;
107    }
108}