package uk.ac.manchester.cs.jfact.kernel; /* This file is part of the JFact DL reasoner Copyright 2011-2013 by Ignazio Palmisano, Dmitry Tsarkov, University of Manchester This library 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 2.1 of the License, or (at your option) any later version. This library 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 this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*/ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.semanticweb.owlapi.model.IRI; import uk.ac.manchester.cs.jfact.helpers.LogAdapter; import uk.ac.manchester.cs.jfact.helpers.Templates; import uk.ac.manchester.cs.jfact.kernel.options.JFactReasonerConfiguration; import conformance.Original; import conformance.PortedFrom; /** taxonomy vertex */ @PortedFrom(file = "taxVertex.h", name = "TaxonomyVertex") public class TaxonomyVertex implements Serializable { private static final long serialVersionUID = 11000L; /** immediate parents and children */ @PortedFrom(file = "taxVertex.h", name = "Links") private LinkedHashSet<TaxonomyVertex> linksParent = new LinkedHashSet<TaxonomyVertex>(); @PortedFrom(file = "taxVertex.h", name = "Links") private LinkedHashSet<TaxonomyVertex> linksChild = new LinkedHashSet<TaxonomyVertex>(); /** entry corresponding to current tax vertex */ @PortedFrom(file = "taxVertex.h", name = "sample") private ClassifiableEntry sample = null; /** synonyms of the sample entry */ @PortedFrom(file = "taxVertex.h", name = "synonyms") private Set<ClassifiableEntry> synonyms = new LinkedHashSet<ClassifiableEntry>(); // labels for different purposes. all for 2 directions: top-down and // bottom-up search /** flag if given vertex was checked; connected with checkLab */ @PortedFrom(file = "taxVertex.h", name = "checked") private long checked; /** flag if given vertex has value; connected with valuedLab */ @Original private long isValued; /** number of common parents of a node */ @PortedFrom(file = "taxVertex.h", name = "common") private int common; /** satisfiability value of a valued vertex */ @PortedFrom(file = "taxVertex.h", name = "checkValue") private boolean checkValue; /** flag to check whether the vertex is in use */ @PortedFrom(file = "taxVertex.h", name = "inUse") private boolean inUse = true; /** * mark vertex as the one corresponding to a given ENTRY * * @param entry * entry */ @PortedFrom(file = "taxVertex.h", name = "setVertexAsHost") public void setVertexAsHost(ClassifiableEntry entry) { entry.setTaxVertex(this); } /** * set sample to ENTRY * * @param entry * entry * @param linkBack * linkBack */ @PortedFrom(file = "taxVertex.h", name = "setSample") public void setSample(ClassifiableEntry entry, boolean linkBack) { sample = entry; if (linkBack) { entry.setTaxVertex(this); } } /** * @param upDirection * upDirection * @return Links */ @PortedFrom(file = "taxVertex.h", name = "neigh") public Iterable<TaxonomyVertex> neigh(boolean upDirection) { return upDirection ? linksParent : linksChild; } // checked part /** * @param checkLab * checkLab * @return true if checked */ @PortedFrom(file = "taxVertex.h", name = "isChecked") public boolean isChecked(long checkLab) { return checkLab == checked; } /** * @param checkLab * checkLab */ @PortedFrom(file = "taxVertex.h", name = "setChecked") public void setChecked(long checkLab) { checked = checkLab; } // value part /** * @param valueLab * valueLab * @return true if values */ @PortedFrom(file = "taxVertex.h", name = "isValued") public boolean isValued(long valueLab) { return valueLab == isValued; } /** @return value */ @PortedFrom(file = "taxVertex.h", name = "getValue") public boolean getValue() { return checkValue; } /** * @param val * val * @param valueLab * valueLab * @return val */ @PortedFrom(file = "taxVertex.h", name = "setValued") public boolean setValued(boolean val, long valueLab) { isValued = valueLab; checkValue = val; return val; } // common part /** @return true if common not 0 */ @PortedFrom(file = "taxVertex.h", name = "isCommon") public boolean isCommon() { return common != 0; } /** increment common */ @PortedFrom(file = "taxVertex.h", name = "setCommon") public void setCommon() { ++common; } /** zero common */ @PortedFrom(file = "taxVertex.h", name = "clearCommon") public void clearCommon() { common = 0; } /** * keep COMMON flag iff both flags are set; * * @param n * n * @return true if it is the case */ @PortedFrom(file = "taxVertex.h", name = "correctCommon") public boolean correctCommon(int n) { if (common == n) { return true; } common = 0; return false; } /** put initial values on the flags */ @PortedFrom(file = "taxVertex.h", name = "initFlags") private void initFlags() { checked = 0; isValued = 0; common = 0; } // get info about taxonomy structure /** @return synonyms */ @PortedFrom(file = "taxVertex.h", name = "begin_syn") public Set<ClassifiableEntry> synonyms() { return synonyms; } /** default constructor */ public TaxonomyVertex() { initFlags(); } /** * init c'tor; use it only for Top/Bot initialisations * * @param p * p */ public TaxonomyVertex(ClassifiableEntry p) { initFlags(); setSample(p, true); } /** * add P as a synonym to curent vertex * * @param p * p */ @PortedFrom(file = "taxVertex.h", name = "addSynonym") public void addSynonym(ClassifiableEntry p) { synonyms.add(p); p.setTaxVertex(this); } /** clears the vertex */ @PortedFrom(file = "taxVertex.h", name = "clear") public void clear() { linksParent.clear(); linksChild.clear(); sample = null; initFlags(); } /** @return primer */ @PortedFrom(file = "taxVertex.h", name = "getPrimer") public ClassifiableEntry getPrimer() { return sample; } /** * add link in given direction to vertex * * @param upDirection * upDirection * @param p * p */ @PortedFrom(file = "taxVertex.h", name = "addNeighbour") public void addNeighbour(boolean upDirection, TaxonomyVertex p) { if (p == null) { throw new IllegalArgumentException("p cannot be null"); } add(upDirection, p); } public void add(boolean direction, TaxonomyVertex t) { if (direction) { linksParent.add(t); } else { linksChild.add(t); } } /** * @param upDirection * upDirection * @return check if vertex has no neighbours in given direction */ @PortedFrom(file = "taxVertex.h", name = "noNeighbours") public boolean noNeighbours(boolean upDirection) { if (upDirection) { return linksParent.isEmpty(); } else { return linksChild.isEmpty(); } } /** @return v if node represents a synonym (v=Up[i]==Down[j]); null otherwise */ @PortedFrom(file = "taxVertex.h", name = "getSynonymNode") public TaxonomyVertex getSynonymNode() { // try to find Vertex such that Vertex\in Up and Vertex\in Down for (TaxonomyVertex q : neigh(true)) { for (TaxonomyVertex r : neigh(false)) { if (q.equals(r)) { return q; } } } return null; } /** * clear all links in a given direction * * @param upDirection * upDirection */ @PortedFrom(file = "taxVertex.h", name = "clearLinks") public void clearLinks(boolean upDirection) { if (upDirection) { linksParent.clear(); } else { linksChild.clear(); } } /** * @param upDirection * upDirection * @param p * p * @return true if link removed */ @PortedFrom(file = "taxVertex.h", name = "removeLink") public boolean removeLink(boolean upDirection, TaxonomyVertex p) { if (upDirection) { return linksParent.remove(p); } return linksChild.remove(p); } // TODO does not work with synonyms /** * @param c * c */ @PortedFrom(file = "taxVertex.h", name = "incorporate") public void incorporate(JFactReasonerConfiguration c) { // setup links for (TaxonomyVertex d : neigh(false)) { for (TaxonomyVertex u : neigh(true)) { if (d.removeLink(true, u)) { u.removeLink(false, d); } } d.removeLink(/* upDirection= */true, this); // safe in general case, crucial for incremental d.addNeighbour(true, this); } for (TaxonomyVertex u : neigh(true)) { u.addNeighbour(false, this); } if (c.isLoggingActive()) { LogAdapter logAdapter = c.getLog(); logAdapter.printTemplate(Templates.INCORPORATE, sample.getName()); logAdapter.print(names(neigh(true))); logAdapter.print("} and down = {"); logAdapter.print(names(neigh(false))); logAdapter.print("}"); } } Iterable<IRI> names(Iterable<TaxonomyVertex> l) { List<IRI> toReturn = new ArrayList<IRI>(); for (TaxonomyVertex t : l) { toReturn.add(t.sample.getName()); } return toReturn; } /** * remove one half of a given node from a graph * * @param upDirection * upDirection */ @PortedFrom(file = "taxVertex.h", name = "removeLinks") public void removeLinks(boolean upDirection) { for (TaxonomyVertex p : neigh(upDirection)) { p.removeLink(!upDirection, this); } clearLinks(upDirection); } /** remove given node from a graph */ @PortedFrom(file = "taxVertex.h", name = "remove") public void remove() { removeLinks(true); removeLinks(false); setInUse(false); } /** @return true iff the node is in use */ @PortedFrom(file = "taxVertex.h", name = "isInUse") public boolean isInUse() { return inUse; } /** * set the inUse value of the node * * @param value * value */ @PortedFrom(file = "taxVertex.h", name = "setInUse") public void setInUse(boolean value) { inUse = value; } /** * merge NODE which is independent to THIS * * @param node * node * @param excludes * excludes * @param curEntry * curEntry */ @PortedFrom(file = "taxVertex.h", name = "mergeIndepNode") public void mergeIndepNode(TaxonomyVertex node, Set<TaxonomyVertex> excludes, ClassifiableEntry curEntry) { // copy synonyms here if (!node.getPrimer().equals(curEntry)) { addSynonym(node.getPrimer()); } for (ClassifiableEntry q : node.synonyms()) { addSynonym(q); } boolean upDirection = true; for (TaxonomyVertex p : node.neigh(upDirection)) { if (!excludes.contains(p)) { addNeighbour(upDirection, p); } p.removeLink(!upDirection, node); } upDirection = false; for (TaxonomyVertex p : node.neigh(upDirection)) { if (!excludes.contains(p)) { addNeighbour(upDirection, p); } p.removeLink(!upDirection, node); } } /** @return synonyms debug print */ @PortedFrom(file = "taxVertex.h", name = "printSynonyms") public String printSynonyms() { assert sample != null; StringBuilder o = new StringBuilder(); if (synonyms.isEmpty()) { o.append('"'); o.append(sample.getName()); o.append('"'); } else { o.append("(\""); o.append(sample.getName()); for (ClassifiableEntry q : synonyms()) { o.append("\"=\""); o.append(q.getName()); } o.append("\")"); } return o.toString(); } /** * @param list * vertexes to print * @return neighbours debug print */ @PortedFrom(file = "taxVertex.h", name = "printNeighbours") private static String printNeighbours(Collection<TaxonomyVertex> list) { StringBuilder o = new StringBuilder(); o.append(" {"); o.append(list.size()); o.append(':'); TreeSet<TaxonomyVertex> sorted = new TreeSet<TaxonomyVertex>( new Comparator<TaxonomyVertex>() { @Override public int compare(TaxonomyVertex o1, TaxonomyVertex o2) { return o1.getPrimer().getName() .compareTo(o2.getPrimer().getName()); } }); sorted.addAll(list); for (TaxonomyVertex p : sorted) { o.append(" \""); o.append(p.sample.getName()); o.append('"'); } o.append('}'); return o.toString(); } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append(printSynonyms()); b.append(printNeighbours(linksParent)); b.append(printNeighbours(linksChild)); b.append('\n'); return b.toString(); } }