/*
* Copyright (C) 2008-2015 by Holger Arndt
*
* This file is part of the Universal Java Matrix Package (UJMP).
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* UJMP is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* UJMP 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with UJMP; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package org.ujmp.core.graphmatrix;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.ujmp.core.Coordinates;
import org.ujmp.core.collections.list.ArrayIndexList;
import org.ujmp.core.enums.ValueType;
import org.ujmp.core.util.CoordinateSetToLongWrapper;
public class DefaultGraphMatrix<N, E> extends AbstractGraphMatrix<N, E> {
private static final long serialVersionUID = -6103776352324576412L;
private boolean directed = true;
private final List<N> nodes = new ArrayIndexList<N>();
private final Map<Coordinates, E> edges = new HashMap<Coordinates, E>();
private final Map<Long, List<Long>> parents = new HashMap<Long, List<Long>>();
private final Map<Long, List<Long>> children = new HashMap<Long, List<Long>>();
public DefaultGraphMatrix() {
}
public DefaultGraphMatrix(List<N> nodes) {
this.nodes.addAll(nodes);
}
public Collection<E> getEdgeList() {
return edges.values();
}
public Iterable<long[]> availableCoordinates() {
return new CoordinateSetToLongWrapper(edges.keySet());
}
public List<N> getNodeList() {
return nodes;
}
public void addNode(N o) {
nodes.add(o);
}
public void removeNode(N o) {
nodes.remove(o);
}
public int getEdgeCount() {
return edges.size();
}
public int getNodeCount() {
return nodes.size();
}
public void clear() {
edges.clear();
parents.clear();
children.clear();
}
public int getChildCount(long nodeIndex) {
List<Long> indices = children.get(nodeIndex);
return indices == null ? 0 : indices.size();
}
public N getNode(long index) {
return nodes.get((int) index);
}
public int getParentCount(long nodeIndex) {
List<Long> indices = parents.get(nodeIndex);
return indices == null ? 0 : indices.size();
}
@SuppressWarnings("unchecked")
public List<Long> getParentIndices(long index) {
List<Long> indices = parents.get(index);
return indices == null ? Collections.EMPTY_LIST : indices;
}
@SuppressWarnings("unchecked")
public List<Long> getChildIndices(long index) {
List<Long> indices = children.get(index);
return indices == null ? Collections.EMPTY_LIST : indices;
}
public void removeNode(long node) {
nodes.remove((int) node);
}
public boolean isDirected() {
return directed;
}
public void setDirected(boolean directed) {
this.directed = directed;
}
public void setNode(N node, long index) {
nodes.set((int) index, node);
}
public synchronized void setEdge(E edge, long nodeIndex1, long nodeIndex2) {
int nmbOfNodes = nodes.size();
if (nodeIndex1 >= nmbOfNodes) {
throw new RuntimeException("accessed node " + nodeIndex1 + ", but only " + nmbOfNodes
+ " available");
}
if (nodeIndex2 >= nmbOfNodes) {
throw new RuntimeException("accessed node " + nodeIndex2 + ", but only " + nmbOfNodes
+ " available");
}
if (edge == null) {
edges.remove(Coordinates.wrap(nodeIndex1, nodeIndex2));
List<Long> childrenNode1 = children.get(nodeIndex1);
if (childrenNode1 != null) {
childrenNode1.remove(nodeIndex1);
}
List<Long> parentsNode2 = parents.get(nodeIndex2);
if (parentsNode2 != null) {
parentsNode2.remove(nodeIndex2);
}
} else {
edges.put(Coordinates.wrap(nodeIndex1, nodeIndex2), edge);
List<Long> childrenNode1 = children.get(nodeIndex1);
if (childrenNode1 == null) {
childrenNode1 = new ArrayList<Long>();
children.put(nodeIndex1, childrenNode1);
}
childrenNode1.add(nodeIndex2);
List<Long> parentsNode2 = parents.get(nodeIndex2);
if (parentsNode2 == null) {
parentsNode2 = new ArrayList<Long>();
parents.put(nodeIndex2, parentsNode2);
}
parentsNode2.add(nodeIndex1);
}
}
public void setEdge(E edge, N node1, N node2) {
long index1 = getIndexOfNode(node1);
if (index1 == -1) {
addNode(node1);
index1 = getIndexOfNode(node1);
}
long index2 = getIndexOfNode(node2);
if (index2 == -1) {
addNode(node2);
index2 = getIndexOfNode(node2);
}
setEdge(edge, index1, index2);
}
public ValueType getValueType() {
return ValueType.OBJECT;
}
public E getEdge(long nodeIndex1, long nodeIndex2) {
return edges.get(Coordinates.wrap(nodeIndex1, nodeIndex2));
}
public void removeEdge(E edge) {
List<Coordinates> coordinatesToDelete = new ArrayList<Coordinates>();
for (Coordinates c : edges.keySet()) {
E e = edges.get(c);
if (e == edge) {
coordinatesToDelete.add(c);
}
}
for (Coordinates c : coordinatesToDelete) {
edges.remove(c);
}
}
public void removeEdge(N node1, N node2) {
setEdge(null, node1, node2);
}
public void removeEdge(long nodeIndex1, long nodeIndex2) {
setEdge(null, nodeIndex1, nodeIndex2);
}
}