Package org.mindswap.pellet

Source Code of org.mindswap.pellet.ABox

// Portions Copyright (c) 2006 - 2008, Clark & Parsia, LLC. <http://www.clarkparsia.com>
// Clark & Parsia, LLC parts of this source code are 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
//
// ---
// Portions Copyright (c) 2003 Ron Alford, Mike Grove, Bijan Parsia, Evren Sirin
// Alford, Grove, Parsia, Sirin parts of this source code are available under the terms of the MIT License.
//
// The MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

package org.mindswap.pellet;

import static java.lang.String.format;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
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 java.util.logging.Level;
import java.util.logging.Logger;

import org.mindswap.pellet.exceptions.InternalReasonerException;
import org.mindswap.pellet.tableau.branch.Branch;
import org.mindswap.pellet.tableau.cache.CachedNode;
import org.mindswap.pellet.tableau.cache.CachedNodeFactory;
import org.mindswap.pellet.tableau.cache.ConceptCache;
import org.mindswap.pellet.tableau.cache.ConceptCacheLRU;
import org.mindswap.pellet.tableau.completion.CompletionStrategy;
import org.mindswap.pellet.tableau.completion.SROIQIncStrategy;
import org.mindswap.pellet.tableau.completion.queue.BasicCompletionQueue;
import org.mindswap.pellet.tableau.completion.queue.CompletionQueue;
import org.mindswap.pellet.tableau.completion.queue.NodeSelector;
import org.mindswap.pellet.tableau.completion.queue.OptimizedBasicCompletionQueue;
import org.mindswap.pellet.tableau.completion.queue.QueueElement;
import org.mindswap.pellet.tbox.TBox;
import org.mindswap.pellet.utils.ATermUtils;
import org.mindswap.pellet.utils.Bool;
import org.mindswap.pellet.utils.CandidateSet;
import org.mindswap.pellet.utils.SetUtils;
import org.mindswap.pellet.utils.Timer;
import org.mindswap.pellet.utils.fsm.State;
import org.mindswap.pellet.utils.fsm.Transition;
import org.mindswap.pellet.utils.fsm.TransitionGraph;
import org.mindswap.pellet.utils.iterator.MultiListIterator;

import aterm.ATerm;
import aterm.ATermAppl;
import aterm.ATermList;

import com.clarkparsia.pellet.BranchEffectTracker;
import com.clarkparsia.pellet.IncrementalChangeTracker;
import com.clarkparsia.pellet.datatypes.DatatypeReasoner;
import com.clarkparsia.pellet.datatypes.DatatypeReasonerImpl;
import com.clarkparsia.pellet.datatypes.exceptions.DatatypeReasonerException;
import com.clarkparsia.pellet.datatypes.exceptions.InvalidLiteralException;
import com.clarkparsia.pellet.datatypes.exceptions.UnrecognizedDatatypeException;
import com.clarkparsia.pellet.expressivity.Expressivity;
import com.clarkparsia.pellet.impl.SimpleBranchEffectTracker;
import com.clarkparsia.pellet.impl.SimpleIncrementalChangeTracker;
import com.clarkparsia.pellet.utils.MultiMapUtils;

/**
* <p>Title: </p>
*
* <p>Description: </p>
*
* <p>Copyright: Copyright (c) 2008</p>
*
* <p>Company: Clark & Parsia, LLC. <http://www.clarkparsia.com></p>
*
* @author Evren Sirin
*/
public class ABox {
  public final static Logger        log          = Logger.getLogger( ABox.class.getName() );


  // following two variables are used to generate names
  // for newly generated individuals. so during rules are
  // applied anon1, anon2, etc. will be generated. This prefix
  // will also make sure that any node whose name starts with
  // this prefix is not a root node
  private int                anonCount      = 0;

  public  ABoxStats            stats        = new ABoxStats();
 
  /**
   * datatype reasoner used for checking the satisfiability of datatypes
   */
  protected final DatatypeReasoner    dtReasoner;

  /**
   * This is a list of nodes. Each node has a name expressed as an ATerm which
   * is used as the key in the Hashtable. The value is the actual node object
   */
  protected Map<ATermAppl, Node>      nodes;

  /**
   * This is a list of node names. This list stores the individuals in the
   * order they are created
   */
  protected List<ATermAppl>        nodeList;

  /**
   * Indicates if any of the completion rules has been applied to modify ABox
   */
  private boolean              changed        = false;

  private boolean              doExplanation;

  // cached satisfiability results
  // the table maps every atomic concept A (and also its negation not(A))
  // to the root node of its completed tree. If a concept is mapped to
  // null value it means it is not satisfiable
  protected ConceptCache          cache;

  // pseudo model for this Abox. This is the ABox that results from
  // completing to the original Abox
  // private ABox pseudoModel;

  // cache of the last completion. it may be different from the pseudo
  // model, e.g. type checking for individual adds one extra assertion
  // last completion is stored for caching the root nodes that was
  // the result of
  private ABox              lastCompletion;
  private boolean              keepLastCompletion;
  private Clash              lastClash;

  // complete ABox means no more tableau rules are applicable
  private boolean              isComplete      = false;

  // the last clash recorded
  private Clash              clash;
 
  private Set<Clash>            assertedClashes;

  // the current branch number
  private int                branch;
  private List<Branch>          branches;

  private List<NodeMerge>          toBeMerged;

  private Map<ATermAppl, int[]>      disjBranchStats;

  // if we are using copy on write, this is where to copy from
  private ABox              sourceABox;

  // return true if init() function is called. This indicates parsing
  // is completed and ABox is ready for completion
  private boolean              initialized      = false;

  // The KB to which this ABox belongs
  private KnowledgeBase          kb;

  public boolean              rulesNotApplied;

  public boolean              ranRete        = false;
  public boolean              useRete        = false;

  private BranchEffectTracker        branchEffects;
  private CompletionQueue          completionQueue;
  private IncrementalChangeTracker    incChangeTracker;

  // flag set when incrementally updating the abox with explicit assertions
  private boolean              syntacticUpdate    = false;

  public ABox(KnowledgeBase kb) {
    this.kb = kb;
    nodes = new HashMap<ATermAppl, Node>();
    nodeList = new ArrayList<ATermAppl>();
    clash = null;
    assertedClashes = new HashSet<Clash>();
    doExplanation = false;
    dtReasoner = new DatatypeReasonerImpl();
    keepLastCompletion = false;

    setBranch( DependencySet.NO_BRANCH );
    branches = new ArrayList<Branch>();
    setDisjBranchStats( new HashMap<ATermAppl, int[]>() );

    toBeMerged = new ArrayList<NodeMerge>();
    rulesNotApplied = true;
   
    if( PelletOptions.TRACK_BRANCH_EFFECTS ) {
          branchEffects = new SimpleBranchEffectTracker();
        }
        else {
          branchEffects = null;
        }
   
    if( PelletOptions.USE_COMPLETION_QUEUE ) {
      if( PelletOptions.USE_OPTIMIZED_BASIC_COMPLETION_QUEUE ) {
              completionQueue = new OptimizedBasicCompletionQueue( this );
            }
            else {
              completionQueue = new BasicCompletionQueue( this );
            }
    }
        else {
          completionQueue = null;
        }
   
    if( PelletOptions.USE_INCREMENTAL_CONSISTENCY ) {
          incChangeTracker = new SimpleIncrementalChangeTracker();
        }
        else {
          incChangeTracker = null;
        }
  }

  public ABox(KnowledgeBase kb, ABox abox, ATermAppl extraIndividual, boolean copyIndividuals) {
    this.kb = kb;
    Timer timer = kb.timers.startTimer( "cloneABox" );


    this.rulesNotApplied = true;
    initialized = abox.initialized;
    setChanged( abox.isChanged() );
    setAnonCount( abox.getAnonCount() );
    cache = abox.cache;
    clash = abox.clash;   
    dtReasoner = abox.dtReasoner;
    doExplanation = abox.doExplanation;
    setDisjBranchStats( abox.getDisjBranchStats() );

    int extra = (extraIndividual == null)
      ? 0
      : 1;
    int nodeCount = extra + (copyIndividuals
      ? abox.nodes.size()
      : 0);

    nodes = new HashMap<ATermAppl, Node>( nodeCount );
    nodeList = new ArrayList<ATermAppl>( nodeCount );

    if( PelletOptions.TRACK_BRANCH_EFFECTS ) {
      if( copyIndividuals ) {
              branchEffects = abox.branchEffects.copy();
            }
            else {
              branchEffects = new SimpleBranchEffectTracker();
            }
    }
        else {
          branchEffects = null;
        }
   
    // copy the queue - this must be done early so that the effects of
    // adding the extra individual do not get removed
    if( PelletOptions.USE_COMPLETION_QUEUE ) {
      if( copyIndividuals ) {
        completionQueue = abox.completionQueue.copy();
        completionQueue.setABox( this );
      }
      else if( PelletOptions.USE_OPTIMIZED_BASIC_COMPLETION_QUEUE ) {
              completionQueue = new OptimizedBasicCompletionQueue( this );
            }
            else {
              completionQueue = new BasicCompletionQueue( this );
            }
    }
        else {
          completionQueue = null;
        }

    if( extraIndividual != null ) {
      Individual n = new Individual( extraIndividual, this, null );
      n.setNominalLevel( Node.BLOCKABLE );
      n.setConceptRoot( true );
      n.addType( ATermUtils.TOP, DependencySet.INDEPENDENT );
      nodes.put( extraIndividual, n );
      nodeList.add( extraIndividual );

      if( PelletOptions.COPY_ON_WRITE ) {
              sourceABox = abox;
            }
    }

    if( copyIndividuals ) {
      toBeMerged = abox.getToBeMerged();
      if( sourceABox == null ) {
        for( int i = 0; i < nodeCount - extra; i++ ) {
          ATermAppl x = abox.nodeList.get( i );
          Node node = abox.getNode( x );
          Node copy = node.copyTo( this );

          nodes.put( x, copy );
          nodeList.add( x );
        }

        for( Node node : nodes.values() ) {
          node.updateNodeReferences();
        }
      }
    }
    else {
      toBeMerged = Collections.emptyList();
      sourceABox = null;
      initialized = false;
    }

    // Copy of the incChangeTracker looks up nodes in the new ABox, so this
    // copy must follow node copying
    if( PelletOptions.USE_INCREMENTAL_CONSISTENCY ) {
      if( copyIndividuals ) {
              incChangeTracker = abox.incChangeTracker.copy( this );
            }
            else {
              incChangeTracker = new SimpleIncrementalChangeTracker();
            }
    }
        else {
          incChangeTracker = null;
        }

    assertedClashes = new HashSet<Clash>();
    for( Clash clash : abox.assertedClashes ) {
      assertedClashes.add( clash.copyTo( this ) );
    }
   
    if( extraIndividual == null || copyIndividuals ) {
      setBranch( abox.branch );
      branches = new ArrayList<Branch>( abox.branches.size() );
      for( int i = 0, n = abox.branches.size(); i < n; i++ ) {
        Branch branch = abox.branches.get( i );
        Branch copy;

        if( sourceABox == null ) {
          copy = branch.copyTo( this );
          copy.setNodeCount( branch.getNodeCount() + extra );
        }
        else {
          copy = branch;
        }
        branches.add( copy );
      }
    }
    else {
      setBranch( DependencySet.NO_BRANCH );
      branches = new ArrayList<Branch>();
    }

    timer.stop();

  }

  /**
   * Create a copy of this ABox with all the nodes and edges.
   *
   * @return
   */
  public ABox copy() {
    return copy(kb);
  }

  /**
   * Create a copy of this ABox with all the nodes and edges and the given KB.
   */
  public ABox copy(KnowledgeBase kb) {
    return new ABox( kb, this, null, true );
  }

  /**
   * Create a copy of this ABox with one more additional individual. This is
   * <b>NOT</b> equivalent to create a copy and then add the individual. The
   * order of individuals in the ABox is important to figure out which
   * individuals exist in the original ontology and which ones are created by
   * the tableau algorithm. This function creates a new ABox such that the
   * individual is supposed to exist in the original ontology. This is very
   * important when satisfiability of a concept starts with a pesudo model
   * rather than the initial ABox.
   *
   * @param extraIndividual
   *            Extra individual to be added to the copy ABox
   * @return
   */
  public ABox copy(ATermAppl extraIndividual, boolean copyIndividuals) {
    return new ABox( kb, this, extraIndividual, copyIndividuals );
  }

  public void copyOnWrite() {
    if( sourceABox == null ) {
          return;
        }

    Timer t = kb.timers.startTimer( "copyOnWrite" );

    List<ATermAppl> currentNodeList = new ArrayList<ATermAppl>( nodeList );
    int currentSize = currentNodeList.size();
    int nodeCount = sourceABox.nodes.size();

    nodeList = new ArrayList<ATermAppl>( nodeCount + 1 );
    nodeList.add( currentNodeList.get( 0 ) );

    for( int i = 0; i < nodeCount; i++ ) {
      ATermAppl x = sourceABox.nodeList.get( i );
      Node node = sourceABox.getNode( x );
      Node copyNode = node.copyTo( this );
      nodes.put( x, copyNode );
      nodeList.add( x );
    }

    if( currentSize > 1 ) {
          nodeList.addAll( currentNodeList.subList( 1, currentSize ) );
        }

    for( Iterator<Node> i = nodes.values().iterator(); i.hasNext(); ) {
      Node node = i.next();

      if( sourceABox.nodes.containsKey( node.getName() ) ) {
              node.updateNodeReferences();
            }
    }
   
   

    for( int i = 0, n = branches.size(); i < n; i++ ) {
      Branch branch = branches.get( i );
      Branch copy = branch.copyTo( this );
      branches.set( i, copy );

      if( i >= sourceABox.getBranches().size() ) {
              copy.setNodeCount( copy.getNodeCount() + nodeCount );
            }
            else {
              copy.setNodeCount( copy.getNodeCount() + 1 );
            }
    }

    t.stop();

    sourceABox = null;
  }

  /**
   * Clear the pseudo model created for the ABox and concept satisfiability.
   *
   * @param clearSatCache
   *            If true clear concept satisfiability cache, if false only
   *            clear pseudo model.
   */
  public void clearCaches(boolean clearSatCache) {
    lastCompletion = null;

    if( clearSatCache ) {
      cache = new ConceptCacheLRU( kb );
    }
  }

  public Bool getCachedSat(ATermAppl c) {
    return cache.getSat( c );
  }

  public ConceptCache getCache() {
    return cache;
  }

  public CachedNode getCached(ATermAppl c) {
    if (ATermUtils.isNominal(c)) {
          return getIndividual(c.getArgument(0)).getSame();
        }
        else {
          return cache.get( c );
        }
  }

  private void cache(Individual rootNode, ATermAppl c, boolean isConsistent) {

    if( !isConsistent ) {
      if( log.isLoggable( Level.FINE ) ) {
        log.fine( "Unsatisfiable: " + ATermUtils.toString( c ) );
        log.fine( "Equivalent to TOP: " + ATermUtils.toString( ATermUtils.negate( c ) ) );
      }

      cache.putSat( c, false );
    }
    else {

      if( log.isLoggable( Level.FINE ) ) {
              log.fine( "Cache " + rootNode.debugString() );
            }
     
      cache.put( c, CachedNodeFactory.createNode( c, rootNode ) );
     
//      System.err.println( c + " " + rootNode.debugString() );
    }
  }

  public Bool isKnownSubClassOf(ATermAppl c1, ATermAppl c2) {
    Bool isSubClassOf = Bool.UNKNOWN;
    CachedNode cached = getCached( c1 );
    if( cached != null ) {
      isSubClassOf = isType( cached, c2 );
    }

    return isSubClassOf;
  }

  public boolean isSubClassOf(ATermAppl c1, ATermAppl c2) {
    if( !doExplanation ) {
      Bool isKnownSubClass = isKnownSubClassOf( c1, c2 );
      if( isKnownSubClass.isKnown() ) {
              return isKnownSubClass.isTrue();
            }
    }
   
    if( log.isLoggable( Level.FINE ) ) {
      long count = kb.timers.getTimer( "subClassSat" ) == null
        ? 0
        : kb.timers.getTimer( "subClassSat" ).getCount();
      log.fine( count + ") Checking subclass [" + ATermUtils.toString( c1 ) + " " + ATermUtils.toString( c2 ) + "]" );
    }

    ATermAppl notC2 = ATermUtils.negate( c2 );
    ATermAppl c = ATermUtils.makeAnd( c1, notC2 );
    Timer t = kb.timers.startTimer( "subClassSat" );
    boolean sub = !isSatisfiable( c, false );
    t.stop();

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( " Result: " + sub + " (" + t.getLast() + "ms)" );
        }

    return sub;
  }

  public boolean isSatisfiable(ATermAppl c) {
    boolean cacheModel = PelletOptions.USE_CACHING
        && (ATermUtils.isPrimitiveOrNegated( c ) || PelletOptions.USE_ADVANCED_CACHING);
    return isSatisfiable( c, cacheModel );
  }

  public boolean isSatisfiable(ATermAppl c, boolean cacheModel) {
    c = ATermUtils.normalize( c );

    // if normalization revealed an obvious unsatisfiability, return
    // immediately
    if( c.equals( ATermUtils.BOTTOM ) ) {
      lastClash = Clash.unexplained(null, DependencySet.INDEPENDENT,
                      "Obvious contradiction in class expression: " + ATermUtils.toString(c));
      return false;
    }

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Satisfiability for " + ATermUtils.toString( c )  );
        }

    if( cacheModel ) {
      CachedNode cached = getCached( c );
      if( cached != null ) {
        boolean satisfiable = !cached.isBottom();
        boolean needToCacheModel = cacheModel && !cached.isComplete();
        if( log.isLoggable( Level.FINE ) ) {
                  log.fine( "Cached sat for " + ATermUtils.toString( c ) + " is " + satisfiable );
                }
        // if explanation is enabled we should actually build the
        // tableau again to generate the clash. we don't cache the
        // explanation up front because generating explanation is costly
        // and we only want to do it when explicitly asked note that
        // when the concepts is satisfiable there is no explanation to
        // be generated so we return the result immediately
        if( !needToCacheModel && (satisfiable || !doExplanation) ) {
                  return satisfiable;
                }
      }
    }

    stats.satisfiabilityCount++;

    Timer t = kb.timers.startTimer( "satisfiability" );
    boolean isSat = isConsistent( SetUtils.<ATermAppl>emptySet(), c, cacheModel );
    t.stop();

    return isSat;
  }

  public CandidateSet<ATermAppl> getObviousInstances(ATermAppl c) {
    return getObviousInstances( c, kb.getIndividuals() );
  }

  public CandidateSet<ATermAppl> getObviousInstances(ATermAppl c, Collection<ATermAppl> individuals) {
    c = ATermUtils.normalize( c );
    Set<ATermAppl> subs = (kb.isClassified() && kb.getTaxonomy().contains( c ))
      ? kb.getTaxonomy().getFlattenedSubs( c, false )
      : Collections.<ATermAppl>emptySet();
    subs.remove( ATermUtils.BOTTOM );

    CandidateSet<ATermAppl> cs = new CandidateSet<ATermAppl>();
    for( ATermAppl x : individuals ) {
      Bool isType = isKnownType( x, c, subs );
      cs.add( x, isType );
    }

    return cs;
  }

  public void getObviousTypes(ATermAppl x, List<ATermAppl> types, List<ATermAppl> nonTypes) {
    assert isComplete() : "Initial consistency check has not been performed!";

    Individual pNode = getIndividual( x );
    if( !pNode.getMergeDependency( true ).isIndependent() ) {
          pNode = getIndividual( x );
        }
        else {
          pNode = pNode.getSame();
        }

    pNode.getObviousTypes( types, nonTypes );
  }

  public CandidateSet<ATermAppl> getObviousSubjects(ATermAppl p, ATermAppl o) {
    CandidateSet<ATermAppl> candidates = new CandidateSet<ATermAppl>( kb.getIndividuals() );
    getObviousSubjects( p, o, candidates );

    return candidates;
  }

  public void getSubjects(ATermAppl p, ATermAppl o, CandidateSet<ATermAppl> candidates) {
    Iterator<ATermAppl> i = candidates.iterator();
    while( i.hasNext() ) {
      ATermAppl s = i.next();

      Bool hasObviousValue = hasObviousPropertyValue( s, p, o );
      candidates.update( s, hasObviousValue );
    }
  }

  public void getObviousSubjects(ATermAppl p, ATermAppl o, CandidateSet<ATermAppl> candidates) {
    Iterator<ATermAppl> i = candidates.iterator();
    while( i.hasNext() ) {
      ATermAppl s = i.next();

      Bool hasObviousValue = hasObviousPropertyValue( s, p, o );
      if( hasObviousValue.isFalse() ) {
              i.remove();
            }
            else {
              candidates.update( s, hasObviousValue );
            }
    }
  }

  public void getObviousObjects(ATermAppl p, CandidateSet<ATermAppl> candidates) {
    p = getRole( p ).getInverse().getName();
    Iterator<ATermAppl> i = candidates.iterator();
    while( i.hasNext() ) {
      ATermAppl s = i.next();

      Bool hasObviousValue = hasObviousObjectPropertyValue( s, p, null );
      candidates.update( s, hasObviousValue );
    }
  }

  public Bool isKnownType(ATermAppl x, ATermAppl c) {
    return isKnownType( x, c, SetUtils.<ATermAppl>emptySet() );
  }

  public Bool isKnownType(ATermAppl x, ATermAppl c, Collection<ATermAppl> subs) {
    assert isComplete() : "Initial consistency check has not been performed!";

    Individual pNode = getIndividual( x );

    boolean isIndependent = true;
    if( pNode.isMerged() ) {
      isIndependent = pNode.getMergeDependency( true ).isIndependent();
      pNode = pNode.getSame();
    }

    Bool isType = isKnownType( pNode, c, subs );

    if( isIndependent ) {
          return isType;
        }
        else if( isType.isTrue() ) {
          return Bool.UNKNOWN;
        }
        else {
          return isType;
        }
  }

  public Bool isKnownType(Individual pNode, ATermAppl concept, Collection<ATermAppl> subs) {
    // Timer t = kb.timers.startTimer( "isKnownType" );
    Bool isType = isType( pNode, concept );
    if( isType.isUnknown() ) {
      Set<ATermAppl> concepts = ATermUtils.isAnd( concept )
        ? ATermUtils.listToSet( (ATermList) concept.getArgument( 0 ) )
        : SetUtils.singleton( concept );

      isType = Bool.TRUE;
      for( ATermAppl c : concepts ) {
        Bool type = pNode.hasObviousType( c );

        if( type.isUnknown() && pNode.hasObviousType( subs ) ) {
          type = Bool.TRUE;
        }
       
        if( type.isKnown() ) {
          isType = isType.and( type );
        }
        else {
          isType = Bool.UNKNOWN;
         
//          boolean justSC = true;

          Collection<ATermAppl> axioms = kb.getTBox().getAxioms( c );
          LOOP: for( ATermAppl axiom : axioms ) {
            ATermAppl term = (ATermAppl) axiom.getArgument( 1 );

//            final AFun afun = axiom.getAFun();
//
//            if( !afun.equals( ATermUtils.SUBFUN ) ) {
//              justSC = false;
//            }

            boolean equivalent = axiom.getAFun().equals( ATermUtils.EQCLASSFUN );
            if( equivalent ) {
              Iterator<ATermAppl> i = ATermUtils.isAnd( term )
                ? new MultiListIterator( (ATermList) term.getArgument( 0 ) )
                : Collections.singleton( term ).iterator();
              Bool knownType = Bool.TRUE;
              while( i.hasNext() && knownType.isTrue() ) {
                term = i.next();
                knownType = isKnownType( pNode, term, SetUtils.<ATermAppl>emptySet() );
              }
              if( knownType.isTrue() ) {
                isType = Bool.TRUE;
                break LOOP;
              }
            }
          }

          // TODO following short-cut might be implemented correctly
          // the main problem here is that concept might be in the
          // types of the individual with a dependency. In this case,
          // Node.hasObviousType returns unknown and changing it to
          // false here is wrong.
//           if( justSC && ATermUtils.isPrimitive( c ) ) {
//            return Bool.FALSE;
//          }

          if( isType.isUnknown() ) {
            return Bool.UNKNOWN;
          }
        }
      }
    }
    // t.stop();

    return isType;
  }

  private Bool isType(CachedNode pNode, ATermAppl c) {
    Bool isType = Bool.UNKNOWN;
   
    boolean isPrimitive = kb.getTBox().isPrimitive( c );
   
    if( isPrimitive && !pNode.isTop() && !pNode.isBottom() && pNode.isComplete() ) {
      DependencySet ds = pNode.getDepends().get( c );
      if( ds == null ) {
        return Bool.FALSE;
      }
      else if( ds.isIndependent() && pNode.isIndependent() ) {
        return Bool.TRUE;
      }
    }
   
    ATermAppl notC = ATermUtils.negate( c );
    CachedNode cached = getCached( notC );
    if( cached != null && cached.isComplete() ) {
      isType = cache.isMergable( kb, pNode, cached ).not();
    }

    if( PelletOptions.CHECK_NOMINAL_EDGES && isType.isUnknown() ) {
      CachedNode cNode = getCached( c );
      if( cNode != null ) {
        isType = cache.checkNominalEdges( kb, pNode, cNode )
      }
    }

    return isType;
  }

  public boolean isSameAs(ATermAppl ind1, ATermAppl ind2) {
    ATermAppl c = ATermUtils.makeValue( ind2 );

    return isType( ind1, c );
  }

  /**
   * Returns true if individual x belongs to type c. This is a logical
   * consequence of the KB if in all possible models x belongs to C. This is
   * checked by trying to construct a model where x belongs to not(c).
   *
   * @param x
   * @param c
   * @return
   */
  public boolean isType(ATermAppl x, ATermAppl c) {
    c = ATermUtils.normalize( c );

    if( !doExplanation() ) {
      Set<ATermAppl> subs;
      if( kb.isClassified() && kb.getTaxonomy().contains( c ) ) {
        subs = kb.getTaxonomy().getFlattenedSubs( c, false );
        subs.remove( ATermUtils.BOTTOM );
      }
            else {
              subs = SetUtils.emptySet();
            }
 
      Bool type = isKnownType( x, c, subs );
      if( type.isKnown() ) {
              return type.isTrue();
            }
    }
    // List list = (List) kb.instances.get( c );
    // if( list != null )
    // return list.contains( x );

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Checking type " + ATermUtils.toString( c ) + " for individual " + ATermUtils.toString( x ) );
        }

    ATermAppl notC = ATermUtils.negate( c );

    Timer t = kb.timers.startTimer( "isType" );
    boolean isType = !isConsistent( SetUtils.singleton( x ), notC, false );
    t.stop();

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Type " + isType + " " + ATermUtils.toString( c ) + " for individual " + ATermUtils.toString( x ) );
        }

    return isType;
  }

  /**
   * Returns true if any of the individuals in the given list belongs to type
   * c.
   *
   * @param c
   * @param inds
   * @return
   */
  public boolean isType(List<ATermAppl> inds, ATermAppl c) {
    c = ATermUtils.normalize( c );

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Checking type " + ATermUtils.toString( c ) + " for individuals " + inds.size() );
        }

    ATermAppl notC = ATermUtils.negate( c );

    boolean isType = !isConsistent( inds, notC, false );

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Type " + isType + " " + ATermUtils.toString( c ) + " for individuals " + inds.size() );
        }

    return isType;
  }

  public Bool hasObviousPropertyValue(ATermAppl s, ATermAppl p, ATermAppl o) {
    Role prop = getRole( p );

    if( prop.isDatatypeRole() ) {
      try {
        Object value = (o == null)
          ? null
          : dtReasoner.getValue( o );
        return hasObviousDataPropertyValue( s, p, value );
      } catch( UnrecognizedDatatypeException e ) {
        log
            .warning( format(
                "Returning false for property value check (%s,%s,%s) due to datatype problem with input literal: %s",
                s, p, o, e.getMessage() ) );
        return Bool.FALSE;
      } catch( InvalidLiteralException e ) {
        log
            .warning( format(
                "Returning false for property value check (%s,%s,%s) due to problem with input literal: %s",
                s, p, o, e.getMessage() ) );
        return Bool.FALSE;
      }
    }
        else {
          return hasObviousObjectPropertyValue( s, p, o );
        }
  }

  public Bool hasObviousDataPropertyValue(ATermAppl s, ATermAppl p, Object value) {
    assert isComplete() : "Initial consistency check has not been performed!";
   
    Individual subj = getIndividual( s );
    Role prop = getRole( p );

    if( prop.isTop() ) {
          return Bool.TRUE;
        }
        else if( prop.isBottom() ) {
          return Bool.FALSE;
        }
   
    // if onlyPositive is set then the answer returned is sound but not
    // complete so we cannot return negative answers
    boolean onlyPositive = false;

    if( !subj.getMergeDependency( true ).isIndependent() ) {
      onlyPositive = true;
      subj = getIndividual( s );
    }
        else {
          subj = subj.getSame();
        }

    Bool hasValue = subj.hasDataPropertyValue( prop, value );
    if( onlyPositive && hasValue.isFalse() ) {
          return Bool.UNKNOWN;
        }

    return hasValue;
  }

  public Bool hasObviousObjectPropertyValue(ATermAppl s, ATermAppl p, ATermAppl o) {
    Role prop = getRole( p );
   
    if( prop.isTop() ) {
          return Bool.TRUE;
        }
        else if( prop.isBottom() ) {
          return Bool.FALSE;
        }

    Set<ATermAppl> knowns = new HashSet<ATermAppl>();
    Set<ATermAppl> unknowns = new HashSet<ATermAppl>();

    getObjectPropertyValues( s, prop, knowns, unknowns, true );

    if( o == null ) {
      if( !knowns.isEmpty() ) {
              return Bool.TRUE;
            }
            else if( !unknowns.isEmpty() ) {
              return Bool.UNKNOWN;
            }
            else {
              return Bool.FALSE;
            }
    }
    else {
      if( knowns.contains( o ) ) {
              return Bool.TRUE;
            }
            else if( unknowns.contains( o ) ) {
              return Bool.UNKNOWN;
            }
            else {
              return Bool.FALSE;
            }
    }
  }

  public boolean hasPropertyValue(ATermAppl s, ATermAppl p, ATermAppl o) {   
    Bool hasObviousValue = hasObviousPropertyValue( s, p, o );
    if( hasObviousValue.isKnown() ) {
      if( hasObviousValue.isFalse() || !doExplanation() ) {
              return hasObviousValue.isTrue();
            }
    }

    ATermAppl c = null;
    if( o == null ) {
      if( kb.isDatatypeProperty( p ) ) {
              c = ATermUtils.makeMin( p, 1, ATermUtils.TOP_LIT );
            }
            else {
              c = ATermUtils.makeMin( p, 1, ATermUtils.TOP );
            }
    }
    else {
      c = ATermUtils.makeHasValue( p, o );
    }

    boolean isType = isType( s, c );

    return isType;
  }

  public List<ATermAppl> getDataPropertyValues(ATermAppl s, Role role, ATermAppl datatype) {
    return getDataPropertyValues( s, role, datatype, false );
  }

  public List<ATermAppl> getDataPropertyValues(ATermAppl s, Role role, ATermAppl datatype,
      boolean onlyObvious) {
    assert isComplete() : "Initial consistency check has not been performed!";
   
    Individual subj = getIndividual( s );

    List<ATermAppl> values = new ArrayList<ATermAppl>();

    boolean isIndependent = true;
    if( subj.isMerged() ) {
      isIndependent = subj.getMergeDependency( true ).isIndependent();
      subj = subj.getSame();
    }

    EdgeList edges = subj.getRSuccessorEdges( role );
    for( int i = 0; i < edges.size(); i++ ) {
      Edge edge = edges.edgeAt( i );
      DependencySet ds = edge.getDepends();
      final Literal literal = (Literal) edge.getTo();
      final ATermAppl literalValue = literal.getTerm();
      if( literalValue != null ) {
        if( datatype != null ) {
          if( !literal.hasType( datatype ) ) {
            try {
              if( !dtReasoner.isSatisfiable( Collections.singleton( datatype ),
                  literal.getValue() ) ) {
                              continue;
                            }
            } catch( DatatypeReasonerException e ) {
              final String msg = format(
                  "Unexpected datatype reasoner exception while fetching property values (%s,%s,%s): %s",
                  s, role, datatype, e.getMessage() );
              log.severe( msg );
              throw new InternalReasonerException( msg );
            }
          }
        }

        if( isIndependent && ds.isIndependent() ) {
                  values.add( literalValue );
                }
                else if( !onlyObvious ) {
          ATermAppl hasValue = ATermUtils.makeHasValue( role.getName(), literalValue );
          if( isType( s, hasValue ) ) {
                      values.add( literalValue );
                    }
        }
      }
    }

    return values;
  }

  public List<ATermAppl> getObviousDataPropertyValues(ATermAppl s, Role prop, ATermAppl datatype) {
    return getDataPropertyValues( s, prop, datatype, true );
  }

  public void getObjectPropertyValues(ATermAppl s, Role role, Set<ATermAppl> knowns,
      Set<ATermAppl> unknowns, boolean getSames) {
    assert isComplete() : "Initial consistency check has not been performed!";

    Individual subj = getIndividual( s );

    boolean isIndependent = true;
    if( subj.isMerged() ) {
      isIndependent = subj.getMergeDependency( true ).isIndependent();
      subj = subj.getSame();
    }

    if( role.isSimple() ) {
          getSimpleObjectPropertyValues( subj, role, knowns, unknowns, getSames );
        }
        else if( !role.hasComplexSubRole() ) {
          getTransitivePropertyValues( subj, role, knowns, unknowns, getSames,
          new HashMap<Individual,Set<Role>>(), true );
        }
        else {
      TransitionGraph<Role> tg = role.getFSM();
      getComplexObjectPropertyValues( subj, tg.getInitialState(), tg, knowns, unknowns,
          getSames, new HashMap<Individual,Set<State<Role>>>(), true );
    }

    if( !isIndependent ) {
      unknowns.addAll( knowns );
      knowns.clear();
    }
  }

  void getSimpleObjectPropertyValues(Individual subj, Role role, Set<ATermAppl> knowns,
      Set<ATermAppl> unknowns, boolean getSames) {
    EdgeList edges = subj.getRNeighborEdges( role );
    for( int i = 0; i < edges.size(); i++ ) {
      Edge edge = edges.edgeAt( i );
      DependencySet ds = edge.getDepends();
      Individual value = (Individual) edge.getNeighbor( subj );

      if( value.isRootNominal() ) {
        if( ds.isIndependent() ) {
          if( getSames ) {
                      getSames( value, knowns, unknowns );
                    }
                    else {
                      knowns.add( value.getName() );
                    }
        }
        else {
          if( getSames ) {
                      getSames( value, unknowns, unknowns );
                    }
                    else {
                      unknowns.add( value.getName() );
                    }
        }
      }
    }
  }

  void getTransitivePropertyValues(Individual subj, Role prop, Set<ATermAppl> knowns,
      Set<ATermAppl> unknowns, boolean getSames, Map<Individual,Set<Role>> visited, boolean isIndependent) {   
    if( !MultiMapUtils.addAll( visited, subj, prop.getSubRoles() ) ) {
          return;
        }

    EdgeList edges = subj.getRNeighborEdges( prop );
    for( int i = 0; i < edges.size(); i++ ) {
      Edge edge = edges.edgeAt( i );
      DependencySet ds = edge.getDepends();
      Individual value = (Individual) edge.getNeighbor( subj );
      Role edgeRole = edge.getFrom().equals( subj )
        ? edge.getRole()
        : edge.getRole().getInverse();
      if( value.isRootNominal() ) {
        if( isIndependent && ds.isIndependent() ) {
          if( getSames ) {
                      getSames( value, knowns, unknowns );
                    }
                    else {
                      knowns.add( value.getName() );
                    }
        }
        else {
          if( getSames ) {
                      getSames( value, unknowns, unknowns );
                    }
                    else {
                      unknowns.add( value.getName() );
                    }
        }
      }

      if( !prop.isSimple() ) {
        // all the following roles might cause this property to
        // propagate
        Set<Role> transRoles = SetUtils.intersection( edgeRole.getSuperRoles(), prop
            .getTransitiveSubRoles() );
        for( Iterator<Role> j = transRoles.iterator(); j.hasNext(); ) {
          Role transRole = j.next();
          getTransitivePropertyValues( value, transRole, knowns, unknowns, getSames,
              visited, isIndependent && ds.isIndependent() );
        }
      }
    }
  }

  void getComplexObjectPropertyValues(Individual subj, State<Role> st, TransitionGraph<Role> tg,
      Set<ATermAppl> knowns, Set<ATermAppl> unknowns, boolean getSames,
      HashMap<Individual,Set<State<Role>>> visited, boolean isIndependent) {
    if( !MultiMapUtils.add( visited, subj, st ) ) {
          return;
        }

    if( tg.isFinal( st ) && subj.isRootNominal() ) {
      log.fine( "add " + subj );
      if( isIndependent ) {
        if( getSames ) {
                  getSames( subj, knowns, unknowns );
                }
                else {
                  knowns.add( subj.getName() );
                }
      }
      else {
        if( getSames ) {
                  getSames( subj, unknowns, unknowns );
                }
                else {
                  unknowns.add( subj.getName() );
                }
      }
    }

    log.fine( subj.toString() );

    for( Transition<Role> t : st.getTransitions() ) {
      Role r = t.getName();
      EdgeList edges = subj.getRNeighborEdges( r );
      for( int i = 0; i < edges.size(); i++ ) {
        Edge edge = edges.edgeAt( i );
        DependencySet ds = edge.getDepends();
        Individual value = (Individual) edge.getNeighbor( subj );

        getComplexObjectPropertyValues( value, t.getTo(), tg, knowns, unknowns, getSames,
            visited, isIndependent && ds.isIndependent() );
      }
    }
  }

  public void getSames(Individual ind, Set<ATermAppl> knowns, Set<ATermAppl> unknowns) {
    knowns.add( ind.getName() );

    boolean thisMerged = ind.isMerged() && !ind.getMergeDependency( true ).isIndependent();

    for( Node other : ind.getMerged() ) {
      if( !other.isRootNominal() ) {
              continue;
            }

      boolean otherMerged = other.isMerged()
          && !other.getMergeDependency( true ).isIndependent();
      if( thisMerged || otherMerged ) {
        unknowns.add( other.getName() );
        getSames( (Individual) other, unknowns, unknowns );
      }
      else {
        knowns.add( other.getName() );
        getSames( (Individual) other, knowns, unknowns );
      }
    }
  }

  /**
   * Return true if this ABox is consistent. Consistent ABox means after
   * applying all the tableau completion rules at least one branch with no
   * clashes was found
   *
   * @return
   */
  public boolean isConsistent() {
    boolean isConsistent = false;
   
    checkAssertedClashes();
     
    isConsistent = isConsistent( SetUtils.<ATermAppl>emptySet(), null, false );

    if( isConsistent ) {
      // put the BOTTOM concept into the cache which will
      // also put TOP in there
      cache.putSat( ATermUtils.BOTTOM, false );

      assert isComplete() : "ABox not marked complete!";
    }   

    return isConsistent;
  }
 
  /**
   * Checks if all the previous asserted clashes are resolved. If there is an
   * unresolved clash, the clash will be set to the first such clash found
   * (selection is arbitrary). The clash remains unchanged if all clashes are
   * resolved. That is, the clash might be non-null after this function even
   * if all asserted clashes are This function is used when incremental
   * deletion is disabled.
   */
  private boolean checkAssertedClashes() {
    Iterator<Clash> i = assertedClashes.iterator();
    while( i.hasNext() ) {
      Clash clash = i.next();       
      Node node = clash.getNode();
      ATermAppl term = clash.args != null
        ? (ATermAppl) clash.args[0]
        : null;
     
      // check if clash is resolved through deletions
      boolean resolved = true;
      switch( clash.getClashType() ) {
      case ATOMIC:
        ATermAppl negation = ATermUtils.negate( term );
        resolved = !node.hasType( term ) || !node.hasType( negation );
        break;
      case NOMINAL:
        resolved = !node.isSame( getNode( term ) );
        break
      case INVALID_LITERAL:
        resolved = false;
        break;
      default:
        log.warning( "Unexpected asserted clash type: " + clash );
        break;
      }
     
      if( resolved ) {
        // discard resolved clash
        i.remove();
      }
      else {
        // this clash is not resolved, no point in continuing
        setClash( clash );
        return false;
      }
    }
   
    return true;
  }

  /**
   * Check the consistency of this ABox possibly after adding some type
   * assertions. If <code>c</code> is null then nothing is added to ABox
   * (pure consistency test) and the individuals should be an empty
   * collection. If <code>c</code> is not null but <code>individuals</code>
   * is empty, this is a satisfiability check for concept <code>c</code> so
   * a new individual will be added with type <code>c</code>. If
   * individuals is not empty, this means we will add type <code>c</code> to
   * each of the individuals in the collection and check the consistency.
   * <p>
   * The consistency checks will be done either on a copy of the ABox or its
   * pseudo model depending on the situation. In either case this ABox will
   * not be modified at all. After the consistency check lastCompletion points
   * to the modified ABox.
   *
   * @param individuals
   * @param c
   * @return
   */
  private boolean isConsistent(Collection<ATermAppl> individuals, ATermAppl c, boolean cacheModel) {
    Timer t = kb.timers.startTimer( "isConsistent" );

    if( log.isLoggable( Level.FINE ) ) {
      if( c == null ) {
              log.fine( "ABox consistency for " + individuals.size() + " individuals" );
            }
            else {
        StringBuilder sb = new StringBuilder();
        sb.append("[");       
        Iterator<ATermAppl> it = individuals.iterator();
        for( int i = 0; i < 100 && it.hasNext(); i++ ) {
          if( i > 0 ) {
                      sb.append( ", " );
                    }
          sb.append( ATermUtils.toString( it.next() ) );
        }
        if( it.hasNext() ) {
                  sb.append( ", ..." );
                }
        sb.append("]");
        log.fine( "Consistency " + ATermUtils.toString( c ) + " for " + individuals.size() + " individuals "
            + sb );
      }
    }

    Expressivity expr = kb.getExpressivityChecker().getExpressivityWith( c );

    // if c is null we are checking the consistency of this ABox as
    // it is and we will not add anything extra
    boolean initialConsistencyCheck = (c == null);

    boolean emptyConsistencyCheck = initialConsistencyCheck && isEmpty();

    // if individuals is empty and we are not building the pseudo
    // model then this is concept satisfiability
    boolean conceptSatisfiability = individuals.isEmpty()
        && (!initialConsistencyCheck || emptyConsistencyCheck);

    // Check if there are any nominals in the KB or nominal
    // reasoning is disabled
    boolean hasNominal = expr.hasNominal() && !PelletOptions.USE_PSEUDO_NOMINALS;

    // Use empty model only if this is concept satisfiability for a KB
    // where there are no nominals
    boolean canUseEmptyABox = conceptSatisfiability && !hasNominal;

    ATermAppl x = null;
    if( conceptSatisfiability ) {
      x = ATermUtils.CONCEPT_SAT_IND;
      individuals = SetUtils.singleton( x );
    }

    if( emptyConsistencyCheck ) {
          c = ATermUtils.TOP;
        }

    ABox abox = canUseEmptyABox
      ? this.copy( x, false )
      : initialConsistencyCheck
        ? this
        : this.copy( x, true );

    for( ATermAppl ind : individuals ) {
      abox.setSyntacticUpdate( true );
      abox.addType( ind, c );
      abox.setSyntacticUpdate( false );
    }

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Consistency check starts" );
        }

    CompletionStrategy strategy = kb.chooseStrategy( abox, expr );

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Strategy: " + strategy.getClass().getName() );
        }

    Timer completionTimer = kb.timers.getTimer( "complete" );
    completionTimer.start();
    try {
      strategy.complete( expr );
    }
    finally {
      completionTimer.stop();
    }

    boolean consistent = !abox.isClosed();

    if( x != null && c != null && cacheModel ) {
      cache( abox.getIndividual( x ), c, consistent );
    }
   
    if( log.isLoggable( Level.FINE ) ) {
      log.fine( "Consistent: " + consistent + " Time: " + t.getElapsed()
          +" Branches " + abox.branches.size()
          +" Tree depth: " + abox.stats.treeDepth + " Tree size: " + abox.getNodes().size()
          +" Restores " + abox.stats.globalRestores + " global " + abox.stats.localRestores + " local"
          +" Backtracks " + abox.stats.backtracks + " avg backjump " + (abox.stats.backjumps/(double)abox.stats.backtracks));
    }

    if( consistent ) {
      if( initialConsistencyCheck && isEmpty() ) {
              setComplete( true );
            }
    }
    else {
      lastClash = abox.getClash();
      if( log.isLoggable( Level.FINE ) ) {
              log.fine( "Clash: " + abox.getClash().detailedString() );
            }
      if( doExplanation && PelletOptions.USE_TRACING ) {
        if( individuals.size() == 1 ) {       
          ATermAppl ind = individuals.iterator().next();

          ATermAppl tempAxiom = ATermUtils.makeTypeAtom( ind, c );
          Set<ATermAppl> explanationSet = getExplanationSet();
          boolean removed = explanationSet.remove( tempAxiom );
          if( !removed ) {
            if( log.isLoggable( Level.FINE ) ) {
                          log.fine( "Explanation set is missing an axiom.\n\tAxiom: " + tempAxiom
                  + "\n\tExplantionSet: " + explanationSet );
                        }
          }
        }
        if( log.isLoggable( Level.FINE ) ) {
          StringBuilder sb = new StringBuilder();
          for( ATermAppl axiom : getExplanationSet() ) {
            sb.append( "\n\t" );
            sb.append( ATermUtils.toString( axiom ) );
          }
          log.fine( "Explanation: " + sb );
        }
      }
    }

    stats.consistencyCount++;

    if( keepLastCompletion ) {
          lastCompletion = abox;
        }
        else {
          lastCompletion = null;
        }

    t.stop();

    return consistent;
  }

  /**
   * Check the consistency of this ABox using the incremental consistency
   * checking approach
   */
  boolean isIncConsistent() {
    assert isComplete() : "Initial consistency check has not been performed!";

    Timer incT = kb.timers.startTimer( "isIncConsistent" );
    Timer t = kb.timers.startTimer( "isConsistent" );

    // throw away old information to let gc do its work
    lastCompletion = null;
   
    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Consistency check starts" );
        }
   
    // currently there is only one incremental consistency strategy
    CompletionStrategy incStrategy = new SROIQIncStrategy( this );

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Strategy: " + incStrategy.getClass().getName() );
        }

    // set abox to not being complete
    setComplete( false );
    Timer completionTimer = kb.timers.getTimer( "complete" );
    completionTimer.start();
    try {
      incStrategy.complete(kb.getExpressivityChecker().getExpressivity());
    }
    finally {
      completionTimer.stop();
    }
   
    boolean consistent = !isClosed();

    if( log.isLoggable( Level.FINE ) ) {
          log.fine( "Consistent: " + consistent + " Tree depth: " + stats.treeDepth
          + " Tree size: " + getNodes().size() );
        }

    if( !consistent ) {
      lastClash = getClash();
      if( log.isLoggable( Level.FINE ) ) {
              log.fine( getClash().detailedString() );
            }
    }

    stats.consistencyCount++;

    lastCompletion = this;

    t.stop();
    incT.stop();
   
    // do not clear the clash information

    // ((Log4JLogger)ABox.log).getLogger().setLevel(Level.OFF);
    // ((Log4JLogger)DependencyIndex.log).getLogger().setLevel(Level.OFF);

    return consistent;
  }

  public EdgeList getInEdges(ATerm x) {
    return getNode( x ).getInEdges();
  }

  public EdgeList getOutEdges(ATerm x) {
    Node node = getNode( x );
    if( node instanceof Literal ) {
          return new EdgeList();
        }
    return ((Individual) node).getOutEdges();
  }

  public Individual getIndividual(ATerm x) {
    Object o = nodes.get( x );
    if(o instanceof Individual){
      return (Individual) o;
    }
    return null;
  }

  public Literal getLiteral(ATerm x) {
    Object o = nodes.get( x );
    if(o instanceof Literal){
      return (Literal) o;
    }
    return null;
  }

  public Node getNode(ATerm x) {
    return nodes.get( x );
  }

  public void addType(ATermAppl x, ATermAppl c) {
    DependencySet ds = PelletOptions.USE_TRACING
      ? new DependencySet( ATermUtils.makeTypeAtom( x, c ) )
      : DependencySet.INDEPENDENT;

    addType( x, c, ds );
  }

  public void addType(ATermAppl x, ATermAppl c, DependencySet ds) {
    c = ATermUtils.normalize( c );

    // when a type is being added to
    // an ABox that has already been completed, the branch
    // of the dependency set will automatically be set to
    // the current branch. We need to set it to the initial
    // branch number to make sure that this type assertion
    // will not be removed during backtracking
    int remember = branch;
    setBranch( DependencySet.NO_BRANCH );

    Individual node = getIndividual( x );
    node.addType( c, ds, false );
   
        while( node.isMerged() ) {
      ds = ds.union( node.getMergeDependency( false ), doExplanation );
      node = (Individual) node.getMergedTo();
      node.addType( c, ds, !node.isMerged() );
   

        setBranch( remember );
  }
 
  public Edge addEdge(ATermAppl p, ATermAppl s, ATermAppl o, DependencySet ds) { 
    Role role = getRole( p );
    Individual subj = getIndividual( s );
    Node obj = getNode( o );
   
    if( subj.isMerged() && obj.isMerged() ) {
          return null;
        }   

    if( obj.isMerged() ) {
      obj.addInEdge( new DefaultEdge(role, subj, obj, ds) );
      ds = ds.union( obj.getMergeDependency( true ), true );
      ds = ds.copy( ds.max() + 1 );
      obj = obj.getSame();
    }
       
    Edge edge = new DefaultEdge(role, subj, obj, ds);
    Edge existingEdge = subj.getOutEdges().getExactEdge( subj, role, obj );
    if( existingEdge == null ) {
      subj.addOutEdge( edge );
    }
    else if( !existingEdge.getDepends().isIndependent() ) {
      subj.removeEdge( existingEdge );
      subj.addOutEdge( edge );
    }
   
    if( subj.isMerged() ) {
      ds = ds.union( subj.getMergeDependency( true ), true );
      ds = ds.copy( ds.max() + 1 );
      subj = subj.getSame();
      edge = new DefaultEdge(role, subj, obj, ds);
     
      if( subj.getOutEdges().hasEdge( edge ) ) {
              return null;
            }
     
      subj.addOutEdge( edge );
      obj.addInEdge( edge );     
    }
    else if( existingEdge == null ) {
      obj.addInEdge( edge );
    }
    else if( !existingEdge.getDepends().isIndependent() ) {
      obj.removeInEdge( existingEdge );
      obj.addInEdge( edge );
    }
   
    return edge;
  }

  /**
   * Remove the given node from the node map which maps names to nodes. Does not remove the node from the node list
   * or other nodes' edge lists.
   *
   * @param x
   * @return
   */
  public boolean removeNode(ATermAppl x) {
    return (nodes.remove( x ) != null);
  }
 
  public void removeType(ATermAppl x, ATermAppl c) {
    c = ATermUtils.normalize( c );

    Node node = getNode( x );
    node.removeType( c );
  }

  /**
   * Add a new literal to the ABox. This function is used only when the
   * literal value does not have a known value, e.g. applyMinRule would create
   * such a literal.
   *
   * @return
   */
  public Literal addLiteral(DependencySet ds) {
    return createLiteral( ATermUtils.makeLiteral( createUniqueName( false ) ), ds );
  }

  /**
   * Add a new literal to the ABox. Literal will be assigned a fresh unique
   * name.
   *
   * @param dataValue
   *            A literal ATerm which should be constructed with one of
   *            ATermUtils.makeXXXLiteral functions
   * @return Literal object that has been created
   */
  public Literal addLiteral(ATermAppl dataValue) {
    int remember = getBranch();
    setBranch( DependencySet.NO_BRANCH );
   
    Literal lit = addLiteral( dataValue, DependencySet.INDEPENDENT );
   
    setBranch( remember );
   
    return lit;
  }

  public Literal addLiteral(ATermAppl dataValue, DependencySet ds) {
    if( dataValue == null || !ATermUtils.isLiteral( dataValue ) ) {
          throw new InternalReasonerException( "Invalid value to create a literal. Value: "
          + dataValue );
        }

    return createLiteral( dataValue, ds );
  }

  /**
   * Helper function to add a literal.
   *
   * @param value
   *            The java object that represents the value of this literal
   * @return
   */
  private Literal createLiteral(ATermAppl dataValue, DependencySet ds) {
    ATermAppl name;
    /*
     * No datatype means the literal is an anonymous variable created for a
     * min cardinality or some values from restriction.
     */
    if( ATermUtils.NO_DATATYPE.equals( dataValue.getArgument( ATermUtils.LIT_URI_INDEX ) ) ) {
          name = dataValue;
        }
        else {
      try {
        name = getDatatypeReasoner().getCanonicalRepresentation( dataValue );
      } catch( InvalidLiteralException e ) {
        final String msg = format( "Attempt to create an invalid literal (%s): %s",
            dataValue, e.getMessage() );
        if (PelletOptions.INVALID_LITERAL_AS_INCONSISTENCY) {
          log.fine( msg );
          name = dataValue;
        } else {
          log.severe( msg );
          throw new InternalReasonerException( msg, e );
        }
      } catch( UnrecognizedDatatypeException e ) {
        final String msg = format(
            "Attempt to create a literal with an unrecognized datatype (%s): %s",
            dataValue, e.getMessage() );
        log.severe( msg );
        throw new InternalReasonerException( msg, e );
      }
    }

    Node node = getNode( name );
    if( node != null ) {
      if( node instanceof Literal ) {

        if( ((Literal) node).getValue() == null && PelletOptions.USE_COMPLETION_QUEUE ) {
          // added for completion queue
          QueueElement newElement = new QueueElement( node );
          this.completionQueue.add( newElement, NodeSelector.LITERAL );
        }

        if( getBranch() >= 0 && PelletOptions.TRACK_BRANCH_EFFECTS ) {
                  branchEffects.add( getBranch(), node.getName() );
                }

        return (Literal) node;
      }
            else {
              throw new InternalReasonerException(
            "Same term refers to both a literal and an individual: " + name );
            }
    }

    int remember = branch;
    setBranch( DependencySet.NO_BRANCH );
   
    /*
     * TODO Investigate the effects of storing asserted value
     * The input version of the literal is not discarded, only the canonical
     * versions are stored in the literal. This may cause problems in cases
     * where the same value space object is presented in the data in multiple
     * forms.
     */
    Literal lit = new Literal( name, dataValue, this, ds );
    lit.addType( ATermUtils.TOP_LIT, ds );
   
    setBranch( remember );
   
    nodes.put( name, lit );
    nodeList.add( name );

    if( lit.getValue() == null && PelletOptions.USE_COMPLETION_QUEUE ) {
      // added for completion queue
      QueueElement newElement = new QueueElement( lit );
      this.completionQueue.add( newElement, NodeSelector.LITERAL );
    }

    if( getBranch() >= 0 && PelletOptions.TRACK_BRANCH_EFFECTS ) {
          branchEffects.add( getBranch(), lit.getName() );
        }

    return lit;
  }

  public Individual addIndividual(ATermAppl x, DependencySet ds) {
    Individual ind = addIndividual( x, null, ds );

    // update affected inds for this branch
    if( getBranch() >= 0 && PelletOptions.TRACK_BRANCH_EFFECTS ) {
          branchEffects.add( getBranch(), ind.getName() );
        }
   
    return ind;
  }

  public Individual addFreshIndividual(Individual parent, DependencySet ds) {
    boolean isNominal = parent == null;
    ATermAppl name = createUniqueName( isNominal );
    Individual ind = addIndividual( name, parent, ds );

    if( isNominal ) {
          ind.setNominalLevel( 1 );
        }

    return ind;
  }

  private Individual addIndividual(ATermAppl x, Individual parent, DependencySet ds) {
    if( nodes.containsKey( x ) ) {
          throw new InternalReasonerException( "adding a node twice " + x );
        }

    setChanged( true );

    Individual n = new Individual( x, this, parent );

    nodes.put( x, n );
    nodeList.add( x );
   
    if( n.getDepth() > stats.treeDepth ) {
      stats.treeDepth = n.getDepth();
      if( log.isLoggable( Level.FINER )) {
              log.finer( "Depth: " + stats.treeDepth + " Size: " + size() );
            }
    }
   
    //this must be performed after the nodeList is updated as this call will update the completion queues
    n.addType( ATermUtils.TOP, ds );

    if( getBranch() > 0 && PelletOptions.TRACK_BRANCH_EFFECTS ) {
          branchEffects.add( getBranch(), n.getName() );
        }

    return n;
  }

  public void addSame(ATermAppl x, ATermAppl y) {
    Individual ind1 = getIndividual( x );
    Individual ind2 = getIndividual( y );

    // ind1.setSame(ind2, new DependencySet(explanationTable.getCurrent()));

    // ind1.setSame(ind2, DependencySet.INDEPENDENT);
    ATermAppl sameAxiom = ATermUtils.makeSameAs( x, y );

    // update syntactic assertions - currently i do not add this to the
    // dependency index
    // now, as it will be added during the actual merge when the completion
    // is performed
    if( PelletOptions.USE_INCREMENTAL_DELETION ) {
          kb.getSyntacticAssertions().add( sameAxiom );
        }

    DependencySet ds = PelletOptions.USE_TRACING
      ? new DependencySet( sameAxiom )
      : DependencySet.INDEPENDENT;
    getToBeMerged().add( new NodeMerge( ind1, ind2, ds ) );
  }

  public void addDifferent(ATermAppl x, ATermAppl y) {
    Individual ind1 = getIndividual( x );
    Individual ind2 = getIndividual( y );

    ATermAppl diffAxiom = ATermUtils.makeDifferent( x, y );

    // update syntactic assertions - currently i do not add this to the
    // dependency index
    // now, as it will simply be used during the completion strategy
    if( PelletOptions.USE_INCREMENTAL_DELETION ) {
          kb.getSyntacticAssertions().add( diffAxiom );
        }

    // ind1.setDifferent(ind2, new
    // DependencySet(explanationTable.getCurrent()));
    DependencySet ds = PelletOptions.USE_TRACING
      ? new DependencySet( diffAxiom )
      : DependencySet.INDEPENDENT;

    // Temporarily reset the branch so that this assertion survives resets
    final int remember = branch;
    setBranch( DependencySet.NO_BRANCH );
   
    ind1.setDifferent( ind2, ds );
   
    setBranch( remember );
  }

  public void addAllDifferent(ATermList list) {
    ATermAppl allDifferent = ATermUtils.makeAllDifferent( list );
    ATermList outer = list;
    while( !outer.isEmpty() ) {
      ATermList inner = outer.getNext();
      while( !inner.isEmpty() ) {
        Individual ind1 = getIndividual( outer.getFirst() );
        Individual ind2 = getIndividual( inner.getFirst() );

        // update syntactic assertions - currently i do not add this to
        // the dependency index
        // now, as it will be added during the actual merge when the
        // completion is performed
        if( PelletOptions.USE_INCREMENTAL_DELETION ) {
                  kb.getSyntacticAssertions().add( allDifferent );
                }

        DependencySet ds = PelletOptions.USE_TRACING
          ? new DependencySet( allDifferent )
          : DependencySet.INDEPENDENT;
         
        final int remember = branch;
        setBranch( DependencySet.NO_BRANCH );
       
        ind1.setDifferent( ind2, ds );
       
        setBranch( remember );

        inner = inner.getNext();
      }
      outer = outer.getNext();
    }
  }

  public boolean isNode(ATerm x) {
    return getNode( x ) != null;
  }

  final public ATermAppl createUniqueName(boolean isNominal) {
    anonCount++;

    ATermAppl name = isNominal
      ? ATermUtils.makeAnonNominal( anonCount )
      : ATermUtils.makeAnon( anonCount );

    return name;
  }

  final public Collection<Node> getNodes() {
    return nodes.values();
  }

  final public List<ATermAppl> getNodeNames() {
    return nodeList;
  }

  @Override
    public String toString() {
    return "[size: " + nodes.size() + " freeMemory: "
        + (Runtime.getRuntime().freeMemory() / 1000000.0) + "mb]";
  }

  /**
   * @return Returns the datatype reasoner.
   */
  public DatatypeReasoner getDatatypeReasoner() {
    return dtReasoner;
  }

  /**
   * @return Returns the isComplete.
   */
  public boolean isComplete() {
    return isComplete;
  }

  /**
   * @param isComplete
   *            The isComplete to set.
   */
  public void setComplete(boolean isComplete) {
    this.isComplete = isComplete;
  }

  /**
   * Returns true if Abox has a clash.
   *
   * @return
   */
  public boolean isClosed() {
    return !PelletOptions.SATURATE_TABLEAU && initialized && clash != null;
  }

  public Clash getClash() {
    return clash;
  }

  public void setClash(Clash clash) {
    if( clash != null ) {
      if( log.isLoggable( Level.FINER ) ) {
        log.finer( "CLSH: " + clash );
        if( clash.getDepends().max() > branch && branch != -1 ) {
                  log.severe( "Invalid clash dependency " + clash + " > " + branch );
                }
      }
     
      if( branch == DependencySet.NO_BRANCH
          && clash.getDepends().getBranch() == DependencySet.NO_BRANCH ) {
        assertedClashes.add( clash );
      }
     
      if( this.clash != null ) {
        if( log.isLoggable( Level.FINER ) ) {
                  log.finer( "Clash was already set \nExisting: " + this.clash + "\nNew     : "
              + clash );
                }

        if( this.clash.getDepends().max() < clash.getDepends().max() ) {
                  return;
                }
      }
    }

    this.clash = clash;
    // CHW - added for incremental deletions
    if( PelletOptions.USE_INCREMENTAL_DELETION ) {
          kb.getDependencyIndex().setClashDependencies( this.clash );
        }

  }

  /**
   * @return Returns the kb.
   */
  public KnowledgeBase getKB() {
    return kb;
  }

  /**
   * Convenience function to get the named role.
   */
  public Role getRole(ATerm r) {
    return kb.getRole( r );
  }

  /**
   * Return the RBox
   */
  public RBox getRBox() {
    return kb.getRBox();
  }

  /**
   * Return the TBox
   */
  public TBox getTBox() {
    return kb.getTBox();
  }

  /**
   * Return the current branch number. Branches are created when a
   * non-deterministic rule, e.g. disjunction or max rule, is being applied.
   *
   * @return Returns the branch.
   */
  public int getBranch() {
    return branch;
  }

  /**
   * Set the branch number (should only be called when backjumping is in
   * progress)
   *
   * @param branch
   */
  public void setBranch(int branch) {
    this.branch = branch;
  }

  /**
   * Increment the branch number (should only be called when a
   * non-deterministic rule, e.g. disjunction or max rule, is being applied)
   *
   * @param branch
   */
  public void incrementBranch() {

    if( PelletOptions.USE_COMPLETION_QUEUE ) {
      completionQueue.incrementBranch( this.branch );
    }

    this.branch++;
  }

  /**
   * Check if the ABox is ready to be completed.
   *
   * @return Returns the initialized.
   */
  public boolean isInitialized() {
    return initialized;
  }

  public void setInitialized(boolean initialized) {
    this.initialized = initialized;
  }

  /**
   * Checks if the explanation is turned on.
   *
   * @return Returns the doExplanation.
   */
  final public boolean doExplanation() {
    return doExplanation;
  }

  /**
   * Enable/disable explanation generation
   *
   * @param doExplanation
   *            The doExplanation to set.
   */
  public void setDoExplanation(boolean doExplanation) {
    this.doExplanation = doExplanation;
  }
 
  public void setExplanation(DependencySet ds) {
    lastClash = Clash.unexplained( null, ds );
  }
 
  public String getExplanation() {
    // Clash lastClash = (lastCompletion != null) ?
    // lastCompletion.getClash() : null;
    if( lastClash == null ) {
          return "No inconsistency was found! There is no explanation generated.";
        }
        else {
          return lastClash.detailedString();
        }
  }

  public Set<ATermAppl> getExplanationSet() {
    if( lastClash == null ) {
          throw new RuntimeException( "No explanation was generated!" );
        }

    return lastClash.getDepends().getExplain();
  }
 
  public BranchEffectTracker getBranchEffectTracker() {
    if( branchEffects == null ) {
          throw new NullPointerException();
        }

    return branchEffects;
  }

  /**
   * Returns the branches.
   */
  public List<Branch> getBranches() {
    return branches;
  }

  public IncrementalChangeTracker getIncrementalChangeTracker() {
    if( incChangeTracker == null ) {
          throw new NullPointerException();
        }

    return incChangeTracker;
  }
 
  /**
   * Return individuals to which we need to apply the tableau rules
   *
   * @return
   */
  public IndividualIterator getIndIterator() {
    return new IndividualIterator( this );
  }

  /**
   * Validate all the edges in the ABox nodes. Used to find bugs in the copy
   * and detach/attach functions.
   */
  public void validate() {
    if( !PelletOptions.VALIDATE_ABOX ) {
          return;
        }
    System.out.print( "VALIDATING..." );
    Iterator<Individual> n = getIndIterator();
    while( n.hasNext() ) {
      Individual node = n.next();
      if( node.isPruned() ) {
              continue;
            }
      validate( node );
    }
  }
 
  void validateTypes(Individual node, List<ATermAppl> negatedTypes) {
    for( int i = 0, n = negatedTypes.size(); i < n; i++ ) {
      ATermAppl a = negatedTypes.get( i );
      if( a.getArity() == 0 ) {
              continue;
            }
      ATermAppl notA = (ATermAppl) a.getArgument( 0 );

      if( node.hasType( notA ) ) {
        if( !node.hasType( a ) ) {
                  throw new InternalReasonerException( "Invalid type found: " + node + " "
              + " " + a + " " + node.debugString() + " " + node.depends );
                }
        throw new InternalReasonerException( "Clash found: " + node + " " + a + " "
            + node.debugString() + " " + node.depends );
      }
    }
  }

  void validate(Individual node) {
    validateTypes( node, node.getTypes( Node.ATOM ) );
    validateTypes( node, node.getTypes( Node.SOME ) );
    validateTypes( node, node.getTypes( Node.OR ) );
    validateTypes( node, node.getTypes( Node.MAX ) );
   
    if( !node.isRoot() ) {
      EdgeList preds = node.getInEdges();
      boolean validPred = preds.size() == 1 || (preds.size() == 2 && preds.hasEdgeFrom( node ));
      if( !validPred ) {
              throw new InternalReasonerException( "Invalid blockable node: " + node + " "
            + node.getInEdges() );
            }

    }
    else if( node.isNominal() ) {
      ATermAppl nominal = ATermUtils.makeValue( node.getName() );
      if( !ATermUtils.isAnonNominal( node.getName() ) && !node.hasType( nominal ) ) {
              throw new InternalReasonerException( "Invalid nominal node: " + node + " "
            + node.getTypes() );
            }
    }

    for( Iterator<ATermAppl> i = node.getDepends().keySet().iterator(); i.hasNext(); ) {
      ATermAppl c = i.next();
      DependencySet ds = node.getDepends( c );
      if( ds.max() > branch || (!PelletOptions.USE_SMART_RESTORE && ds.getBranch() > branch) ) {
              throw new InternalReasonerException( "Invalid ds found: " + node + " " + c + " "
            + ds + " " + branch );
      // if( c.getAFun().equals( ATermUtils.VALUEFUN ) ) {
      // if( !PelletOptions.USE_PSEUDO_NOMINALS ) {
      // Individual z = getIndividual(c.getArgument(0));
      // if(z == null)
      // throw new InternalReasonerException("Nominal to non-existing
      // node: " + node + " " + c + " " + ds + " " + branch);
      // }
      // }
            }
    }
    for( Iterator<Node> i = node.getDifferents().iterator(); i.hasNext(); ) {
      Node ind = i.next();
      DependencySet ds = node.getDifferenceDependency( ind );
      if( ds.max() > branch || ds.getBranch() > branch ) {
              throw new InternalReasonerException( "Invalid ds: " + node + " != " + ind + " "
            + ds );
            }
      if( ind.getDifferenceDependency( node ) == null ) {
              throw new InternalReasonerException( "Invalid difference: " + node + " != " + ind
            + " " + ds );
            }
    }
    EdgeList edges = node.getOutEdges();
    for( int e = 0; e < edges.size(); e++ ) {
      Edge edge = edges.edgeAt( e );
      Node succ = edge.getTo();
      if( nodes.get( succ.getName() ) != succ ) {
              throw new InternalReasonerException( "Invalid edge to a non-existing node: " + edge
            + " " + nodes.get( succ.getName() ) + "("
            + nodes.get( succ.getName() ).hashCode() + ")" + succ + "("
            + succ.hashCode() + ")" );
            }
      if( !succ.getInEdges().hasEdge( edge ) ) {
              throw new InternalReasonerException( "Invalid edge: " + edge );
            }
      if( succ.isMerged() ) {
              throw new InternalReasonerException( "Invalid edge to a removed node: " + edge
            + " " + succ.isMerged() );
            }
      DependencySet ds = edge.getDepends();
      if( ds.max() > branch || ds.getBranch() > branch ) {
              throw new InternalReasonerException( "Invalid ds: " + edge + " " + ds );
            }
      EdgeList allEdges = node.getEdgesTo( succ );
      if( allEdges.getRoles().size() != allEdges.size() ) {
              throw new InternalReasonerException( "Duplicate edges: " + allEdges );
            }
    }
    edges = node.getInEdges();
    for( int e = 0; e < edges.size(); e++ ) {
      Edge edge = edges.edgeAt( e );
      DependencySet ds = edge.getDepends();
      if( ds.max() > branch || ds.getBranch() > branch ) {
              throw new InternalReasonerException( "Invalid ds: " + edge + " " + ds );
            }
    }
  }

  /**
   * Print the ABox as a completion tree (child nodes are indented).
   */
  public void printTree() {
    if( !PelletOptions.PRINT_ABOX ) {
          return;
        }
    System.err.println( "PRINTING... " + DependencySet.INDEPENDENT );
    Iterator<Node> n = nodes.values().iterator();
    while( n.hasNext() ) {
      Node node = n.next();
      if( !node.isRoot() || node instanceof Literal ) {
              continue;
            }
      printNode( (Individual) node, new HashSet<Individual>(), "   " );
    }
  }

  /**
   * Print the node in the completion tree.
   *
   * @param node
   * @param printed
   * @param indent
   */
  private void printNode(Individual node, Set<Individual> printed, String indent) {
    boolean printOnlyName = (node.isNominal() && !printed.isEmpty());

    System.err.print( node );
    if( !printed.add( node ) ) {
      System.err.println();
      return;
    }
    if( node.isMerged() ) {
      System.err.println( " -> " + node.getMergedTo() + " "
          + node.getMergeDependency( false ) );
      return;
    }
    else if( node.isPruned() ) {
          throw new InternalReasonerException( "Pruned node: " + node );
        }


    System.err.print( " = " );
    for(int i = 0; i < Node.TYPES; i++) {
      for( ATermAppl c : node.getTypes( i ) ) {
        System.err.print( ATermUtils.toString( c ) );
        System.err.print( ", ");
      }
    }
    System.err.println( node.getDifferents() );

    if( printOnlyName ) {
          return;
        }

    indent += "  ";
    Iterator<Edge> i = node.getOutEdges().iterator();
    while( i.hasNext() ) {
      Edge edge = i.next();
      Node succ = edge.getTo();
      EdgeList edges = node.getEdgesTo( succ );

      System.err.print( indent + "[" );
      for( int e = 0; e < edges.size(); e++ ) {
        if( e > 0 ) {
                  System.err.print( ", " );
                }
        System.err.print( edges.edgeAt( e ).getRole() );
      }
      System.err.print( "] " );
      if( succ instanceof Individual ) {
              printNode( (Individual) succ, printed, indent );
            }
            else {
              System.err.println( " (Literal) " + ATermUtils.toString(succ.getName()) + " " + ATermUtils.toString(succ.getTypes()) );
            }
    }
  }

  public Clash getLastClash() {
    return lastClash;
  }

  public ABox getLastCompletion() {
    return lastCompletion;
  }

  public boolean isKeepLastCompletion() {
    return keepLastCompletion;
  }

  public void setKeepLastCompletion(boolean keepLastCompletion) {
    this.keepLastCompletion = keepLastCompletion;
  }

  /**
   * Return the number of nodes in the ABox. This number includes both the
   * individuals and the literals.
   *
   * @return
   */
  public int size() {
    return nodes.size();
  }

  /**
   * Returns true if there are no individuals in the ABox.
   *
   * @return
   */
  public boolean isEmpty() {
    return nodes.isEmpty();
  }

  public void setLastCompletion(ABox comp) {
    lastCompletion = comp;
  }

  /**
   * Set whether changes to the update should be treated as syntactic updates,
   * i.e., if the changes are made on explicit source axioms. This is used for
   * the completion queue for incremental consistency checking purposes.
   *
   * @param boolean
   *            val The value
   */
  protected void setSyntacticUpdate(boolean val) {
    syntacticUpdate = val;
  }

  /**
   * Set whether changes to the update should be treated as syntactic updates,
   * i.e., if the changes are made on explicit source axioms. This is used for
   * the completion queue for incremental consistency checking purposes.
   *
   * @param boolean
   *            val The value
   */
  protected boolean isSyntacticUpdate() {
    return syntacticUpdate;
  }

  public CompletionQueue getCompletionQueue() {
    return completionQueue;
  }

  /**
   * Reset the ABox to contain only asserted information. Any ABox assertion
   * added by tableau rules will be removed.
   */
  public void reset() {
    if( !isComplete() ) {
          return;
        }
   
    setComplete( false );
   
    Iterator<ATermAppl> i = nodeList.iterator();
    while( i.hasNext() ) {
      ATermAppl nodeName = i.next();
      Node node = nodes.get( nodeName );
      if( !node.isRootNominal() ) {
        i.remove();
        nodes.remove( nodeName );
      }
      else {
        node.reset( false );
      }
    }
   
    setComplete( false );
    setInitialized( false );
    // clear the clash. we can safely clear the clash because
    // either this was an asserted clash and already stored in the
    // assertedClashes (and will be verified before consistency change)
    // or this was a clash that occurred during completion and will
    // reoccur (if no already resolved) since we will run the tableau
    // completion again
    setClash( null );
   
    setBranch( DependencySet.NO_BRANCH );
    branches = new ArrayList<Branch>();
    setDisjBranchStats( new HashMap<ATermAppl, int[]>() );
    rulesNotApplied = true;
  }
 
  public void resetQueue() {
    for( Node node : nodes.values() ) {     
      node.reset(true);
    }
  }

  /**
   * @param anonCount the anonCount to set
   */
  public int setAnonCount(int anonCount) {
    return this.anonCount = anonCount;
  }

  /**
   * @return the anonCount
   */
  public int getAnonCount() {
    return anonCount;
  }

  /**
   * @param disjBranchStats the disjBranchStats to set
   */
  public void setDisjBranchStats(Map<ATermAppl, int[]> disjBranchStats) {
    this.disjBranchStats = disjBranchStats;
  }

  /**
   * @return the disjBranchStats
   */
  public Map<ATermAppl, int[]> getDisjBranchStats() {
    return disjBranchStats;
  }

  /**
   * @param changed the changed to set
   */
  public void setChanged(boolean changed) {
    this.changed = changed;
  }

  /**
   * @return the changed
   */
  public boolean isChanged() {
    return changed;
  }

  /**
   * @return the toBeMerged
   */
  public List<NodeMerge> getToBeMerged() {
    return toBeMerged;
  }
}
TOP

Related Classes of org.mindswap.pellet.ABox

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.