All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.obolibrary.robot.RelaxOperation Maven / Gradle / Ivy

Go to download

Core library for ROBOT: Library for working with OWL ontologies, especially Open Biological and Biomedical Ontologes (OBO).

The newest version!
package org.obolibrary.robot;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.AxiomType;
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.OWLEquivalentClassesAxiom;
import org.semanticweb.owlapi.model.OWLObjectCardinalityRestriction;
import org.semanticweb.owlapi.model.OWLObjectIntersectionOf;
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLObjectSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Add additional SubClassOf axioms that are relaxed forms of equivalence axioms.
 *
 * 

This is a form of incomplete reasoning that is useful when either axioms are invisible to EL * reasoners, or to produce an existential subclass graph that has SomeValuesFrom superclasses * materialized. * *

Motivation

* * It is frequently convenient to view an ontology without equivalence axioms. This is often for * structural reasons. Certain editions of ontologies may come with a guarantee that the existential * graph formed by all SubClassOf axioms (between named classes and existential axioms) is both * complete (w.r.t graph operations) and non-redundant. Including EquivalentClasses axioms can * introduce redundancy at the graph view level. For example, the genus is frequently more general * than the inferred superclasses. * *

To ensure that the existential graph is graph-complete it's necessary to write new SubClassOf * axioms that are entailed by (but weaker than) Equivalence axioms * *

Basic Operation

* * For any equivalence axiom between a name class C and either a single existential X_1 or the class * expression IntersectionOf(X_1 ... X_n), generate axioms * C SubClassOf X_1 * ... * C SubClassOf X_n * Additionally, if X_i is a qualified cardinality constraint, weaken to an existential * *

Usage

* * For ELK reasoners, it is recommended to use this prior to the reasoning step, as relaxation can * reveal weaker forms of axioms that are outside EL. * *

It is recommended that the reduce operation is executed after relaxation, to remove any * redundancies within the subclass graph * *

Note that the materialize operation may seem to make the relax step pointless; materialization * produces the most specific existential parent. However, in some cases relaxation should still be * performed: - if Elk is used (see above) - if materialization is only performed on a subset of * properties * *

The standard sequence is: relax-materialize-reduce, or relax-reason-reduce * * @see issue 7 * @see issue 135 * @author Chris Mungall */ public class RelaxOperation { /** Logger. */ private static final Logger logger = LoggerFactory.getLogger(RelaxOperation.class); /** * Return a map from option name to default option value, for all the available reasoner options. * * @return a map with default values for all available options */ public static Map getDefaultOptions() { // options.put("remove-redundant-subclass-axioms", "true"); return new HashMap<>(); } /** * Replace EquivalentClass axioms with weaker SubClassOf axioms. * * @param ontology The OWLOntology to relax * @param options A map of options for the operation */ public static void relax(OWLOntology ontology, Map options) { relax(ontology); } /** * Replace EquivalentClass axioms with weaker SubClassOf axioms. * * @param ontology The OWLOntology to relax */ public static void relax(OWLOntology ontology) { relax(ontology, false, false, false); } /** * Replace EquivalentClass axioms with weaker SubClassOf axioms. * * @param ontology The OWLOntology to relax * @param enforceOboFormat if true, only axioms allowed in OBO format are asserted as a * consequence of relax * @param excludeNamedClasses if true, equivalent class axioms between named classes are ignored * during processing * @param includeSubclassOf if true, equivalent class axioms between named classes are ignored * during processing */ public static void relax( OWLOntology ontology, boolean enforceOboFormat, boolean excludeNamedClasses, boolean includeSubclassOf) { OWLOntologyManager manager = OWLManager.createOWLOntologyManager(); OWLDataFactory dataFactory = manager.getOWLDataFactory(); Set newAxioms = new HashSet<>(); Set eqAxioms = ontology.getAxioms(AxiomType.EQUIVALENT_CLASSES); for (OWLEquivalentClassesAxiom ax : eqAxioms) { for (OWLClassExpression x : ax.getClassExpressions()) { // we only relax in cases where the equivalence is between one // named and one anon expression if (!x.isAnonymous()) { OWLClass c = (OWLClass) x; // ax = EquivalentClasses(x y1 y2 ...) for (OWLClassExpression y : ax.getClassExpressionsMinus(c)) { // if we are excluding equivalents between named classes, skip if (!y.isAnonymous() && excludeNamedClasses) { continue; } relaxExpression(c, y, newAxioms, enforceOboFormat, dataFactory); } } } } if (includeSubclassOf) { Set subClassAxioms = ontology.getAxioms(AxiomType.SUBCLASS_OF); for (OWLSubClassOfAxiom ax : subClassAxioms) { OWLClassExpression subClass = ax.getSubClass(); OWLClassExpression superClass = ax.getSuperClass(); // we only relax in cases where the subclass is a named class // and the superclass a complex expression if (!subClass.isAnonymous() && superClass.isAnonymous()) { OWLClass namedSubClass = (OWLClass) subClass; relaxExpression(namedSubClass, superClass, newAxioms, enforceOboFormat, dataFactory); } } } // remove redundant axiom for (OWLAxiom ax : newAxioms) { logger.info("NEW: " + ax); manager.addAxiom(ontology, ax); } } private static void relaxExpression( OWLClass namedSubClass, OWLClassExpression anonymousSuperClass, Set newAxioms, boolean enforceOboFormat, OWLDataFactory dataFactory) { // limited structural reasoning: // return (P some Z), if: // - y is of the form (P some Z) // - y is of the form ((P some Z) and ...), // or any level of nesting for (OWLObjectSomeValuesFrom svf : getSomeValuesFromAncestor(anonymousSuperClass, enforceOboFormat, dataFactory)) { newAxioms.add(dataFactory.getOWLSubClassOfAxiom(namedSubClass, svf)); } for (OWLClass z : getNamedAncestors(anonymousSuperClass)) { newAxioms.add(dataFactory.getOWLSubClassOfAxiom(namedSubClass, z)); } } /** * Given an OWLClassExpression y, return a set of OWLObjectSomeValuesFrom objects (p some v), * where (p some v) is a superclass of y. * *

Not guaranteed to be complete * * @param x The OWLClassExpression to check. * @param dataFactory OWLDataFactory * @return the set of OWLObjectSomeValuesFrom objects */ private static Set getSomeValuesFromAncestor( OWLClassExpression x, boolean enforceOboFormat, OWLDataFactory dataFactory) { Set svfs = new HashSet<>(); if (x instanceof OWLObjectSomeValuesFrom) { OWLObjectSomeValuesFrom svf = (OWLObjectSomeValuesFrom) x; if (!enforceOboFormat || isOboFormatConformant(svf)) { svfs.add(svf); } } else if (x instanceof OWLObjectCardinalityRestriction) { OWLObjectCardinalityRestriction ocr = (OWLObjectCardinalityRestriction) x; OWLClassExpression filler = ocr.getFiller(); OWLObjectPropertyExpression p = ocr.getProperty(); if (ocr.getCardinality() > 0) { OWLObjectSomeValuesFrom svf = dataFactory.getOWLObjectSomeValuesFrom(p, filler); if (!enforceOboFormat || isOboFormatConformant(svf)) { svfs.add(svf); } } } else if (x instanceof OWLObjectIntersectionOf) { for (OWLClassExpression op : ((OWLObjectIntersectionOf) x).getOperands()) { svfs.addAll(getSomeValuesFromAncestor(op, enforceOboFormat, dataFactory)); } } return svfs; } private static boolean isOboFormatConformant(OWLObjectSomeValuesFrom svf) { return !svf.getProperty().isAnonymous() && !svf.getFiller().isAnonymous(); } /** * Given an OWLClassExpression y, return a set of named classes c, such that c is a superclass of * y, * *

obtained by relaxing/unwinding expression, in a way that is guaranteed valid but not * guaranteed complete. * *

This is effectively poor-mans reasoning over IntersectionOf; e.g * *

   * C SubClassOf (C and ...)
   * 
* * @param x The OWLClassExpression to unwind. * @return the set of OWLClass superclasses */ private static Set getNamedAncestors(OWLClassExpression x) { Set cs = new HashSet<>(); if (!x.isAnonymous()) { cs.add(x.asOWLClass()); } else if (x instanceof OWLObjectIntersectionOf) { for (OWLClassExpression op : ((OWLObjectIntersectionOf) x).getOperands()) { cs.addAll(getNamedAncestors(op)); } } return cs; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy