Package com.clarkparsia.pellet.rules.rete

Source Code of com.clarkparsia.pellet.rules.rete.Compiler$ProductionNodeCreator

// Copyright (c) 2006 - 2008, Clark & Parsia, LLC. <http://www.clarkparsia.com>
// This source code is available under the terms of the Affero General Public License v3.
//
// Please see LICENSE.txt for full license terms, including the availability of proprietary exceptions.
// Questions, comments, or requests for clarification: licensing@clarkparsia.com

package com.clarkparsia.pellet.rules.rete;

import static java.lang.String.format;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.mindswap.pellet.ABox;
import org.mindswap.pellet.DependencySet;
import org.mindswap.pellet.Individual;
import org.mindswap.pellet.PelletOptions;
import org.mindswap.pellet.Role;
import org.mindswap.pellet.exceptions.InternalReasonerException;
import org.mindswap.pellet.utils.SetUtils;

import aterm.ATermAppl;

import com.clarkparsia.pellet.datatypes.exceptions.InvalidLiteralException;
import com.clarkparsia.pellet.datatypes.exceptions.UnrecognizedDatatypeException;
import com.clarkparsia.pellet.rules.BindingHelper;
import com.clarkparsia.pellet.rules.ContinuousRulesStrategy;
import com.clarkparsia.pellet.rules.VariableUtils;
import com.clarkparsia.pellet.rules.builtins.BuiltIn;
import com.clarkparsia.pellet.rules.builtins.BuiltInRegistry;
import com.clarkparsia.pellet.rules.model.AtomDConstant;
import com.clarkparsia.pellet.rules.model.AtomDObject;
import com.clarkparsia.pellet.rules.model.AtomDVariable;
import com.clarkparsia.pellet.rules.model.AtomIConstant;
import com.clarkparsia.pellet.rules.model.AtomIVariable;
import com.clarkparsia.pellet.rules.model.AtomObject;
import com.clarkparsia.pellet.rules.model.AtomObjectVisitor;
import com.clarkparsia.pellet.rules.model.AtomVariable;
import com.clarkparsia.pellet.rules.model.BuiltInAtom;
import com.clarkparsia.pellet.rules.model.ClassAtom;
import com.clarkparsia.pellet.rules.model.DataRangeAtom;
import com.clarkparsia.pellet.rules.model.DatavaluedPropertyAtom;
import com.clarkparsia.pellet.rules.model.DifferentIndividualsAtom;
import com.clarkparsia.pellet.rules.model.IndividualPropertyAtom;
import com.clarkparsia.pellet.rules.model.Rule;
import com.clarkparsia.pellet.rules.model.RuleAtom;
import com.clarkparsia.pellet.rules.model.RuleAtomVisitor;
import com.clarkparsia.pellet.rules.model.SameIndividualAtom;
import com.clarkparsia.pellet.rules.rete.NodeProvider.ConstantNodeProvider;
import com.clarkparsia.pellet.rules.rete.NodeProvider.TokenNodeProvider;
import com.clarkparsia.pellet.rules.rete.NodeProvider.WMENodeProvider;

/**
* <p>
* Title: Compiler
* </p>
* <p>
* Description:
* </p>
* <p>
* Copyright: Copyright (c) 2007
* </p>
* <p>
* Company: Clark & Parsia, LLC. <http://www.clarkparsia.com>
* </p>
*/
public class Compiler {
  protected ContinuousRulesStrategy strategy;
  private ABox abox;
  private AlphaNetwork alphaNet;
 
  private SafetyChecker safetyChecker = new SafetyChecker();

  public Compiler(ContinuousRulesStrategy strategy) {
    this.strategy = strategy;
    this.abox = strategy.getABox();
    alphaNet = new AlphaNetwork(abox);
  }
 
  public AlphaNetwork getAlphaNet() {
    return alphaNet;
  }

  private RuleAtom pickNextAtom(List<RuleAtom> atoms, Set<AtomVariable> bound) {
    int index = 0;
    if (bound.isEmpty()) {
      for (int i = 0; i < atoms.size(); i++) {
        RuleAtom atom = atoms.get(i);   
        if (safetyChecker.isSafe(atom)) {
          return atoms.remove(i);
        }
      }
    }
    else {
      for (int i = 0; i < atoms.size(); i++) {
        RuleAtom atom = atoms.get(i);
        if (SetUtils.intersects(bound, atom.getAllArguments())) {
          index = i;
          if (safetyChecker.isSafe(atom)) {
            break;
          }
        }
      }
    }

    return atoms.remove(index);   
  }

  public void compile(Rule rule, final Set<ATermAppl> explain) {   
    List<RuleAtom> atoms = new ArrayList<RuleAtom>();
    List<BuiltInCall> builtins = new ArrayList<BuiltInCall>();
   
    for (RuleAtom atom : rule.getBody()) {
      if (atom instanceof BuiltInAtom) {
        builtins.add(new BuiltInCall(abox, (BuiltInAtom) atom));
      }
      else if (atom instanceof DataRangeAtom) {
//        builtins.add(new Pair<RuleAtom, BindingHelper>(atom, new DataRangeBindingHelper(abox, (DataRangeAtom) atom)));
      }
      else {
        atoms.add(atom);
      }
    }
   
    Set<AtomVariable> bound = new HashSet<AtomVariable>();
    List<RuleAtom> processed = new ArrayList<RuleAtom>();
   
    int lastSafe = -1;
    ReteNode lastSafeBeta = null;
   
    boolean canReuseBeta = false;
   
    RuleAtom atom = null;
    ReteNode node = null;
    while (!atoms.isEmpty()) {
      atom = pickNextAtom(atoms, bound);
     
      if (!safetyChecker.isSafe(atom)) {
        lastSafe = processed.size();
        lastSafeBeta = node;
      }
     
      AlphaNode alpha = alphaNet.addNode(atom);
      List<? extends AtomObject> args = atom.getAllArguments();
     
      List<FilterCondition> conditions = new ArrayList<FilterCondition>();
      if (!processed.isEmpty()) {
        for (int i = 0, n = args.size(); i < n; i++) {
          AtomObject arg = args.get(i);
          if (arg instanceof AtomVariable) {
            TokenNodeProvider provider = createNodeProvider((AtomVariable) arg, processed);
            if (provider != null) {
                        conditions.add(new JoinCondition(new WMENodeProvider(i), provider));
            }
          }
              }
      }
     
      processed.add(atom);
     
      bound.addAll(VariableUtils.getVars(atom));
     
      // any builtin that can be evaluated with current bindings should be handled here
      for (Iterator<BuiltInCall> i = builtins.iterator(); i.hasNext();) {
              BuiltInCall call = i.next();
              if (bound.containsAll(call.getPrerequisitesVars(bound))) {             
                Collection<? extends AtomVariable> bindableVars = call.getBindableVars(bound);
                if (bindableVars.isEmpty() || bound.containsAll(bindableVars)) {
                  conditions.add(call.createCondition(processed));
                  i.remove();
                }
              }             
            }

      boolean firstBeta = (node == null);
      BetaNode newBeta = null;
     
      if (canReuseBeta) {
        if (firstBeta) {
          for (BetaNode existingBeta : alpha.getBetas()) {
            if (existingBeta.isTop()) {
              newBeta = existingBeta;
              break;
            }
          }
        }
        else {
          Collection<BetaNode> sharedBetas = SetUtils.intersection(alpha.getBetas(), node.getBetas());
          for (BetaNode existingBeta : sharedBetas) {
            if (existingBeta instanceof BetaMemoryNode) {
              BetaMemoryNode existingBetaMem = (BetaMemoryNode) existingBeta;
              if (existingBetaMem.getConditions().equals(conditions)) {
                newBeta = existingBeta;
                break;
              }
            }
          }
        }
      }
     
      if (newBeta == null) {
        newBeta = firstBeta ? new BetaTopNode(alpha) : new BetaMemoryNode(alpha, conditions);
        canReuseBeta = false;
      }
     
      alpha.addChild(newBeta);
      if (!firstBeta) {
        node.addChild(newBeta);
      }
      node = newBeta;
     
      // process builtins at the end since binding builtins may change
      int bindingCount = -1;
      while (!builtins.isEmpty() && bindingCount != bound.size()) {
        bindingCount = bound.size();
        for (Iterator<BuiltInCall> i = builtins.iterator(); i.hasNext();) {
                BuiltInCall call = i.next();
                if (bound.containsAll(call.getPrerequisitesVars(bound))) { 
                  // create the beta node before updating processed atoms
            newBeta = call.createBeta(processed);
            node.addChild(newBeta);
            node = newBeta;           
            processed.add(call.atom);
            bound.addAll(call.getBindableVars(bound));
            canReuseBeta = false;
            i.remove();
          }             
              }
      }
    }
   
    if (!builtins.isEmpty()) {
      throw new UnsupportedOperationException("Builtin using unsafe variables: " + builtins);
    }
   

    if (lastSafe == 0) {
      strategy.addUnsafeRule(rule, explain);
    }
    else if (lastSafe > 0) {
      Map<AtomVariable, NodeProvider> args = new HashMap<AtomVariable, NodeProvider>();
      for (int i = 0; i < lastSafe; i++) {
              for (AtomObject arg : processed.get(i).getAllArguments()) {
                  if (arg instanceof AtomVariable && !args.containsKey(arg)) {
                    args.put((AtomVariable) arg, createNodeProvider((AtomVariable) arg, processed));
                  }
                }
            }
     
      lastSafeBeta.addChild(new ProductionNode.ProduceBinding(strategy, explain, rule, args))
    }
   
    if (rule.getHead().isEmpty()) {
      node.addChild(new ProductionNode.Inconsistency(strategy, explain));
    }
    else {
      ProductionNodeCreator creator = new ProductionNodeCreator(processed, explain);
      for ( RuleAtom headAtom : rule.getHead() ) {
        node.addChild(creator.create(headAtom));
      }
    }
  }
 
  private static TokenNodeProvider createNodeProvider(AtomVariable arg, List<RuleAtom> processed) {
    return (TokenNodeProvider) createNodeProvider(arg, processed, false);
  }
 
  private static NodeProvider createNodeProvider(AtomVariable arg, List<RuleAtom> processed, boolean lastWME) {
    for (int index = 0, n = processed.size(); index < n; index++) {
      RuleAtom sharedAtom = processed.get(index)
            int indexArg = sharedAtom.getAllArguments().indexOf(arg);
            if (indexArg != -1) {
              if (lastWME && index == n -1) {
                return new WMENodeProvider(indexArg);
              }
              else {
                return new TokenNodeProvider(index, indexArg);
              }
            }
        }
   
    return null;
  }

  private class SafetyChecker implements RuleAtomVisitor {
   
    private boolean result = false;
   
    /**
     * May return true if atom is something that
     * will be added to the ABox during completion.
     */
    public boolean isSafe(RuleAtom atom) {
      atom.accept(this);
      return result;
    }

    public void visit(BuiltInAtom atom) {
      result = true;
    }

    public void visit(ClassAtom atom) {
      ATermAppl c = atom.getPredicate();
      result = abox.getKB().getTBox().isPrimitive( c );
    }

    public void visit(DataRangeAtom atom) {
      result = true;
    }

    public void visit(DatavaluedPropertyAtom atom) {
      result = true;
    }

    public void visit(DifferentIndividualsAtom atom) {
      result = false;
    }

    public void visit(IndividualPropertyAtom atom) {
      result = abox.getRole( atom.getPredicate() ).isSimple();
    }

    public void visit(SameIndividualAtom atom) {
      result = true;
    }
  }
 
  private class ProductionNodeCreator implements RuleAtomVisitor {     
    private final AtomObjectTranslator translator;
    
    private Set<ATermAppl> explain;
    private ProductionNode node;

    public ProductionNodeCreator(List<RuleAtom> processed, Set<ATermAppl> explain) {
      this.translator = new AtomObjectTranslator(abox, processed, false);
      this.explain = explain;
    }
   
    private ProductionNode create(RuleAtom atom) {
      node = null;
      atom.accept(this);
      if (node == null) {
        throw new UnsupportedOperationException("Not supported " + atom);
      }
      return node;
    }
   
    @Override
    public void visit(SameIndividualAtom atom) {
      NodeProvider s = translator.translateObject(atom.getArgument1());
      NodeProvider o = translator.translateObject(atom.getArgument2());
      node = new ProductionNode.SameAs(strategy, explain, s, o);
    }
   
    @Override
    public void visit(IndividualPropertyAtom atom) {
      NodeProvider s = translator.translateObject(atom.getArgument1());
      NodeProvider o = translator.translateObject(atom.getArgument2());
      Role r = abox.getRole(atom.getPredicate());
      node = new ProductionNode.Edge(strategy, explain, s, r, o);
    }
   
    @Override
    public void visit(DifferentIndividualsAtom atom) {
      NodeProvider s = translator.translateObject(atom.getArgument1());
      NodeProvider o = translator.translateObject(atom.getArgument2());
      node = new ProductionNode.DiffFrom(strategy, explain, s, o);
    }
   
    @Override
    public void visit(DatavaluedPropertyAtom atom) {
      NodeProvider s = translator.translateObject(atom.getArgument1());
      NodeProvider o = translator.translateObject(atom.getArgument2());
      Role r = abox.getRole(atom.getPredicate());
      node = new ProductionNode.Edge(strategy, explain, s, r, o);
    }
   
    @Override
    public void visit(DataRangeAtom atom) {
      // TODO Auto-generated method stub
     
    }
   
    @Override
    public void visit(ClassAtom atom) {
      NodeProvider s = translator.translateObject(atom.getArgument());
      ATermAppl type = atom.getPredicate();
      node = new ProductionNode.Type(strategy, explain, s, type);
    }
   
    @Override
    public void visit(BuiltInAtom atom) {
      // TODO Auto-generated method stub     
    }
  }

  private static class AtomObjectTranslator implements AtomObjectVisitor {
    private DependencySet dependency = DependencySet.INDEPENDENT;
    private NodeProvider result = null;
   
    private final ABox abox;
    private final List<RuleAtom> processed;
    private final boolean lastWME;
   

    public AtomObjectTranslator(ABox abox, List<RuleAtom> processed, boolean lastWME) {
      this.abox = abox;
          this.processed = processed;
          this.lastWME = lastWME;
        }

    public DependencySet getDependency() {
      return dependency;
    }

    public NodeProvider translateObject(AtomObject obj) {
      return translateObject(obj, false);
    }
   
    public NodeProvider translateObject(AtomObject obj, boolean allowNull) {
      dependency = DependencySet.INDEPENDENT;
      obj.accept(this);
      if (result == null && !allowNull) {
        throw new UnsupportedOperationException();
            }
      return result;
    }

    public void visit(AtomDConstant constant) {
      ATermAppl canonical;
      final ATermAppl literal = constant.getValue();
      try {
        canonical = abox.getKB().getDatatypeReasoner()
            .getCanonicalRepresentation(literal);
      } catch( InvalidLiteralException e ) {
        final String msg = format( "Invalid literal (%s) in SWRL data constant: %s",
            literal, e.getMessage() );
        if( PelletOptions.INVALID_LITERAL_AS_INCONSISTENCY ) {
          canonical = literal;
        }
        else {
          throw new InternalReasonerException( msg, e );
        }
      } catch( UnrecognizedDatatypeException e ) {
        final String msg = format(
            "Unrecognized datatype in literal appearing (%s) in SWRL data constant: %s",
            literal, e.getMessage() );
        throw new InternalReasonerException( msg, e );
      }
     
      result = new ConstantNodeProvider(abox.addLiteral(canonical));
    }

    public void visit(AtomDVariable variable) {
      result = createNodeProvider(variable, processed, lastWME);
    }

    public void visit(AtomIConstant constant) {
      abox.copyOnWrite();
      Individual individual = abox.getIndividual(constant.getValue());
//      if (individual.isMerged()) {
//        dependency = individual.getMergeDependency(true);
//        individual = individual.getSame();
//      }

      result = new ConstantNodeProvider(individual);
    }

    public void visit(AtomIVariable variable) {
      result = createNodeProvider(variable, processed, lastWME);
    }
  }
 
  private static class BuiltInCall {
    private ABox abox;
    private BuiltInAtom atom;
    private BuiltIn builtin;
    private BindingHelper helper;
   
        public BuiltInCall(ABox abox, BuiltInAtom atom) {
          this.abox = abox;
          this.atom = atom;
      builtin = BuiltInRegistry.instance.getBuiltIn(atom.getPredicate());
      helper = builtin.createHelper(atom);
        }

    public BetaBuiltinNode createBeta(List<RuleAtom> processed) {
          return new BetaBuiltinNode(abox, atom.getPredicate(), builtin, createProviders(processed, false));
        }

    public FilterCondition createCondition(List<RuleAtom> processed) {
          return new BuiltInCondition(abox, atom.getPredicate(), builtin, createProviders(processed, true));
        }

    private NodeProvider[] createProviders(List<RuleAtom> processed, boolean lastWME) {
      List<AtomDObject> args = atom.getAllArguments();
      NodeProvider[] providers = new NodeProvider[args.size()];
      AtomObjectTranslator translator = new AtomObjectTranslator(abox, processed, lastWME);
      for (int i = 0; i < providers.length; i++) {
              providers[i] = translator.translateObject(args.get(i), true);
            }
     
          return providers;
        }
   
        public Collection<? extends AtomVariable> getPrerequisitesVars(Collection<AtomVariable> bound) {
          return helper.getPrerequisiteVars(bound);
        }
   
        public Collection<? extends AtomVariable> getBindableVars(Collection<AtomVariable> bound) {
          return helper.getBindableVars(bound);
        }   
       
        @Override
        public String toString() {
            return atom.toString();
        }
  }
}
TOP

Related Classes of com.clarkparsia.pellet.rules.rete.Compiler$ProductionNodeCreator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.