com.googlecode.blaisemath.graph.longitudinal.IntervalLongitudinalGraph Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of blaise-graphtheory Show documentation
Show all versions of blaise-graphtheory Show documentation
Link graph definitions, algorithms, and visualization.
The newest version!
/*
* IntervalLongitudinalGraph.java
* Created Jul 5, 2010
*/
package com.googlecode.blaisemath.graph.longitudinal;
/*
* #%L
* BlaiseGraphTheory
* --
* Copyright (C) 2009 - 2016 Elisha Peterson
* --
* 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%
*/
import com.google.common.collect.Sets;
import com.googlecode.blaisemath.graph.Graph;
import com.googlecode.blaisemath.graph.SparseGraph;
import com.googlecode.blaisemath.util.Edge;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* A graph whose nodes and edges all come with associated time intervals. When queried
* for a slice, this class returns a view of just the elements of the underlying graph
* that exist at the specified time. Implemented as a sparse graph.
*
* @param the type of the nodes
*
* @author Elisha Peterson
*/
public class IntervalLongitudinalGraph implements LongitudinalGraph {
/** Whether graph is directed. */
boolean directed;
/** Stores the start/stop times for each node; also stores the vertices. */
private Map> nodeTimes;
/** Stores the edges with associated start/stop times. */
private Set> edges;
/** Stores the time domain via the minimum time and maximum time. */
double minTime, maxTime;
/** # of time steps to use (impacts how time slices are done) */
int timeSteps = 100;
/** Do not permit instantiation */
private IntervalLongitudinalGraph(boolean directed) {
this.directed = directed;
nodeTimes = new HashMap>();
edges = new HashSet>();
}
//
//
// FACTORY METHODS
//
/**
* Factory method to generate longitudinal graph with given properties.
* @param graph node type
* @param directed whether graph is directed
* @param timeSteps how many time steps to use
* @param nodeTimes mapping of vertices together with time intervals
* @param edgeTimes mapping of edges together with time intervals
* @return created graph
*/
public static IntervalLongitudinalGraph getInstance(boolean directed, int timeSteps,
Map nodeTimes, Map> edgeTimes) {
if (nodeTimes == null || edgeTimes == null) {
throw new NullPointerException("getInstance: nodeTimes and edgeTimes must be non-null!");
}
IntervalLongitudinalGraph result = new IntervalLongitudinalGraph(directed);
result.timeSteps = timeSteps;
for (Entry en : nodeTimes.entrySet()) {
result.nodeTimes.put(en.getKey(), Arrays.asList(en.getValue()));
}
Map> added = new HashMap>();
for (V x : edgeTimes.keySet()) {
Map getx = edgeTimes.get(x);
for (V y : getx.keySet()) {
if (!directed && added.containsKey(y) && added.get(y).contains(x)) {
continue;
}
if (!added.containsKey(x)) {
added.put(x, new HashSet());
}
added.get(x).add(y);
result.edges.add(new IntervalTimeEdge(x,y,getx.get(y)));
}
}
result.adjustDomain();
return result;
}
/**
* Factory method to generate longitudinal graph with given properties.
* @param graph node type
* @param directed whether graph is directed
* @param timeSteps how many time steps to use
* @param nodeTimes mapping of vertices together with list of node time intervals
* @param edgeTimes mapping of edges together with list of edge time intervals
* @return created graph
*/
public static IntervalLongitudinalGraph getInstance2(boolean directed, int timeSteps,
Map> nodeTimes, Map>> edgeTimes) {
if (nodeTimes == null || edgeTimes == null) {
throw new NullPointerException("getInstance: nodeTimes and edgeTimes must be non-null!");
}
IntervalLongitudinalGraph result = new IntervalLongitudinalGraph(directed);
result.timeSteps = timeSteps;
result.nodeTimes.putAll(nodeTimes);
for (Entry>> en1 : edgeTimes.entrySet()) {
for (Entry> en2 : en1.getValue().entrySet()) {
result.edges.add(new IntervalTimeEdge(en1.getKey(),en2.getKey(), en2.getValue()));
if (!directed) {
result.edges.add(new IntervalTimeEdge(en2.getKey(),en1.getKey(), en2.getValue()));
}
}
}
result.adjustDomain();
// ensure symmetric if undirected
if (!directed) {
ArrayList
@Override public String toString() {
return "NODES: " + nodeTimes.keySet() + "; EDGES: " + edges;
}
@Override
public boolean isDirected() {
return directed;
}
@Override
public Collection getAllNodes() {
return nodeTimes.keySet();
}
@Override
public List getNodeIntervals(V v) {
return nodeTimes.containsKey(v) ? nodeTimes.get(v) : null;
}
/**
* Return edge between specified vertices.
* @param v1 first vertex
* @param v2 second vertex
* @return edge if it exists, null otherwise
*/
public IntervalTimeEdge getEdge(V v1, V v2) {
for (IntervalTimeEdge e : edges) {
if (e.getNode1() == v1 && e.getNode2() == v2) {
return e;
}
}
return null;
}
@Override
public List getEdgeIntervals(V v1, V v2) {
IntervalTimeEdge edge = getEdge(v1,v2);
return edge == null ? null : edge.getTimes();
}
@Override
public Graph slice(double time, boolean exact) {
Set nodes = nodeSlice(time);
Set> edges = Sets.newHashSet();
for (IntervalTimeEdge e : edgeSlice(time)) {
edges.add(new Edge(e));
}
return SparseGraph.createFromEdges(directed, nodes, edges);
}
@Override
public double getMinimumTime() {
return minTime;
}
@Override
public double getMaximumTime() {
return maxTime;
}
@Override
public List getTimes() {
return new AbstractList() {
@Override
public Double get(int index) {
return minTime + index*(maxTime-minTime)/(double)size();
}
@Override
public int size() {
return timeSteps;
}
};
}
/**
* Return set of nodes at specified time.
* @param time slice time
* @return nodes active at given time
*/
public Set nodeSlice(double time) {
Set nodes = new HashSet();
for (V v : nodeTimes.keySet()) {
List intervals = nodeTimes.get(v);
if (in(time, intervals)) {
nodes.add(v);
}
}
return nodes;
}
/**
* Return set of edges at specified time
* @param time slice time
* @return edges active at given slice
*/
public Set> edgeSlice(double time) {
Set> sliceEdges = new HashSet>();
for (IntervalTimeEdge e : this.edges) {
if (in(time, e.getTimes())) {
sliceEdges.add(e);
}
}
return sliceEdges;
}
//
//
// UTILITIES
//
/**
* Computes the min and max times and uses them for the time domain
* @throws IllegalArgumentException if any of the provided time intervals are not
* properly formatted (2 elements, first is min, second is max)
*/
private void adjustDomain() throws IllegalArgumentException {
minTime = Double.POSITIVE_INFINITY;
maxTime = Double.NEGATIVE_INFINITY;
for (List vv : nodeTimes.values()) {
for (double[] v : vv) {
if (v == null || v.length != 2) {
throw new IllegalArgumentException("Bad array in set; must be of length 2: " + Arrays.toString(v));
}
if (v[0] > v[1]) {
throw new IllegalArgumentException("Time interval must have first argument <= second: " + Arrays.toString(v));
}
if (!Double.isInfinite(v[0])) {
minTime = Math.min(minTime, v[0]);
}
if (!Double.isInfinite(v[1])) {
maxTime = Math.max(maxTime, v[1]);
}
}
}
for (IntervalTimeEdge edge : edges) {
for (double[] v : edge.getTimes()) {
if (v == null || v.length != 2) {
throw new IllegalArgumentException("Bad array in set; must be of length 2: " + Arrays.toString(v));
}
if (v[0] > v[1]) {
throw new IllegalArgumentException("Time interval must have first argument <= second: " + Arrays.toString(v));
}
if (!Double.isInfinite(v[0])) {
minTime = Math.min(minTime, v[0]);
}
if (!Double.isInfinite(v[1])) {
maxTime = Math.max(maxTime, v[1]);
}
}
}
}
/**
* Checks to see if time is in stated interval(s)
* @param time the time
* @param ivs list of intervals
* @return true if current time is in any of the intervals, false otherwise & if argument is null
*/
private static boolean in(double time, List ivs) {
if (ivs == null) return false;
for (double[] iv : ivs) {
if (iv[0] <= time && iv[1] >= time) {
return true;
}
}
return false;
}
//
//
//
// INNER CLASSES
//
/**
* Class annotation an edge with a collection of time intervals.
* @param graph node type
*/
public static class IntervalTimeEdge extends Edge {
private final List times;
public IntervalTimeEdge(V v1, V v2, double[] interval) {
this(v1, v2, Arrays.asList(interval));
}
public IntervalTimeEdge(V v1, V v2, List times) {
super(v1, v2);
this.times = times;
}
public List getTimes() {
return times;
}
}
//
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy