autofacts.java
来自「Mandarax是一个规则引擎的纯Java实现。它支持多类型的事实和基于反映的规」· Java 代码 · 共 302 行
JAVA
302 行
/*
* Copyright (C) 1999-2004 <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</a>
*
* 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.mandarax.util;
import java.io.Serializable;
import java.util.*;
import org.apache.commons.collections.iterators.ArrayIterator;
import org.mandarax.kernel.*;
/**
* AutoFacts are generic clause sets. AutoFacts facilitate the task of integrating facts
* generated from data into the knowledge base at run time (=time when we run the inference engine).<br>
* It is very useful to subclass <code>AutoFacts</code>, overridding the method <code>getExtension(Class type)</code>.
* This method returns a collection of instances for the respective type. E.g., assume we have an
* instance <code>af</code> of such a subclass with <code>getExtension</code> returning
* (the <code>Integer</code> instances) 1,2 and 3 for <code>Integer.class</code>. Now assume that we perform
* <code>af.clauses(1<x,null)</code>, where <code>1<x</code> stands for the fact consisting of the
* <code>IntArithmetic.LESS_THAN</code> predicate, a constant term wrapping the integer 1,
* and a variable term of the type <code>Integer</code> named "x". Then the iterator returned
* iterates over two facts: <code>1<2</code> and <code>1<3</code>. If we perform
* <code>af.clauses(x<y,null)</code>
* (two variables!), the iterator iterates over three facts <code>1<2</code>,<code>1<3</code>,
* <code>2<3</code>. This will also work if the parameter(s) contains functions (with a known semantics),
* e.g., the iterator returned by <code>af.clauses(x*x<x+x,null)</code> (where * and + stand for
* the respective function defined as static members in <code>IntArithmetic</code>) will iterate over
* one fact only: <code>1*1<1+1</code>. <br>
* If <code>clauses()</code> is used without parameters, the set of facts iterated is defined as
* follows:
* <ul>
* <li> The predicate of each fact must be in the array returned by <code>getPredicates()</code>.
* <li> For each type of any slot of the predicate, the extension
* is computed, and a fact is build for each combination of these extensions.
* </ul>
* E.g., if <code>getPredicates()</code> returns <code>{IntArithmetic.LESS_THAN,IntArithmetic.EQUALS}</code>,
* and the extension for <code>Integer.class</code> is defined as {1,2,3}, then <code>clauses()</code> returns an
* iterator iterating over the following facts: <code>1=1</code>,<code>2=2<code> ,<code>3=3</code> ,
* <code>1<2</code>, <code>1<3</code> and <code>2<3</code>. <br>
* In the math test package and in the example.crm package are a couple of examples showing how to use
* auto facts.
* @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
* @version 3.4 <7 March 05>
* @since 1.2
* @deprecated use JFunction and JPredicate instead. Warning: session support has not been added to AutoFacts
*/
public class AutoFacts extends AbstractPropertiesSupport implements ClauseSet,Serializable {
protected transient List clauseSetChangeListener = new Vector();
protected org.mandarax.kernel.Predicate[] predicates;
private String name = "Automatically built fact base";
/**
* Constructor.
*/
public AutoFacts() {
super ();
}
/**
* Add a clause set listener.
* @param l a listener
*/
public void addClauseSetChangeListener(ClauseSetChangeListener l) {
clauseSetChangeListener.add (l);
}
/**
* Iterate all clauses. We generate a set of clauses for all predicates
* returned by <code>getPredicates()</code> only if for all types
* of any term of this predicate a non empty extension is defined.
* (see also class comment)
*/
public org.mandarax.util.ClauseIterator clauses() {
if(predicates == null) {
return new ZeroClauseIterator ();
}
List allIterators = new ArrayList (predicates.length);
ClauseIterator nextIterator = null;
for(int i = 0; i < predicates.length; i++) {
nextIterator = getClauseIterator (predicates[i]);
if(nextIterator != null) {
allIterators.add (nextIterator);
}
}
if(allIterators.isEmpty ()) {
return new ZeroClauseIterator ();
} else {
return new MergedClauseIterator (allIterators);
}
}
/**
* Get a clause iterator.
* @return a clause iterator
* @param query the query clause
* @param additionalParameter an additional parameter
*/
public ClauseIterator clauses(org.mandarax.kernel.Clause query,
Object additionalParameter) {
Fact leadingFact = getFact (query);
// extract the variables
Object[] obj = extractVariables (leadingFact).toArray ();
VariableTerm[] vars = new VariableTerm[obj.length];
System.arraycopy (obj, 0, vars, 0, obj.length);
// get the extension for each variable
Collection[] extensions = new Collection[vars.length];
for(int i = 0; i < extensions.length; i++) {
extensions[i] = getExtension (vars[i].getType ());
}
// iterate over the extensions
if(vars.length == 0) {
return new SingleAutoFactIterator (leadingFact, this);
} else {
return new AutoFactIterator (
leadingFact, new MultipleCollectionIterator (extensions),
vars, this);
}
}
/**
* Extract the variables from a fact or complex term.
* @return a collection of variables
* @param tc a fact or complex term
*/
private Collection extractVariables(TermContainer tc) {
Collection coll = new HashSet ();
Term[] terms = tc.getTerms ();
Term t;
for(int i = 0; i < terms.length; i++) {
t = terms[i];
if(t.isCompound ()) {
coll.addAll (extractVariables ((ComplexTerm) t));
} else {
if(terms[i].isVariable ()) {
coll.add (t);
}
}
}
return coll;
}
/**
* Fire a clause set change event
* @param e an event
*/
protected void fireClauseSetChangeEvent(ClauseSetChangeEvent e) {
ClauseSetChangeListener l;
for(Iterator it =
clauseSetChangeListener.iterator (); it.hasNext (); ) {
l = (ClauseSetChangeListener) it.next ();
l.clauseSetChanged (e);
}
}
/**
* Get a clause iterator for the respective predicate.
* @return a clause iterator.
* @param p a predicate
*/
private ClauseIterator getClauseIterator(Predicate p) {
Class[] struct = p.getStructure ();
LogicFactory lfact = LogicFactory.getDefaultFactory ();
VariableTerm[] vars = new VariableTerm[struct.length];
Collection[] extensions = new Collection[struct.length];
Collection ex = null;
for(int i = 0; i < struct.length; i++) {
ex = getExtension (struct[i]);
if((ex == null) || ex.isEmpty ()) {
return null;
// in this case we cannot build an iterator since we do not know which objects do use in facts
}
extensions[i] = ex;
vars[i] = lfact.createVariableTerm ("x" + i, struct[i]);
}
Fact template = lfact.createFact (p, vars);
return new AutoFactIterator (
template, new MultipleCollectionIterator (extensions), vars,
this);
}
/**
* Get the extension for a type. Note that by default
* an empty set is returned. This will lead to a clause set
* containing at most one fact. If the auto fact set should
* build facts for combinations of variable replacements, then
* this method needs to be overridden by a subclass.
* @return a collection of objects of the respective type
* @param type a type
*/
protected Collection getExtension(Class type) {
return new ArrayList ();
}
/**
* Get the fact for a query. The query clause is passed
* by the inference engine, so we basically implement a selection rule here!
* @todo .. add a method that takes a selection rules as parameter ?
* @return org.mandarax.kernel.Fact
* @param query org.mandarax.kernel.Clause
*/
private Fact getFact(Clause query) {
return(Fact) query.getNegativeLiterals ().get (0);
}
/**
* Get the key
* @return the key (i.e., the predicates for this clause set)
*/
public Object getKey() {
return predicates;
}
/**
* Get the name of the auto fact set.
* @return a name
*/
public String getName() {
return name;
}
/**
* Get the predicates.
* @return the predicates
*/
public org.mandarax.kernel.Predicate[] getPredicates() {
return predicates;
}
/**
* Get an iterator iterating over the predicates contained in this clause set.
* @return an iterator
*/
public Iterator predicates() {
if (predicates==null) return new ArrayIterator(new Predicate[]{});
else return new ArrayIterator(predicates);
}
/**
* Remove a clause set listener.
* @param l a listener
*/
public void removeClauseSetChangeListener(ClauseSetChangeListener l) {
clauseSetChangeListener.remove (l);
}
/**
* Set a name.
* @param aName a name
*/
public void setName(String aName) {
name = aName;
}
/**
* Set the predicates,
* @param newPredicates the predicates
*/
public void setPredicates(org.mandarax.kernel.Predicate[] newPredicates) {
predicates = newPredicates;
}
/**
* Convert the object to a string.
* @return the string representation of this object
*/
public String toString() {
return getName ();
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?