org.mindswap.pellet.KnowledgeBase.java Source code

Java tutorial

Introduction

Here is the source code for org.mindswap.pellet.KnowledgeBase.java

Source

//The MIT License
//
//Copyright (c) 2003 Ron Alford, Mike Grove, Bijan Parsia, Evren Sirin
//
//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.

/*
 * Created on May 5, 2004
 */
package org.mindswap.pellet;

import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Constructor;
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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mindswap.pellet.datatypes.Datatype;
import org.mindswap.pellet.datatypes.DatatypeReasoner;
import org.mindswap.pellet.exceptions.InconsistentOntologyException;
import org.mindswap.pellet.exceptions.InternalReasonerException;
import org.mindswap.pellet.exceptions.UnsupportedFeatureException;
import org.mindswap.pellet.output.OutputFormatter;
import org.mindswap.pellet.query.QueryEngine;
import org.mindswap.pellet.query.QueryResults;
import org.mindswap.pellet.taxonomy.Taxonomy;
import org.mindswap.pellet.taxonomy.TaxonomyBuilder;
import org.mindswap.pellet.tbox.TBox;
import org.mindswap.pellet.tbox.impl.TBoxImpl;
import org.mindswap.pellet.utils.ATermUtils;
import org.mindswap.pellet.utils.Bool;
import org.mindswap.pellet.utils.SetUtils;
import org.mindswap.pellet.utils.SizeEstimate;
import org.mindswap.pellet.utils.Timer;
import org.mindswap.pellet.utils.Timers;

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

import com.hp.hpl.jena.query.Syntax;

/**
 * @author Evren Sirin
 */
public class KnowledgeBase {
    protected static Log log = LogFactory.getLog(KRSSLoader.class);

    /**
     * @deprecated Edit log4j.properties to turn on debugging
     */
    public static boolean DEBUG = false;

    protected ABox abox;
    protected TBox tbox;
    protected RBox rbox;

    private Set individuals;

    protected TaxonomyBuilder builder;
    protected Taxonomy taxonomy;
    protected Taxonomy roleTaxonomy;

    private boolean consistent;

    private SizeEstimate estimate;

    protected int status;

    protected static final int UNCHANGED = 0x0000;
    protected static final int ABOX_CHANGED = 0x0001;
    protected static final int TBOX_CHANGED = 0x0002;
    protected static final int RBOX_CHANGED = 0x0004;
    protected static final int ALL_CHANGED = 0x0007;
    protected static final int CONSISTENCY = 0x0008;
    protected static final int CLASSIFICATION = 0x0010;
    protected static final int REALIZATION = 0x0020;

    /**
     * The URI of the ontology this KB belongs to. Note that most of the time
     * this value will be null because the KB will not know the exact URI of the
     * ontology.
     */
    protected String ontology;

    Map instances;
    //   private Map typeChecks;

    private Expressivity expressivity;

    /**
     * Timers used in various different parts fo KB. There may be many different timers
     * created here depending on the level of debugging or application requirements.
     * However, there are three major timers that are guaranteed to exist.
     * <ul>
     *    <li> <b>main</b> - This is the main timer that exists in any Timers objects. All
     * the other timers defined in here will have this timer as its dependant so setting
     * a timeout on this timer will put a limit on every operation done inside KB.</li>
     *    <li> <b>preprocessing</b> - This is the operation where TBox creation, absorbtion and
     * normalization is done. It alos includes computing hierarchy of properties in RBox and 
     * merging the individuals in Abox if there are explicit sameAs assertions.</li>
     *    <li> <b>consistency</b> - This is the timer for ABox consistency check. Putting a 
     * timeout will mean that any single consistency check should be completed in a certain
     * amount of time.</li>
     *</ul>
     */
    public Timers timers = new Timers();

    private Set rules;

    /**
     * 
     */
    public KnowledgeBase() {
        clear();

        timers.createTimer("preprocessing");
        timers.createTimer("consistency");

        status = ALL_CHANGED;
    }

    /**
     * Create a KB based on an existing one. New KB has a copy of the ABox 
     * but TBox and RBox is shared between two. 
     * 
     * @param kb
     */
    public KnowledgeBase(KnowledgeBase kb) {
        abox = kb.abox.copy();
        //      abox.pseudoModel = kb.abox.pseudoModel.copy();
        tbox = kb.tbox;
        rbox = kb.rbox;

        expressivity = kb.expressivity;
        individuals = new HashSet(kb.individuals);

        instances = new HashMap(kb.instances);

        status = ALL_CHANGED;

        timers = kb.timers;
        //      timers.createTimer("preprocessing");
        //      timers.createTimer("consistency");
    }

    public Expressivity getExpressivity() {
        prepare();

        return expressivity;
    }

    public void clear() {
        abox = new ABox(this);
        tbox = new TBoxImpl(this);
        rbox = new RBox();

        expressivity = new Expressivity(this);
        individuals = new HashSet();

        instances = new HashMap();
        //      typeChecks = new HashMap();

        builder = null;

        status = ALL_CHANGED;
    }

    public KnowledgeBase copy() {
        return new KnowledgeBase(this);
    }

    public void loadKRSS(Reader reader) throws IOException {
        KRSSLoader loader = new KRSSLoader();
        loader.load(reader, this);
    }

    public void addClass(ATermAppl c) {
        if (c.equals(ATermUtils.TOP) || ATermUtils.isComplexClass(c))
            return;

        status |= TBOX_CHANGED;
        tbox.addClass(c);

        if (log.isDebugEnabled())
            log.debug("class " + c);
    }

    public void addSubClass(ATermAppl c1, ATermAppl c2) {
        if (c1.equals(c2))
            return;

        status |= TBOX_CHANGED;

        if (ATermUtils.isOneOf(c1)) {
            if (!PelletOptions.USE_PSEUDO_NOMINALS) {
                if (PelletOptions.USE_NOMINAL_ABSORPTION) {
                    ATermList list = (ATermList) c1.getArgument(0);
                    while (!list.isEmpty()) {
                        ATermAppl nominal = (ATermAppl) list.getFirst();
                        ATermAppl ind = (ATermAppl) nominal.getArgument(0);
                        addIndividual(ind);
                        addType(ind, c2);
                        list = list.getNext();
                    }
                }
            }
        } else {
            ATermAppl subAxiom = ATermUtils.makeSub(c1, c2);
            tbox.addAxiom(subAxiom);
            if (log.isDebugEnabled())
                log.debug("sub " + c1 + " " + c2);
        }
    }

    /**
     * @deprecated Use {@link #addEquivalentClass(ATermAppl, ATermAppl)} instead 
     */
    public void addSameClass(ATermAppl c1, ATermAppl c2) {
        addEquivalentClass(c1, c2);
    }

    public void addEquivalentClass(ATermAppl c1, ATermAppl c2) {
        if (c1.equals(c2))
            return;

        status |= TBOX_CHANGED;

        if (PelletOptions.USE_NOMINAL_ABSORPTION && (ATermUtils.isOneOf(c2) || ATermUtils.isOneOf(c1))) {
            addSubClass(c1, c2);
            addSubClass(c2, c1);
        } else {
            ATermAppl sameAxiom = ATermUtils.makeSame(c1, c2);
            tbox.addAxiom(sameAxiom);
            if (log.isDebugEnabled())
                log.debug("same " + c1 + " " + c2);
        }
    }

    public void addDisjointClass(ATerm c1, ATerm c2) {
        status |= TBOX_CHANGED;
        ATerm notC2 = ATermUtils.makeNot(c2);
        ATerm notC1 = ATermUtils.makeNot(c1);
        tbox.addAxiom(ATermUtils.makeSub(c1, notC2));
        tbox.addAxiom(ATermUtils.makeSub(c2, notC1));
        if (log.isDebugEnabled())
            log.debug("disjoint " + c1 + " " + c2);
    }

    public void addComplementClass(ATerm c1, ATerm c2) {
        status |= TBOX_CHANGED;
        ATerm notC2 = ATermUtils.makeNot(c2);

        if (c1.equals(notC2))
            return;

        ATerm notC1 = ATermUtils.makeNot(c1);
        tbox.addAxiom(ATermUtils.makeSame(c1, notC2));
        tbox.addAxiom(ATermUtils.makeSame(c2, notC1));
        if (log.isDebugEnabled())
            log.debug("complement " + c1 + " " + c2);
    }

    /**
     * 
     * Add the value of a DatatypeProperty. 
     * 
     * @param p Datatype Property
     * @param ind Individual value being added to
     * @param literalValue A literal ATerm which should be constructed with one of
     * ATermUtils.makeXXXLiteral functions
     * 
     * @deprecated Use addPropertyValue instead
     */
    public void addDataPropertyValue(ATermAppl p, ATermAppl s, ATermAppl o) {
        addPropertyValue(p, s, o);
    }

    public Individual addIndividual(ATermAppl i) {
        Node node = abox.getNode(i);
        if (node == null) {
            status |= ABOX_CHANGED;
            node = abox.addIndividual(i);
            node.setOntology(ontology);
            individuals.add(i);
            if (log.isDebugEnabled())
                log.debug("individual " + i);
        } else if (node instanceof Literal)
            throw new UnsupportedFeatureException(
                    "Trying to use a literal as an individual. Literal ID: " + i.getName());

        return (Individual) node;
    }

    public void addType(ATermAppl i, ATermAppl c) {
        status |= ABOX_CHANGED;
        abox.addType(i, c);
        if (log.isDebugEnabled())
            log.debug("type " + i + " " + c);
    }

    public void addSame(ATermAppl i1, ATermAppl i2) {
        status |= ABOX_CHANGED;
        abox.addSame(i1, i2);
        if (log.isDebugEnabled())
            log.debug("same " + i1 + " " + i2);
    }

    public void addDifferent(ATermAppl i1, ATermAppl i2) {
        status |= ABOX_CHANGED;
        abox.addDifferent(i1, i2);
        if (log.isDebugEnabled())
            log.debug("diff " + i1 + " " + i2);
    }

    /**
     * @deprecated Use addPropertyValue instead
     */
    public void addObjectPropertyValue(ATermAppl p, ATermAppl s, ATermAppl o) {
        addPropertyValue(p, s, o);
    }

    public boolean addPropertyValue(ATermAppl p, ATermAppl s, ATermAppl o) {
        status |= ABOX_CHANGED;

        Individual subj = abox.getIndividual(s);
        Role role = getRole(p);
        Node obj = null;

        if (subj == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(s + " is not a known individual!");
        }

        if (role == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(p + " is not a known property!");
        }

        if (role.isObjectRole()) {
            obj = abox.getIndividual(o);
            if (obj == null) {
                if (ATermUtils.isLiteral(o)) {
                    System.err.println("Ignoring literal value " + o + " for object property " + p);
                    return false;
                } else {
                    if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                        return false;
                    else
                        throw new UnsupportedFeatureException(o + " is not a known individual!");
                }
            }
        } else if (role.isDatatypeRole()) {
            obj = abox.addLiteral(o);
        }

        subj.addEdge(role, obj, DependencySet.INDEPENDENT);

        if (log.isDebugEnabled())
            log.debug("prop-value " + s + " " + p + " " + o);

        return true;
    }

    public void addProperty(ATermAppl p) {
        status |= RBOX_CHANGED;
        rbox.addRole(p);
        if (log.isDebugEnabled())
            log.debug("undefined-prop " + p);
    }

    /**
     * Add a new object property. If property was earlier defined to be a datatype 
     * property then this function will simply return without changing the KB.
     * 
     * @param p Name of the property
     * @return True if property is added, false if not
     */
    public boolean addObjectProperty(ATerm p) {
        status |= RBOX_CHANGED;
        Role role = rbox.addObjectRole((ATermAppl) p);
        if (log.isDebugEnabled())
            log.debug("object-prop " + p);

        return role.isObjectRole();
    }

    /**
     * Add a new object property. If property was earlier defined to be a datatype 
     * property then this function will simply return without changing the KB.
     * 
     * @param p
     * @return True if property is added, false if not
     */
    public boolean addDatatypeProperty(ATerm p) {
        status |= RBOX_CHANGED;
        Role role = rbox.addDatatypeRole((ATermAppl) p);
        if (log.isDebugEnabled())
            log.debug("data-prop " + p);

        return role.isDatatypeRole();
    }

    public void addOntologyProperty(ATermAppl p) {
        status |= RBOX_CHANGED;
        rbox.addOntologyRole(p);
        if (log.isDebugEnabled())
            log.debug("onto-prop " + p);
    }

    public void addAnnotationProperty(ATermAppl p) {
        status |= RBOX_CHANGED;
        rbox.addAnnotationRole(p);
        if (log.isDebugEnabled())
            log.debug("annotation-prop " + p);
    }

    public void addSubProperty(ATermAppl p1, ATermAppl p2) {
        status |= RBOX_CHANGED;
        rbox.addSubRole(p1, p2);

        if (log.isDebugEnabled())
            log.debug("sub-prop " + p1 + " " + p2);
    }

    /**
     * @deprecated Use {@link #addEquivalentClass(ATermAppl, ATermAppl)} instead 
     */
    public void addSameProperty(ATermAppl p1, ATermAppl p2) {
        addEquivalentProperty(p1, p2);
    }

    public void addEquivalentProperty(ATermAppl p1, ATermAppl p2) {
        status |= RBOX_CHANGED;
        rbox.addSubRole(p1, p2);
        rbox.addSubRole(p2, p1);

        if (log.isDebugEnabled())
            log.debug("same-prop " + p1 + " " + p2);
    }

    public void addInverseProperty(ATermAppl p1, ATermAppl p2) {
        status |= RBOX_CHANGED;
        rbox.addInverseRole(p1, p2);
        if (log.isDebugEnabled())
            log.debug("inv-prop " + p1 + " " + p2);
    }

    public void addTransitiveProperty(ATermAppl p) {
        status |= RBOX_CHANGED;

        Role r = rbox.getDefinedRole(p);

        r.setTransitive(true);
        if (log.isDebugEnabled())
            log.debug("trans-prop " + p);
    }

    public void addSymmetricProperty(ATermAppl p) {
        status |= RBOX_CHANGED;
        rbox.addInverseRole(p, p);
        if (log.isDebugEnabled())
            log.debug("sym-prop " + p);
    }

    public void addFunctionalProperty(ATermAppl p) {
        status |= RBOX_CHANGED;
        Role r = rbox.getDefinedRole(p);

        r.setFunctional(true);
        if (log.isDebugEnabled())
            log.debug("func-prop " + p);
    }

    public void addInverseFunctionalProperty(ATerm p) {
        status |= RBOX_CHANGED;

        Role role = rbox.getDefinedRole(p);

        role.setInverseFunctional(true);
        if (log.isDebugEnabled())
            log.debug("inv-func-prop " + p);
    }

    public void addDomain(ATerm p, ATermAppl c) {
        status |= RBOX_CHANGED;

        Role r = rbox.getDefinedRole(p);

        r.addDomain(c);

        if (log.isDebugEnabled())
            log.debug("domain " + p + " " + c + " (" + r.getDomain() + ")");
    }

    public void addRange(ATerm p, ATermAppl c) {
        status |= RBOX_CHANGED;

        Role r = rbox.getDefinedRole(p);

        r.addRange(c);

        if (log.isDebugEnabled())
            log.debug("range " + p + " " + c);
    }

    public boolean isDatatype(ATerm p) {
        DatatypeReasoner dtReasoner = getDatatypeReasoner();
        return dtReasoner.isDefined(p.toString());
    }

    public void addDatatype(ATerm p) {
        DatatypeReasoner dtReasoner = getDatatypeReasoner();
        if (!dtReasoner.isDefined(p.toString())) {
            status |= TBOX_CHANGED;

            dtReasoner.defineUnknownDatatype(p.toString());
            if (log.isDebugEnabled())
                log.debug("datatype " + p);
        }
    }

    public void loadDatatype(ATerm p) {
        DatatypeReasoner dtReasoner = getDatatypeReasoner();
        if (!dtReasoner.isDefined(p.toString())) {
            status |= TBOX_CHANGED;

            dtReasoner.loadUserDefinedDatatype(p.toString());
            if (log.isDebugEnabled())
                log.debug("datatype " + p);
        }
    }

    public void addDataRange(String datatypeURI, ATermList values) {
        DatatypeReasoner dtReasoner = getDatatypeReasoner();
        if (!dtReasoner.isDefined(datatypeURI.toString())) {
            status |= TBOX_CHANGED;

            Datatype dataRange = dtReasoner.enumeration(ATermUtils.listToSet(values));
            getDatatypeReasoner().defineDatatype(datatypeURI.toString(), dataRange);
            if (log.isDebugEnabled())
                log.debug("datarange " + datatypeURI.toString() + " " + values);
        }
    }

    public boolean removeObjectPropertyValue(ATermAppl p, ATermAppl i1, ATermAppl i2) {
        boolean removed = false;

        Individual subj = abox.getIndividual(i1);
        Individual obj = abox.getIndividual(i2);
        Role role = getRole(p);

        if (subj == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                throw new UnsupportedFeatureException(i1 + " is not an individual!");
            else
                return false;
        }

        if (obj == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(i2 + " is not an individual!");
        }

        if (role == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(p + " is not a property!");
        }

        EdgeList edges = subj.getEdgesTo(obj, role);
        for (int i = 0; i < edges.size(); i++) {
            Edge edge = edges.edgeAt(i);
            if (edge.getRole().equals(role)) {
                subj.removeEdge(edge);
                status |= ABOX_CHANGED;
                removed = true;
                break;
            }
        }

        if (log.isDebugEnabled())
            log.debug("Remove ObjectPropertyValue " + i1 + " " + p + " " + i2);

        return removed;
    }

    public void removeType(ATermAppl ind, ATermAppl c) {
        status |= ABOX_CHANGED;
        Individual subj = abox.getIndividual(ind);

        if (subj == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return;
            else
                throw new UnsupportedFeatureException(ind + " is not an individual!");
        }

        subj.removeType(c);

        if (log.isDebugEnabled())
            log.debug("Remove Type " + ind + " " + c);
    }

    public void prepare() {
        if (!isChanged())
            return;

        boolean explain = abox.doExplanation();
        abox.setDoExplanation(true);

        Timer timer = timers.startTimer("preprocessing");

        boolean reuseTaxonomy = (taxonomy != null) && !isTBoxChanged()
                && (!expressivity.hasNominal() || PelletOptions.USE_PSEUDO_NOMINALS);

        // size of Tg before absorbption
        int sizeTg = 0;
        if (isTBoxChanged()) {
            if (log.isDebugEnabled())
                log.debug("Splitting...");
            tbox.split();

            sizeTg = tbox.getTgSize();

            if (PelletOptions.USE_ABSORPTION) {
                if (log.isDebugEnabled())
                    log.debug("Absorbing...");
                tbox.absorb();
            }

            if (log.isDebugEnabled())
                log.debug("Normalizing...");
            tbox.normalize();
            if (log.isDebugEnabled())
                log.debug("Internalizing...");
            tbox.internalize();

            // changes in tbox may cause new domain and ranges to added so process
            // rbox again
            if (log.isDebugEnabled())
                log.debug("Role hierarchy...");
            //          Timer t = timers.startTimer("rbox");
            rbox.computeRoleHierarchy();
            //         t.stop();
        } else if (isRBoxChanged()) {
            if (log.isDebugEnabled())
                log.debug("Role hierarchy...");
            rbox.computeRoleHierarchy();
        }

        // The prepartion of TBox and RBox is finished so we set the 
        // status to UNCHANGED now. Expressivity check can only work 
        // with prepared KB's
        status = UNCHANGED;

        if (log.isDebugEnabled())
            log.debug("Expressivity...");
        expressivity.compute();

        if (log.isDebugEnabled())
            log.debug("ABox init...");
        //      abox.initialize();      
        instances.clear();
        if (log.isDebugEnabled())
            log.debug("done.");

        estimate = new SizeEstimate(this);
        abox.setDoExplanation(explain);

        abox.clearCaches(!reuseTaxonomy);
        if (reuseTaxonomy)
            status |= CLASSIFICATION;
        else
            taxonomy = null;

        timer.stop();

        if (PelletOptions.PRINT_SIZE) {
            System.out.print("Expressivity: " + expressivity + ", ");
            System.out.print("Classes: " + getClasses().size() + " ");
            System.out.print("Properties: " + getProperties().size() + " ");
            System.out.print("Individuals: " + individuals.size());
            if (sizeTg > 0) {
                System.out.print(", GCIs: " + tbox.getTgSize() + " (");
                System.out.print((sizeTg - tbox.getTgSize()) + " absorbed)");
            }
            System.out.print(" Strategy: " + chooseStrategy(abox));
            System.out.println();
            //         tbox.print();
        }
    }

    public String getInfo() {
        prepare();

        StringBuffer buffer = new StringBuffer();
        buffer.append("Expressivity: " + expressivity + " ");
        buffer.append("Classes: " + getClasses().size() + " ");
        buffer.append("Properties: " + getProperties().size() + " ");
        buffer.append("Individuals: " + individuals.size() + " ");
        if (expressivity.hasNominal())
            buffer.append("Nominals: " + expressivity.getNominals().size() + " ");
        if (tbox.getTgSize() > 0) {
            buffer.append("GCIs: " + tbox.getTgSize());
        }

        return buffer.toString();
    }

    /**
     * Returns true if the consistency check has been done and nothing in th KB
     * has changed after that.
     */
    public boolean isConsistencyDone() {
        // check if consistency bit is set but none of the change bits
        return (status & (CONSISTENCY | ALL_CHANGED)) == CONSISTENCY;
    }

    /**
     * Returns true if the classification check has been done and nothing in th KB
     * has changed after that.
     */
    public boolean isClassified() {
        return (status & (CLASSIFICATION | ALL_CHANGED)) == CLASSIFICATION;
    }

    public boolean isRealized() {
        return (status & (REALIZATION | ALL_CHANGED)) == REALIZATION;
    }

    public boolean isChanged() {
        return (status & ALL_CHANGED) != 0;
    }

    public boolean isTBoxChanged() {
        return (status & TBOX_CHANGED) != 0;
    }

    public boolean isRBoxChanged() {
        return (status & RBOX_CHANGED) != 0;
    }

    public boolean isABoxChanged() {
        return (status & ABOX_CHANGED) != 0;
    }

    private void consistency() {
        if (isConsistencyDone())
            return;

        // always turn on explanations for the first consistency check
        boolean explain = abox.doExplanation();
        abox.setDoExplanation(true);

        prepare();

        Timer timer = timers.startTimer("consistency");

        consistent = abox.isConsistent();
        abox.setDoExplanation(explain);

        if (!consistent) {
            System.err.println("WARNING: Inconsistent ontology. Reason: " + getExplanation());
        }

        timer.stop();

        status |= CONSISTENCY;
    }

    public boolean isConsistent() {
        consistency();

        return consistent;
    }

    public void ensureConsistency() {
        if (!isConsistent())
            throw new InconsistentOntologyException("Cannot do reasoning with inconsistent ontologies!");
    }

    public void classify() {
        ensureConsistency();

        if (isClassified())
            return;

        Timer timer = timers.startTimer("classify");

        builder = getTaxonomyBuilder();

        taxonomy = builder.classify();

        timer.stop();

        // if user canceled return
        if (taxonomy == null) {
            builder = null;
            return;
        }

        status |= CLASSIFICATION;
    }

    public void realize() {
        if (isRealized())
            return;

        classify();

        if (!isClassified())
            return;

        Timer timer = timers.startTimer("realize");

        taxonomy = builder.realize();

        timer.stop();

        // if user canceled return
        if (taxonomy == null) {
            builder = null;
            return;
        }

        status |= REALIZATION;
    }

    /**
     * Return the set of all named classes. Returned set is unmodifiable!
     * 
     * @return
     */
    public Set getClasses() {
        return Collections.unmodifiableSet(tbox.getClasses());
    }

    /**
     * Return the set of all named classes including TOP and BOTTOM. Returned set is modifiable.
     * 
     * @return
     */
    public Set getAllClasses() {
        return Collections.unmodifiableSet(tbox.getAllClasses());
    }

    /**
     * Return the set of all properties.
     * 
     * @return
     */
    public Set getProperties() {
        Set set = new HashSet();
        Iterator i = rbox.getRoles().iterator();
        while (i.hasNext()) {
            Role role = (Role) i.next();
            ATermAppl p = role.getName();
            if (ATermUtils.isPrimitive(p) && (role.isObjectRole() || role.isDatatypeRole()))
                set.add(p);
        }
        return set;
    }

    /**
     * Return the set of all object properties.
     * 
     * @return
     */
    public Set getObjectProperties() {
        Set set = new HashSet();
        Iterator i = rbox.getRoles().iterator();
        while (i.hasNext()) {
            Role role = (Role) i.next();
            ATermAppl p = role.getName();
            if (ATermUtils.isPrimitive(p) && role.isObjectRole())
                set.add(p);
        }
        return set;
    }

    public Set getTransitiveProperties() {
        Set set = new HashSet();
        Iterator i = rbox.getRoles().iterator();
        while (i.hasNext()) {
            Role role = (Role) i.next();
            ATermAppl p = role.getName();
            if (ATermUtils.isPrimitive(p) && role.isTransitive())
                set.add(p);
        }
        return set;
    }

    public Set getSymmetricProperties() {
        Set set = new HashSet();
        Iterator i = rbox.getRoles().iterator();
        while (i.hasNext()) {
            Role role = (Role) i.next();
            ATermAppl p = role.getName();
            if (ATermUtils.isPrimitive(p) && role.isSymmetric())
                set.add(p);
        }
        return set;
    }

    public Set getFunctionalProperties() {
        Set set = new HashSet();
        Iterator i = rbox.getRoles().iterator();
        while (i.hasNext()) {
            Role role = (Role) i.next();
            ATermAppl p = role.getName();
            if (ATermUtils.isPrimitive(p) && role.isFunctional())
                set.add(p);
        }
        return set;
    }

    public Set getInverseFunctionalProperties() {
        Set set = new HashSet();
        Iterator i = rbox.getRoles().iterator();
        while (i.hasNext()) {
            Role role = (Role) i.next();
            ATermAppl p = role.getName();
            if (ATermUtils.isPrimitive(p) && role.isInverseFunctional())
                set.add(p);
        }
        return set;
    }

    /**
     * Return the set of all object properties.
     * 
     * @return
     */
    public Set getDataProperties() {
        Set set = new HashSet();
        Iterator i = rbox.getRoles().iterator();
        while (i.hasNext()) {
            Role role = (Role) i.next();
            ATermAppl p = role.getName();
            if (ATermUtils.isPrimitive(p) && role.isDatatypeRole())
                set.add(p);
        }
        return set;
    }

    /**
     * Return the set of all individuals. Returned set is unmodifiable!
     * 
     * @return
     */
    public Set getIndividuals() {
        return Collections.unmodifiableSet(individuals);
    }

    public Role getProperty(ATerm r) {
        return rbox.getRole(r);
    }

    public int getPropertyType(ATerm r) {
        Role role = getProperty(r);
        return (role == null) ? Role.UNTYPED : role.getType();
    }

    public boolean isClass(ATerm c) {
        return tbox.getClasses().contains(c) || c.equals(ATermUtils.TOP) || ATermUtils.isComplexClass(c);
    }

    public boolean isProperty(ATerm p) {
        return rbox.isRole(p);
    }

    public boolean isDatatypeProperty(ATerm p) {
        return getPropertyType(p) == Role.DATATYPE;
    }

    public boolean isObjectProperty(ATerm p) {
        return getPropertyType(p) == Role.OBJECT;
    }

    public boolean isABoxProperty(ATerm p) {
        int type = getPropertyType(p);
        return (type == Role.OBJECT) || (type == Role.DATATYPE);
    }

    public boolean isAnnotationProperty(ATerm p) {
        return getPropertyType(p) == Role.ANNOTATION;
    }

    public boolean isOntologyProperty(ATerm p) {
        return getPropertyType(p) == Role.ONTOLOGY;
    }

    public boolean isIndividual(ATerm ind) {
        return getIndividuals().contains(ind);
    }

    public boolean isTransitiveProperty(ATermAppl r) {
        Role role = getRole(r);

        if (role == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(r + " is not a known property");
        }

        if (role.isTransitive())
            return true;

        ensureConsistency();

        ATermAppl c = ATermUtils.makeTermAppl("_C_");
        ATermAppl notC = ATermUtils.makeNot(c);
        ATermAppl test = ATermUtils.makeAnd(ATermUtils.makeSomeValues(r, ATermUtils.makeSomeValues(r, c)),
                ATermUtils.makeAllValues(r, notC));

        return !abox.isSatisfiable(test);
    }

    public boolean isSymmetricProperty(ATermAppl p) {
        return isInverse(p, p);
    }

    public boolean isFunctionalProperty(ATermAppl p) {
        Role role = getRole(p);

        if (role == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(p + " is not a known property");
        }

        if (role.isFunctional())
            return true;

        ATermAppl max1P = ATermUtils.makeMax(p, 1);
        return isSubClassOf(ATermUtils.TOP, max1P);
    }

    public boolean isInverseFunctionalProperty(ATermAppl p) {
        Role role = getRole(p);

        if (role == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(p + " is not a known property");
        }

        if (role.isInverseFunctional())
            return true;
        else if (!role.isObjectRole())
            return false;

        ATermAppl invP = role.getInverse().getName();
        ATermAppl max1invP = ATermUtils.makeMax(invP, 1);
        return isSubClassOf(ATermUtils.TOP, max1invP);
    }

    public boolean isSubPropertyOf(ATermAppl sub, ATermAppl sup) {
        Role roleSub = rbox.getRole(sub);
        Role roleSup = rbox.getRole(sup);

        if (roleSub == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(roleSub + " is not a known property");
        }

        if (roleSup == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(roleSup + " is not a known property");
        }

        if (roleSub.isSubRoleOf(roleSup))
            return true;

        ensureConsistency();

        ATermAppl c = ATermUtils.makeTermAppl("_C_");
        ATermAppl notC = ATermUtils.makeNot(c);
        ATermAppl test = ATermUtils.makeAnd(ATermUtils.makeSomeValues(sub, c), ATermUtils.makeAllValues(sup, notC));

        return !abox.isSatisfiable(test);
    }

    public boolean isEquivalentProperty(ATermAppl p1, ATermAppl p2) {
        return isSubPropertyOf(p1, p2) && isSubPropertyOf(p2, p1);
    }

    public boolean isInverse(ATermAppl r1, ATermAppl r2) {
        Role role1 = getRole(r1);
        Role role2 = getRole(r2);

        if (role1 == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(r1 + " is not a known property");
        }

        if (role2 == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(r2 + " is not a known property");
        }

        // the following condition is wrong due to nominals, see OWL test 
        // cases SymmetricProperty-002
        //        if( !role1.hasNamedInverse() )
        //            return false;
        //        else 
        if (role1.getInverse().equals(role2))
            return true;

        ensureConsistency();

        ATermAppl c = ATermUtils.makeTermAppl("_C_");
        ATermAppl notC = ATermUtils.makeNot(c);
        ATermAppl test = ATermUtils.makeAnd(c, ATermUtils.makeSomeValues(r1, ATermUtils.makeAllValues(r2, notC)));

        return !abox.isSatisfiable(test);
    }

    public boolean hasDomain(ATermAppl p, ATermAppl c) {
        ATermAppl minP1 = ATermUtils.makeMin(p, 1);
        return isSubClassOf(minP1, c);
    }

    public boolean hasRange(ATermAppl p, ATermAppl c) {
        ATermAppl allValues = ATermUtils.makeAllValues(p, c);
        return isSubClassOf(ATermUtils.TOP, allValues);
    }

    public boolean isDatatype(ATermAppl c) {
        return abox.getDatatypeReasoner().isDefined(c.getName());
    }

    public boolean isSatisfiable(ATermAppl c) {
        ensureConsistency();

        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(c + " is not a known class!");
        }

        return abox.isSatisfiable(c);
    }

    /**
     * Returns true if there is at leaat one individual that belongs to the given class
     * 
     * @param c
     * @return
     */
    public boolean hasInstance(ATerm d) {
        ensureConsistency();

        ATermAppl c = ATermUtils.normalize((ATermAppl) d);

        List unknowns = new ArrayList();
        Iterator i = abox.getIndIterator();
        while (i.hasNext()) {
            ATermAppl x = ((Individual) i.next()).getName();

            Bool knownType = abox.isKnownType(x, c);
            if (knownType.isTrue())
                return true;
            else if (knownType.isUnknown())
                unknowns.add(x);
        }

        boolean hasInstance = !unknowns.isEmpty() && abox.isType(unknowns, c);

        return hasInstance;
    }

    public boolean isSubTypeOf(ATermAppl d1, ATermAppl d2) {
        if (!isDatatype(d1)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(d1 + " is not a known datatype");
        }

        if (!isDatatype(d2)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(d2 + " is not a known datatype");
        }

        return getDatatypeReasoner().isSubTypeOf(d1, d2);
    }

    /**
     * Check if class c1 is subclass of class c2.
     * 
     * @param c1
     * @param c2
     * @return
     */
    public boolean isSubClassOf(ATermAppl c1, ATermAppl c2) {
        ensureConsistency();

        if (!isClass(c1)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(c1 + " is not a known class");
        }

        if (!isClass(c2)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(c2 + " is not a known class");
        }

        if (c1.equals(c2))
            return true;

        // normalize concepts
        c1 = ATermUtils.normalize(c1);
        c2 = ATermUtils.normalize(c2);

        if (isClassified()) {
            Bool isSubNode = taxonomy.isSubNodeOf(c1, c2);
            if (isSubNode.isKnown())
                return isSubNode.isTrue();
        }

        return abox.isSubClassOf(c1, c2);
    }

    /**
     * @deprecated  As of Pellet 1.1.1, replaced by {@link #isSubClassOf(ATermAppl,ATermAppl)}
     */
    public boolean isSubclassOf(ATermAppl c1, ATermAppl c2) {
        return isSubClassOf(c1, c2);
    }

    /**
     * Check if class c1 is equivalent to class c2.    
     * 
     * @param c1
     * @param c2
     * @return
     */
    public boolean isEquivalentClass(ATermAppl c1, ATermAppl c2) {
        return isSubClassOf(c1, c2) && isSubClassOf(c2, c1);
    }

    // Two concepts are disjoint if their intersection is empty
    public boolean isDisjoint(ATermAppl c1, ATermAppl c2) {
        ATermAppl notC2 = ATermUtils.makeNot(c2);

        return isSubClassOf(c1, notC2);
    }

    public boolean isComplement(ATermAppl c1, ATermAppl c2) {
        ATermAppl notC2 = ATermUtils.makeNot(c2);

        return isEquivalentClass(c1, notC2);
    }

    /**
     * Answers the isType question without doing any satisfiability check. It might return
     * <code>Bool.TRUE</code>, <code>Bool.FALSE</code>, or <code>Bool.UNKNOWN</code>.
     * If <code>Bool.UNKNOWN</code> is returned <code>isType</code> function needs to be called to get
     * the answer.  
     * 
     * @param x
     * @param c
     * @return
     */
    public Bool isKnownType(ATermAppl x, ATermAppl c) {
        ensureConsistency();

        c = ATermUtils.normalize(c);

        return abox.isKnownType(x, c);
    }

    public boolean isType(ATermAppl x, ATermAppl c) {
        ensureConsistency();

        if (!isIndividual(x)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(x + " is not an individual!");
        }
        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(c + " is not a valid class expression");
        }

        if (isRealized() && taxonomy.contains(c))
            return taxonomy.getInstances(c).contains(x);

        //      Integer count = (Integer) typeChecks.get( c );
        //      if( count == null ) 
        //          count = new Integer( 1 );
        //      else
        //          count = new Integer( count.intValue() + 1 );
        //      
        //      if( count.intValue() > PelletOptions.AUTO_RETRIEVE_LIMIT ) {
        //          typeChecks.remove( c );
        //          list = retrieve( c );
        //          return list.contains( c );
        //      }      
        //      else
        //          typeChecks.put( c, count );

        return abox.isType(x, c);
    }

    public boolean isSameAs(ATermAppl t1, ATermAppl t2) {
        ensureConsistency();

        if (!isIndividual(t1)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(t1 + " is not an individual!");
        }
        if (!isIndividual(t2)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(t2 + " is not an individual!");
        }

        if (t1.equals(t2))
            return true;

        Set knowns = new HashSet();
        Set unknowns = new HashSet();

        Individual ind = abox.getPseudoModel().getIndividual(t1);
        if (ind.isMerged() && !ind.getMergeDependency(true).isIndependent())
            abox.getSames((Individual) ind.getSame(), unknowns, unknowns);
        else
            abox.getSames((Individual) ind.getSame(), knowns, unknowns);

        if (knowns.contains(t2))
            return true;
        else if (!unknowns.contains(t2))
            return false;
        else
            return abox.isSameAs(t1, t2);
    }

    public boolean isDifferentFrom(ATermAppl t1, ATermAppl t2) {
        Individual ind1 = abox.getIndividual(t1);
        Individual ind2 = abox.getIndividual(t2);

        if (ind1 == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(t1 + " is not an individual!");
        }

        if (ind2 == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(t2 + " is not an individual!");
        }

        if (ind1.isDifferent(ind2))
            return true;

        ATermAppl c = ATermUtils.makeNot(ATermUtils.makeValue(t2));

        return isType(t1, c);
    }

    public boolean hasPropertyValue(ATermAppl s, ATermAppl p, ATermAppl o) {
        ensureConsistency();

        if (!isIndividual(s)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(s + " is not an individual!");
        }

        if (!isProperty(p)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return false;
            else
                throw new UnsupportedFeatureException(p + " is not a known property!");
        }

        if (o != null) {
            if (isDatatypeProperty(p)) {
                if (!ATermUtils.isLiteral(o))
                    return false;
            } else if (!isIndividual(o)) {
                return false;
            }
        }

        return abox.hasPropertyValue(s, p, o);
    }

    /**
     * Answers the hasPropertyValue question without doing any satisfiability check. It might 
     * return <code>Boolean.TRUE</code>, <code>Boolean.FALSE</code>, or <code>null</code> (unknown).
     * If the null value is returned <code>hasPropertyValue</code> function needs to be called to 
     * get the answer.  
     * 
     * @param s Subject
     * @param p Predicate
     * @param o Object (<code>null</code> can be used as wildcard)
     * @return
     */
    public Bool hasKnownPropertyValue(ATermAppl s, ATermAppl p, ATermAppl o) {
        ensureConsistency();

        return abox.hasObviousPropertyValue(s, p, o);
    }

    /**
     * @return Returns the abox.
     */
    public ABox getABox() {
        return abox;
    }

    /**
     * @return Returns the rbox.
     */
    public RBox getRBox() {
        return rbox;
    }

    /**
     * @return Returns the tbox.
     */
    public TBox getTBox() {
        return tbox;
    }

    /**
     * @return Returns the DatatypeReasoner
     */
    public DatatypeReasoner getDatatypeReasoner() {
        return abox.getDatatypeReasoner();
    }

    /**
     * Returns the (named) superclasses of class c. Depending onthe second parameter the resulting
     * list will include etiher all or only the direct superclasses.
     * 
     * A class d is a direct superclass of c iff
     * <ol>
     *   <li> d is superclass of c </li> 
     *   <li> there is no other class x such that x is superclass of c and d is superclass of x </li>
     * </ol>
     * The class c itself is not included in the list but all the other classes that
     * are sameAs c are put into the list. Also note that the returned
     * list will always have at least one element. The list will either include one other
     * concept from the hierachy or the TOP concept if no other class subsumes c. By definition
     * TOP concept is superclass of every concept. 
     * 
     * <p>*** This function will first classify the whole ontology ***</p>
     * 
     * @param c class whose superclasses are returned
     * @return A set of sets, where each set in the collection represents an equivalence 
     * class. The elements of the inner class are ATermAppl objects. 
     */
    public Set getSuperClasses(ATermAppl c, boolean direct) {
        c = ATermUtils.normalize(c);

        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(c + " is not a class!");
        }

        classify();

        if (!taxonomy.contains(c))
            builder.classify(c);

        return taxonomy.getSupers(c, direct);
    }

    /** 
     * Returns all the (named) subclasses of class c. The
     * class c itself is not included in the list but all the other classes that
     * are equivalent to c are put into the list. Also note that the returned
     * list will always have at least one element, that is the BOTTOM concept. By definition
     * BOTTOM concept is subclass of every concept.
     * This function is equivalent to calling getSubClasses(c, true).
     * 
     * <p>*** This function will first classify the whole ontology ***</p>
     * 
     * @param c class whose subclasses are returned 
     * @return A set of sets, where each set in the collection represents an equivalence 
     * class. The elements of the inner class are ATermAppl objects. 
     */
    public Set getSubClasses(ATermAppl c) {
        return getSubClasses(c, false);
    }

    public Set getDisjoints(ATermAppl c) {
        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(c + " is not a class!");
        }

        ATermAppl notC = ATermUtils.normalize(ATermUtils.makeNot(c));
        Set disjoints = getSubClasses(notC);

        if (tbox.getAllClasses().contains(notC))
            disjoints.add(getAllEquivalentClasses(notC));

        return disjoints;
    }

    public Set getComplements(ATermAppl c) {
        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(c + " is not a class!");
        }

        ATermAppl notC = ATermUtils.normalize(ATermUtils.makeNot(c));
        Set complements = getEquivalentClasses(notC);

        if (tbox.getAllClasses().contains(notC))
            complements.add(notC);

        return complements;
    }

    /**
     * Returns the (named) classes individual belongs to. Depending on the second parameter the 
     * result will include either all types or only the direct types.
     * 
     * @param ind An individual name
     * @param direct If true return only the direct types, otherwise return all types
     * @return A set of sets, where each set in the collection represents an equivalence 
     * class. The elements of the inner class are ATermAppl objects. 
     */
    public Set getTypes(ATermAppl ind, boolean direct) {
        if (!isIndividual(ind)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(ind + " is not an individual!");
        }

        realize();

        return taxonomy.getTypes(ind, direct);
    }

    /**
     * Get all the (named) classes individual belongs to. 
     *  
     * <p>*** This function will first realize the whole ontology ***</p>
     * 
     * @param ind An individual name
     * @return A set of sets, where each set in the collection represents an equivalence 
     * class. The elements of the inner class are ATermAppl objects. 
     */
    public Set getTypes(ATermAppl ind) {
        if (!isIndividual(ind)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(ind + " is not an individual!");
        }

        realize();

        return taxonomy.getTypes(ind);
    }

    public ATermAppl getType(ATermAppl ind) {
        if (!isIndividual(ind)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return null;
            else
                throw new UnsupportedFeatureException(ind + " is not an individual!");
        }

        // there is always at least one atomic class guranteed to exist (i.e. owl:Thing)
        return (ATermAppl) abox.getIndividual(ind).getTypes(Node.ATOM).iterator().next();
    }

    public ATermAppl getType(ATermAppl ind, boolean direct) {
        if (!isIndividual(ind)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return null;
            else
                throw new UnsupportedFeatureException(ind + " is not an individual!");
        }

        realize();

        Set setOfSets = taxonomy.getTypes(ind, direct);
        Set set = (Set) setOfSets.iterator().next();
        return (ATermAppl) set.iterator().next();
    }

    /** 
     * Returns all the instances of concept c. If TOP concept is used every individual in the
     * knowledge base will be returned
     * 
     * @param c class whose instanceses are returned 
     * @return A set of ATerm objects
     */
    public Set getInstances(ATermAppl c) {
        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(c + " is not a class!");
        }

        if (isRealized() && taxonomy.contains(c))
            return taxonomy.getInstances(c);

        return new HashSet(retrieve(c, individuals));
    }

    /**
     * Returns the instances of class c. Depending on the second parameter the resulting
     * list will include all or only the direct instances. An individual x is a direct
     * instance of c iff x is of type c and there is no subclass d of c such that x is of
     * type d. 
     * 
     * <p>*** This function will first realize the whole ontology ***</p>
     * 
     * @param c class whose instances are returned
     * @param direct if true return only the direct instances, otherwise return all the instances
     * @return A set of ATerm objects
     */
    public Set getInstances(ATermAppl c, boolean direct) {
        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(c + " is not a class!");
        }

        if (!direct)
            return getInstances(c);

        if (ATermUtils.isPrimitive(c)) {
            realize();

            return taxonomy.getInstances(c, direct);
        }

        return Collections.EMPTY_SET;
    }

    /**
     * Returns all the classes that are equivalent to class c, excluding c itself. 
     * 
     * <p>*** This function will first classify the whole ontology ***</p>
     * 
     * @param c class whose equivalent classes are found
     * @return A set of ATerm objects
     */
    public Set getEquivalentClasses(ATermAppl c) {
        c = ATermUtils.normalize(c);

        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(c + " is not a class!");
        }

        classify();

        if (!taxonomy.contains(c))
            builder.classify(c);

        return taxonomy.getEquivalents(c);
    }

    /**
     * Returns all the classes that are equivalent to class c, including c itself.
     * 
     * <p>*** This function will first classify the whole ontology ***</p>
     * 
     * @param c class whose equivalent classes are found
     * @return A set of ATerm objects
     */
    public Set getAllEquivalentClasses(ATermAppl c) {
        c = ATermUtils.normalize(c);

        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(c + " is not a class!");
        }

        classify();

        if (!taxonomy.contains(c))
            builder.classify(c);

        return taxonomy.getAllEquivalents(c);
    }

    /** 
     * Returns all the superclasses (implicitly or explicitly defined) of class c. The
     * class c itself is not included in the list. but all the other classes that
     * are sameAs c are put into the list. Also note that the returned
     * list will always have at least one element, that is TOP concept. By definition
     * TOP concept is superclass of every concept.
     * This function is equivalent to calling getSuperClasses(c, true).
     * 
     * <p>*** This function will first classify the whole ontology ***</p>
     * 
     * @param c class whose superclasses are returned 
     * @return A set of sets, where each set in the collection represents an equivalence 
     * class. The elements of the inner class are ATermAppl objects. 
     */
    public Set getSuperClasses(ATermAppl c) {
        return getSuperClasses(c, false);
    }

    /**
     * Returns the (named) subclasses of class c. Depending onthe second parameter the result
     * will include either all subclasses or only the direct subclasses.
     * 
     * A class d is a direct subclass of c iff
     * <ol>
     *   <li>d is subclass of c</li> 
     *   <li>there is no other class x different from c and d such that x is subclass 
     *   of c and d is subclass of x</li>
     * </ol> 
     * The class c itself is not included in the list but all the other classes that
     * are sameAs c are put into the list. Also note that the returned
     * list will always have at least one element. The list will either include one other
     * concept from the hierachy or the BOTTOM concept if no other class is subsumed by c. 
     * By definition BOTTOM concept is subclass of every concept. 
     * 
     * <p>*** This function will first classify the whole ontology ***</p>
     * 
     * @param c class whose subclasses are returned
     * @param direct If true return only the direct subclasses, otherwise return all the subclasses
     * @return A set of sets, where each set in the collection represents an equivalence 
     * class. The elements of the inner class are ATermAppl objects. 
     */
    public Set getSubClasses(ATermAppl c, boolean direct) {
        c = ATermUtils.normalize(c);

        if (!isClass(c)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(c + " is not a class!");
        }

        classify();

        if (!taxonomy.contains(c))
            builder.classify(c);

        return taxonomy.getSubs(c, direct);
    }

    /**
     * Return all the super properties of p.
     * 
     * @param prop
     * @return A set of sets, where each set in the collection represents a set of equivalent 
     * properties. The elements of the inner class are Role objects. 
     */
    public Set getSuperProperties(ATermAppl prop) {
        return getSuperProperties(prop, false);
    }

    /**
     * Return the super properties of p. Depending on the second parameter the result
     * will include either all super properties or only the direct super properties.
     * 
     * @param prop
     * @param direct If true return only the direct super properties, otherwise return all the 
     * super properties
     * @return A set of sets, where each set in the collection represents a set of equivalent 
     * properties. The elements of the inner class are Role objects. 
     */
    public Set getSuperProperties(ATermAppl prop, boolean direct) {
        prepare();

        return rbox.getTaxonomy().getSupers(prop, direct);
    }

    /**
     * Return all the sub properties of p.
     * 
     * @param prop
     * @return A set of sets, where each set in the collection represents a set of equivalent 
     * properties. The elements of the inner class are ATermAppl objects. 
     */
    public Set getSubProperties(ATermAppl prop) {
        return getSubProperties(prop, false);
    }

    /**
     * Return the sub properties of p. Depending on the second parameter the result
     * will include either all subproperties or only the direct subproperties.
     * 
     * @param prop
     * @param direct If true return only the direct subproperties, otherwise return all the subproperties
     * @return A set of sets, where each set in the collection represents a set of equivalent 
     * properties. The elements of the inner class are ATermAppl objects. 
     */
    public Set getSubProperties(ATermAppl prop, boolean direct) {
        prepare();

        return rbox.getTaxonomy().getSubs(prop, direct);
    }

    /**
     * Return all the properties that are equivalent to p.
     * 
     * @param prop
     * @return A set of ATermAppl objects. 
     */
    public Set getEquivalentProperties(ATermAppl prop) {
        prepare();

        return rbox.getTaxonomy().getEquivalents(prop);
    }

    public Set getAllEquivalentProperties(ATermAppl prop) {
        prepare();

        return rbox.getTaxonomy().getAllEquivalents(prop);
    }

    /**
     * Return the inverse property and all its equivalent properties.
     * 
     * @param prop
     * @return
     */
    public Set getInverses(ATerm name) {
        Role prop = rbox.getRole(name);
        if (prop == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(name + " is not a property!");
        }
        Role invR = prop.getInverse();
        if (invR != null && !invR.isAnon()) {
            Set inverses = getAllEquivalentProperties(invR.getName());
            return inverses;
        }

        return SetUtils.EMPTY_SET;
    }

    /**
     * Return the (explicit or implicit) domain restrictions on the property. Unlike
     * other functions the result may contain unnamed classes (represented as ATerm
     * objects). If the domain is an intersection then all the elements of the 
     * intersection will be included in the resulting set. 
     * 
     * @param prop
     * @return
     */
    public Set getDomains(ATermAppl name) {
        Set set = new HashSet();
        Role prop = rbox.getRole(name);
        if (prop == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(name + " is not a property!");
        }

        ATermAppl domain = prop.getDomain();
        if (domain != null) {
            if (ATermUtils.isAnd(domain))
                set = ATermUtils.getPrimitives((ATermList) domain.getArgument(0));
            else if (ATermUtils.isPrimitive(domain))
                set = SetUtils.singleton(domain);
        }

        return set;
    }

    /**
     * Return the (explicit or implicit) range restrictions on the property. Unlike
     * other functions the result may contain unnamed classes (represented as ATerm
     * objects). If the range is an intersection then all the elements of the 
     * intersection will be included in the resulting set. 
     * 
     * @param prop
     * @return
     */
    public Set getRanges(ATerm name) {
        ensureConsistency();

        Set set = SetUtils.EMPTY_SET;
        Role prop = rbox.getRole(name);
        if (prop == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return set;
            else
                throw new UnsupportedFeatureException(name + " is not a property!");
        }
        ATermAppl range = prop.getRange();
        if (range != null) {
            if (ATermUtils.isAnd(range))
                set = ATermUtils.getPrimitives((ATermList) range.getArgument(0));
            else if (ATermUtils.isPrimitive(range))
                set = SetUtils.singleton(range);
        }

        return set;
    }

    /**
     * Return all the indviduals asserted to be equal to the given individual inluding
     * the individual itself.
     * 
     * @param name
     * @return
     */
    public Set getAllSames(ATermAppl name) {
        ensureConsistency();

        Set knowns = new HashSet();
        Set unknowns = new HashSet();

        Individual ind = abox.getPseudoModel().getIndividual(name);
        if (ind == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return SetUtils.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(name + " is not an individual!");
        }

        if (ind.isMerged() && !ind.getMergeDependency(true).isIndependent()) {
            knowns.add(name);
            abox.getSames((Individual) ind.getSame(), unknowns, unknowns);
            unknowns.remove(name);
        } else
            abox.getSames((Individual) ind.getSame(), knowns, unknowns);

        //      System.out.print( name + " " + ind + " " + knowns + " + " + unknowns + " = ");

        for (Iterator i = unknowns.iterator(); i.hasNext();) {
            ATermAppl other = (ATermAppl) i.next();
            if (abox.isSameAs(name, other))
                knowns.add(other);
        }
        //      System.out.println( knowns );

        return knowns;
    }

    /**
     * Return all the indviduals asserted to be equal to the given individual but not the
     * the individual itself.
     * 
     * @param name
     * @return
     */
    public Set getSames(ATermAppl name) {
        Set sames = getAllSames(name);
        sames.remove(name);

        return sames;
    }

    /**
     * Run the given RDQL query. 
     * 
     * @deprecated Use QueryEngine.exec methods instead
     *  
     * @param query
     * @return
     */
    public QueryResults runQuery(String queryStr) {
        return QueryEngine.exec(queryStr, this, Syntax.syntaxRDQL);
    }

    /**
     * Return all literal values for a given dataproperty that belongs to
     * the specified datatype.
     * 
     * @param r
     * @param x
     * @param lang
     * @return List of ATermAppl objects representing literals. These objects are in the form
     * literal(value, lang, datatypeURI).
     */
    public List getDataPropertyValues(ATermAppl r, ATermAppl x, Datatype datatype) {
        ensureConsistency();

        Individual ind = abox.getIndividual(x);
        Role role = rbox.getRole(r);

        if (ind == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_LIST;
            else
                throw new UnsupportedFeatureException(x + " is not an individual!");
        }

        if (role == null || !role.isDatatypeRole()) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_LIST;
            else
                throw new UnsupportedFeatureException(r + " is not a known data property!");
        }

        return abox.getObviousDataPropertyValues(x, role, datatype);
    }

    public Set getPossibleProperties(ATermAppl x) {
        ensureConsistency();

        Individual ind = abox.getIndividual(x);

        if (ind == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_SET;
            else
                throw new UnsupportedFeatureException(x + " is not an individual!");
        }

        return abox.getPossibleProperties(x);
    }

    /**
     * Return all literal values for a given dataproperty that has the specified 
     * language identifier.
     * 
     * @param r
     * @param x
     * @param lang
     * @return List of ATermAppl objects.
     */
    public List getDataPropertyValues(ATermAppl r, ATermAppl x, String lang) {
        List values = getDataPropertyValues(r, x);
        if (lang == null)
            return values;

        List result = new ArrayList();
        Iterator i = values.iterator();
        while (i.hasNext()) {
            ATermAppl lit = (ATermAppl) i.next();
            String litLang = ((ATermAppl) lit.getArgument(1)).getName();

            if (litLang.equals(lang))
                result.add(lit);
        }

        return result;
    }

    /**
     * Return all literal values for a given dataproperty and subject value.
     * 
     * @param r
     * @param x
     * @return List of ATermAppl objects.
     */
    public List getDataPropertyValues(ATermAppl r, ATermAppl x) {
        return getDataPropertyValues(r, x, (Datatype) null);
    }

    /**
     * Return all property values for a given object property and subject value.
     * 
     * @param r
     * @param x
     * @return A list of ATermAppl objects
     */
    public List getObjectPropertyValues(ATermAppl r, ATermAppl x) {
        Role role = rbox.getRole(r);

        if (role == null || !role.isObjectRole())
            throw new UnsupportedFeatureException(
                    "getObjectPropertyValues function can only be used with object properties. " + "Property: "
                            + role);

        // TODO  get rid of unnecessary Set + List creation
        Set knowns = new HashSet();
        Set unknowns = new HashSet();

        abox.getObjectPropertyValues(x, role, knowns, unknowns);

        if (!unknowns.isEmpty()) {
            ATermAppl valueX = ATermUtils.makeHasValue(role.getInverse().getName(), x);
            ATermAppl c = ATermUtils.normalize(valueX);

            binaryInstanceRetrieval(c, new ArrayList(unknowns), knowns);
        }

        return new ArrayList(knowns);
    }

    /**
     * Return all property values for a given property and subject value. 
     * 
     * @param r
     * @param x
     * @return List of ATermAppl objects.
     */
    public List getPropertyValues(ATermAppl r, ATermAppl x) {
        Role role = rbox.getRole(r);

        if (role.isObjectRole())
            return getObjectPropertyValues(r, x);
        else
            return getDataPropertyValues(r, x);
    }

    /**
     * List all subjects with a given property and property value.
     * 
     * @param r
     * @param x If property is an object property an ATermAppl object
     * that is the URI of the individual, if the property is a data property 
     * an ATerm object that contains the literal value (See
     * {#link #getIndividualsWithDataProperty(ATermAppl, ATermAppl)} for details)
     * @return List of ATermAppl objects.
     */
    public List getIndividualsWithProperty(ATermAppl r, ATermAppl x) {
        Role role = rbox.getRole(r);

        if (role == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_LIST;
            else
                throw new UnsupportedFeatureException(r + " is not a known property!");
        }

        if (role.isObjectRole())
            return getIndividualsWithObjectProperty(r, x);
        else
            return getIndividualsWithDataProperty(r, x);
    }

    /**
     * List all subjects with the given literal value for the specified
     * data property. 
     * 
     * @param r An ATerm object that contains the literal value in the form
     * literal(lexicalValue, langIdentifier, datatypeURI). Should be created
     * with ATermUtils.makeXXXLiteral() functions.
     * @param x
     * @return List of ATermAppl objects.
     */
    public List getIndividualsWithDataProperty(ATermAppl r, ATermAppl litValue) {
        ensureConsistency();

        Object value = getDatatypeReasoner().getValue(litValue);

        if (value == null) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_LIST;
            else
                throw new UnsupportedFeatureException(litValue + " is not a valid literal value!");
        }

        List knowns = new ArrayList();
        List unknowns = new ArrayList();

        Iterator i = abox.getIndIterator();
        while (i.hasNext()) {
            ATermAppl subj = ((Individual) i.next()).getName();

            Bool hasObviousValue = abox.hasObviousDataPropertyValue(subj, r, value);
            if (hasObviousValue.isUnknown())
                unknowns.add(subj);
            else if (hasObviousValue.isTrue())
                knowns.add(subj);
        }

        if (!unknowns.isEmpty()) {
            ATermAppl c = ATermUtils.normalize(ATermUtils.makeHasValue(r, litValue));

            binaryInstanceRetrieval(c, unknowns, knowns);
        }

        return knowns;
    }

    /**
     * List all subjects with the given value for the specified object
     * property. 
     * 
     * @param r
     * @param o An ATerm object that is the URI of an individual
     * @return List of ATermAppl objects.
     */
    public List getIndividualsWithObjectProperty(ATermAppl r, ATermAppl o) {
        ensureConsistency();

        if (!isIndividual(o)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_LIST;
            else
                throw new UnsupportedFeatureException(o + " is not an individual!");
        }

        Role role = rbox.getRole(r);

        ATermAppl invR = role.getInverse().getName();

        return getObjectPropertyValues(invR, o);
    }

    /**
     * List all properties asserted between a subject and object.
     * 
     */
    public List getProperties(ATermAppl s, ATermAppl o) {
        if (!isIndividual(s)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_LIST;
            else
                throw new UnsupportedFeatureException(s + " is not an individual!");
        }

        if (!isIndividual(o)) {
            if (PelletOptions.SILENT_UNDEFINED_ENTITY_HANDLING)
                return Collections.EMPTY_LIST;
            else
                throw new UnsupportedFeatureException(o + " is not an individual!");
        }

        List props = new ArrayList();

        Iterator i = ATermUtils.isLiteral(o) ? getDataProperties().iterator() : getObjectProperties().iterator();
        while (i.hasNext()) {
            ATermAppl p = (ATermAppl) i.next();
            if (abox.hasPropertyValue(s, p, o))
                props.add(p);
        }

        return props;
    }

    public Map getPropertyValues(ATermAppl pred) {
        Map result = new HashMap();

        Iterator subjects = retrieveIndividualsWithProperty(pred).iterator();
        while (subjects.hasNext()) {
            ATermAppl subj = (ATermAppl) subjects.next();
            List objects = getPropertyValues(pred, subj);
            if (!objects.isEmpty())
                result.put(subj, objects);
        }

        return result;
    }

    /**
     * Return all the indiviuals that belong to the given class which is not
     * necessarily a named class.
     * 
     * @param d
     * @return
     */
    public List retrieve(ATermAppl d, Collection individuals) {
        ensureConsistency();

        ATermAppl c = ATermUtils.normalize(d);

        if (instances.containsKey(c))
            return (List) instances.get(c);
        else if (isRealized() && taxonomy.contains(c))
            return new ArrayList(getInstances(c));

        Timer timer = timers.startTimer("retrieve");
        ATermAppl notC = ATermUtils.negate(c);
        List knowns = new ArrayList();
        //        Map unknown = new HashMap();

        // this is mostly to ensure that a model for notC is cached
        if (!abox.isSatisfiable(notC)) {
            // if negation is unsat c itself is TOP
            knowns.addAll(getIndividuals());
        } else if (abox.isSatisfiable(c)) {
            Set subs = isClassified() ? taxonomy.getSubs(c, false, true) : SetUtils.EMPTY_SET;
            subs.remove(ATermUtils.BOTTOM);

            List unknowns = new ArrayList();
            Iterator i = individuals.iterator();
            while (i.hasNext()) {
                ATermAppl x = (ATermAppl) i.next();

                Bool isType = abox.isKnownType(x, c, subs);
                if (isType.isTrue())
                    knowns.add(x);
                else if (isType.isUnknown()) {
                    abox.isKnownType(x, c, subs);
                    unknowns.add(x);
                }
            }

            if (!unknowns.isEmpty() && abox.isType(unknowns, c)) {
                binaryInstanceRetrieval(c, unknowns, knowns);
            }
        }
        timer.stop();

        if (PelletOptions.CACHE_RETRIEVAL)
            instances.put(c, knowns);

        return knowns;
    }

    //   private List filterList(ATermAppl c, List candidates, Collection results) {
    //       List filtered = candidates;
    //       
    //       Clash clash = abox.getLastClash();
    //       // if the clash is not dependant on a branch and the node is one of the candidates remove it
    //       if( clash.depends.isIndependent() && clash.isAtomic() && clash.args[0].equals(c) ) {
    //           int index = candidates.indexOf( clash.node.getName() );
    //           if( index >= 0 ) {
    //               System.out.println( 
    //                   "Filter obvious instance " + clash.node + " while retrieving " + c );
    //               Collections.swap( candidates, index, 0 );
    //               results.add( candidates.get( 0 ) );
    //               filtered = candidates.subList( 1, candidates.size() );
    //           }
    //       }
    //       
    //       return filtered;
    //   }

    public List retrieveIndividualsWithProperty(ATermAppl r) {
        ensureConsistency();

        List result = new ArrayList();
        Iterator i = abox.getIndIterator();
        while (i.hasNext()) {
            ATermAppl x = ((Individual) i.next()).getName();

            if (!abox.hasObviousPropertyValue(x, r, null).isFalse())
                result.add(x);
        }

        return result;
    }

    public void binaryInstanceRetrieval(ATermAppl c, List candidates, Collection results) {
        if (candidates.isEmpty())
            return;
        else {
            List[] partitions = partition(candidates);
            partitionInstanceRetrieval(c, partitions, results);
        }
    }

    private void partitionInstanceRetrieval(ATermAppl c, List[] partitions, Collection results) {
        if (partitions[0].size() == 1) {
            ATermAppl i = (ATermAppl) partitions[0].get(0);
            binaryInstanceRetrieval(c, partitions[1], results);

            if (isType(i, c))
                results.add(i);
        } else if (!abox.isType(partitions[0], c)) {
            binaryInstanceRetrieval(c, partitions[1], results);
        } else {
            //          partitions[0] = filterList(c, partitions[0], results);
            if (!abox.isType(partitions[1], c)) {
                binaryInstanceRetrieval(c, partitions[0], results);
            } else {
                //             partitions[1] = filterList(c, partitions[1], results);
                binaryInstanceRetrieval(c, partitions[0], results);
                binaryInstanceRetrieval(c, partitions[1], results);
            }
        }
    }

    private List[] partition(List candidates) {
        List[] partitions = new List[2];
        int n = candidates.size();
        if (n <= 1) {
            partitions[0] = candidates;
            partitions[1] = new ArrayList();
        } else {
            partitions[0] = candidates.subList(0, n / 2);
            partitions[1] = candidates.subList(n / 2, n);
        }

        return partitions;
    }

    //   private List binarySubClassRetrieval(ATermAppl c, List candidates) {
    //      if(candidates.isEmpty())
    //         return new ArrayList();
    //      else{
    //         List[] partitions = partition(candidates);
    //         return partitionSubClassRetrieval(c, partitions);
    //      }
    //   }
    //   
    //   private List partitionSubClassRetrieval(ATermAppl c, List[] partitions) {      
    //      if(partitions[0].size() == 1) {
    //         ATermAppl d = (ATermAppl) partitions[0].get(0);
    //         List l = binarySubClassRetrieval(c, partitions[1]);
    //
    //         if(isSubclassOf(d, c))
    //            l.add(d);
    //         
    //         return l;
    //      }
    //      else if(!abox.isSubClassOf(partitions[0], c))
    //         return binarySubClassRetrieval(c, partitions[1]);
    //      else if(!abox.isSubClassOf(partitions[1], c))
    //         return binarySubClassRetrieval(c, partitions[0]);
    //      else {
    //         List l1 = binarySubClassRetrieval(c, partitions[0]);
    //         List l2 = binarySubClassRetrieval(c, partitions[1]);
    //         
    //         l1.addAll(l2);
    //         
    //         return l1;
    //      }
    //   }

    /**
     * Print the class hierarchy on the standard output.
     */
    public void printClassTree() {
        classify();

        taxonomy.print();
    }

    public void printClassTree(OutputFormatter out) {
        classify();

        taxonomy.print(out);
    }

    public boolean doExplanation() {
        return abox.doExplanation();
    }

    /**
     * @param doExplanation The doExplanation to set.
     */
    public void setDoExplanation(boolean doExplanation) {
        abox.setDoExplanation(doExplanation);
    }

    public String getExplanation() {
        return abox.getExplanation();
    }

    public void setDoDependencyAxioms(boolean doDepAxioms) {
        if (log.isDebugEnabled())
            log.debug("Setting DoDependencyAxioms = " + doDepAxioms);
    }

    public boolean getDoDependencyAxioms() {
        return false;
    }

    public Set getExplanationSet() {
        return SetUtils.EMPTY_SET;
    }

    /**
     * @param rbox The rbox to set.
     */
    public void setRBox(RBox rbox) {
        this.rbox = rbox;
    }

    /**
     * @param tbox The tbox to set.
     */
    public void setTBox(TBox tbox) {
        this.tbox = tbox;
    }

    /**
     * Choose a completion strategy based on the expressivity of the KB. The
     * abox given is not necessarily the ABox that belongs to this KB but
     * can be a derivative.
     * 
     * @return
     */
    CompletionStrategy chooseStrategy(ABox abox) {
        //if there are dl-safe rules present, use RuleStrategy which is a subclass of SHOIN
        // only problem is, we're using SHOIN everytime there are rule-  it is  faster to use SHN + Rules in some cases      
        if (this.getRules() != null) {
            return new RuleStrategy(abox);
        }
        if (PelletOptions.DEFAULT_COMPLETION_STRATEGY != null) {
            Class[] types = new Class[] { ABox.class };
            Object[] args = new Object[] { abox };
            try {
                Constructor cons = PelletOptions.DEFAULT_COMPLETION_STRATEGY.getConstructor(types);
                return (CompletionStrategy) cons.newInstance(args);
            } catch (Exception e) {
                e.printStackTrace();
                throw new InternalReasonerException(
                        "Failed to create the default completion strategy defined in PelletOptions!");
            }
        } else if (PelletOptions.USE_COMPLETION_STRATEGY) {
            Expressivity expressivity = getExpressivity();

            boolean emptyStrategy = (abox.size() == 1)
                    && ((Individual) abox.getIndIterator().next()).getOutEdges().isEmpty();

            boolean fullDatatypeReasoning = PelletOptions.USE_FULL_DATATYPE_REASONING
                    && (expressivity.hasCardinalityD() || expressivity.hasKeys());

            if (!fullDatatypeReasoning) {
                if (expressivity.hasNominal()) {
                    if (expressivity.hasInverse())
                        return new SHOINStrategy(abox);
                    else
                        return new SHONStrategy(abox);
                } else if (expressivity.hasInverse())
                    return new SHINStrategy(abox);
                else if (emptyStrategy && !expressivity.hasCardinalityD() && !expressivity.hasKeys())
                    return new EmptySHNStrategy(abox);
                else
                    return new SHNStrategy(abox);
            }
        }

        return new SHOINStrategy(abox);
    }

    /**
     * Returns the URI of the ontology this KB belongs to. A KB is not always 
     * guaranteed to have this value because 1) Parser does not always know
     * the URI of the onotlogy (i.e. Jena models) 2) Multiple ontologies may
     * be loaded to the same KB (in this case this value may return one of
     * the ontologies arbitrarily)
     * 
     * This value has no siginificance in reasoning except for EconnectedKB's.
     * 
     * @return 
     */
    public String getOntology() {
        return ontology;
    }

    /**
     * Set the URI of the ontology this Kb belongs to.
     * 
     * @param ontology 
     */
    public void setOntology(String ontology) {
        this.ontology = ontology;
    }

    /**
     * Set a timeout for the main timer. Used to stop an automated test after a
     * reasonable amount of time has passed.
     * 
     * @param timeout
     */
    public void setTimeout(long timeout) {
        timers.mainTimer.setTimeout(timeout);
    }

    /**
     * @param term
     * @return
     */
    Role getRole(ATerm term) {
        return rbox.getRole(term);
    }

    /**
     * Get the classification results.
     */
    public Taxonomy getTaxonomy() {
        classify();

        return taxonomy;
    }

    public TaxonomyBuilder getTaxonomyBuilder() {
        if (builder == null)
            builder = new TaxonomyBuilder(this);

        return builder;
    }

    public Taxonomy getRoleTaxonomy() {
        prepare();

        return rbox.getTaxonomy();
    }

    public SizeEstimate getSizeEstimate() {
        return estimate;
    }

    public void setRules(Set rules) {
        // TODO Auto-generated method stub
        this.rules = rules;
    }

    public Set getRules() {
        // TODO Auto-generated method stub
        return this.rules;
    }
}