Package com.clarkparsia.pellet.el

Source Code of com.clarkparsia.pellet.el.ELClassifier

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

package com.clarkparsia.pellet.el;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.mindswap.pellet.Role;
import org.mindswap.pellet.taxonomy.CDOptimizedTaxonomyBuilder;
import org.mindswap.pellet.taxonomy.POTaxonomyBuilder;
import org.mindswap.pellet.taxonomy.TaxonomyBuilder;
import org.mindswap.pellet.utils.ATermUtils;
import org.mindswap.pellet.utils.MultiValueMap;
import org.mindswap.pellet.utils.PartialOrderComparator;
import org.mindswap.pellet.utils.PartialOrderRelation;
import org.mindswap.pellet.utils.Timer;
import org.mindswap.pellet.utils.Timers;

import aterm.AFun;
import aterm.ATermAppl;
import aterm.ATermList;

import com.clarkparsia.pellet.utils.CollectionUtils;

/**
* <p>
* Title:
* </p>
* <p>
* Description:
* </p>
* <p>
* Copyright: Copyright (c) 2007
* </p>
* <p>
* Company: Clark & Parsia, LLC. <http://www.clarkparsia.com>
* </p>
*
* @author Evren Sirin
*/
public class ELClassifier extends CDOptimizedTaxonomyBuilder implements TaxonomyBuilder {
  public static final Logger            logger  = Logger.getLogger( ELClassifier.class.getName() );

  public final Timers                timers  = new Timers();

  public ConceptInfo                TOP;
  public ConceptInfo                BOTTOM;
 
  private boolean                  hasComplexRoles;

  private MultiValueMap<ConceptInfo, Trigger>    queue;

  private Map<ATermAppl, ConceptInfo>        concepts;

  private RoleChainCache              roleChains;
  private RoleRestrictionCache          roleRestrictions;

  private PartialOrderComparator<ATermAppl>  subsumptionComparator  = new PartialOrderComparator<ATermAppl>() {
    public PartialOrderRelation compare(ATermAppl a, ATermAppl b) {
//      if( a == ATermUtils.BOTTOM )
//        return PartialOrderRelation.LESS;
//      else if( b == ATermUtils.TOP )
//        return PartialOrderRelation.GREATER;

      ConceptInfo aInfo = getInfo( a );
      ConceptInfo bInfo = getInfo( b );

      if( aInfo.hasSuperClass( bInfo ) ) {
        if( bInfo.hasSuperClass( aInfo ) ) {
          return PartialOrderRelation.EQUAL;
        }
        else {
          return PartialOrderRelation.LESS;
        }
      }
      else if( bInfo.hasSuperClass( aInfo ) ) {
        return PartialOrderRelation.GREATER;
      }
      else {
        return PartialOrderRelation.INCOMPARABLE;
      }
    }
  };

  public ELClassifier() {
  }
 
  protected void reset() {
    super.reset();
   
    hasComplexRoles = kb.getExpressivity().hasTransitivity()
        || kb.getExpressivity().hasComplexSubRoles();
   
    queue = new MultiValueMap<ConceptInfo, Trigger>();
    concepts = CollectionUtils.makeMap();
   
    roleChains = new RoleChainCache(kb);
    roleRestrictions = new RoleRestrictionCache( kb.getRBox() );
  }

  /**
   * {@inheritDoc}
   */
  public boolean classify() {
    reset();
   
    kb.prepare();
   
    Timer t = timers.startTimer( "createConcepts" );
    logger.info( "Creating structures" );
    createConcepts();
    logger.info( "Created structures" );
    t.stop();
   
    monitor.setProgressTitle( "Classifiying" );
    monitor.setProgressLength( queue.size() );
    monitor.taskStarted();

    printStructures();

    logger.info( "Processing queue" );
    t = timers.startTimer( "processQueue" );
    processQueue();
    t.stop();
    logger.info( "Processed queue" );

    if( logger.isLoggable( Level.FINE ) )
      print();

    logger.info( "Building hierarchy" );
    t = timers.startTimer( "buildHierarchy" );
   
    taxonomy = new ELTaxonomyBuilder().build( concepts );
//    buildTaxonomyWithPO();
   
    t.stop();
    logger.info( "Builded hierarchy" );

    monitor.taskFinished();
   
    return true;
  }

  private void buildTaxonomyWithPO() {
    POTaxonomyBuilder builder = new POTaxonomyBuilder(kb, subsumptionComparator);
    taxonomy = builder.getTaxonomy();
   
    for( ConceptInfo ci : concepts.values() ) {
      classify( ci );
    }
  }
 
  private void classify(ConceptInfo ci) {
    ATermAppl c = ci.getConcept();
    if( !ATermUtils.isPrimitive( c ) )
      return;
   
    if( ci.getSuperClasses().contains(BOTTOM) ) {
      taxonomy.addEquivalentNode( c, taxonomy.getBottom() );
      return;
    }
   
    Set<ATermAppl> equivalents = new HashSet<ATermAppl>();
    for( ConceptInfo subsumer : ci.getSuperClasses() ) {
      if( !ATermUtils.isPrimitive( subsumer.getConcept() ) ) {
        continue;
      }

      if( ci.equals( subsumer ) ) {
        continue;
      }
      else if( subsumer.hasSuperClass( ci ) ) {
        equivalents.add( subsumer.getConcept() );
      }
      else {
        classify( subsumer );
      }     
    }

    taxonomy.addEquivalents( c, equivalents );
  }

  private void addExistential(ConceptInfo ci, ATermAppl prop, ConceptInfo qi) {
    if (ci.hasSuccessor(prop, qi)) return;
   
    addExistentialP( ci, prop, qi );

    Set<Set<ATermAppl>> supEqs = kb.getSuperProperties(prop);
    for( Set<ATermAppl> supEq : supEqs ) {
      for( ATermAppl sup : supEq ) {
        addExistentialP( ci, sup, qi );
      }
    }
  }

  private void addExistentialP(ConceptInfo ci, ATermAppl prop, ConceptInfo qi) {
    if (ci.hasSuccessor(prop, qi)) return;
   
    for( ConceptInfo supInfo : qi.getSuperClasses() ) {
      if( ci.addSuccessor( prop, supInfo ) ) {
        if (supInfo.equals(BOTTOM)) {
          addSubsumer(ci, BOTTOM);
         
          Iterator<ConceptInfo> preds = ci.getPredecessors().flattenedValues();
          while( preds.hasNext() ) {
            addSubsumer(preds.next(), BOTTOM);
          }
        }
       
        ATermAppl some = ATermUtils.makeSomeValues( prop, supInfo.getConcept() );
        ConceptInfo si = getInfo( some );
        if( si != null ) {
          addToQueue( ci, si.getTriggers() );
        }
      }
    }
   
    ATermAppl q = qi.getConcept();
    if (ATermUtils.isAnd(q)) {
      ATermList list = (ATermList) q.getArgument( 0 );
      while( !list.isEmpty() ) {
        ATermAppl conj = (ATermAppl) list.getFirst();
        ConceptInfo conjInfo = createConcept(conj);
        if( ci.addSuccessor( prop, conjInfo ) ) {
          ATermAppl some = ATermUtils.makeSomeValues( prop, conj );
          ConceptInfo si = createConcept( some );
          addToQueue( ci, si.getTriggers() );
        }

        list = list.getNext();
      }
    }

    ATermAppl propRange = roleRestrictions.getRange(prop);
    if (propRange != null) {
      ATermAppl some = ATermUtils.makeSomeValues(prop, propRange);
      ConceptInfo si = createConcept(some);
      addSubsumer(ci, si);
    }
   
    if( hasComplexRoles ) {
      for (Entry<ATermAppl, Set<ConceptInfo>> entry : ci.getPredecessors().entrySet()) {
        ATermAppl predProp = entry.getKey();
        for (ConceptInfo pred : entry.getValue()) {
          for (ATermAppl supProp : roleChains.getAllSuperRoles(predProp, prop)) {
            addExistential(pred, supProp, qi);
          }
        }
      }
 
      for (Entry<ATermAppl, Set<ConceptInfo>> entry : qi.getSuccessors().entrySet()) {
        ATermAppl succProp = entry.getKey();
        for (ConceptInfo succ : entry.getValue()) {
          for (ATermAppl supProp : roleChains.getAllSuperRoles(prop, succProp)) {
            addExistential(ci, supProp, succ);
          }
        }
      }
    }
  }

  private void addToQueue(ConceptInfo ci, Set<Trigger> triggers) {
    if( queue.addAll( ci, triggers ) ) {
      if( logger.isLoggable( Level.FINE ) )
        logger.fine( "Add to queue: " + ci + " " + triggers );
    }
  }

  private void addSubsumer(ConceptInfo ci, ConceptInfo supInfo) {
    if (ci.hasSuperClass(supInfo)) return;

    ci.addSuperClass(supInfo);
   
    if (ATermUtils.isBottom(supInfo.getConcept())) {     
      Iterator<ConceptInfo> preds = ci.getPredecessors().flattenedValues();
      while( preds.hasNext() ) {
        addSubsumer( preds.next(), supInfo );
      }
      return;
    }
   
    addToQueue(ci, supInfo.getTriggers());   
   
    ATermAppl c = supInfo.getConcept();
    if( logger.isLoggable( Level.FINE ) )
      logger.fine( "Adding subsumers to " + ci + " " + c + " " + ci.getSuperClasses() );

    if( ATermUtils.isAnd( c ) ) {
      ATermList list = (ATermList) c.getArgument( 0 );
      while( !list.isEmpty() ) {
        ATermAppl conj = (ATermAppl) list.getFirst();
       
        addSubsumer( ci, createConcept( conj ) );

        list = list.getNext();
      }
    } else if( ATermUtils.isSomeValues( c ) ) {
      ATermAppl p = (ATermAppl) c.getArgument( 0 );
      ATermAppl qualification = (ATermAppl) c.getArgument( 1 );
      ConceptInfo q = createConcept( qualification );

      addExistential( ci, p, q );
    } else {
      assert ATermUtils.isPrimitive( c );
    }

    for( Map.Entry<ATermAppl, Set<ConceptInfo>> e : ci.getPredecessors().entrySet() ) {
      ATermAppl prop = e.getKey();
      for( ConceptInfo pred: e.getValue() ) {
        ATermAppl some = ATermUtils.makeSomeValues( prop, c );
        ConceptInfo si = getInfo( some );
        if( si != null) {
          addToQueue( pred, si.getTriggers() );
        }
      }
    }
  }

  private ConceptInfo createConcept(ATermAppl c) {
    ConceptInfo ci = getInfo( c );
    if( ci == null ) {
      ci = new ConceptInfo( c, hasComplexRoles, false );
      concepts.put( c, ci );
      ci.addSuperClass( TOP );
      addSubsumer(ci, ci);

      if( ATermUtils.isAnd( c ) ) {
        ConceptInfo[] conjuncts = createConceptArray((ATermList) c.getArgument(0));
        for (ConceptInfo conjInfo : conjuncts) {
          conjInfo.addTrigger(new Trigger(conjuncts, ci));
        }
      } else if( ATermUtils.isSomeValues( c ) ) {
        ATermAppl q = (ATermAppl) c.getArgument(1);
        createConcept(q);
        ci.addTrigger(new Trigger(ci));
      }
    }

    return ci;
 

  private ConceptInfo[] createConceptArray(ATermList list) {
    ConceptInfo[] a = new ConceptInfo[list.getLength()];

    for( int i = 0; !list.isEmpty(); list = list.getNext() )
      a[i++] = createConcept( (ATermAppl) list.getFirst() );

    return a;
  }

  private void createConceptsFromAxiom(ATermAppl sub, ATermAppl sup) {
    ConceptInfo ciSub = createConcept( sub );
    ConceptInfo ciSup = createConcept( sup );

    Trigger trigger = new Trigger( ciSup );
   
    ciSub.addTrigger(trigger);
  }

  private void toELSubClassAxioms(ATermAppl axiom) {
    AFun fun = axiom.getAFun();
    ATermAppl sub = (ATermAppl) axiom.getArgument(0);
    ATermAppl sup = (ATermAppl) axiom.getArgument(1);
   
    ATermAppl subEL = ELSyntaxUtils.simplify(sub);
    if (fun.equals(ATermUtils.SUBFUN)) {
      if (ATermUtils.isPrimitive(sup) || ATermUtils.isBottom(sup)) {
        createConceptsFromAxiom(subEL, sup);
        return;
      }
     
      ATermAppl supEL = ELSyntaxUtils.simplify(sup);
      createConceptsFromAxiom(subEL, supEL);
    } else if (fun.equals( ATermUtils.EQCLASSFUN )) {
      ATermAppl supEL = ELSyntaxUtils.simplify(sup);
      createConceptsFromAxiom(subEL, supEL);
      createConceptsFromAxiom(supEL, subEL);
    } else {
      throw new IllegalArgumentException("Axiom " + axiom + " is not EL.");
    }
  }
 
  private void normalizeAxioms() {
    //EquivalentClass -> SubClasses
    //Disjoint Classes -> SubClass
    //Normalize ATerm lists to sets
    Collection<ATermAppl> assertedAxioms = kb.getTBox().getAssertedAxioms();
    for (ATermAppl assertedAxiom : assertedAxioms ) {
      toELSubClassAxioms(assertedAxiom);
    }

    //Convert Role Domains to axioms
    for (Entry<ATermAppl, ATermAppl> entry : roleRestrictions.getDomains().entrySet()) {
      ATermAppl roleName = entry.getKey();
      ATermAppl domain = entry.getValue();
      createConceptsFromAxiom(ATermUtils.makeSomeValues(roleName, ATermUtils.TOP), domain);
    }
   
    //Convert Reflexive Roles to axioms
    for (Role role : kb.getRBox().getRoles()) {
      if (role.isReflexive()) {
        ATermAppl range = roleRestrictions.getRange(role.getName());
        if (range == null) continue;
       
        createConceptsFromAxiom(ATermUtils.TOP, range);
      }
    }
  }

  private void createConcepts() {
    TOP    = new ConceptInfo( ATermUtils.TOP, hasComplexRoles, false );
    concepts.put( ATermUtils.TOP, TOP );
    TOP.addSuperClass(TOP);
   
    BOTTOM  = new ConceptInfo( ATermUtils.BOTTOM, hasComplexRoles, false );
    concepts.put( ATermUtils.BOTTOM, BOTTOM );
    BOTTOM.addSuperClass(BOTTOM);
   
    for (ATermAppl c : kb.getClasses()) {
      createConcept(c);
    }
   
    normalizeAxioms();
   
    final Set<Trigger> TOP_TRIGGERS = TOP.getTriggers();
    for( ConceptInfo ci : concepts.values() ) {
      Set<Trigger> queueList = CollectionUtils.makeSet(TOP_TRIGGERS);
      queueList.addAll( ci.getTriggers() );

      if( !queueList.isEmpty() )
        queue.addAll( ci, queueList );
    }
  }

  private ConceptInfo getInfo(ATermAppl concept) {
    return concepts.get( concept );
  }

  public void print() {
    for( ConceptInfo ci : concepts.values() ) {
      System.out.println( ci + " " + ci.getSuperClasses() );
    }
    System.out.println();
    roleChains.print();
  }

  public void printStructures() {
    if( logger.isLoggable( Level.FINE ) ) {
      for( ConceptInfo ci : concepts.values() ) {
        logger.fine( ci + "\t" + ci.getTriggers() + "\t" + ci.getSuperClasses() );
      }
    }
  }

  private void processQueue() {
    int startingSize = queue.size();
    while( !queue.isEmpty() ) {
      int processed = startingSize - queue.size();
      if( monitor.getProgress() < processed )
        monitor.setProgress( processed );

      MultiValueMap<ConceptInfo, Trigger> localQueue = queue;
      queue = new MultiValueMap<ConceptInfo, Trigger>();
     
      for (Entry<ConceptInfo, Set<Trigger>> entry : localQueue.entrySet()) {
        ConceptInfo ci = entry.getKey();
        for (Trigger trigger : entry.getValue()) {
          processTrigger(ci, trigger);
        }
      }
    }
  }

  private void processTrigger(ConceptInfo ci, Trigger trigger) {
    if (trigger.isTriggered(ci)) {
      //if( logger.isLoggable( Level.FINE ) ) logger.fine( "Process (true) for " + ci + " " + trigger );
     
      addSubsumer(ci, trigger.getConsequence());
    }
  }
}
TOP

Related Classes of com.clarkparsia.pellet.el.ELClassifier

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.