org.semanticweb.elk.reasoner.taxonomy.TaxonomyPrinter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elk-reasoner Show documentation
Show all versions of elk-reasoner Show documentation
The core ELK Reasoner package
The newest version!
/*
* #%L
* elk-reasoner
*
* $Id$
* $HeadURL$
* %%
* Copyright (C) 2011 Department of Computer Science, University of Oxford
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.semanticweb.elk.reasoner.taxonomy;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.semanticweb.elk.owl.interfaces.ElkAxiom;
import org.semanticweb.elk.owl.interfaces.ElkClass;
import org.semanticweb.elk.owl.interfaces.ElkEntity;
import org.semanticweb.elk.owl.interfaces.ElkNamedIndividual;
import org.semanticweb.elk.owl.interfaces.ElkObject;
import org.semanticweb.elk.owl.interfaces.ElkObjectProperty;
import org.semanticweb.elk.owl.managers.ElkObjectEntityRecyclingFactory;
import org.semanticweb.elk.owl.printers.OwlFunctionalStylePrinter;
import org.semanticweb.elk.owl.visitors.AbstractElkEntityVisitor;
import org.semanticweb.elk.owl.visitors.ElkEntityVisitor;
import org.semanticweb.elk.reasoner.taxonomy.hashing.InstanceTaxonomyHasher;
import org.semanticweb.elk.reasoner.taxonomy.hashing.TaxonomyHasher;
import org.semanticweb.elk.reasoner.taxonomy.model.InstanceNode;
import org.semanticweb.elk.reasoner.taxonomy.model.InstanceTaxonomy;
import org.semanticweb.elk.reasoner.taxonomy.model.Taxonomy;
import org.semanticweb.elk.reasoner.taxonomy.model.TaxonomyNode;
import org.semanticweb.elk.reasoner.taxonomy.model.TypeNode;
import org.semanticweb.elk.util.collections.Operations;
/**
* Class of static helper functions for printing and hashing a taxonomy. It is
* primarily intended to be used for controlling the output of classification.
*
* @author Markus Kroetzsch
* @author Peter Skocovsky
*/
public class TaxonomyPrinter {
/**
* Convenience method for printing a {@link Taxonomy} to a file at the given
* location.
*
* @see #dumpTaxomomy(Taxonomy, Writer, boolean)
*
* @param taxonomy
* the {@link Taxonomy} to be printed
* @param filePath
* the file location
* @param addHash
* if true, a hash string will be added at the end of the output
* using comment syntax of OWL 2 Functional Style
* @throws IOException
* If an I/O error occurs
*/
public static void dumpTaxomomyToFile(
final Taxonomy extends ElkEntity> taxonomy, final String filePath,
final boolean addHash) throws IOException {
final FileWriter fstream = new FileWriter(filePath);
final BufferedWriter writer = new BufferedWriter(fstream);
try {
dumpTaxomomy(taxonomy, writer, addHash);
} finally {
writer.close();
}
}
/**
* Print the contents of the given {@link Taxonomy} to the specified
* {@link Writer}. Expressions are ordered for generating the output,
* ensuring that the output is deterministic.
*
* @param taxonomy
* the {@link Taxonomy} to be printed
* @param writer
* the {@link Writer} used for printing
* @param addHash
* if true, a hash string will be added at the end of the output
* using comment syntax of OWL 2 Functional Style
* @throws IOException
* If an I/O error occurs
*/
public static void dumpTaxomomy(
final Taxonomy extends ElkEntity> taxonomy, final Writer writer,
final boolean addHash) throws IOException {
writer.append("Ontology(\n");
processTaxomomy(taxonomy, writer);
writer.append(")\n");
if (addHash) {
writer.append("\n# Hash code: " + getHashString(taxonomy) + "\n");
}
writer.flush();
}
/**
* Convenience method for printing an {@link InstanceTaxonomy} to a file at
* the given location.
*
* @see org.semanticweb.elk.reasoner.taxonomy.TaxonomyPrinter#dumpInstanceTaxomomy
*
* @param taxonomy
* the {@link Taxonomy} to be printed
* @param filePath
* the file location
* @param addHash
* if true, a hash string will be added at the end of the output
* using comment syntax of OWL 2 Functional Style
* @throws IOException
* If an I/O error occurs
*/
public static void dumpInstanceTaxomomyToFile(
final InstanceTaxonomy extends ElkEntity, ? extends ElkEntity> taxonomy,
final String filePath, final boolean addHash) throws IOException {
final FileWriter fstream = new FileWriter(filePath);
final BufferedWriter writer = new BufferedWriter(fstream);
try {
dumpInstanceTaxomomy(taxonomy, writer, addHash);
} finally {
writer.close();
}
}
/**
* Print the contents of the given {@link InstanceTaxonomy} to the specified
* Writer. Expressions are ordered for generating the output, ensuring that
* the output is deterministic.
*
* @param taxonomy
* the {@link Taxonomy} to be printed
* @param writer
* the {@link Writer} used for printing
* @param addHash
* if true, a hash string will be added at the end of the output
* using comment syntax of OWL 2 Functional Style
* @throws IOException
* If an I/O error occurs
*/
public static void dumpInstanceTaxomomy(
final InstanceTaxonomy extends ElkEntity, ? extends ElkEntity> taxonomy,
final Writer writer, final boolean addHash) throws IOException {
writer.write("Ontology(\n");
processInstanceTaxomomy(taxonomy, writer);
writer.write(")\n");
if (addHash) {
writer.write(
"\n# Hash code: " + getInstanceHashString(taxonomy) + "\n");
}
writer.flush();
}
/**
* Get a hash string for the given {@link Taxonomy}. Besides possible hash
* collisions (which have very low probability) the hash string is the same
* for two inputs if and only if the inputs describe the same taxonomy. So
* it can be used to compare classification results.
*
* @param taxonomy
* the {@link Taxonomy} for which to compute the hash
* @return hash string
*/
public static String getHashString(Taxonomy extends ElkEntity> taxonomy) {
return Integer.toHexString(TaxonomyHasher.hash(taxonomy));
}
public static String getInstanceHashString(
InstanceTaxonomy extends ElkEntity, ? extends ElkEntity> taxonomy) {
return Integer.toHexString(InstanceTaxonomyHasher.hash(taxonomy));
}
/**
* Process a taxonomy and write a normalized serialization.
*
* @param taxonomy
* the {@link Taxonomy} to be processed
* @param writer
* the {@link Writer} used for printing
* @throws IOException
* If an I/O error occurs
* @param
* the type of objects stored in the {@link Taxonomy}
*/
protected static void processTaxomomy(
final Taxonomy taxonomy, final Appendable writer)
throws IOException {
final ElkObject.Factory factory = new ElkObjectEntityRecyclingFactory();
// Declarations.
final List members = new ArrayList(
taxonomy.getNodes().size() * 2);
for (final TaxonomyNode node : taxonomy.getNodes()) {
for (final T member : node) {
// TODO: this should check whether IRIs are predefined!
if (!member.getIri().equals(
taxonomy.getTopNode().getCanonicalMember().getIri())
&& !member.getIri().equals(taxonomy.getBottomNode()
.getCanonicalMember().getIri())) {
members.add(member);
}
}
}
Collections.sort(members, taxonomy.getKeyProvider().getComparator());
printDeclarations(members, factory, writer);
// Relations.
final TreeSet canonicalMembers = new TreeSet(
taxonomy.getKeyProvider().getComparator());
for (final TaxonomyNode node : taxonomy.getNodes()) {
canonicalMembers.add(node.getCanonicalMember());
}
for (final T canonicalMember : canonicalMembers) {
final TaxonomyNode node = taxonomy.getNode(canonicalMember);
final ArrayList orderedEquivalentMembers = new ArrayList(
node.size());
for (final T member : node) {
orderedEquivalentMembers.add(member);
}
Collections.sort(orderedEquivalentMembers,
taxonomy.getKeyProvider().getComparator());
final TreeSet orderedSuperMembers = new TreeSet(
taxonomy.getKeyProvider().getComparator());
for (final TaxonomyNode superNode : node.getDirectSuperNodes()) {
orderedSuperMembers.add(superNode.getCanonicalMember());
}
printMemberAxioms(canonicalMember, orderedEquivalentMembers,
orderedSuperMembers, taxonomy, factory, writer);
}
}
private static void printDeclarations(
final Iterable members, final ElkObject.Factory factory,
final Appendable writer) throws IOException {
for (final T member : members) {
final ElkAxiom axiom = factory.getDeclarationAxiom(member);
OwlFunctionalStylePrinter.append(writer, axiom, true);
writer.append('\n');
}
}
/**
* Process axioms related to one member of {@link Taxonomy}, where the
* relevant related members are given in two ordered collections of
* equivalent members and super-members, respectively. The method serializes
* the axioms to the Writer.
*
*/
private static void printMemberAxioms(
final I member, final List equivalentMembers,
final SortedSet directSuperMembers, final Taxonomy taxonomy,
final ElkObject.Factory factory, final Appendable writer)
throws IOException {
if (equivalentMembers.size() > 1) {
final ElkAxiom axiom = member.accept(
getEquivalentAxiomProvider(equivalentMembers, factory));
OwlFunctionalStylePrinter.append(writer, axiom, true);
writer.append('\n');
}
// TODO: this should exclude implicit axioms as owl:Thing ⊑ owl:Nothing
if (!member.equals(taxonomy.getBottomNode().getCanonicalMember())) {
for (final T superMember : directSuperMembers) {
if (!superMember
.equals(taxonomy.getTopNode().getCanonicalMember())) {
final ElkAxiom axiom = member
.accept(getSubAxiomProvider(superMember, factory));
OwlFunctionalStylePrinter.append(writer, axiom, true);
writer.append('\n');
}
}
}
}
private static ElkEntityVisitor getEquivalentAxiomProvider(
final List extends ElkEntity> equivalent,
final ElkObject.Factory factory) {
return new AbstractElkEntityVisitor() {
@Override
protected ElkAxiom defaultVisit(final ElkEntity entity) {
return null;
}
@Override
public ElkAxiom visit(final ElkClass cls) {
return factory.getEquivalentClassesAxiom(
new ArrayList(Operations.getCollection(
Operations.filter(equivalent, ElkClass.class),
equivalent.size())));
}
@Override
public ElkAxiom visit(final ElkNamedIndividual ind) {
return factory.getSameIndividualAxiom(
new ArrayList(
Operations.getCollection(
Operations.filter(equivalent,
ElkNamedIndividual.class),
equivalent.size())));
}
@Override
public ElkAxiom visit(final ElkObjectProperty prop) {
return factory.getEquivalentObjectPropertiesAxiom(
new ArrayList(
Operations.getCollection(
Operations.filter(equivalent,
ElkObjectProperty.class),
equivalent.size())));
}
};
}
private static ElkEntityVisitor getSubAxiomProvider(
final ElkEntity superEntity, final ElkObject.Factory factory) {
return new AbstractElkEntityVisitor() {
@Override
protected ElkAxiom defaultVisit(final ElkEntity entity) {
return null;
}
@Override
public ElkAxiom visit(final ElkClass cls) {
if (superEntity instanceof ElkClass) {
return factory.getSubClassOfAxiom(cls,
(ElkClass) superEntity);
}
// else
return defaultVisit(cls);
}
@Override
public ElkAxiom visit(final ElkNamedIndividual ind) {
if (superEntity instanceof ElkClass) {
return factory.getClassAssertionAxiom(
(ElkClass) superEntity, ind);
}
// else
return defaultVisit(ind);
}
@Override
public ElkAxiom visit(final ElkObjectProperty prop) {
if (superEntity instanceof ElkObjectProperty) {
return factory.getSubObjectPropertyOfAxiom(prop,
(ElkObjectProperty) superEntity);
}
// else
return defaultVisit(prop);
}
};
}
protected static void processInstanceTaxomomy(
final InstanceTaxonomy taxonomy, final Appendable writer)
throws IOException {
final ElkObject.Factory factory = new ElkObjectEntityRecyclingFactory();
// Declarations.
final List members = new ArrayList(
taxonomy.getInstanceNodes().size() * 2);
for (final InstanceNode node : taxonomy.getInstanceNodes()) {
for (final I member : node) {
members.add(member);
}
}
Collections.sort(members,
taxonomy.getInstanceKeyProvider().getComparator());
printDeclarations(members, factory, writer);
// TBox.
processTaxomomy(taxonomy, writer);
// ABox.
final TreeSet canonicalIndividuals = new TreeSet(
taxonomy.getInstanceKeyProvider().getComparator());
for (final InstanceNode node : taxonomy.getInstanceNodes()) {
canonicalIndividuals.add(node.getCanonicalMember());
}
for (final I individual : canonicalIndividuals) {
final InstanceNode node = taxonomy
.getInstanceNode(individual);
final ArrayList orderedSameIndividuals = new ArrayList(
node.size());
for (final I member : node) {
orderedSameIndividuals.add(member);
}
Collections.sort(orderedSameIndividuals,
taxonomy.getInstanceKeyProvider().getComparator());
final TreeSet orderedTypes = new TreeSet(
taxonomy.getKeyProvider().getComparator());
for (final TypeNode typeNode : node.getDirectTypeNodes()) {
orderedTypes.add(typeNode.getCanonicalMember());
}
printMemberAxioms(individual, orderedSameIndividuals, orderedTypes,
taxonomy, factory, writer);
}
}
}