/*******************************************************************************
* This file is part of ecco.
*
* ecco is distributed under the terms of the GNU Lesser General Public License (LGPL), Version 3.0.
*
* Copyright 2011-2014, The University of Manchester
*
* ecco is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* ecco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with ecco.
* If not, see http://www.gnu.org/licenses/.
******************************************************************************/
package uk.ac.manchester.cs.diff.concept;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLLogicalAxiom;
import org.semanticweb.owlapi.model.OWLObject;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.reasoner.InferenceType;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import uk.ac.manchester.cs.diff.axiom.LogicalDiff;
import uk.ac.manchester.cs.diff.concept.change.ConceptChange;
import uk.ac.manchester.cs.diff.concept.change.LHSConceptChange;
import uk.ac.manchester.cs.diff.concept.change.RHSConceptChange;
import uk.ac.manchester.cs.diff.concept.changeset.ConceptChangeSet;
import uk.ac.manchester.cs.diff.concept.sigma.Signature;
import uk.ac.manchester.cs.diff.concept.witnesses.WitnessAxioms;
import uk.ac.manchester.cs.diff.concept.witnesses.WitnessConcepts;
import uk.ac.manchester.cs.diff.concept.witnesses.WitnessGroup;
import uk.ac.manchester.cs.diff.output.csv.CSVConceptDiffReport;
import uk.ac.manchester.cs.diff.output.xml.XMLConceptDiffReport;
import uk.ac.manchester.cs.diff.utils.ReasonerLoader;
/**
* @author Rafael S. Goncalves <br>
* Information Management Group (IMG) <br>
* School of Computer Science <br>
* University of Manchester <br>
*/
public class SubconceptDiff implements ConceptDiff {
protected OWLOntology ont1, ont2;
protected OWLReasoner ont1reasoner, ont2reasoner;
protected OWLDataFactory df;
protected Map<OWLClass,Set<OWLClassExpression>> ont1_diffL, ont1_diffR, ont2_diffL, ont2_diffR;
protected Set<OWLAxiom> extraAxioms;
protected Set<OWLEntity> sigma;
protected boolean verbose, atomicOnly = false;
protected ConceptChangeSet changeSet;
/**
* Constructor for subconcept diff w.r.t. Sigma = sig(O1) U sig(O2)
* @param ont1 Ontology 1
* @param ont2 Ontology 2
* @param verbose Verbose mode
*/
public SubconceptDiff(OWLOntology ont1, OWLOntology ont2, boolean verbose) {
this.ont1 = ont1;
this.ont2 = ont2;
this.verbose = verbose;
df = OWLManager.getOWLDataFactory();
sigma = new HashSet<OWLEntity>(new Signature().getUnionConceptNames(ont1, ont2));
sigma.add(df.getOWLNothing()); sigma.add(df.getOWLThing());
initDataStructures();
equalizeSignatures(ont1, ont2);
}
/**
* Constructor for subconcept diff w.r.t. given signature
* @param ont1 Ontology 1
* @param ont2 Ontology 2
* @param sig Signature (set of concept names)
* @param verbose Verbose mode
*/
public SubconceptDiff(OWLOntology ont1, OWLOntology ont2, Set<OWLEntity> sig, boolean verbose) {
this.ont1 = ont1;
this.ont2 = ont2;
this.sigma = sig;
this.verbose = verbose;
df = OWLManager.getOWLDataFactory();
initDataStructures();
equalizeSignatures(ont1, ont2);
}
/**
* Instantiate diff data structures: maps of concept names to sets of witness concepts
*/
private void initDataStructures() {
ont1_diffL = new HashMap<OWLClass,Set<OWLClassExpression>>();
ont1_diffR = new HashMap<OWLClass,Set<OWLClassExpression>>();
ont2_diffL = new HashMap<OWLClass,Set<OWLClassExpression>>();
ont2_diffR = new HashMap<OWLClass,Set<OWLClassExpression>>();
}
/**
* Get the concept-based change set between the given ontologies
* @return Concept-based change set
*/
public ConceptChangeSet getDiff() {
long start = System.currentTimeMillis();
System.out.println("Computing concept diff...");
if(verbose) System.out.println(" Input signature: sigma contains " + sigma.size() + " concept names");
Map<OWLClass,OWLClassExpression> map = null;
if(!atomicOnly) map = getSubConceptsMapping();
classifyOntologies(ont1, ont2);
Set<OWLClass> affected = computeChangeWitnesses(map);
long mid = System.currentTimeMillis();
if(!atomicOnly) {
ont1.getOWLOntologyManager().removeAxioms(ont1, extraAxioms);
ont2.getOWLOntologyManager().removeAxioms(ont2, extraAxioms);
classifyOntologies(ont1, ont2);
}
changeSet = splitDirectIndirectChanges(affected, ont1reasoner, ont2reasoner);
long end = System.currentTimeMillis();
changeSet.setEntailmentDiffTime((mid-start)/1000.0);
changeSet.setPartitioningTime((end-mid)/1000.0);
changeSet.setTotalTime((end-start)/1000.0);
System.out.println("finished concept diff (" + (end-start)/1000.0 + " secs)");
if(verbose) printDiff();
return changeSet;
}
/**
* Classify both ontologies
* @param ont1 Ontology 1
* @param ont2 Ontology 2
*/
public void classifyOntologies(OWLOntology ont1, OWLOntology ont2) {
long start = System.currentTimeMillis();
System.out.print(" Precomputing inferences... ");
ExecutorService exec = Executors.newFixedThreadPool(2);
Classifier ont1worker = new Classifier(ont1);
Classifier ont2worker = new Classifier(ont2);
exec.execute(ont1worker); exec.execute(ont2worker);
exec.shutdown();
try {
exec.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("done (" + (System.currentTimeMillis()-start)/1000.0 + " secs)");
ont1reasoner = ont1worker.getReasoner(); ont2reasoner = ont2worker.getReasoner();
}
/**
* Compute change witnesses between the given ontologies
* @param map Map of fresh concept names to complex concepts
* @return Set of affected concept names
*/
protected Set<OWLClass> computeChangeWitnesses(Map<OWLClass,OWLClassExpression> map) {
System.out.print(" Computing change witnesses... ");
Set<OWLClass> affected = new HashSet<OWLClass>();
long start = System.currentTimeMillis();
// Get specialisation and generalisation witnesses for each concept
for(OWLEntity subc : sigma) {
if(subc instanceof OWLClass) {
OWLClass c = (OWLClass)subc;
WitnessConcepts specWit = getSpecialisationWitnesses(c, map, ont1reasoner, ont2reasoner);
WitnessConcepts genWit = getGeneralisationWitnesses(c, map, ont1reasoner, ont2reasoner);
if((specWit != null && !specWit.isEmpty()) || (genWit != null && !genWit.isEmpty())) affected.add(c);
if(genWit != null) {
addChangeToMap(c, genWit.getLHSWitnesses(), ont1_diffR);
addChangeToMap(c, genWit.getRHSWitnesses(), ont2_diffR);
}
if(specWit != null) {
addChangeToMap(c, specWit.getLHSWitnesses(), ont1_diffL);
addChangeToMap(c, specWit.getRHSWitnesses(), ont2_diffL);
}
}
}
long end = System.currentTimeMillis();
System.out.println("done (" + (end-start)/1000.0 + " secs)");
return affected;
}
/**
* Distinguish between directly and indirectly affected concepts
* @param affected Set of affected concept names
* @param ont1reasoner Ontology 1 reasoner
* @param ont2reasoner Ontology 2 reasoner
* @return Concept-based change set
*/
protected ConceptChangeSet splitDirectIndirectChanges(Set<OWLClass> affected, OWLReasoner ont1reasoner, OWLReasoner ont2reasoner) {
System.out.print(" Splitting directly and indirectly affected concepts... ");
long start = System.currentTimeMillis();
/*
* TODO: The filtering of changes to (or via) Bottom and Top is somewhat crippled: The OWL API only allows us to extract unsatisfiable
* and global *atomic* concepts, meaning that we'd have to test whether each extracted subconcept is unsatisfiable or equivalent to Top
*/
Set<OWLClass> topSuper1 = ont1reasoner.getEquivalentClasses(df.getOWLThing()).getEntities();
Set<OWLClass> topSuper2 = ont2reasoner.getEquivalentClasses(df.getOWLThing()).getEntities();
Set<OWLClass> botSub1 = ont1reasoner.getUnsatisfiableClasses().getEntitiesMinusBottom();
Set<OWLClass> botSub2 = ont2reasoner.getUnsatisfiableClasses().getEntitiesMinusBottom();
WitnessGroup lhs_spec = getWitnesses(ont1_diffL, ont1reasoner, true, topSuper1, botSub1);
WitnessGroup lhs_gen = getWitnesses(ont1_diffR, ont1reasoner, false, topSuper1, botSub1);
WitnessGroup rhs_spec = getWitnesses(ont2_diffL, ont2reasoner, true, topSuper2, botSub2);
WitnessGroup rhs_gen = getWitnesses(ont2_diffR, ont2reasoner, false, topSuper2, botSub2);
long end = System.currentTimeMillis();
System.out.println("done (" + (end-start)/1000.0 + " secs)");
return sortOutChangeSet(affected, lhs_spec, lhs_gen, rhs_spec, rhs_gen);
}
/**
* Given the set of affected concepts, and their respective (direct and/or indirect witnesses), create a concept-based change set
* for both ontologies, as well as an overall change set representation which takes into account changes in both ontologies
* @param affected Set of affected concept names
* @param lhs_spec Pack of direct and indirect specialisation witnesses in ontology 1
* @param lhs_gen Pack of direct and indirect generalisation witnesses in ontology 1
* @param rhs_spec Pack of direct and indirect specialisation witnesses in ontology 2
* @param rhs_gen Pack of direct and indirect generalisation witnesses in ontology 2
* @return Concept change set
*/
private ConceptChangeSet sortOutChangeSet(Set<OWLClass> affected, WitnessGroup lhs_spec, WitnessGroup lhs_gen, WitnessGroup rhs_spec, WitnessGroup rhs_gen) {
Set<RHSConceptChange> rhsConceptChanges = new HashSet<RHSConceptChange>();
Set<LHSConceptChange> lhsConceptChanges = new HashSet<LHSConceptChange>();
Set<ConceptChange> conceptChanges = new HashSet<ConceptChange>();
for(OWLClass c : affected) {
WitnessAxioms ls = new WitnessAxioms(lhs_spec.getDirectWitnesses(c), lhs_spec.getIndirectWitnesses(c));
WitnessAxioms rs = new WitnessAxioms(rhs_spec.getDirectWitnesses(c), rhs_spec.getIndirectWitnesses(c));
WitnessAxioms lg = new WitnessAxioms(lhs_gen.getDirectWitnesses(c), lhs_gen.getIndirectWitnesses(c));
WitnessAxioms rg = new WitnessAxioms(rhs_gen.getDirectWitnesses(c), rhs_gen.getIndirectWitnesses(c));
if(!ls.isEmpty() || !lg.isEmpty())
lhsConceptChanges.add(new LHSConceptChange(c, ls, lg));
if(!rs.isEmpty() || !rg.isEmpty())
rhsConceptChanges.add(new RHSConceptChange(c, rs, rg));
// Create overall change
if(!ls.isEmpty() || !lg.isEmpty() || !rs.isEmpty() || !rg.isEmpty()) {
Set<OWLAxiom> dirSpec = new HashSet<OWLAxiom>(ls.getDirectWitnesses());
dirSpec.addAll(rs.getDirectWitnesses());
Set<OWLAxiom> indirSpec = new HashSet<OWLAxiom>(ls.getIndirectWitnesses());
indirSpec.addAll(rs.getIndirectWitnesses());
Set<OWLAxiom> dirGen = new HashSet<OWLAxiom>(lg.getDirectWitnesses());
dirGen.addAll(rg.getDirectWitnesses());
Set<OWLAxiom> indirGen = new HashSet<OWLAxiom>(lg.getIndirectWitnesses());
indirGen.addAll(rg.getIndirectWitnesses());
ConceptChange change = new ConceptChange(c, dirSpec, indirSpec, dirGen, indirGen);
conceptChanges.add(change);
}
}
return new ConceptChangeSet(lhsConceptChanges, rhsConceptChanges, conceptChanges);
}
/**
* Add affected concept and given witnesses to the specified diff map
* @param affected Set of affected concepts
* @param witnesses Set of witnesses
* @param map Map of new concepts to subconcepts
*/
protected void addChangeToMap(OWLClass affected, Set<OWLClassExpression> witnesses, Map<OWLClass,Set<OWLClassExpression>> map) {
if(!witnesses.isEmpty())
map.put(affected, witnesses);
}
/**
* Get the sets of (LHS and RHS) generalisation witnesses for the given concept
* @param subc Concept
* @param map Map of fresh concept names to the concepts they represent
* @param ont1reasoner Ontology 1 reasoner
* @param ont2reasoner Ontology 2 reasoner
* @return Generalisation concept witnesses for the given concept
*/
protected WitnessConcepts getGeneralisationWitnesses(OWLClass subc, Map<OWLClass,OWLClassExpression> map,
OWLReasoner ont1reasoner, OWLReasoner ont2reasoner) {
Set<OWLClass> ind1 = ont1reasoner.getEquivalentClasses(subc).getEntitiesMinus(subc);
Set<OWLClass> ind2 = ont2reasoner.getEquivalentClasses(subc).getEntitiesMinus(subc);
ind1.addAll(ont1reasoner.getSubClasses(subc, false).getFlattened());
ind2.addAll(ont2reasoner.getSubClasses(subc, false).getFlattened());
// Remove bottom
ind1.remove(df.getOWLNothing()); ind2.remove(df.getOWLNothing());
if(!subc.isOWLThing())
return getDifferentConcepts(ind1, ind2, map);
else
return null;
}
/**
* Get the sets of (LHS and RHS) specialisation witnesses for the given concept
* @param subc Concept
* @param map Map of fresh concept names to the concepts they represent
* @param ont1reasoner Ontology 1 reasoner
* @param ont2reasoner Ontology 2 reasoner
* @return Specialisation concept witnesses for the given concept
*/
protected WitnessConcepts getSpecialisationWitnesses(OWLClass subc, Map<OWLClass,OWLClassExpression> map,
OWLReasoner ont1reasoner, OWLReasoner ont2reasoner) {
Set<OWLClass> ind1 = ont1reasoner.getEquivalentClasses(subc).getEntitiesMinus(subc);
Set<OWLClass> ind2 = ont2reasoner.getEquivalentClasses(subc).getEntitiesMinus(subc);
ind1.addAll(ont1reasoner.getSuperClasses(subc, false).getFlattened());
ind2.addAll(ont2reasoner.getSuperClasses(subc, false).getFlattened());
// Remove top
ind1.remove(df.getOWLThing()); ind2.remove(df.getOWLThing());
if(!subc.isOWLNothing())
return getDifferentConcepts(ind1, ind2, map);
else
return null;
}
/**
* Get the witnesses for the the difference in the given sub or superclass sets
* @param set1 Set of classes
* @param set2 Set of classes
* @param map Map of fresh concept names to concepts
* @return Witness concepts in the sub or superclass sets diff
*/
private WitnessConcepts getDifferentConcepts(Set<OWLClass> set1, Set<OWLClass> set2, Map<OWLClass,OWLClassExpression> map) {
Set<OWLClassExpression> rhsWit = getWitnessDiff(set1, set2, map);
Set<OWLClassExpression> lhsWit = getWitnessDiff(set2, set1, map);
return new WitnessConcepts(lhsWit, rhsWit);
}
/**
* Get the set of different concepts between the given sets
* @param set1 Set of classes
* @param set2 Set of classes
* @param map Map of fresh concept names to concepts
* @return Set of different concepts between sets
*/
private Set<OWLClassExpression> getWitnessDiff(Set<OWLClass> set1, Set<OWLClass> set2, Map<OWLClass,OWLClassExpression> map) {
Set<OWLClassExpression> wit = new HashSet<OWLClassExpression>();
for(OWLClass c : set2) {
if(!set1.contains(c)) {
OWLClassExpression ce = c;
if(map != null && map.containsKey(c))
ce = map.get(c);
wit.add(ce);
}
}
return wit;
}
/**
* Extrapolate direct and indirect witnesses from the given map of affected concepts and witnesses
* @param affectedConceptMap Map of concepts to their change witnesses
* @param reasoner Reasoner instance
* @param diffL true if checking specialisations, false if generalisations
* @param topSuper Superclasses of Top
* @param unsat Unsatisfiable classes
* @return Pack of direct and indirect witnesses
*/
private WitnessGroup getWitnesses(Map<OWLClass,Set<OWLClassExpression>> affectedConceptMap, OWLReasoner reasoner, boolean diffL,
Set<OWLClass> topSuper, Set<OWLClass> unsat) {
Map<OWLClassExpression,Set<OWLClass>> witMap = getWitnessMap(affectedConceptMap);
Map<OWLClass,Set<OWLAxiom>> directWits = new HashMap<OWLClass,Set<OWLAxiom>>();
Map<OWLClass,Set<OWLAxiom>> indirectWits = new HashMap<OWLClass,Set<OWLAxiom>>();
for(OWLClassExpression ce : witMap.keySet()) {
Set<OWLClass> subs = null;
if(diffL) {
if(!reasoner.isSatisfiable(ce) || reasoner.isEntailed(df.getOWLEquivalentClassesAxiom(ce, df.getOWLThing()))) {
subs = reasoner.getEquivalentClasses(ce).getEntities();
if(!ce.isAnonymous()) subs.remove((OWLClass)ce);
}
else {
subs = reasoner.getSubClasses(ce, true).getFlattened();
subs.removeAll(unsat); // Remove unsat classes
}
}
else {
if(!reasoner.isSatisfiable(ce) || reasoner.isEntailed(df.getOWLEquivalentClassesAxiom(ce, df.getOWLThing()))) {
subs = reasoner.getEquivalentClasses(ce).getEntities();
if(!ce.isAnonymous()) subs.remove((OWLClass)ce);
}
else {
subs = reasoner.getSuperClasses(ce, true).getFlattened();
subs.removeAll(unsat); // Remove unsat classes
subs.removeAll(topSuper);
}
}
for(OWLClass c : witMap.get(ce)) {
if(subs.contains(c)) { // direct witness
if(directWits.containsKey(c)) {
Set<OWLAxiom> wits = directWits.get(c);
if(diffL) wits.add(df.getOWLSubClassOfAxiom(c, ce));
else wits.add(df.getOWLSubClassOfAxiom(ce, c));
directWits.put(c, wits);
}
else {
if(diffL) directWits.put(c, new HashSet<OWLAxiom>(Collections.singleton(df.getOWLSubClassOfAxiom(c, ce))));
else directWits.put(c, new HashSet<OWLAxiom>(Collections.singleton(df.getOWLSubClassOfAxiom(ce, c))));
}
}
else { // indirect witness
if(indirectWits.containsKey(c)) {
Set<OWLAxiom> wits = indirectWits.get(c);
if(diffL) wits.add(df.getOWLSubClassOfAxiom(c, ce));
else wits.add(df.getOWLSubClassOfAxiom(ce, c));
indirectWits.put(c, wits);
}
else {
if(diffL) indirectWits.put(c, new HashSet<OWLAxiom>(Collections.singleton(df.getOWLSubClassOfAxiom(c, ce))));
else indirectWits.put(c, new HashSet<OWLAxiom>(Collections.singleton(df.getOWLSubClassOfAxiom(ce, c))));
}
}
}
}
return new WitnessGroup(directWits, indirectWits);
}
/**
* Given a map of concepts to witnesses, get a reversed map of witnesses to concepts whose change they witness
* @param map Map of concepts to witnesses
* @return Map of witnesses to concepts whose change they witness
*/
private Map<OWLClassExpression,Set<OWLClass>> getWitnessMap(Map<OWLClass,Set<OWLClassExpression>> map) {
Map<OWLClassExpression,Set<OWLClass>> output = new HashMap<OWLClassExpression,Set<OWLClass>>();
for(OWLClass c : map.keySet()) {
Set<OWLClassExpression> wits = map.get(c);
for(OWLClassExpression wit : wits) {
if(output.containsKey(wit)) {
Set<OWLClass> classes = output.get(wit);
classes.add(c);
output.put(wit, classes);
}
else
output.put(wit, new HashSet<OWLClass>(Collections.singleton(c)));
}
}
return output;
}
/**
* Class hierarchy pre-computation
*/
class Classifier implements Runnable {
private OWLOntology ont;
private OWLReasoner reasoner;
private double time;
public Classifier(OWLOntology ont) {
this.ont = ont;
}
@Override
public void run() {
reasoner = new ReasonerLoader(ont, false).createReasoner(false);
long start = System.currentTimeMillis();
reasoner.precomputeInferences(InferenceType.CLASS_HIERARCHY);
long end = System.currentTimeMillis();
time = (end-start)/1000.0;
}
public OWLReasoner getReasoner() {
return reasoner;
}
public double getClassificationTime() {
return time;
}
}
/**
* Collect sub-concepts in both ontologies
* @return Set of subconcepts
*/
protected Set<OWLClassExpression> collectSCs() {
if(verbose) System.out.print(" Extracting subconcepts from given ontologies... ");
Set<OWLClassExpression> scs = new HashSet<OWLClassExpression>();
getSubConcepts(ont1, scs);
getSubConcepts(ont2, scs);
if(verbose) System.out.println("done (nr. of subconcepts: " + scs.size() + ")");
return scs;
}
/**
* Get sub-concepts of an ontology
* @param ont Ontology
* @param sc Set of subconcepts
* @return Updated set of subconcepts
*/
protected Set<OWLClassExpression> getSubConcepts(OWLOntology ont, Set<OWLClassExpression> sc) {
Set<OWLLogicalAxiom> axs = ont.getLogicalAxioms();
for(OWLAxiom ax : axs) {
Set<OWLClassExpression> ax_sc = ax.getNestedClassExpressions();
for(OWLClassExpression ce : ax_sc) {
if(!sc.contains(ce) && !ce.isOWLThing() && !ce.isOWLNothing()) {
if(ce.isAnonymous() && sigma.containsAll(ce.getClassesInSignature())) {
sc.add(ce); getSubConcepts(ce, sc);
}
}
}
}
return sc;
}
/**
* Recursively get subconcepts of subconcept
* @param ce Subconcept
* @param sc Set of subconcepts
*/
private void getSubConcepts(OWLClassExpression ce, Set<OWLClassExpression> sc) {
if(ce.getNestedClassExpressions().size() > 0) {
for(OWLClassExpression c : ce.getNestedClassExpressions()) {
if(!sc.contains(c) && !c.isOWLThing() && !c.isOWLNothing()) {
if(c.isAnonymous()) {
sc.add(c);
getSubConcepts(c, sc);
}
}
}
}
}
/**
* Create a mapping between a new term "TempX" and each sub-concept, and add the appropriate
* equivalence axioms to each ontology
* @return Map of new terms to subconcepts
*/
private Map<OWLClass,OWLClassExpression> getSubConceptsMapping() {
Set<OWLClassExpression> sc = collectSCs();
OWLDataFactory df = OWLManager.getOWLDataFactory();
Map<OWLClass,OWLClassExpression> map = new HashMap<OWLClass,OWLClassExpression>();
int counter = 1;
extraAxioms = new HashSet<OWLAxiom>();
for(OWLClassExpression ce : sc) {
if(ce.isAnonymous()) {
OWLClass c = df.getOWLClass(IRI.create("diffSubc_" + counter));
map.put(c, ce);
OWLAxiom ax = df.getOWLEquivalentClassesAxiom(c, ce);
extraAxioms.add(ax); counter++;
}
}
ont1.getOWLOntologyManager().addAxioms(ont1, extraAxioms);
ont2.getOWLOntologyManager().addAxioms(ont2, extraAxioms);
return map;
}
/**
* Check whether two sets of objects contain the same elements
* @param set1 Set of OWL objects
* @param set2 Set of OWL objects
* @return true if sets have the same elements, false otherwise
*/
@SuppressWarnings("unused")
private boolean equals(Set<? extends OWLObject> set1, Set<? extends OWLObject> set2) {
boolean isEqual = true;
for(OWLObject c : set1) {
if(!set2.contains(c)) {
isEqual = false;
break;
}
}
if(isEqual) {
for(OWLObject c : set2) {
if(!set1.contains(c)) {
isEqual = false;
break;
}
}
}
return isEqual;
}
/**
* Determine if the given pair of ontologies are logically equivalent
* @param ont1 Ontology 1
* @param ont2 Ontology 2
* @return true if ontologies are equivalent, false otherwise
*/
protected boolean equiv(OWLOntology ont1, OWLOntology ont2) {
LogicalDiff diff = new LogicalDiff(ont1, ont2, false);
return diff.isEquivalent();
}
/**
* Given two ontologies, inject entity declarations so that both ontologies
* end up with the same signature
* @param ont1 Ontology 1
* @param ont2 Ontology 2
*/
protected void equalizeSignatures(OWLOntology ont1, OWLOntology ont2) {
Set<OWLEntity> ont1sig = ont1.getSignature();
Set<OWLEntity> ont2sig = ont2.getSignature();
ont1sig.removeAll(ont2sig);
ont2sig.removeAll(ont1sig);
List<AddAxiom> ont1axs = new ArrayList<AddAxiom>();
for(OWLEntity c : ont1sig) {
ont1axs.add(new AddAxiom(ont2, df.getOWLDeclarationAxiom(c)));
}
ont2.getOWLOntologyManager().applyChanges(ont1axs);
List<AddAxiom> ont2axs = new ArrayList<AddAxiom>();
for(OWLEntity c : ont2sig) {
ont2axs.add(new AddAxiom(ont1, df.getOWLDeclarationAxiom(c)));
}
ont1.getOWLOntologyManager().applyChanges(ont2axs);
}
/**
* Trigger the use of atomic concept diff
* @param atomicOnly true if only atomic concepts should be taken into account, false otherwise
*/
public void setAtomicConceptDiff(boolean atomicOnly) {
this.atomicOnly = atomicOnly;
}
/**
* Get the XML report for concept diff
* @return Concept diff report object
*/
public XMLConceptDiffReport getXMLReport() {
return new XMLConceptDiffReport(changeSet);
}
/**
* Get a CSV change report
* @return Change report as a CSV document
*/
public String getCSVChangeReport() {
return new CSVConceptDiffReport().getReport(changeSet);
}
/**
* Print diff results
*/
public void printDiff() {
System.out.println(" Concept changes:");
System.out.println("\t[ont1]" +
"\tSpecialised: " + changeSet.getLHSSpecialisedConcepts().size() +
"\tGeneralised: " + changeSet.getLHSGeneralisedConcepts().size() +
"\tTotal affected: " + changeSet.getLHSAffectedConcepts().size());
System.out.println("\t[ont2]" +
"\tSpecialised: " + changeSet.getRHSSpecialisedConcepts().size() +
"\tGeneralised: " + changeSet.getRHSGeneralisedConcepts().size() +
"\tTotal affected: " + changeSet.getRHSAffectedConcepts().size());
System.out.println("\t[total]" +
"\tSpecialised: " + changeSet.getAllSpecialisedConcepts().size() +
"\tGeneralised: " + changeSet.getAllGeneralisedConcepts().size() +
"\tTotal affected: " + changeSet.getAllAffectedConcepts().size());
System.out.println("\n\tAffected concepts categorisation:");
System.out.println("\t Directly generalised: " + changeSet.getAllDirectlyGeneralised().size());
System.out.println("\t Directly specialised: " + changeSet.getAllDirectlySpecialised().size());
System.out.println("\t Purely directly generalised: " + changeSet.getAllPurelyDirectlyGeneralised().size());
System.out.println("\t Purely directly specialised: " + changeSet.getAllPurelyDirectlySpecialised().size());
System.out.println("\t Purely indirectly generalised: " + changeSet.getAllPurelyIndirectlyGeneralised().size());
System.out.println("\t Purely indirectly specialised: " + changeSet.getAllPurelyIndirectlySpecialised().size());
System.out.println("\t Mixed generalised: " + changeSet.getAllMixedGeneralised().size());
System.out.println("\t Mixed specialised: " + changeSet.getAllMixedSpecialised().size() + "\n");
}
}