/*
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.ranking.impl;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import org.gephi.ranking.api.NodeRanking;
import org.gephi.ranking.api.EdgeRanking;
import org.gephi.data.attributes.api.AttributeColumn;
import org.gephi.data.attributes.api.AttributeType;
import org.gephi.data.attributes.api.AttributeUtils;
import org.gephi.data.attributes.api.Estimator;
import org.gephi.data.attributes.type.DynamicType;
import org.gephi.data.attributes.type.TimeInterval;
import org.gephi.graph.api.DirectedGraph;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.Graph;
import org.gephi.graph.api.HierarchicalGraph;
import org.gephi.graph.api.Node;
/**
*
* @author Mathieu Bastian
*/
public class RankingFactory {
public static NodeRanking getNodeAttributeRanking(AttributeColumn column, Graph graph) {
NodeRanking nodeRanking = new NodeAttributeRanking(column);
setMinMax((AbstractRanking) nodeRanking, graph);
return nodeRanking;
}
public static EdgeRanking getEdgeAttributeRanking(AttributeColumn column, Graph graph) {
EdgeRanking edgeRanking = new EdgeAttributeRanking(column);
setMinMax((AbstractRanking) edgeRanking, graph);
return edgeRanking;
}
public static NodeRanking getNodeDynamicAttributeRanking(AttributeColumn column, Graph graph, TimeInterval timeInterval, Estimator estimator) {
DynamicNodeAttributeRanking nodeRanking = new DynamicNodeAttributeRanking(column, timeInterval, estimator);
setMinMax((AbstractRanking) nodeRanking, graph);
return nodeRanking;
}
public static EdgeRanking getEdgeDynamicAttributeRanking(AttributeColumn column, Graph graph, TimeInterval timeInterval, Estimator estimator) {
DynamicEdgeAttributeRanking edgeRanking = new DynamicEdgeAttributeRanking(column, timeInterval, estimator);
setMinMax((AbstractRanking) edgeRanking, graph);
return edgeRanking;
}
public static NodeRanking getNodeDegreeRanking(Graph graph) {
NodeRanking nodeRanking = new NodeDegreeRanking(graph);
setMinMax((AbstractRanking) nodeRanking, graph);
return nodeRanking;
}
public static NodeRanking getNodeInDegreeRanking(DirectedGraph graph) {
NodeRanking nodeRanking = new NodeInDegreeRanking(graph);
setMinMax((AbstractRanking) nodeRanking, graph);
return nodeRanking;
}
public static NodeRanking getNodeOutDegreeRanking(DirectedGraph graph) {
NodeRanking nodeRanking = new NodeOutDegreeRanking(graph);
setMinMax((AbstractRanking) nodeRanking, graph);
return nodeRanking;
}
public static NodeRanking getNodeChildrenCountRanking(HierarchicalGraph graph) {
NodeRanking nodeRanking = new NodeChildrenCountRanking(graph);
setMinMax((AbstractRanking) nodeRanking, graph);
return nodeRanking;
}
public static boolean refreshRanking(AbstractRanking ranking, Graph graph, TimeInterval timeInterval) {
if (ranking instanceof DynamicNodeAttributeRanking) {
((DynamicNodeAttributeRanking) ranking).timeInterval = timeInterval;
} else if (ranking instanceof DynamicEdgeAttributeRanking) {
((DynamicEdgeAttributeRanking) ranking).timeInterval = timeInterval;
}
double hash = ranking.hash;
ranking.setGraph(graph);
setMinMax(ranking, graph);
return ranking.hash != hash;
}
public static boolean isNumberColumn(AttributeColumn column) {
AttributeType type = column.getType();
if (type == AttributeType.DOUBLE
|| type == AttributeType.FLOAT
|| type == AttributeType.INT
|| type == AttributeType.LONG
|| type == AttributeType.BYTE
|| type == AttributeType.BIGDECIMAL
|| type == AttributeType.BIGINTEGER
|| type == AttributeType.SHORT) {
return true;
}
return false;
}
public static boolean isDynamicNumberColumn(AttributeColumn column) {
AttributeType type = column.getType();
AttributeUtils.getDefault().isDynamicNumberColumn(column);
if (type == AttributeType.DYNAMIC_BIGDECIMAL
|| type == AttributeType.DYNAMIC_BIGINTEGER
|| type == AttributeType.DYNAMIC_BYTE
|| type == AttributeType.DYNAMIC_DOUBLE
|| type == AttributeType.DYNAMIC_FLOAT
|| type == AttributeType.DYNAMIC_INT
|| type == AttributeType.DYNAMIC_LONG
|| type == AttributeType.DYNAMIC_SHORT) {
return true;
}
return false;
}
protected static void setMinMax(AbstractRanking ranking, Graph graph) {
if (ranking instanceof NodeRanking) {
List<Comparable> objects = new ArrayList<Comparable>();
for (Node node : graph.getNodes().toArray()) {
Comparable value = (Comparable) ranking.getValue(node);
if (value != null) {
objects.add(value);
}
}
ranking.hash = objects.hashCode();
ranking.setMinimumValue((Number) getMin(objects.toArray(new Comparable[0])));
ranking.setMaximumValue((Number) getMax(objects.toArray(new Comparable[0])));
} else if (ranking instanceof EdgeRanking) {
List<Comparable> objects = new ArrayList<Comparable>();
for (Edge edge : graph.getEdges().toArray()) {
Comparable value = (Comparable) ranking.getValue(edge);
if (value != null) {
objects.add(value);
}
}
ranking.hash = objects.hashCode();
ranking.setMinimumValue((Number) getMin(objects.toArray(new Comparable[0])));
ranking.setMaximumValue((Number) getMax(objects.toArray(new Comparable[0])));
}
}
private static Object getMin(Comparable[] values) {
switch (values.length) {
case 0:
return null;
case 1:
return values[0];
// values.length > 1
default:
Comparable<?> min = values[0];
for (int index = 1; index < values.length; index++) {
Comparable o = values[index];
if (o.compareTo(min) < 0) {
min = o;
}
}
return min;
}
}
private static Object getMax(Comparable[] values) {
switch (values.length) {
case 0:
return null;
case 1:
return values[0];
// values.length > 1
default:
Comparable<?> max = values[0];
for (int index = 1; index < values.length; index++) {
Comparable o = values[index];
if (o.compareTo(max) > 0) {
max = o;
}
}
return max;
}
}
private static class NodeDegreeRanking extends AbstractRanking<Node, Integer> implements NodeRanking<Integer> {
public NodeDegreeRanking(Graph graph) {
this.graph = graph;
}
public Integer getValue(Node element) {
return graph.getDegree(element);
}
public float normalize(Integer value) {
return (float) ((value - minimum) / (float) (maximum - minimum));
}
public Integer unNormalize(float normalizedValue) {
return (int) (normalizedValue * (maximum - minimum)) + minimum;
}
public String getName() {
return "Degree";
}
@Override
public String toString() {
return getName();
}
public Class getType() {
return Integer.class;
}
}
private static class NodeInDegreeRanking extends AbstractRanking<Node, Integer> implements NodeRanking<Integer> {
public NodeInDegreeRanking(DirectedGraph graph) {
this.graph = graph;
}
public Integer getValue(Node element) {
return ((DirectedGraph) graph).getInDegree(element);
}
public float normalize(Integer value) {
return (float) ((value - minimum) / (float) (maximum - minimum));
}
public Integer unNormalize(float normalizedValue) {
return (int) (normalizedValue * (maximum - minimum)) + minimum;
}
public String getName() {
return "InDegree";
}
@Override
public String toString() {
return getName();
}
public Class getType() {
return Integer.class;
}
}
private static class NodeOutDegreeRanking extends AbstractRanking<Node, Integer> implements NodeRanking<Integer> {
public NodeOutDegreeRanking(DirectedGraph graph) {
this.graph = graph;
}
public Integer getValue(Node element) {
return ((DirectedGraph) graph).getOutDegree(element);
}
public float normalize(Integer value) {
return (float) ((value - minimum) / (float) (maximum - minimum));
}
public Integer unNormalize(float normalizedValue) {
return (int) (normalizedValue * (maximum - minimum)) + minimum;
}
public String getName() {
return "OutDegree";
}
@Override
public String toString() {
return getName();
}
public Class getType() {
return Integer.class;
}
}
private static class NodeChildrenCountRanking extends AbstractRanking<Node, Integer> implements NodeRanking<Integer> {
public NodeChildrenCountRanking(HierarchicalGraph graph) {
this.graph = graph;
}
public Integer getValue(Node element) {
return ((HierarchicalGraph) graph).getChildrenCount(element);
}
public float normalize(Integer value) {
return (float) ((value - minimum) / (float) (maximum - minimum));
}
public Integer unNormalize(float normalizedValue) {
return (int) (normalizedValue * (maximum - minimum)) + minimum;
}
public String getName() {
return "Children count";
}
@Override
public String toString() {
return getName();
}
public Class getType() {
return Integer.class;
}
}
protected abstract static class AttributeRanking<Element, Type extends Number> extends AbstractRanking<Element, Type> {
protected AttributeColumn column;
public AttributeRanking(AttributeColumn attributeColumn) {
this.column = attributeColumn;
}
public String getName() {
return column.getTitle();
}
@Override
public String toString() {
return getName();
}
public Class getType() {
return column.getType().getType();
}
public float normalize(Type value) {
return (value.floatValue() - minimum.floatValue()) / (float) (maximum.floatValue() - minimum.floatValue());
}
public Type unNormalize(float normalizedValue) {
double val = (normalizedValue * (maximum.doubleValue() - minimum.doubleValue())) + minimum.doubleValue();
switch (column.getType()) {
case BIGDECIMAL:
return (Type) new BigDecimal(val);
case BIGINTEGER:
return (Type) new BigInteger("" + val);
case DOUBLE:
return (Type) new Double(val);
case FLOAT:
return (Type) new Float(val);
case INT:
return (Type) new Integer((int) val);
case LONG:
return (Type) new Long((long) val);
case SHORT:
return (Type) new Short((short) val);
default:
return (Type) new Double(val);
}
}
}
private static class NodeAttributeRanking<Type extends Number> extends AttributeRanking<Node, Type> implements NodeRanking<Type> {
public NodeAttributeRanking(AttributeColumn column) {
super(column);
}
public Type getValue(Node node) {
return (Type) node.getNodeData().getAttributes().getValue(column.getIndex());
}
}
private static class EdgeAttributeRanking<Type extends Number> extends AttributeRanking<Edge, Type> implements EdgeRanking<Type> {
public EdgeAttributeRanking(AttributeColumn column) {
super(column);
}
public Type getValue(Edge edge) {
return (Type) edge.getEdgeData().getAttributes().getValue(column.getIndex());
}
}
private static class DynamicNodeAttributeRanking<Type extends Number> extends AttributeRanking<Node, Type> implements NodeRanking<Type> {
private TimeInterval timeInterval;
private Estimator estimator;
public DynamicNodeAttributeRanking(AttributeColumn column, TimeInterval timeInterval, Estimator estimator) {
super(column);
this.timeInterval = timeInterval;
this.estimator = estimator;
}
public Type getValue(Node node) {
DynamicType<Type> dynamicType = (DynamicType<Type>) node.getNodeData().getAttributes().getValue(column.getIndex());
if (dynamicType != null) {
return (Type) dynamicType.getValue(timeInterval == null ? Double.NEGATIVE_INFINITY : timeInterval.getLow(),
timeInterval == null ? Double.POSITIVE_INFINITY : timeInterval.getHigh(), estimator);
}
return null;
}
}
private static class DynamicEdgeAttributeRanking<Type extends Number> extends AttributeRanking<Edge, Type> implements EdgeRanking<Type> {
private TimeInterval timeInterval;
private Estimator estimator;
public DynamicEdgeAttributeRanking(AttributeColumn column, TimeInterval timeInterval, Estimator estimator) {
super(column);
this.timeInterval = timeInterval;
this.estimator = estimator;
}
public Type getValue(Edge edge) {
DynamicType<Type> dynamicType = (DynamicType<Type>) edge.getEdgeData().getAttributes().getValue(column.getIndex());
if (dynamicType != null) {
return (Type) dynamicType.getValue(timeInterval == null ? Double.NEGATIVE_INFINITY : timeInterval.getLow(),
timeInterval == null ? Double.POSITIVE_INFINITY : timeInterval.getHigh(), estimator);
}
return null;
}
}
}