⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fruleengine.java

📁 jena2.5.4推理机系统的一种最基本实现 HP实验室出品
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/******************************************************************
 * File:        FRuleEngine.java
 * Created by:  Dave Reynolds
 * Created on:  28-May-2003
 * 
 * (c) Copyright 2003, 2004, 2005, 2006, 2007 Hewlett-Packard Development Company, LP
 * [See end of file]
 * $Id: FRuleEngine.java,v 1.27 2007/01/02 11:48:41 andy_seaborne Exp $
 *****************************************************************/
package com.hp.hpl.jena.reasoner.rulesys.impl;

import com.hp.hpl.jena.reasoner.*;
import com.hp.hpl.jena.reasoner.rulesys.*;
import com.hp.hpl.jena.graph.*;
import java.util.*;

import com.hp.hpl.jena.util.OneToManyMap;
import com.hp.hpl.jena.util.PrintUtil;
import com.hp.hpl.jena.util.iterator.*;
import com.hp.hpl.jena.vocabulary.RDF;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * The processing engine for forward production rules. It neeeds to reference
 * an enclosing ForwardInfGraphI which holds the raw data and deductions.
 * 
 * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
 * @version $Revision: 1.27 $ on $Date: 2007/01/02 11:48:41 $
 */
public class FRuleEngine implements FRuleEngineI {
    
    /** The parent InfGraph which is employing this engine instance */
    protected ForwardRuleInfGraphI infGraph;
    
    /** Set of rules being used */
    protected List rules;
    
    /** Map from predicate node to rule + clause, Node_ANY is used for wildcard predicates */
    protected OneToManyMap clauseIndex;
    
    /** List of predicates used in rules to assist in fast data loading */
    protected HashSet predicatesUsed;
    
    /** Flag, if true then there is a wildcard predicate in the rule set so that selective insert is not useful */
    protected boolean wildcardRule;
     
    /** Set to true to flag that derivations should be logged */
    protected boolean recordDerivations;
    
    /** performance stats - number of rules passing initial trigger */
    int nRulesTriggered = 0;
    
    /** performance stats - number of rules fired */
    long nRulesFired = 0;
    
    /** performance stats - number of rules fired during axiom initialization */
    long nAxiomRulesFired = -1;
    
    /** True if we have processed the axioms in the rule set */
    boolean processedAxioms = false;
    
    protected static Log logger = LogFactory.getLog(FRuleEngine.class);
    
//  =======================================================================
//  Constructors

    /**
     * Constructor.
     * @param parent the F or FB infGraph that it using this engine, the parent graph
     * holds the deductions graph and source data.
     * @param rules the rule set to be processed
     */
    public FRuleEngine(ForwardRuleInfGraphI parent, List rules) {
        infGraph = parent;
        this.rules = rules;
    }

    /**
     * Constructor. Build an empty engine to which rules must be added
     * using setRuleStore().
     * @param parent the F or FB infGraph that it using this engine, the parent graph
     * holds the deductions graph and source data.
     */
    public FRuleEngine(ForwardRuleInfGraphI parent) {
        infGraph = parent;
    }
    
//  =======================================================================
//  Control methods

    /**
     * Process all available data. This should be called once a deductions graph
     * has be prepared and loaded with any precomputed deductions. It will process
     * the rule axioms and all relevant existing exiting data entries.
     * @param ignoreBrules set to true if rules written in backward notation should be ignored
     * @param inserts the set of triples to be processed, normally this is the
     * raw data graph but may include additional deductions made by preprocessing hooks
     */
    public void init(boolean ignoreBrules, Finder inserts) {
        if (clauseIndex == null) compile(rules, ignoreBrules);
        findAndProcessAxioms();
        nAxiomRulesFired = nRulesFired;
        logger.debug("Axioms fired " + nAxiomRulesFired + " rules");
        fastInit(inserts);
    }
    
    /**
     * Process all available data. This version expects that all the axioms 
     * have already be preprocessed and the clause index already exists.
     * @param inserts the set of triples to be processed, normally this is the
     * raw data graph but may include additional deductions made by preprocessing hooks
     */
    public void fastInit(Finder inserts) {
        findAndProcessActions();
        // Create the reasoning context
        BFRuleContext context = new BFRuleContext(infGraph);
        // Insert the data
        if (wildcardRule) {
            for (Iterator i = inserts.find(new TriplePattern(null, null, null)); i.hasNext(); ) {
                context.addTriple((Triple)i.next());
            }
        } else {
            for (Iterator p = predicatesUsed.iterator(); p.hasNext(); ) {
                Node predicate = (Node)p.next();
                for (Iterator i = inserts.find(new TriplePattern(null, predicate, null)); i.hasNext(); ) {
                    context.addTriple((Triple)i.next());
                }
            }
        }
        // Run the engine
        addSet(context);
    }

    /**
     * Add one triple to the data graph, run any rules triggered by
     * the new data item, recursively adding any generated triples.
     */
    public synchronized void add(Triple t) {
        BFRuleContext context = new BFRuleContext(infGraph);
        context.addTriple(t);
        addSet(context);
    }
    
    /**
     * Remove one triple to the data graph.
     * @return true if the effects could be correctly propagated or
     * false if not (in which case the entire engine should be restarted).
     */
    public synchronized boolean delete(Triple t) {
        // Incremental delete not supported
        return false;
    }
    
    /**
     * Return the number of rules fired since this rule engine instance
     * was created and initialized
     */
    public long getNRulesFired() {
        return nRulesFired;
    }
    
    /**
     * Return true if the internal engine state means that tracing is worthwhile.
     * It will return false during the axiom bootstrap phase.
     */
    public boolean shouldTrace() {
//        return processedAxioms;
        return true;
    }

    /**
     * Set to true to enable derivation caching
     */
    public void setDerivationLogging(boolean recordDerivations) {
        this.recordDerivations = recordDerivations;
    }
    
    /**
     * Access the precomputed internal rule form. Used when precomputing the
     * internal axiom closures.
     */
    public Object getRuleStore() {
        return new RuleStore(clauseIndex, predicatesUsed, wildcardRule);
    }
    
    /**
     * Set the internal rule from from a precomputed state.
     */
    public void setRuleStore(Object ruleStore) {
        RuleStore rs = (RuleStore)ruleStore;
        clauseIndex = rs.clauseIndex;
        predicatesUsed = rs.predicatesUsed;
        wildcardRule = rs.wildcardRule;
    }
    
//  =======================================================================
//  Internal methods

    /**
     * Add a set of new triple to the data graph, run any rules triggered by
     * the new data item, recursively adding any generated triples.
     * Technically the triples having been physically added to either the
     * base or deduction graphs and the job of this function is just to
     * process the stack of additions firing any relevant rules.
     * @param context a context containing a set of new triples to be added
     */
    public void addSet(BFRuleContext context) {
        Triple t;
        while ((t = context.getNextTriple()) != null) {
            if (infGraph.shouldTrace()) {
                logger.info("Processing: " + PrintUtil.print(t));
            }
            // Check for rule triggers
            HashSet firedRules = new HashSet();
            Iterator i1 = clauseIndex.getAll(t.getPredicate());
            Iterator i2 = clauseIndex.getAll(Node.ANY);
            Iterator i = new ConcatenatedIterator(i1, i2);
            while (i.hasNext()) {
                ClausePointer cp = (ClausePointer) i.next();
                if (firedRules.contains(cp.rule)) continue;
                context.resetEnv( cp.rule.getNumVars() );
                TriplePattern trigger = (TriplePattern) cp.rule.getBodyElement(cp.index);
                if (match(trigger, t, context.getEnvStack())) {
                    nRulesTriggered++;
                    context.setRule(cp.rule);
                    if (matchRuleBody(cp.index, context)) {
                        firedRules.add(cp.rule);
                        nRulesFired++;
                    }
                }
            }
        }
    }
    
    /**
     * Compile a list of rules into the internal rule store representation.
     * @param rules the list of Rule objects
     * @param ignoreBrules set to true if rules written in backward notation should be ignored
     * @return an object that can be installed into the engine using setRuleStore.
     */
    public void compile(List rules, boolean ignoreBrules) {
        clauseIndex = new OneToManyMap();
        predicatesUsed = new HashSet();
        wildcardRule = false;
            
        for (Iterator i = rules.iterator(); i.hasNext(); ) {
            Rule r = (Rule)i.next();
            if (ignoreBrules && r.isBackward()) continue;
            Object[] body = r.getBody();
            for (int j = 0; j < body.length; j++) {
                if (body[j] instanceof TriplePattern) {
                    Node predicate = ((TriplePattern) body[j]).getPredicate();
                    ClausePointer cp = new ClausePointer(r, j);
                    if (predicate.isVariable()) {
                        clauseIndex.put(Node.ANY, cp);
                        wildcardRule = true;
                    } else {
                        clauseIndex.put(predicate, cp);
                        if (! wildcardRule) {
                            predicatesUsed.add(predicate);
                        }
                    }
                }
            }
        }
            
        if (wildcardRule) predicatesUsed = null;
    }
        
    /**
     * Scan the rules for any axioms and insert those
     */
    protected void findAndProcessAxioms() {
        BFRuleContext context = new BFRuleContext(infGraph);
        for (Iterator i = rules.iterator(); i.hasNext(); ) {
            Rule r = (Rule)i.next();
            if (r.bodyLength() == 0) {
                // An axiom
                for (int j = 0; j < r.headLength(); j++) {
                    Object head = r.getHeadElement(j);
                    if (head instanceof TriplePattern) {
                        TriplePattern h = (TriplePattern) head;
                        Triple t = new Triple(h.getSubject(), h.getPredicate(), h.getObject());
                        context.addTriple(t);
                        infGraph.getDeductionsGraph().add(t);
                    }
                }
            }
        }
        addSet(context);
        processedAxioms = true;
    }
        
    /**
     * Scan the rules for any actions and run those
     */
    protected void findAndProcessActions() {
        BFRuleContext context = new BFRuleContext(infGraph);
        for (Iterator i = rules.iterator(); i.hasNext(); ) {
            Rule r = (Rule)i.next();
            if (r.bodyLength() == 0) {
                // An axiom
                for (int j = 0; j < r.headLength(); j++) {
                    Object head = r.getHeadElement(j);
                    if (head instanceof Functor) {
                        Functor f = (Functor)head;
                        Builtin imp = f.getImplementor();
                        if (imp != null) {
                            context.setRule(r);
                            imp.headAction(f.getArgs(), f.getArgLength(), context);
                        } else {
                            throw new ReasonerException("Invoking undefined Functor " + f.getName() +" in " + r.toShortString());
                        }
                    }
                }
            }
        }
    }
    
    /**
     * Match the rest of a set of rule clauses once an initial rule
     * trigger has fired. Carries out any actions as a side effect.
     * @param trigger the index of the clause which has already be successfully matched
     * @param context a context containing a set of new triples to be added
     * @return true if the rule actually fires
     */
    private boolean matchRuleBody(int trigger, BFRuleContext context) {
        Rule rule = context.getRule();
        // Create an ordered list of body clauses to process, best at the end
        Object[] body = rule.getBody();
        int len = body.length;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -