/*******************************************************************************
* Copyright 2012 University of Southern California
*
* 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.
*
* This code was developed by the Information Integration Group as part
* of the Karma project at the Information Sciences Institute of the
* University of Southern California. For more information, publications,
* and related projects, please see: http://www.isi.edu/integration
******************************************************************************/
package edu.isi.karma.modeling.alignment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.jgrapht.UndirectedGraph;
import org.jgrapht.graph.DirectedWeightedMultigraph;
import org.jgrapht.traverse.BreadthFirstIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.isi.karma.modeling.Uris;
import edu.isi.karma.rep.alignment.CompactLink;
import edu.isi.karma.rep.alignment.CompactObjectPropertyLink;
import edu.isi.karma.rep.alignment.CompactSubClassLink;
import edu.isi.karma.rep.alignment.DefaultLink;
import edu.isi.karma.rep.alignment.LabeledLink;
import edu.isi.karma.rep.alignment.LinkPriorityComparator;
import edu.isi.karma.rep.alignment.LinkType;
import edu.isi.karma.rep.alignment.Node;
public class TreePostProcess {
static Logger logger = LoggerFactory.getLogger(TreePostProcess.class);
private GraphBuilder graphBuilder;
private DirectedWeightedMultigraph<Node, DefaultLink> tree;
private Node root = null;
// private List<Node> dangledVertexList;
// Constructor
public TreePostProcess(
GraphBuilder graphBuilder,
UndirectedGraph<Node, DefaultLink> tree,
Set<LabeledLink> newLinks,
boolean findRoot) {
this.graphBuilder = graphBuilder;
this.tree = (DirectedWeightedMultigraph<Node, DefaultLink>)GraphUtil.asDirectedGraph(tree);
buildOutputTree(true);
addLinks(newLinks);
if (findRoot) {
this.root = selectRoot(this.tree);
}
}
public TreePostProcess(
GraphBuilder graphBuilder,
UndirectedGraph<Node, DefaultLink> tree) {
this.graphBuilder = graphBuilder;
this.tree = (DirectedWeightedMultigraph<Node, DefaultLink>)GraphUtil.asDirectedGraph(tree);
buildOutputTree(false);
}
// Public Methods
public DirectedWeightedMultigraph<Node, LabeledLink> getTree() {
return (DirectedWeightedMultigraph<Node, LabeledLink>)GraphUtil.asLabeledGraph(this.tree);
}
public Node getRoot() {
return this.root;
}
// Private Methods
private static List<Node> findPossibleRoots(DirectedWeightedMultigraph<Node, DefaultLink> tree) {
List<Node> possibleRoots = new ArrayList<>();
// If tree contains the Thing, we return it as the root
for (Node v: tree.vertexSet()) {
if (v.getLabel() != null && v.getLabel().getUri() != null && v.getLabel().getUri().equals(Uris.THING_URI)) {
possibleRoots.add(v);
}
}
int maxReachableNodes = -1;
int reachableNodes;
List<Node> vertexList = new ArrayList<>();
List<Integer> reachableNodesList = new ArrayList<>();
for (Node v: tree.vertexSet()) {
BreadthFirstIterator<Node, DefaultLink> i =
new BreadthFirstIterator<>(tree, v);
reachableNodes = -1;
while (i.hasNext()) {
i.next();
reachableNodes ++;
}
vertexList.add(v);
reachableNodesList.add(reachableNodes);
if (reachableNodes > maxReachableNodes) {
maxReachableNodes = reachableNodes;
}
}
for (int i = 0; i < vertexList.size(); i++)
if (reachableNodesList.get(i).intValue() == maxReachableNodes)
possibleRoots.add(vertexList.get(i));
return possibleRoots;
}
public static Node selectRoot(DirectedWeightedMultigraph<Node, DefaultLink> tree) {
List<Node> possibleRoots = findPossibleRoots(tree);
if (possibleRoots == null || possibleRoots.isEmpty())
return null;
Collections.sort(possibleRoots);
return possibleRoots.get(0);
}
private void buildOutputTree(boolean allowedChangingGraph) {
String sourceId, targetId;
DefaultLink[] links = tree.edgeSet().toArray(new DefaultLink[0]);
// String linkSourceId;//, linkTargetId;
List<LabeledLink> temp1 = null;
// List<LabeledLink> temp2 = null;
List<LabeledLink> possibleLinks = new ArrayList<>();
for (DefaultLink link : links) {
if (link instanceof CompactLink) {
// links from source to target
sourceId = link.getSource().getId();
targetId = link.getTarget().getId();
possibleLinks.clear();
if (link instanceof CompactSubClassLink) {
temp1 = this.graphBuilder.getPossibleLinks(sourceId, targetId, LinkType.SubClassLink, null);
// temp2 = this.graphBuilder.getPossibleLinks(targetId, sourceId, LinkType.SubClassLink, null);
} else if (link instanceof CompactObjectPropertyLink) {
temp1 = this.graphBuilder.getPossibleLinks(sourceId, targetId,
LinkType.ObjectPropertyLink, ((CompactObjectPropertyLink) link).getObjectPropertyType());
// temp2 = this.graphBuilder.getPossibleLinks(targetId, sourceId,
// LinkType.ObjectPropertyLink, ((CompactObjectPropertyLink) link).getObjectPropertyType());
}
if (temp1 != null) possibleLinks.addAll(temp1);
// if (temp2 != null) possibleLinks.addAll(temp2);
Collections.sort(possibleLinks, new LinkPriorityComparator());
if (!possibleLinks.isEmpty()) {
// pick the first one
LabeledLink newLink = possibleLinks.get(0);
// linkSourceId = LinkIdFactory.getLinkSourceId(newLink.getId());
//linkTargetId = LinkIdFactory.getLinkTargetId(newLink.getId());
// if (linkSourceId.equals(sourceId)) {
tree.addEdge(link.getSource(), link.getTarget(), newLink);
tree.setEdgeWeight(newLink, link.getWeight());
if (allowedChangingGraph) this.graphBuilder.addLink(link.getSource(), link.getTarget(), newLink);
// } else {
// tree.addEdge(link.getTarget(), link.getSource(), newLink);
// tree.setEdgeWeight(newLink, link.getWeight());
// if (allowedChangingGraph) this.graphBuilder.addLink(link.getTarget(), link.getSource(), newLink);
// }
tree.removeEdge(link);
if (allowedChangingGraph) this.graphBuilder.removeLink(link);
} else {
logger.error("Something is going wrong. " +
"There should be at least one possible object property between " +
link.getSource().getLabel().getUri() +
" and " + link.getTarget().getLabel().getUri());
return;
}
}
}
}
private void addLinks(Set<LabeledLink> links) {
if (links == null)
return;
for (LabeledLink link : links) {
if (!this.tree.containsEdge(link) &&
this.tree.containsVertex(link.getSource()) &&
this.tree.containsVertex(link.getTarget())) {
this.tree.addEdge(link.getSource(), link.getTarget(), link);
}
}
}
}