com.clarkparsia.modularity.AxiomBasedModuleExtractor Maven / Gradle / Ivy
// Copyright (c) 2006 - 2008, Clark & Parsia, LLC.
// 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: [email protected]
package com.clarkparsia.modularity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.mindswap.pellet.utils.DisjointSet;
import org.mindswap.pellet.utils.SetUtils;
import org.mindswap.pellet.utils.progress.ConsoleProgressMonitor;
import org.mindswap.pellet.utils.progress.ProgressMonitor;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLEntity;
import com.clarkparsia.owlapi.modularity.locality.LocalityClass;
import com.clarkparsia.owlapi.modularity.locality.LocalityEvaluator;
import com.clarkparsia.owlapi.modularity.locality.SyntacticLocalityEvaluator;
import com.clarkparsia.owlapiv3.OntologyUtils;
/**
*
* Title:
*
*
* Description:
*
*
* Copyright: Copyright (c) 2007
*
*
* Company: Clark & Parsia, LLC.
*
*
* @author Evren Sirin
*/
public class AxiomBasedModuleExtractor extends AbstractModuleExtractor {
public static final Logger log = Logger
.getLogger( AxiomBasedModuleExtractor.class
.getName() );
private boolean optimizeForSharedModules = true;
public AxiomBasedModuleExtractor() {
super();
}
public AxiomBasedModuleExtractor(LocalityClass localityClass) {
super( new SyntacticLocalityEvaluator( localityClass ) );
}
public AxiomBasedModuleExtractor(LocalityEvaluator localityEvaluator) {
super( localityEvaluator );
}
private OWLEntity extractModuleSignature(OWLEntity entity, Set stackElements,
List currentCycle, Set module) {
assert !modules.containsKey( entity ) : "po already contained entity";
assert currentCycle.isEmpty() : "non-empty current cycle passed into function";
Set myCycle = new HashSet();
if( entity != null ) {
module.add( entity );
myCycle.add( entity );
stackElements.add( entity );
modules.put( entity, module );
}
int oldSize = -1;
Set previousModule = new HashSet();
while( module.size() != oldSize ) {
oldSize = module.size();
List newMembers = new ArrayList();
// Previous updates to the module may cause additional axioms to be
// non-local
{
Set addedEntities = SetUtils.difference( module, previousModule );
previousModule = new HashSet( module );
Set testLocal = new HashSet();
for( OWLEntity e : addedEntities ) {
for( OWLAxiom a : getAxioms( e ) ) {
if( testLocal.add( a ) && !isLocal( a, module ) ) {
for( OWLEntity ent : getSignature( a ) ) {
if( module.add( ent ) )
newMembers.add( ent );
}
}
}
}
}
// Recursive calls may modify the module, iterating over a static
// view in an array avoids concurrent modification problems
for( OWLEntity member : newMembers ) {
// ignore self references
if( myCycle.contains( member ) )
continue;
// if we have never seen this entity extract its module
if( !modules.containsKey( member ) ) {
Set memberMod = new HashSet();
List memberCycle = new ArrayList();
OWLEntity root = extractModuleSignature( member, stackElements, memberCycle,
memberMod );
module.addAll( memberMod );
// Option 1: No cycle was identified, extraction successful
if( root.equals( member ) ) {
assert !stackElements.contains( member ) : "Recursive call did not cleanup stack";
}
// Option 2: entity is in a cycle
else {
myCycle.addAll( memberCycle );
// Option 2a: entity was the root of the cycle
if( myCycle.contains( root ) ) {
stackElements.addAll( memberCycle );
}
// Option 2b: entity is mid-cycle
else {
currentCycle.addAll( myCycle );
return root;
}
}
}
// entity is in a cycle
else if( stackElements.contains( member ) ) {
currentCycle.addAll( myCycle );
return member;
}
else {
// simply retrieve and copy the precomputed module
module.addAll( modules.get( member ) );
}
}
for( OWLEntity e : myCycle )
modules.put( e, module );
}
stackElements.removeAll( myCycle );
return entity;
}
/**
* This is the recursive method to actually extract the signature for an
* entity
*
* @param po
* the partial order which houses all modules; this is updated as
* the function proceeds
* @param modMap
* index to track the root class for nodes contained in cycles
* @param entity
* the entity to extract
*/
private void extractModuleSignature(OWLEntity entity, DisjointSet modEqCls,
ArrayList stack, Set stackElements) {
/*
* Two conditions should never occur
*/
assert !stack.contains( entity ) : "stack contained entity already";
assert !modules.containsKey( entity ) : "po already contained entity";
Set module = new HashSet();
if( entity != null ) {
stack.add( entity );
stackElements.add( entity );
modEqCls.add( entity );
module.add( entity );
modules.put( entity, module );
}
int oldSize = -1;
Set previousModule = new HashSet();
while( module.size() != oldSize ) {
oldSize = module.size();
List newMembers = new ArrayList();
// Previous updates to the module may cause additional axioms to be
// non-local
{
Set addedEntities = SetUtils.difference( module, previousModule );
previousModule = new HashSet( module );
Set testLocal = new HashSet();
for( OWLEntity e : addedEntities ) {
for( OWLAxiom a : getAxioms( e ) ) {
if( testLocal.add( a ) && !isLocal( a, module ) ) {
for( OWLEntity ent : getSignature( a ) ) {
if( module.add( ent ) )
newMembers.add( ent );
}
}
}
}
}
// Recursive calls may modify the module, iterating over a static
// view in an array avoids concurrent modification problems
for( OWLEntity member : newMembers ) {
// ignore self references
if( member.equals( entity ) )
continue;
// if we have never seen this entity extract its module
if( !modules.containsKey( member ) )
extractModuleSignature( member, modEqCls, stack, stackElements );
// the node might even be on the stack
if( stackElements.contains( member ) ) {
// sanity check
assert stack.contains( member ) : "node was supposed to be on the stack";
// all the entities in the stack up until that node
// will end up having the same module
boolean foundMember = false;
for( int i = stack.size() - 1; !foundMember; i-- ) {
OWLEntity next = stack.get( i );
modEqCls.union( member, next );
foundMember = next.equals( member );
}
}
else {
// simply retrieve and copy the precomputed module
module.addAll( modules.get( member ) );
}
}
}
for( OWLEntity other : modEqCls.elements() ) {
if( modEqCls.isSame( entity, other ) ) {
modules.get( other ).addAll( module );
}
}
stack.remove( stack.size() - 1 );
stackElements.remove( entity );
}
/**
* {@inheritDoc}
*/
protected void extractModuleSignatures(Set extends OWLEntity> entities) {
log.fine( "Extract module for " + entities );
ProgressMonitor monitor = new ConsoleProgressMonitor();
monitor.setProgressTitle( "Extracting" );
monitor.setProgressLength( entities.size() );
monitor.taskStarted();
Set nonLocalModule = new HashSet();
for( OWLAxiom axiom : getAxioms() ) {
if( !isLocal( axiom, Collections. emptySet() ) )
nonLocalModule.addAll( OntologyUtils.getSignature( axiom ) );
}
// iterate over classes passed in, and extract all their modules
for( OWLEntity ent : entities ) {
monitor.incrementProgress();
if( log.isLoggable( Level.FINE ) )
log.fine( "Class: " + ent );
if( !modules.containsKey( ent ) )
if( optimizeForSharedModules )
extractModuleSignature( ent, new HashSet(),
new ArrayList(), new HashSet( nonLocalModule ) );
else
extractModuleSignature( ent, new DisjointSet(),
new ArrayList(), new HashSet( nonLocalModule ) );
}
monitor.taskFinished();
if( log.isLoggable( Level.FINE ) )
log.fine( modules.toString() );
}
/**
* {@inheritDoc}
*/
public Set extractModule(Set extends OWLEntity> signature) {
if( isChanged() )
resetModules();
Set module = new HashSet( signature );
for( OWLAxiom axiom : getAxioms() ) {
if( !isLocal( axiom, Collections. emptySet() ) )
module.addAll( OntologyUtils.getSignature( axiom ) );
}
if( !entityAxioms.isEmpty() ) {
if( optimizeForSharedModules )
extractModuleSignature( null, new HashSet(),
new ArrayList(), module );
else
extractModuleSignature( null, new DisjointSet(),
new ArrayList(), module );
}
return getModuleAxioms( module );
}
/**
* Returns if shared modules optimization is on.
*/
public boolean isOptimizeForSharedModules() {
return optimizeForSharedModules;
}
/**
* Sets the the option to optimize for shared modules during module
* extraction. This option improves the performance of axiom-based module
* extractor when there are many shared modules in the ontology. This option
* seems to improve the performance of modularization for NCI thesaurus
* significantly but has slight overhead for some other ontologies (it is
* not clear if the overhead would more dramatic in other untested cases).
* This option has no effect on graph-based extractor which by default
* includes optimization for shared modules that does not have negative
* impact on any ontology.
*/
public void setOptimizeForSharedModules(boolean optimizeForSharedModules) {
this.optimizeForSharedModules = optimizeForSharedModules;
}
}