org.deri.iris.rules.compiler.RuleCompiler.java Source code

Java tutorial

Introduction

Here is the source code for org.deri.iris.rules.compiler.RuleCompiler.java

Source

/*
 * Integrated Rule Inference System (IRIS):
 * An extensible rule inference system for datalog with extensions.
 * 
 * Copyright (C) 2008 Semantic Technology Institute (STI) Innsbruck, 
 * University of Innsbruck, Technikerstrasse 21a, 6020 Innsbruck, Austria.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
 * MA  02110-1301, USA.
 */
package org.deri.iris.rules.compiler;

import org.apache.commons.collections15.IteratorUtils;
import org.deri.iris.Configuration;
import org.deri.iris.EvaluationException;
import org.deri.iris.api.basics.*;
import org.deri.iris.api.builtins.IBuiltinAtom;
import org.deri.iris.api.terms.IConstructedTerm;
import org.deri.iris.api.terms.ITerm;
import org.deri.iris.api.terms.IVariable;
import org.deri.iris.facts.IFacts;
import org.deri.iris.rules.RuleHeadEquality;
import org.deri.iris.storage.IRelation;
import org.deri.iris.utils.equivalence.IEquivalentTerms;
import org.deri.iris.utils.equivalence.IgnoreTermEquivalence;

import java.util.*;

/**
 * A rule compiler for creating objects that compute new facts using
 * forward-chaining techniques.
 */
public class RuleCompiler {

    /**
     * Constructor.
     * 
     * @param facts The facts that will be used by the compiled rules.
     */
    public RuleCompiler(IFacts facts, Configuration configuration) {
        this(facts, new IgnoreTermEquivalence(), configuration);
    }

    /**
     * Creates a new RuleCompiler.
     * 
     * @param facts The facts that will be used by the compiled rules.
     * @param equivalentTerms The equivalent terms.
     * @param configuration The configuration.
     */
    public RuleCompiler(IFacts facts, IEquivalentTerms equivalentTerms, Configuration configuration) {
        mFacts = facts;
        mConfiguration = configuration;
        mEquivalentTerms = equivalentTerms;
    }

    /**
     * Compile a rule. No optimisations of any kind are attempted.
     * 
     * @param rule The rule to be compiled
     * @return The compiled rule, ready to be evaluated
     * @throws EvaluationException If the query can not be compiled for any
     *             reason.
     */
    public ICompiledRule compile(IRule rule) throws EvaluationException {
        LinkedHashMap<RuleElement, ILiteral> elementsToLiteral = compileBody(rule.getBody());
        List<RuleElement> elements = IteratorUtils.toList(elementsToLiteral.keySet().iterator());

        List<IVariable> variables;

        if (elements.size() == 0)
            variables = new ArrayList<IVariable>();
        else {
            RuleElement lastElement = elements.get(elements.size() - 1);
            variables = lastElement.getOutputVariables();
        }

        ILiteral headLiteral = rule.getHead().get(0);
        IAtom headAtom = headLiteral.getAtom();
        ITuple headTuple = headAtom.getTuple();

        HeadSubstituter substituter;

        // We create a special head substituter for rules with head
        // equality, that establishes equivalence relation between terms in the
        // equivalent terms data-structure.
        if (RuleHeadEquality.hasRuleHeadEquality(rule)) {
            substituter = new RuleHeadEqualitySubstituter(variables, headTuple, elementsToLiteral, mEquivalentTerms,
                    mConfiguration);
        } else {
            substituter = new HeadSubstituter(variables, headTuple, elementsToLiteral, mConfiguration);
        }

        elements.add(substituter);

        //Amir added
        for (int e = 0; e < elements.size() - 2; e++) {
            RuleElement elt = elements.get(e);
            elt.FindIndices(elements);
        }

        return new CompiledRule(elements, headAtom.getPredicate(), headLiteral, mConfiguration);
    }

    /**
     * Compile a query. No optimisations of any kind are attempted.
     * 
     * @param query The query to be compiled
     * @return The compiled query, ready to be evaluated
     * @throws EvaluationException If the query can not be compiled for any
     *             reason.
     */
    public ICompiledRule compile(IQuery query) throws EvaluationException {
        List<RuleElement> elements = IteratorUtils.toList(compileBody(query.getLiterals()).keySet().iterator());

        return new CompiledRule(elements, null, null, mConfiguration);
    }

    /**
     * Compile a rule body (or query). The literals are compiled in the order
     * given. However, if one literal can not be compiled, because one or more
     * of its variables are not bound from the proceeding literal, then it is
     * skipped an re-tried later.
     * 
     * @param bodyLiterals The list of literals to compile
     * @return The compiled rule elements.
     * @throws EvaluationException If a rule construct can not be compiled (e.g.
     *             a built-in has constructed terms)
     */
    private LinkedHashMap<RuleElement, ILiteral> compileBody(Collection<ILiteral> bodyLiterals)
            throws EvaluationException {
        List<ILiteral> literals = new ArrayList<ILiteral>(bodyLiterals);

        LinkedHashMap<RuleElement, ILiteral> elements = new LinkedHashMap<RuleElement, ILiteral>();

        List<IVariable> previousVariables = new ArrayList<IVariable>();

        while (elements.size() < bodyLiterals.size()) {
            EvaluationException lastException = null;

            boolean added = false;
            for (int l = 0; l < literals.size(); ++l) {
                ILiteral literal = literals.get(l);
                IAtom atom = literal.getAtom();
                boolean positive = literal.isPositive();

                RuleElement element;

                try {
                    if (atom instanceof IBuiltinAtom) {
                        IBuiltinAtom builtinAtom = (IBuiltinAtom) atom;

                        boolean constructedTerms = false;
                        for (ITerm term : atom.getTuple()) {
                            if (term instanceof IConstructedTerm) {
                                constructedTerms = true;
                                break;
                            }
                        }

                        if (constructedTerms)
                            element = new BuiltinForConstructedTermArguments(previousVariables, builtinAtom,
                                    positive, mEquivalentTerms, mConfiguration);
                        else
                            element = new Builtin(atom.getPredicate(), atom.getTuple(), previousVariables,
                                    builtinAtom, positive, mEquivalentTerms, mConfiguration);
                    } else {
                        IPredicate predicate = atom.getPredicate();
                        IRelation relation = mFacts.get(predicate);
                        ITuple viewCriteria = atom.getTuple();

                        if (positive) {
                            if (previousVariables.size() == 0) {
                                // First sub-goal
                                element = new FirstSubgoal(predicate, relation, viewCriteria, mEquivalentTerms,
                                        mConfiguration);
                            } else {
                                element = new Joiner(previousVariables, predicate, relation, viewCriteria,
                                        mEquivalentTerms, mConfiguration.indexFactory,
                                        mConfiguration.relationFactory);
                            }
                        } else {
                            // This *is* allowed to be the first literal for
                            // rules such as:
                            // p('a') :- not q('b')
                            // or even:
                            // p('a') :- not q(?X)
                            element = new Differ(previousVariables, relation, viewCriteria, mEquivalentTerms,
                                    mConfiguration);
                        }
                    }
                    previousVariables = element.getOutputVariables();

                    elements.put(element, literals.get(l));

                    literals.remove(l);
                    added = true;
                    break;
                } catch (EvaluationException e) {
                    // Oh dear. Store the exception and try the next literal.
                    lastException = e;
                }
            }
            if (!added) {
                // No more literals, so the last error really was serious.
                throw lastException;
            }
        }

        if (elements.size() > 0) {
            RuleElement lastElement = null;
            for (RuleElement element : elements.keySet()) {
                lastElement = element;
            }

            assert lastElement != null;
            RuleElement element = new EquivalenceResolver(lastElement.getOutputVariables(), mEquivalentTerms,
                    mConfiguration);
            elements.put(element, null);
        }

        return elements;
    }

    /** The equivalent terms. */
    private IEquivalentTerms mEquivalentTerms;

    /** The knowledge-base facts used to attach to the compiled rule elements. */
    private final IFacts mFacts;

    /** The knowledge-base configuration. */
    private final Configuration mConfiguration;
}