Package com.clarkparsia.pellet.el

Source Code of com.clarkparsia.pellet.el.SimplifiedELClassifier$QueueElement

// 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.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
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.Taxonomy;
import org.mindswap.pellet.taxonomy.TaxonomyBuilder;
import org.mindswap.pellet.utils.ATermUtils;
import org.mindswap.pellet.utils.MultiValueMap;
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;
import com.clarkparsia.pellet.utils.TermFactory;

/**
* <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 SimplifiedELClassifier extends CDOptimizedTaxonomyBuilder implements TaxonomyBuilder {
  public static final Logger            logger  = Logger.getLogger( SimplifiedELClassifier.class.getName() );
 
  private static class QueueElement {
    private final ConceptInfo sub;
    private final ConceptInfo sup;

    public QueueElement(ConceptInfo sub, ConceptInfo sup) {
          this.sub = sub;
          this.sup = sup;
        }
  }

  public final Timers                timers  = new Timers();
 
  private static final boolean          PREPROCESS_DOMAINS        = false;

  private static final boolean          MATERIALIZE_SUPER_PROPERTIES  = false;

  private ConceptInfo                TOP;
  private ConceptInfo                BOTTOM;

  private boolean                  hasComplexRoles;

  private Queue<QueueElement>            primaryQueue;

  private Map<ATermAppl, ConceptInfo>        concepts;

  private MultiValueMap<ATermAppl, ConceptInfo>  existentials;
  private MultiValueMap<ConceptInfo, ConceptInfo>  conjunctions;

  private RoleChainCache              roleChains;
  private RoleRestrictionCache          roleRestrictions;

  public SimplifiedELClassifier() {
  }
 
  @Override
    protected void reset() {
    super.reset();
   
    hasComplexRoles = kb.getExpressivity().hasTransitivity()
        || kb.getExpressivity().hasComplexSubRoles();
   
    primaryQueue = new LinkedList<QueueElement>();
   
    concepts = CollectionUtils.makeMap();
   
    existentials = new MultiValueMap<ATermAppl, ConceptInfo>();
    conjunctions = new MultiValueMap<ConceptInfo, ConceptInfo>();
   
    roleChains = new RoleChainCache(kb);
    roleRestrictions = new RoleRestrictionCache( kb.getRBox() );
  }

  /**
   * {@inheritDoc}
   */
  @Override
    public boolean classify() {
    logger.fine( "Reset" );
    reset();
   
    Timer t = timers.startTimer( "createConcepts" );
    logger.fine( "Creating structures" );
    createConcepts();
    logger.fine( "Created structures" );
    t.stop();
   
    int queueSize =  primaryQueue.size();
    monitor.setProgressTitle( "Classifiying" );
    monitor.setProgressLength( queueSize );
    monitor.taskStarted();
   
    logger.fine( "Processing queue" );
    t = timers.startTimer( "processQueue" );
    processQueue();
    t.stop();
    logger.fine( "Processed queue" );

    if( logger.isLoggable( Level.FINER ) ) {
      print();
    }   
   
    monitor.setProgress( queueSize );

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

    monitor.taskFinished();
   
    return true;
  }
 
  private void addSuccessor(ConceptInfo pred, ATermAppl p, ConceptInfo succ) {
    if( !pred.addSuccessor( p, succ ) ) {
      return;
   
   
    if( logger.isLoggable( Level.FINER ) ) {
      logger.finer( "Adding " + pred + " -> " + ATermUtils.toString( p ) + " -> " + succ );
    }
   
    if( succ == BOTTOM ) {     
      addToQueue( pred, BOTTOM );     
      return;
    }
   
    for( ConceptInfo supOfSucc : succ.getSuperClasses() ) {
      addSuccessor( pred, p, supOfSucc );
    }

    if( !roleChains.isAnon( p ) ) {
      if( MATERIALIZE_SUPER_PROPERTIES ) {
        if( existentials.contains( p, succ ) ) {
          ATermAppl some = ATermUtils.makeSomeValues( p, succ.getConcept() );
          addToQueue( pred, concepts.get( some ) );
        }

        Set<Role> superRoles = kb.getRole( p ).getSuperRoles();
        for( Role superRole : superRoles ) {
          addSuccessor( pred, superRole.getName(), succ );
        }
      }
      else {
        Set<Role> superRoles = kb.getRole( p ).getSuperRoles();
        for( Role superRole : superRoles ) {
          if( existentials.contains( superRole.getName(), succ ) ) {
            ATermAppl some = ATermUtils.makeSomeValues( superRole.getName(), succ.getConcept() );
            addToQueue( pred, concepts.get( some ) );
          }
        }
      }
    }

    if( !PREPROCESS_DOMAINS ) {
      ATermAppl propDomain = roleRestrictions.getDomain( p );
      if( propDomain != null ) {
        addToQueue( pred, concepts.get( propDomain ) );
      }
    }
   
   
    if( hasComplexRoles ) {   
      for (Entry<ATermAppl, Set<ConceptInfo>> entry : CollectionUtils.makeList(pred.getPredecessors().entrySet())) {
        ATermAppl predProp = entry.getKey();
        for (ATermAppl supProp : roleChains.getAllSuperRoles(predProp, p)) {
          for (ConceptInfo predOfPred : CollectionUtils.makeList(entry.getValue())) {
            addSuccessor(predOfPred, supProp, succ);
          }
        }
      }
 
      for (Entry<ATermAppl, Set<ConceptInfo>> entry : CollectionUtils.makeList(succ.getSuccessors().entrySet())) {
        ATermAppl succProp = entry.getKey();
        for (ATermAppl supProp : roleChains.getAllSuperRoles(p, succProp)) {
          for (ConceptInfo succOfSucc : CollectionUtils.makeList(entry.getValue())) {
            addSuccessor(pred, supProp, succOfSucc);
          }
        }
      }
    }
  }
 
  private void addToQueue(ConceptInfo sub, ConceptInfo sup) {
    if( sub.addSuperClass( sup ) ) {
      primaryQueue.add( new QueueElement(sub, sup) );
      if( logger.isLoggable( Level.FINER ) ) {
        logger.finer( "Queue " + sub + " " + sup );
      }
    }
  }

  private void addSuperClass(ConceptInfo sub, ConceptInfo sup) {
    if( logger.isLoggable( Level.FINER ) ) {
      logger.finer( "Adding " + sub + " < " + sup );
    }
   
    if( sup == BOTTOM ) {
      Iterator<ConceptInfo> preds = sub.getPredecessors().flattenedValues();
      while( preds.hasNext() ) {
        addToQueue( preds.next(), sup );
      }
      return;
    }

    for( ConceptInfo supOfSup : sup.getSuperClasses() ) {
      if( !supOfSup.equals( sup ) ) {
        addToQueue( sub, supOfSup );
      }
    }   

    ATermAppl c = sup.getConcept();
    if( ATermUtils.isAnd( c ) ) {
      ATermList list = (ATermList) c.getArgument( 0 );
      while( !list.isEmpty() ) {
        ATermAppl conj = (ATermAppl) list.getFirst();
       
        addToQueue( sub, concepts.get( conj ) );

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

      addSuccessor( sub, p, concepts.get( qualification ) );
    } else {
      assert ATermUtils.isPrimitive( c );
    }

    Set<ConceptInfo> referredConjunctions = conjunctions.get( sup );
    if( referredConjunctions != null ) {
      for( ConceptInfo conjunction : referredConjunctions ) {
        ATermList list = (ATermList) conjunction.getConcept().getArgument( 0 );
        while( !list.isEmpty() ) {
          ATermAppl conj = (ATermAppl) list.getFirst();
         
          if( !sub.hasSuperClass( concepts.get( conj ) ) ) {
            break;
          }
         
          list = list.getNext();
        }
       
        if( list.isEmpty() ) {
          addToQueue( sub, conjunction );
        }
      }
    }
   
   
    for( Entry<ATermAppl, Set<ConceptInfo>> e : sub.getPredecessors().entrySet() ) {
      ATermAppl prop = e.getKey();
      if( MATERIALIZE_SUPER_PROPERTIES ) {
        if( existentials.contains( prop, sup ) ) {
          ATermAppl some = ATermUtils.makeSomeValues( prop, c );
          for( ConceptInfo pred : e.getValue() ) {
            addToQueue( pred, concepts.get( some ) );
          }
        }
      }
      else {
        Role role = kb.getRole( prop );
        if( role != null ) {
          Set<Role> superRoles = role.getSuperRoles();
          for( Role superRole : superRoles ) {
            if( existentials.contains( superRole.getName(), sup ) ) {
              ATermAppl some = ATermUtils.makeSomeValues( superRole.getName(), c );
              for( ConceptInfo pred : e.getValue() ) {
                addToQueue( pred, concepts.get( some ) );
              }
            }
          }
        }
      }
    }
  }

  private ConceptInfo createConcept(ATermAppl c) {
    ConceptInfo concept = concepts.get( c );
    if( concept == null ) {
      concept = new ConceptInfo( c, hasComplexRoles, false );
     
      if( ATermUtils.isAnd( c ) ) {
        ATermList list = (ATermList) c.getArgument(0);
        for( ; !list.isEmpty(); list = list.getNext() ) {
          ATermAppl conj = (ATermAppl) list.getFirst();
         
          ConceptInfo conjConcept = createConcept( conj );
          addToQueue( concept, conjConcept );
         
          conjunctions.add( conjConcept, concept )
        }
      }
      else if( ATermUtils.isSomeValues( c ) ) {
        ATermAppl p = (ATermAppl) c.getArgument(0);
        ATermAppl q = (ATermAppl) c.getArgument(1);
       
        if (ATermUtils.isInv(p))
          throw new UnsupportedOperationException("Anonmyous inverse found in restriction: "
                          + ATermUtils.toString(c));
       
        ATermAppl range = roleRestrictions.getRange( p );
        if( range != null ) {
          ATermAppl newQ = ATermUtils.makeSimplifiedAnd( Arrays.asList( range, q ) );
          if( !newQ.equals( q ) ) {
            ATermAppl newC = ATermUtils.makeSomeValues( p, newQ );
            concept = createConcept( newC );
            concepts.put( c, concept );
            c = newC;
          }
        }
       
        ConceptInfo succ = createConcept(q);
       
        existentials.add( p, succ );
       
        // Add this to the queue so that successor relation some(p,q) -> p -> q will be established. Due to
        // sub property interactions adding successor relation here directly causes missing inferences.
        // Note that, we are taking advantage of the fact that concept.addSuperClass(concept) call has not
        // been executed yet which would have caused the add queue call to have no effect.
        addToQueue( concept, concept );
      }
     
      concepts.put( c, concept );
     
      concept.addSuperClass( concept );
     
      if( TOP != null ) {
        addToQueue( concept, TOP );
      }
    }
   
    return concept;
  }

  private void createConceptsFromAxiom(ATermAppl sub, ATermAppl sup) {
    addToQueue( createConcept( sub ), createConcept( sup ) );
 
 
  private void createDisjointAxiom(ATermAppl c1, ATermAppl c2) {
    createConcept( c1 );
    createConcept( c2 );

    ATermAppl and = ATermUtils.makeSimplifiedAnd( Arrays.asList( c1, c2 ) );
    createConceptsFromAxiom( and, ATermUtils.BOTTOM );
  }

  private void processAxiom(ATermAppl axiom) {
    AFun fun = axiom.getAFun();

    if( fun.equals( ATermUtils.DISJOINTSFUN ) ) {
      ATermList concepts = (ATermList) axiom.getArgument( 0 );
      int n = concepts.getLength();
      ATermAppl[] simplified = new ATermAppl[n];
      for( int i = 0; !concepts.isEmpty(); concepts = concepts.getNext(), i++ ) {
        simplified[i] = ELSyntaxUtils.simplify( (ATermAppl) concepts.getFirst() );
      }
      for( int i = 0; i < n - 1; i++ ) {
        for( int j = i + 1; j < n; j++ ) {
          createDisjointAxiom( simplified[i], simplified[j] );
        }
      }
    }
    else {
      ATermAppl sub = (ATermAppl) axiom.getArgument( 0 );
      ATermAppl sup = (ATermAppl) axiom.getArgument( 1 );

      sub = ELSyntaxUtils.simplify( sub );
      sup = ELSyntaxUtils.simplify( sup );

      if( fun.equals( ATermUtils.SUBFUN ) ) {
        createConceptsFromAxiom( sub, sup );
      }
      else if( fun.equals( ATermUtils.EQCLASSFUN ) ) {
        createConceptsFromAxiom( sub, sup );
        createConceptsFromAxiom( sup, sub );
      }
      else if( fun.equals( ATermUtils.DISJOINTFUN ) ) {
        createDisjointAxiom( sub, sup );
      }
      else {
        throw new IllegalArgumentException( "Axiom " + axiom + " is not EL." );
      }
    }
  }
 
  private void processAxioms() {
    //EquivalentClass -> SubClasses
    //Disjoint Classes -> SubClass
    //Normalize ATerm lists to sets
    Collection<ATermAppl> assertedAxioms = kb.getTBox().getAssertedAxioms();
    for (ATermAppl assertedAxiom : assertedAxioms ) {
      processAxiom(assertedAxiom);
    }

    if( PREPROCESS_DOMAINS ) {
      //Convert ATermAppl 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 = createConcept( ATermUtils.TOP );
    BOTTOM = createConcept( ATermUtils.BOTTOM );
   
    for( ATermAppl c : kb.getClasses() ) {
      createConcept( c );
    }

    processAxioms();
   
    logger.fine( "Process domain and ranges" );
    for (ATermAppl c : roleRestrictions.getRanges().values()) {
      createConcept( c );
    }
   
    for (ATermAppl c : roleRestrictions.getDomains().values()) {
      createConcept( c );
    }
  }

  public void print() {
    for( ATermAppl c : concepts.keySet() ) {
      log.finer( c + " " + concepts.get( c ).getSuperClasses() );
    }
    log.finer("");
    roleChains.print();
  }

  private void processQueue() {
    int startingSize = primaryQueue.size();
    while( !primaryQueue.isEmpty()) {
      int processed = startingSize - primaryQueue.size();
      if( monitor.getProgress() < processed ) {
        monitor.setProgress( processed );
     
         
      QueueElement qe = primaryQueue.remove();
      addSuperClass( qe.sub, qe.sup );
    }
  }
 
  @Override
  public Map<ATermAppl, Set<ATermAppl>> getToldDisjoints() {
    return Collections.emptyMap();
  }

  @Override
  public Taxonomy<ATermAppl> getToldTaxonomy() {
    return new Taxonomy<ATermAppl>( kb.getTBox().getClasses(), TermFactory.TOP, TermFactory.BOTTOM );
  }
}
TOP

Related Classes of com.clarkparsia.pellet.el.SimplifiedELClassifier$QueueElement

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.