Skip to content

Commit

Permalink
Implement #157
Browse files Browse the repository at this point in the history
  • Loading branch information
mbastian committed Dec 23, 2022
1 parent b4ec718 commit 5dde25b
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 3 deletions.
18 changes: 18 additions & 0 deletions src/main/java/org/gephi/graph/api/Graph.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ public interface Graph {
*/
public boolean removeAllNodes(Collection<? extends Node> nodes);

/**
* Retains only nodes in this graph that are contained in the specified
* collection.
*
* @param nodes the node collection
* @return true if at least one node has been removed, false otherwise
*/
public boolean retainNodes(Collection<? extends Node> nodes);

/**
* Retains only edges in this graph that are contained in the specified
* collection.
*
* @param edges the edge collection
* @return true if at least one edge has been removed, false otherwise
*/
public boolean retainEdges(Collection<? extends Edge> edges);

/**
* Returns true if <em>node</em> is contained in this graph.
*
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/org/gephi/graph/api/Subgraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ public interface Subgraph extends Graph {
@Override
public boolean removeAllNodes(Collection<? extends Node> nodes);

/**
* Retains only nodes in this subgraph that are contained in the specified
* collection.
* <p>
* The nodes should be part of the root graph.
*
* @param nodes the node collection
* @return true if at least one node has been removed, false otherwise
*/
public boolean retainNodes(Collection<? extends Node> nodes);

/**
* Removes an edge from this subgraph.
* <p>
Expand All @@ -132,6 +143,17 @@ public interface Subgraph extends Graph {
@Override
public boolean removeAllEdges(Collection<? extends Edge> edges);

/**
* Retains only edges in this subgraph that are contained in the specified
* collection.
* <p>
* The edges should be part of the root graph.
*
* @param edges the edge collection
* @return true if at least one edge has been removed, false otherwise
*/
public boolean retainEdges(Collection<? extends Edge> edges);

/**
* Fills the subgraph so all elements in the graph are in the subgraph.
*/
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/gephi/graph/impl/EdgeStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -1021,8 +1021,9 @@ public boolean retainAll(Collection<?> c) {
}
}
return changed;
} else {
} else if (size > 0) {
clear();
return true;
}
return false;
}
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/org/gephi/graph/impl/GraphStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.gephi.graph.impl;

import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
Expand Down Expand Up @@ -297,6 +298,16 @@ public boolean removeAllNodes(Collection<? extends Node> nodes) {
}
}

@Override
public boolean retainNodes(Collection<? extends Node> nodes) {
autoWriteLock();
try {
return nodeStore.retainAll(nodes);
} finally {
autoWriteUnlock();
}
}

@Override
public boolean removeAllEdges(Collection<? extends Edge> edges) {
autoWriteLock();
Expand All @@ -307,6 +318,16 @@ public boolean removeAllEdges(Collection<? extends Edge> edges) {
}
}

@Override
public boolean retainEdges(Collection<? extends Edge> edges) {
autoWriteLock();
try {
return edgeStore.retainAll(edges);
} finally {
autoWriteUnlock();
}
}

public NodeStore getNodeStore() {
return nodeStore;
}
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/org/gephi/graph/impl/GraphViewDecorator.java
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,26 @@ public boolean removeAllNodes(Collection<? extends Node> nodes) {
}
}

@Override
public boolean retainNodes(Collection<? extends Node> nodes) {
graphStore.autoWriteLock();
try {
return view.retainNodes(nodes);
} finally {
graphStore.autoWriteUnlock();
}
}

@Override
public boolean retainEdges(Collection<? extends Edge> edges) {
graphStore.autoWriteLock();
try {
return view.retainEdges(edges);
} finally {
graphStore.autoWriteUnlock();
}
}

@Override
public boolean contains(Node node) {
checkValidNodeObject(node);
Expand Down
58 changes: 58 additions & 0 deletions src/main/java/org/gephi/graph/impl/GraphViewImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

import cern.colt.bitvector.BitVector;
import cern.colt.bitvector.QuickBitVector;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -264,6 +267,61 @@ public boolean removeNodeAll(final Collection<? extends Node> nodes) {
return false;
}

public boolean retainNodes(final Collection<? extends Node> c) {
if (nodeView) {
if (!c.isEmpty()) {
IntOpenHashSet set = new IntOpenHashSet(c.size());
for (Node o : c) {
checkValidNodeObject(o);
set.add(o.getStoreId());
}

boolean changed = false;
int nodeSize = nodeBitVector.size();
for (int i = 0; i < nodeSize; i++) {
boolean t = nodeBitVector.get(i);
if (t && !set.contains(i)) {
if (removeNode(getNode(i))) {
changed = true;
}
}
}
return changed;
} else if (nodeCount != 0) {
clear();
return true;
}
}
return false;
}

public boolean retainEdges(final Collection<? extends Edge> c) {
if (edgeView) {
if (!c.isEmpty()) {
IntOpenHashSet set = new IntOpenHashSet(c.size());
for (Edge o : c) {
checkValidEdgeObject(o);
set.add(o.getStoreId());
}

boolean changed = false;
int edgeSize = edgeBitVector.size();
for (int i = 0; i < edgeSize; i++) {
boolean t = edgeBitVector.get(i);
if (t && !set.contains(i)) {
removeEdge(getEdge(i));
changed = true;
}
}
return changed;
} else if (edgeCount != 0) {
clearEdges();
return true;
}
}
return false;
}

public boolean removeEdge(final Edge edge) {
checkEdgeView();

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/gephi/graph/impl/NodeStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,9 @@ public boolean retainAll(final Collection<?> c) {
}
}
return changed;
} else {
} else if (size > 0) {
clear();
return true;
}
return false;
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/gephi/graph/impl/UndirectedDecorator.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ public boolean removeAllNodes(Collection<? extends Node> nodes) {
return store.removeAllNodes(nodes);
}

@Override
public boolean retainNodes(Collection<? extends Node> nodes) {
return store.retainNodes(nodes);
}

@Override
public boolean retainEdges(Collection<? extends Edge> edges) {
return store.retainEdges(edges);
}

@Override
public boolean contains(Node node) {
return store.contains(node);
Expand Down
22 changes: 22 additions & 0 deletions src/test/java/org/gephi/graph/impl/BasicGraphStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,28 @@ public boolean removeAllNodes(Collection<? extends Node> nodes) {
return true;
}

@Override
public boolean retainNodes(Collection<? extends Node> nodes) {
Set<Node> nodeSet = new HashSet<>(nodes);
for (Node n : nodes) {
if (!nodeSet.contains(n)) {
removeNode(n);
}
}
return true;
}

@Override
public boolean retainEdges(Collection<? extends Edge> edges) {
Set<Edge> edgeSet = new HashSet<>(edges);
for (Edge e : edges) {
if (!edgeSet.contains(e)) {
removeEdge(e);
}
}
return true;
}

@Override
public boolean contains(Node node) {
return nodeStore.contains(node);
Expand Down
10 changes: 9 additions & 1 deletion src/test/java/org/gephi/graph/impl/GraphGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,20 @@ public static GraphStore generateTinyGraphStoreWithMutualEdge() {
}

public static GraphStore generateSmallGraphStore() {
return generateSmallGraphStore(true);
}

public static GraphStore generateSmallGraphStoreWithoutSelfLoop() {
return generateSmallGraphStore(false);
}

private static GraphStore generateSmallGraphStore(boolean allowSelfLoops) {
int edgeCount = 100;
GraphStore graphStore = new GraphModelImpl().store;
NodeImpl[] nodes = generateNodeList(Math
.max((int) Math.ceil(Math.sqrt(edgeCount * 2)), (int) (edgeCount / 10.0)), graphStore);
graphStore.addAllNodes(Arrays.asList(nodes));
EdgeImpl[] edges = generateEdgeList(graphStore.nodeStore, edgeCount, 0, true, true, false);
EdgeImpl[] edges = generateEdgeList(graphStore.nodeStore, edgeCount, 0, true, allowSelfLoops, false);
graphStore.addAllEdges(Arrays.asList(edges));
return graphStore;
}
Expand Down
34 changes: 34 additions & 0 deletions src/test/java/org/gephi/graph/impl/GraphStoreTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,40 @@ public void testRemoveAllEdges() {
}
}

@Test
public void testRetainNodes() {
GraphStore graphStore = GraphGenerator.generateSmallGraphStore();
Node[] nodes = graphStore.getNodes().toArray();
Assert.assertFalse(graphStore.retainNodes(Arrays.asList(nodes)));
Assert.assertEquals(graphStore.getNodeCount(), nodes.length);

Assert.assertTrue(graphStore.retainNodes(Collections.EMPTY_LIST));
Assert.assertEquals(graphStore.getNodeCount(), 0);

graphStore = GraphGenerator.generateSmallGraphStore();
nodes = graphStore.getNodes().toArray();
graphStore.retainNodes(Collections.singletonList(nodes[0]));
Assert.assertEquals(graphStore.getNodeCount(), 1);
Assert.assertTrue(graphStore.contains(nodes[0]));
}

@Test
public void testRetainEdges() {
GraphStore graphStore = GraphGenerator.generateSmallGraphStore();
Edge[] edges = graphStore.getEdges().toArray();
Assert.assertFalse(graphStore.retainEdges(Arrays.asList(edges)));
Assert.assertEquals(graphStore.getEdgeCount(), edges.length);

Assert.assertTrue(graphStore.retainEdges(Collections.EMPTY_LIST));
Assert.assertEquals(graphStore.getEdgeCount(), 0);

graphStore = GraphGenerator.generateSmallGraphStore();
edges = graphStore.getEdges().toArray();
graphStore.retainEdges(Collections.singletonList(edges[0]));
Assert.assertEquals(graphStore.getEdgeCount(), 1);
Assert.assertTrue(graphStore.contains(edges[0]));
}

@Test
public void testGetOpposite() {
GraphStore graphStore = GraphGenerator.generateTinyGraphStore();
Expand Down
49 changes: 49 additions & 0 deletions src/test/java/org/gephi/graph/impl/GraphViewDecoratorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
import org.gephi.graph.api.DirectedSubgraph;
import org.gephi.graph.api.Edge;
Expand Down Expand Up @@ -356,6 +358,53 @@ public void testUndirectedRemoveNodesFirst() {
Assert.assertEquals(graph.getEdgeCount(), 0);
}

@Test
public void testDirectedRetainNodes() {
GraphStore graphStore = GraphGenerator.generateSmallGraphStoreWithoutSelfLoop();
GraphViewStore store = graphStore.viewStore;
GraphViewImpl view = store.createView();

DirectedSubgraph graph = store.getDirectedGraph(view);
view.fill();

Assert.assertFalse(graph.retainNodes(graphStore.getNodes().toCollection()));
Assert.assertEquals(graph.getNodeCount(), graphStore.getNodeCount());

Assert.assertTrue(graph.retainNodes(Collections.EMPTY_LIST));
Assert.assertEquals(graph.getNodeCount(), 0);

view.fill();
Edge edge = graphStore.getEdges().toArray()[0];
Assert.assertTrue(graph.retainNodes(Arrays.asList(edge.getSource(), edge.getTarget())));
Assert.assertEquals(graph.getNodeCount(), 2);
Assert.assertTrue(graph.contains(edge.getSource()));
Assert.assertTrue(graph.contains(edge.getTarget()));
Assert.assertTrue(graph.contains(edge));
}

@Test
public void testDirectedRetainEdges() {
GraphStore graphStore = GraphGenerator.generateSmallGraphStoreWithoutSelfLoop();
GraphViewStore store = graphStore.viewStore;
GraphViewImpl view = store.createView();

DirectedSubgraph graph = store.getDirectedGraph(view);
view.fill();

Assert.assertFalse(graph.retainEdges(graphStore.getEdges().toCollection()));
Assert.assertEquals(graph.getEdgeCount(), graphStore.getEdgeCount());

Assert.assertTrue(graph.retainEdges(Collections.EMPTY_LIST));
Assert.assertEquals(graph.getEdgeCount(), 0);

view.fill();
Edge edge = graphStore.getEdges().toArray()[0];
Assert.assertTrue(graph.retainEdges(Collections.singletonList(edge)));
Assert.assertEquals(graph.getNodeCount(), graphStore.getNodeCount());
Assert.assertEquals(graph.getEdgeCount(), 1);
Assert.assertTrue(graph.contains(edge));
}

@Test
public void testDirectedClearEdges() {
GraphStore graphStore = GraphGenerator.generateSmallMultiTypeGraphStore();
Expand Down

0 comments on commit 5dde25b

Please sign in to comment.