Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion src/main/java/org/gephi/graph/api/GraphModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.DataOutput;
import java.io.IOException;
import java.time.ZoneId;
import java.util.function.Predicate;
import org.gephi.graph.impl.GraphModelImpl;

/**
Expand Down Expand Up @@ -488,16 +489,38 @@ public static interface DefaultColumns {

/**
* Creates a new graph view.
* <p>
* By default, the view applies to both nodes and edges, so this is equivalent
* to {@link #createView(boolean, boolean) createView(true, true)}.
* <p>
* New views are by default empty, i.e. no nodes and no edges are visible in the
* view.
*
* @return newly created graph view
*/
public GraphView createView();

/**
* Creates a new graph view.
* <p>
* The node and edge filters allows to restrict the view filtering to only nodes
* or only edges. If node only, all edges connected to included nodes will be
* included too. If edge only, all nodes are included but only the edges
* matching the view are included.
*
* @param nodeFilter predicate to filter nodes, or null to include all nodes
* @param edgeFilter predicate to filter edges, or null to include all edges
* @return newly created graph view
*/
public GraphView createView(Predicate<Node> nodeFilter, Predicate<Edge> edgeFilter);

/**
* Creates a new graph view.
* <p>
* The node and edge parameters allows to restrict the view filtering to only
* nodes or only edges. By default, the view applies to both nodes and edges.
* nodes or only edges. If node only, all edges connected to included nodes will
* be included too. If edge only, all nodes are included but only the edges
* matching the view are included.
*
* @param node true to enable node view, false otherwise
* @param edge true to enable edge view, false otherwise
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/gephi/graph/impl/GraphModelImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.time.ZoneId;
import java.util.Arrays;
import java.util.function.Predicate;
import org.gephi.graph.api.Configuration;
import org.gephi.graph.api.DirectedGraph;
import org.gephi.graph.api.DirectedSubgraph;
Expand Down Expand Up @@ -251,6 +252,11 @@ public GraphView createView() {
return store.viewStore.createView();
}

@Override
public GraphView createView(Predicate<Node> nodeFilter, Predicate<Edge> edgeFilter) {
return store.viewStore.createView(nodeFilter, edgeFilter);
}

@Override
public GraphView createView(boolean node, boolean edge) {
return store.viewStore.createView(node, edge);
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/gephi/graph/impl/GraphViewDecorator.java
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,9 @@ public boolean hasEdge(final Object id) {

@Override
public NodeIterable getNodes() {
if (!view.isNodeView()) {
return graphStore.getNodes();
}
return new NodeIterableWrapper(() -> new NodeViewIterator(graphStore.nodeStore.iterator()),
NodeViewSpliterator::new, graphStore.getAutoLock());
}
Expand Down
56 changes: 48 additions & 8 deletions src/main/java/org/gephi/graph/impl/GraphViewImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import org.gephi.graph.api.DirectedSubgraph;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.Graph;
Expand Down Expand Up @@ -77,6 +78,53 @@ public GraphViewImpl(final GraphStore store, boolean nodes, boolean edges) {
this.interval = Interval.INFINITY_INTERVAL;
}

public GraphViewImpl(final GraphStore store, Predicate<Node> nodePredicate, Predicate<Edge> edgePredicate) {
this(store, nodePredicate != null, edgePredicate != null);

// Fill - optimized with iterators and manual counting
if (nodePredicate != null) {
int count = 0;
for (Node node : graphStore.nodeStore) {
if (nodePredicate.test(node)) {
nodeBitVector.set(node.getStoreId());
count++;
}
}
nodeCount = count;
incrementNodeVersion();
}

// Process edges with iterator
int count = 0;
for (Edge edge : graphStore.edgeStore) {
// Cache store IDs
int sourceId = edge.getSource().getStoreId();
int targetId = edge.getTarget().getStoreId();

// Filter by node predicate if needed
if (nodePredicate != null && (!nodeBitVector.get(sourceId) || !nodeBitVector.get(targetId))) {
continue;
}

// Filter by edge predicate if needed
if (edgePredicate != null && !edgePredicate.test(edge)) {
continue;
}

edgeBitVector.set(edge.getStoreId());
int type = edge.getType();
typeCounts[type]++;
count++;

if (((EdgeImpl) edge).isMutual() && !edge.isSelfLoop() && containsEdge(graphStore.edgeStore
.get(edge.getTarget(), edge.getSource(), type, false))) {
mutualEdgeTypeCounts[type]++;
mutualEdgesCount++;
}
}
edgeCount = count;
}

public GraphViewImpl(final GraphViewImpl view, boolean nodes, boolean edges) {
this.graphStore = view.graphStore;
this.nodeView = nodes;
Expand Down Expand Up @@ -962,14 +1010,6 @@ protected void destroyAllObservers() {
}
}

protected void ensureNodeVectorSize(NodeImpl node) {
// BitSet automatically grows as needed, no manual resizing required
}

protected void ensureEdgeVectorSize(EdgeImpl edge) {
// BitSet automatically grows as needed, no manual resizing required
}

protected void setEdgeType(EdgeImpl edgeImpl, int oldType, boolean wasMutual) {
ensureTypeCountArrayCapacity(edgeImpl.type);
typeCounts[oldType]--;
Expand Down
60 changes: 26 additions & 34 deletions src/main/java/org/gephi/graph/impl/GraphViewStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
import java.util.function.Predicate;
import org.gephi.graph.api.DirectedSubgraph;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.Graph;
Expand Down Expand Up @@ -54,6 +55,17 @@ public GraphViewImpl createView() {
return createView(true, true);
}

public GraphViewImpl createView(Predicate<Node> nodeFilter, Predicate<Edge> edgeFilter) {
graphStore.autoWriteLock();
try {
GraphViewImpl graphView = new GraphViewImpl(graphStore, nodeFilter, edgeFilter);
addView(graphView);
return graphView;
} finally {
graphStore.autoWriteUnlock();
}
}

public GraphViewImpl createView(boolean nodes, boolean edges) {
graphStore.autoWriteLock();
try {
Expand Down Expand Up @@ -232,58 +244,38 @@ public void destroyGraphObserver(GraphObserverImpl graphObserver) {
graphViewImpl.destroyGraphObserver(graphObserver);
}

protected void addNode(NodeImpl node) {
if (views.length > 0) {
for (GraphViewImpl view : views) {
if (view != null) {
view.ensureNodeVectorSize(node);
}
}
}
}

protected void removeNode(NodeImpl node) {
if (views.length > 0) {
for (GraphViewImpl view : views) {
if (view != null) {
view.removeNode(node);
}
for (GraphViewImpl view : views) {
if (view != null) {
view.removeNode(node);
}
}
}

protected void addEdge(EdgeImpl edge) {
if (views.length > 0) {
for (GraphViewImpl view : views) {
if (view != null) {
view.ensureEdgeVectorSize(edge);

if (view.nodeView && !view.edgeView) {
view.addEdgeInNodeView(edge);
}
for (GraphViewImpl view : views) {
if (view != null) {
if (view.nodeView && !view.edgeView) {
view.addEdgeInNodeView(edge);
}
}
}
}

protected void setEdgeType(EdgeImpl edge, int oldType, boolean wasMutual) {
if (views.length > 0) {
for (GraphViewImpl view : views) {
if (view != null) {
if ((view.nodeView && !view.edgeView) || (view.edgeView && view.containsEdge(edge))) {
view.setEdgeType(edge, oldType, wasMutual);
}
for (GraphViewImpl view : views) {
if (view != null) {
if ((view.nodeView && !view.edgeView) || (view.edgeView && view.containsEdge(edge))) {
view.setEdgeType(edge, oldType, wasMutual);
}
}
}
}

protected void removeEdge(EdgeImpl edge) {
if (views.length > 0) {
for (GraphViewImpl view : views) {
if (view != null) {
view.removeEdge(edge);
}
for (GraphViewImpl view : views) {
if (view != null) {
view.removeEdge(edge);
}
}
}
Expand Down
3 changes: 0 additions & 3 deletions src/main/java/org/gephi/graph/impl/NodeStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,6 @@ public boolean add(final Node n) {
currentBlock.add(node);
dictionary.put(node.getId(), node.storeId);
}
if (viewStore != null) {
viewStore.addNode(node);
}
node.indexAttributes();

if (spatialIndex != null) {
Expand Down
Loading