/*
* File: WeightedDenseMemoryGraph.java
* Authors: Jeremy D. Wendt
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright 2016, Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the U.S. Government.
* Export of this program may require a license from the United States
* Government. See CopyrightHistory.txt for complete details.
*
*/
package gov.sandia.cognition.graph;
import gov.sandia.cognition.util.DefaultKeyValuePair;
import gov.sandia.cognition.collection.DoubleArrayList;
import gov.sandia.cognition.util.Pair;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* Implementation for a weighted graph type
*
* @author jdwendt
*
* @param <NodeNameType>
*/
public class WeightedDenseMemoryGraph<NodeNameType>
extends DenseMemoryGraph<NodeNameType>
implements DirectedWeightedNodeEdgeGraph<NodeNameType>
{
private static final long serialVersionUID = 9009145019650654200L;
/**
* Storage for the weights -- This stays in-line with the edges when the
* edges are added and sorted
*/
private DoubleArrayList weights;
/**
* Default constructor creates an empty graph
*
* Execution: O(1)
*/
public WeightedDenseMemoryGraph()
{
this(5, 10);
}
/**
* Initialize an empty graph with a default size (for speed-ups later)
*
* Execution: O(m + n) for reserving necessary space
*
* @param expectedNumNodes
* @param expectedNumEdges
*/
public WeightedDenseMemoryGraph(int expectedNumNodes,
int expectedNumEdges)
{
super(expectedNumNodes, expectedNumEdges);
weights = new DoubleArrayList(expectedNumEdges);
}
/**
* @see IDirectedWeightedGraph#addEdge(Object, Object)
*
* Execution: O(1)
*/
@Override
public void addEdge(NodeNameType left,
NodeNameType right)
{
addEdge(left, right, 1.0);
}
/**
* @see IDirectedWeightedGraph#addEdge(Object, Object, double)
*
* Execution: O(1)
*/
@Override
public void addEdge(NodeNameType left,
NodeNameType right,
double weight)
{
super.addEdge(left, right);
weights.add(weight);
}
/**
* Overrides the parent's version to ensure the weights swap at the same
* time the edges do
*/
@Override
protected void swap(int i,
int j)
{
super.swap(i, j);
weights.swap(i, j);
}
/**
* Execution: O(log m + d) where d is the degree of the specified node
* (which can be O(m) but is usually O(1)). NOTE: This has a one-time O(m
* log m) cost after adding new edges.
*
* @param node The node whose successors are wanted
*/
@Override
public Collection<Pair<NodeNameType, Double>> getSuccessorsWithWeights(
NodeNameType node)
{
Set<Pair<NodeNameType, Double>> ret = new HashSet<>();
// first check that the given node is in the graph
int nodeId = getNodeId(node);
int m = getNumEdges();
// find matching node pair, and iterate through all that match
int idx0 = getFirstEdgeFrom(nodeId);
if (idx0 >= 0 && idx0 <= m)
{
for (int i = idx0; i < m; ++i)
{
Pair<Integer, Integer> endPts = getEdgeEndpointIds(i);
if (endPts.getFirst() == nodeId)
{
ret.add(new DefaultKeyValuePair<>(
getNode(endPts.getSecond()), weights.get(i)));
}
else if (endPts.getFirst() > nodeId)
{
break;
}
}
}
// return the accumulated set of successors
return ret;
}
/**
* @see IDirectedWeightedGraph#getEdgeWeight(int)
*
* Execution: O(1) with a one-time O(m log m) cost after calling addEdge.
*/
@Override
public double getEdgeWeight(int id)
{
optimizeEdges();
return weights.get(id);
}
/**
* @see gov.sandia.graph.BasicDenseMemoryGraph#clear()
*/
@Override
public void clear()
{
super.clear();
weights.clear();
}
/**
* Helper method for serializing the input to file.
*
* @param fileName The filename (with optional path) to write this out to
* @param graph The graph to write
*/
public static void serialize(String fileName,
WeightedDenseMemoryGraph<?> graph)
{
try (ObjectOutputStream out
= new ObjectOutputStream(new FileOutputStream(fileName)))
{
out.writeObject(graph);
}
catch (IOException ioe)
{
throw new RuntimeException(ioe);
}
}
/**
* Helper method for deserializing from a file
*
* @param fileName The file (with path if necessary) to read a graph from
* @return The file object read from the input filename
*/
public static WeightedDenseMemoryGraph<?> deserialize(String fileName)
{
WeightedDenseMemoryGraph<?> graph = null;
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(
fileName)))
{
graph = (WeightedDenseMemoryGraph<?>) in.readObject();
}
catch (IOException | ClassNotFoundException e)
{
throw new RuntimeException(e);
}
return graph;
}
}