/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.graph.dhns.core;
import org.gephi.utils.collection.avl.ParamAVLIterator;
import org.gephi.graph.dhns.edge.AbstractEdge;
import org.gephi.graph.dhns.edge.MetaEdgeImpl;
import org.gephi.graph.dhns.node.AbstractNode;
import org.gephi.graph.dhns.node.iterators.TreeIterator;
import org.gephi.graph.dhns.node.iterators.TreeListIterator;
import org.gephi.graph.dhns.predicate.Tautology;
/**
* Business class for managing Edges and MetaEdges.
*
* @author Mathieu Bastian
*/
public class EdgeProcessor {
//Architecture
private final TreeStructure treeStructure;
private final Dhns dhns;
private final GraphViewImpl view;
private final int viewId;
//Cache
private ParamAVLIterator<AbstractEdge> edgeIterator;
public EdgeProcessor(Dhns dhns, GraphViewImpl view) {
this.dhns = dhns;
this.treeStructure = view.getStructure();
this.view = view;
this.viewId = view.getViewId();
this.edgeIterator = new ParamAVLIterator<AbstractEdge>();
}
public AbstractEdge[] clearEdges(AbstractNode node) {
int edgesCount = node.getEdgesInTree().getCount() + node.getEdgesOutTree().getCount();
if (edgesCount == 0) {
return null;
}
AbstractEdge[] clearedEdges = new AbstractEdge[edgesCount];
int i = 0;
if (node.getEdgesInTree().getCount() > 0) {
edgeIterator.setNode(node.getEdgesInTree());
while (edgeIterator.hasNext()) {
AbstractEdge edge = edgeIterator.next();
removeEdgeFromMetaEdge(edge);
AbstractNode source = edge.getSource(viewId);
view.decEdgesCountTotal(1);
boolean mutual = !edge.isSelfLoop() && node.getEdgesOutTree().hasNeighbour(source);
if (node.isEnabled() && source.isEnabled()) {
view.decEdgesCountEnabled(1);
node.decEnabledInDegree();
source.decEnabledOutDegree();
if (mutual) {
source.decEnabledMutualDegree();
node.decEnabledMutualDegree();
view.decMutualEdgesEnabled(1);
}
}
if (mutual) {
view.decMutualEdgesTotal(1);
}
source.getEdgesOutTree().remove(edge);
clearedEdges[i] = edge;
i++;
}
node.getEdgesInTree().clear();
}
if (node.getEdgesOutTree().getCount() > 0) {
edgeIterator.setNode(node.getEdgesOutTree());
while (edgeIterator.hasNext()) {
AbstractEdge edge = edgeIterator.next();
removeEdgeFromMetaEdge(edge);
AbstractNode target = edge.getTarget(viewId);
if (!edge.isSelfLoop()) {
view.decEdgesCountTotal(1);
if (node.isEnabled()) {
node.decEnabledOutDegree();
target.decEnabledInDegree();
view.decEdgesCountEnabled(1);
}
}
edge.getTarget(viewId).getEdgesInTree().remove(edge);
clearedEdges[i] = edge;
i++;
}
node.getEdgesOutTree().clear();
}
return clearedEdges;
}
public void clearEdgesWithoutRemove(AbstractNode node) {
if (node.getEdgesInTree().getCount() > 0) {
edgeIterator.setNode(node.getEdgesInTree());
while (edgeIterator.hasNext()) {
AbstractEdge edge = edgeIterator.next();
removeEdgeFromMetaEdge(edge);
}
}
if (node.getEdgesOutTree().getCount() > 0) {
edgeIterator.setNode(node.getEdgesOutTree());
while (edgeIterator.hasNext()) {
AbstractEdge edge = edgeIterator.next();
removeEdgeFromMetaEdge(edge);
}
}
}
public void clearMetaEdges(AbstractNode node) {
if (node.getMetaEdgesInTree().getCount() > 0) {
edgeIterator.setNode(node.getMetaEdgesInTree());
while (edgeIterator.hasNext()) {
AbstractEdge edge = edgeIterator.next();
AbstractNode source = edge.getSource(viewId);
if (!edge.isSelfLoop() && node.getEdgesOutTree().hasNeighbour(source)) {
node.decMutualMetaEdgeDegree();
source.decMutualMetaEdgeDegree();
view.decMutualMetaEdgesTotal(1);
}
source.getMetaEdgesOutTree().remove((MetaEdgeImpl) edge);
view.decMetaEdgesCount(1);
}
node.getMetaEdgesInTree().clear();
}
if (node.getMetaEdgesOutTree().getCount() > 0) {
edgeIterator.setNode(node.getMetaEdgesOutTree());
while (edgeIterator.hasNext()) {
AbstractEdge edge = edgeIterator.next();
edge.getTarget(viewId).getMetaEdgesInTree().remove((MetaEdgeImpl) edge);
view.decMetaEdgesCount(1);
}
node.getMetaEdgesOutTree().clear();
}
}
public void clearMetaEdgesOutOfRange(AbstractNode enabledNode, AbstractNode rangeNode) {
int rangeStart = rangeNode.getPre();
int rangeLimit = rangeStart + rangeNode.size;
if (enabledNode.getMetaEdgesOutTree().getCount() > 0) {
edgeIterator.setNode(enabledNode.getMetaEdgesOutTree());
while (edgeIterator.hasNext()) {
MetaEdgeImpl metaEdge = (MetaEdgeImpl) edgeIterator.next();
AbstractNode target = metaEdge.getTarget(viewId);
int targetPre = target.getPre();
if (targetPre >= rangeStart && targetPre <= rangeLimit) {
//The meta edge has to be removed because it's in the range
if (!metaEdge.isSelfLoop() && target.getEdgesInTree().hasNeighbour(enabledNode)) {
enabledNode.decMutualMetaEdgeDegree();
target.decMutualMetaEdgeDegree();
view.decMutualMetaEdgesTotal(1);
}
edgeIterator.remove();
target.getMetaEdgesInTree().remove(metaEdge);
view.decMetaEdgesCount(1);
}
}
}
if (enabledNode.getMetaEdgesInTree().getCount() > 0) {
edgeIterator.setNode(enabledNode.getMetaEdgesInTree());
while (edgeIterator.hasNext()) {
MetaEdgeImpl metaEdge = (MetaEdgeImpl) edgeIterator.next();
int sourcePre = metaEdge.getSource(viewId).getPre();
if (sourcePre >= rangeStart && sourcePre <= rangeLimit) {
//The meta edge has to be removed because it's in the range
edgeIterator.remove();
metaEdge.getSource(viewId).getMetaEdgesOutTree().remove(metaEdge);
view.decMetaEdgesCount(1);
}
}
}
}
public AbstractEdge[] clearAllEdges() {
AbstractEdge[] edges = new AbstractEdge[view.getEdgesCountTotal()];
int i = 0;
for (TreeListIterator itr = new TreeListIterator(treeStructure.getTree()); itr.hasNext();) {
AbstractNode node = itr.next();
edgeIterator.setNode(node.getEdgesOutTree());
while (edgeIterator.hasNext()) {
AbstractEdge edge = edgeIterator.next();
dhns.getGraphStructure().removeFromDictionnary(edge);
edges[i++] = edge;
}
node.getEdgesInTree().clear();
node.getEdgesOutTree().clear();
node.setEnabledInDegree(0);
node.setEnabledOutDegree(0);
node.setEnabledMutualDegree(0);
node.clearMetaEdges();
}
view.setEdgesCountTotal(0);
view.setEdgesCountEnabled(0);
view.setMutualEdgesEnabled(0);
view.setMutualEdgesTotal(0);
return edges;
}
public void clearAllMetaEdges() {
for (TreeListIterator itr = new TreeListIterator(treeStructure.getTree()); itr.hasNext();) {
AbstractNode node = itr.next();
node.clearMetaEdges();
node.setMutualMetaEdgeDegree(0);
}
view.setMetaEdgesCountTotal(0);
view.setMutualMetaEdgesTotal(0);
}
public void computeMetaEdges(AbstractNode node, AbstractNode enabledAncestor) {
if (!dhns.getSettingsManager().isAutoMetaEdgeCreation()) {
return;
}
if (enabledAncestor == null) {
enabledAncestor = node;
}
int clusterEnd = node.getPre() + node.size;
for (int i = node.pre; i <= clusterEnd; i++) {
AbstractNode desc = treeStructure.getNodeAt(i);
if (desc.getEdgesOutTree().getCount() > 0) {
edgeIterator.setNode(desc.getEdgesOutTree());
while (edgeIterator.hasNext()) {
AbstractEdge edge = edgeIterator.next();
AbstractNode[] enabledAncestors = treeStructure.getEnabledAncestorsOrSelf(edge.getTarget(viewId));
if (enabledAncestors != null) {
for (int j = 0; j < enabledAncestors.length; j++) {
AbstractNode targetNode = enabledAncestors[j];
if (!(targetNode == edge.getTarget(viewId) && enabledAncestor == edge.getSource(viewId))) {
createMetaEdge(enabledAncestor, targetNode, edge);
}
}
}
// AbstractNode targetNode = treeStructure.getEnabledAncestorOrSelf(edge.getTarget(viewId));
// if (targetNode != null && !(targetNode == edge.getTarget(viewId) && enabledAncestor == edge.getSource(viewId))) {
// //Create Meta Edge if not exist
// createMetaEdge(enabledAncestor, targetNode, edge);
// }
}
}
if (desc.getEdgesInTree().getCount() > 0) {
edgeIterator.setNode(desc.getEdgesInTree());
while (edgeIterator.hasNext()) {
AbstractEdge edge = edgeIterator.next();
AbstractNode[] enabledAncestors = treeStructure.getEnabledAncestorsOrSelf(edge.getSource(viewId));
if (enabledAncestors != null) {
for (int j = 0; j < enabledAncestors.length; j++) {
AbstractNode sourceNode = enabledAncestors[j];
if (!(sourceNode == edge.getSource(viewId) && enabledAncestor == edge.getTarget(viewId))) {
createMetaEdge(sourceNode, enabledAncestor, edge);
}
}
}
// AbstractNode sourceNode = treeStructure.getEnabledAncestorOrSelf(edge.getSource(viewId));
// if (sourceNode != null && !(sourceNode == edge.getSource(viewId) && enabledAncestor == edge.getTarget(viewId))) {
// //Create Meta Edge if not exist
// createMetaEdge(sourceNode, enabledAncestor, edge);
// }
}
}
}
}
public void computeMetaEdges() {
for (TreeIterator itr = new TreeIterator(treeStructure, true, Tautology.instance); itr.hasNext();) {
AbstractNode node = itr.next();
computeMetaEdges(node, node);
}
}
private void createMetaEdge(AbstractNode source, AbstractNode target, AbstractEdge edge) {
AbstractNode edgeSource = edge.getSource(viewId);
AbstractNode edgeTarget = edge.getTarget(viewId);
if (edgeSource == source && edgeTarget == target) {
return;
}
if (source == target) {
return;
}
MetaEdgeImpl metaEdge = getMetaEdge(source, target);
if (metaEdge == null) {
metaEdge = createMetaEdge(source, target);
}
if (metaEdge != null) {
if (metaEdge.addEdge(edge)) {
dhns.getSettingsManager().getMetaEdgeBuilder().pushEdge(edge, edgeSource, edgeTarget, metaEdge);
}
}
}
private MetaEdgeImpl createMetaEdge(AbstractNode source, AbstractNode target) {
if (source == target) {
return null;
}
MetaEdgeImpl newEdge = dhns.factory().newMetaEdge(source, target);
source.getMetaEdgesOutTree().add(newEdge);
target.getMetaEdgesInTree().add(newEdge);
if (!newEdge.isSelfLoop() && target.getEdgesInTree().hasNeighbour(source)) {
source.incMutualMetaEdgeDegree();
target.incMutualMetaEdgeDegree();
view.incMutualMetaEdgesTotal(1);
}
view.incMetaEdgesCount(1);
return newEdge;
}
public void createMetaEdge(AbstractEdge edge) {
if (!dhns.getSettingsManager().isAutoMetaEdgeCreation()) {
return;
}
if (edge.isSelfLoop()) {
return;
}
AbstractNode[] sourceAncestors = treeStructure.getEnabledAncestorsOrSelf(edge.getSource(viewId));
AbstractNode[] targetAncestors = treeStructure.getEnabledAncestorsOrSelf(edge.getTarget(viewId));
if (sourceAncestors != null && targetAncestors != null) {
for (int i = 0; i < sourceAncestors.length; i++) {
for (int j = 0; j < targetAncestors.length; j++) {
AbstractNode sourceParent = sourceAncestors[i];
AbstractNode targetParent = targetAncestors[j];
if (sourceParent != targetParent) {
createMetaEdge(sourceParent, targetParent, edge);
}
}
}
}
// AbstractNode sourceParent = treeStructure.getEnabledAncestorOrSelf(edge.getSource(viewId));
// AbstractNode targetParent = treeStructure.getEnabledAncestorOrSelf(edge.getTarget(viewId));
//
// if (sourceParent != null && targetParent != null && sourceParent != targetParent) {
// createMetaEdge(sourceParent, targetParent, edge);
// }
}
public void removeEdgeFromMetaEdge(AbstractEdge edge) {
if (!dhns.getSettingsManager().isAutoMetaEdgeCreation()) {
return;
}
if (edge.isSelfLoop()) {
return;
}
MetaEdgeImpl metaEdge = getMetaEdge(edge);
if (metaEdge != null) {
if (metaEdge.removeEdge(edge)) {
AbstractNode edgeSource = edge.getSource(viewId);
AbstractNode edgeTarget = edge.getTarget(viewId);
dhns.getSettingsManager().getMetaEdgeBuilder().pullEdge(edge, edgeSource, edgeTarget, metaEdge);
}
if (metaEdge.isEmpty()) {
AbstractNode source = metaEdge.getSource(viewId);
AbstractNode target = metaEdge.getTarget(viewId);
if(!metaEdge.isSelfLoop() && source.getMetaEdgesInTree().hasNeighbour(target)) {
source.decMutualMetaEdgeDegree();
target.decMutualMetaEdgeDegree();
view.decMutualMetaEdgesTotal(1);
}
source.getMetaEdgesOutTree().remove(metaEdge);
target.getMetaEdgesInTree().remove(metaEdge);
view.decMetaEdgesCount(1);
}
}
}
private MetaEdgeImpl getMetaEdge(AbstractNode source, AbstractNode target) {
if (source == target) {
return null;
}
return source.getMetaEdgesOutTree().getItem(target.getNumber());
}
private MetaEdgeImpl getMetaEdge(AbstractEdge edge) {
if (edge.isSelfLoop()) {
return null;
}
AbstractNode sourceParent = treeStructure.getEnabledAncestorOrSelf(edge.getSource(viewId));
AbstractNode targetParent = treeStructure.getEnabledAncestorOrSelf(edge.getTarget(viewId));
if (sourceParent != null && targetParent != null && sourceParent != targetParent) {
return getMetaEdge(sourceParent, targetParent);
}
return null;
}
public AbstractEdge[] flattenNode(AbstractNode node) {
AbstractEdge[] newEdges = null;
if (!node.getMetaEdgesInTree().isEmpty() || !node.getMetaEdgesOutTree().isEmpty()) {
newEdges = new AbstractEdge[node.getMetaEdgesInTree().getCount() + node.getMetaEdgesOutTree().getCount()];
}
int i = 0;
if (!node.getMetaEdgesInTree().isEmpty()) {
for (edgeIterator.setNode(node.getMetaEdgesInTree()); edgeIterator.hasNext();) {
AbstractEdge edge = edgeIterator.next();
AbstractNode source = edge.getSource(viewId);
edgeIterator.remove();
source.getMetaEdgesOutTree().remove((MetaEdgeImpl) edge);
view.decMetaEdgesCount(1);
if (!node.getEdgesInTree().hasNeighbour(source)) {
AbstractEdge realEdge = dhns.factory().newEdge(source, node, edge.getWeight(), edge.isDirected());
realEdge.getEdgeData().moveFrom(edge.getEdgeData());
realEdge.setWeight(edge.getWeight());
newEdges[i] = realEdge;
source.getEdgesOutTree().add(realEdge);
node.getEdgesInTree().add(realEdge);
source.incEnabledOutDegree();
node.incEnabledInDegree();
view.incEdgesCountEnabled(1);
view.incEdgesCountTotal(1);
if (source.getEdgesInTree().hasNeighbour(node)) {
//Mutual
source.incEnabledMutualDegree();
node.incEnabledMutualDegree();
view.incMutualEdgesEnabled(1);
view.incMutualEdgesTotal(1);
}
}
i++;
}
}
if (!node.getMetaEdgesOutTree().isEmpty()) {
for (edgeIterator.setNode(node.getMetaEdgesOutTree()); edgeIterator.hasNext();) {
AbstractEdge edge = edgeIterator.next();
AbstractNode target = edge.getTarget(viewId);
edgeIterator.remove();
target.getMetaEdgesInTree().remove((MetaEdgeImpl) edge);
view.decMetaEdgesCount(1);
if (!node.getEdgesOutTree().hasNeighbour(target)) {
AbstractEdge realEdge = dhns.factory().newEdge(node, target, edge.getWeight(), edge.isDirected());
realEdge.getEdgeData().moveFrom(edge.getEdgeData());
realEdge.setWeight(edge.getWeight());
newEdges[i] = realEdge;
node.getEdgesOutTree().add(realEdge);
target.getEdgesInTree().add(realEdge);
node.incEnabledOutDegree();
target.incEnabledInDegree();
view.incEdgesCountEnabled(1);
view.incEdgesCountTotal(1);
if (target.getEdgesOutTree().hasNeighbour(node)) {
//Mutual
node.incEnabledMutualDegree();
target.incEnabledMutualDegree();
view.incMutualEdgesEnabled(1);
view.incMutualEdgesTotal(1);
}
}
i++;
}
}
view.decMutualMetaEdgesTotal(node.getMutualMetaEdgeDegree());
node.setMutualMetaEdgeDegree(0);
return newEdges;
}
public void incrementEdgesCounting(AbstractNode enabledNode, AbstractNode parent) {
for (edgeIterator.setNode(enabledNode.getEdgesOutTree()); edgeIterator.hasNext();) {
AbstractEdge edge = edgeIterator.next();
AbstractNode target = edge.getTarget(view.getViewId());
if (target.isEnabled()) {
view.incEdgesCountEnabled(1);
enabledNode.incEnabledOutDegree();
target.incEnabledInDegree();
if (target.getEdgesOutTree().hasNeighbour(enabledNode)) {
if (parent == null || (parent != null && target.parent != parent) || (parent != null && target.parent == parent && target.getId() < enabledNode.getId())) {
view.incMutualEdgesEnabled(1);
enabledNode.incEnabledMutualDegree();
target.incEnabledMutualDegree();
}
}
}
}
for (edgeIterator.setNode(enabledNode.getEdgesInTree()); edgeIterator.hasNext();) {
AbstractEdge edge = edgeIterator.next();
AbstractNode source = edge.getSource(view.getViewId());
if (source.isEnabled() && (parent == null || source.parent != parent)) {
view.incEdgesCountEnabled(1);
enabledNode.incEnabledInDegree();
source.incEnabledOutDegree();
}
}
}
public void decrementEdgesCouting(AbstractNode disabledNode, AbstractNode parent) {
for (edgeIterator.setNode(disabledNode.getEdgesOutTree()); edgeIterator.hasNext();) {
AbstractEdge edge = edgeIterator.next();
AbstractNode target = edge.getTarget(view.getViewId());
if (target.isEnabled() || (parent != null && target.parent == parent)) {
target.decEnabledInDegree();
disabledNode.decEnabledOutDegree();
view.decEdgesCountEnabled(1);
if (target.getEdgesOutTree().hasNeighbour(disabledNode) && (parent == null || (parent != null && target.parent == parent && target.getId() < disabledNode.getId()))) {
target.decEnabledMutualDegree();
disabledNode.decEnabledMutualDegree();
view.decMutualEdgesEnabled(1);
}
}
}
for (edgeIterator.setNode(disabledNode.getEdgesInTree()); edgeIterator.hasNext();) {
AbstractEdge edge = edgeIterator.next();
AbstractNode source = edge.getSource(view.getViewId());
if (source.isEnabled()) {
view.decEdgesCountEnabled(1);
disabledNode.decEnabledInDegree();
source.decEnabledOutDegree();
}
}
}
public void resetEdgesCounting(AbstractNode node) {
node.setEnabledInDegree(0);
node.setEnabledOutDegree(0);
node.setEnabledMutualDegree(0);
}
public void computeEdgesCounting(AbstractNode node) {
for (edgeIterator.setNode(node.getEdgesOutTree()); edgeIterator.hasNext();) {
AbstractEdge edge = edgeIterator.next();
AbstractNode target = edge.getTarget(view.getViewId());
if (target.isEnabled()) {
target.incEnabledInDegree();
node.incEnabledOutDegree();
view.incEdgesCountEnabled(1);
if (target.getEdgesOutTree().hasNeighbour(node) && target.getId() < node.getId()) {
target.incEnabledMutualDegree();
node.incEnabledMutualDegree();
view.incMutualEdgesEnabled(1);
}
}
}
}
}