Skip to content

Commit

Permalink
Neighborlist is now a synchronized queue, to avoid multithreading errors
Browse files Browse the repository at this point in the history
  • Loading branch information
tdebatty committed Feb 15, 2017
1 parent f354fdd commit f605635
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 9 deletions.
5 changes: 3 additions & 2 deletions src/main/java/info/debatty/java/graphs/Graph.java
Original file line number Diff line number Diff line change
Expand Up @@ -1143,19 +1143,20 @@ public int hashCode() {
}

@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Graph<?> other = (Graph<?>) obj;
System.out.println("Delegating to map...");
if (this.map != other.map && (this.map == null || !this.map.equals(other.map))) {
return false;
}
return true;
}


}
4 changes: 2 additions & 2 deletions src/main/java/info/debatty/java/graphs/NeighborList.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package info.debatty.java.graphs;

import info.debatty.java.util.BoundedPriorityQueue;
import info.debatty.java.util.SynchronizedBoundedPriorityQueue;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -12,7 +12,7 @@
*
* @author Thibault Debatty
*/
public class NeighborList extends BoundedPriorityQueue<Neighbor>
public class NeighborList extends SynchronizedBoundedPriorityQueue<Neighbor>
implements Serializable {

public static <T> ArrayList<Edge>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package info.debatty.java.util;

import java.io.Serializable;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.PriorityQueue;

/**
* This class implements a bounded priority queue A structure that always keeps
Expand All @@ -10,7 +10,8 @@
* @author Thibault Debatty
* @param <E>
*/
public class BoundedPriorityQueue<E> extends PriorityBlockingQueue<E> implements Serializable {
public class BoundedPriorityQueue<E> extends PriorityQueue<E>
implements Serializable {

private final int capacity;

Expand Down Expand Up @@ -84,6 +85,7 @@ public final int getCapacity() {
* @param other
* @return
*/
@Override
public boolean equals(final Object other) {
if (other == null) {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* The MIT License
*
* Copyright 2017 Thibault Debatty.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package info.debatty.java.util;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Queue;

/**
*
* @author Thibault Debatty
* @param <E>
*/
public class SynchronizedBoundedPriorityQueue<E>
implements Serializable, Iterable<E>, Collection<E>, Queue<E> {

private final BoundedPriorityQueue<E> queue;

public SynchronizedBoundedPriorityQueue(final int capacity) {
queue = new BoundedPriorityQueue<E>(capacity);
}

@Override
public Iterator<E> iterator() {
return queue.iterator();
}

@Override
public int size() {
synchronized (this) {
return queue.size();
}
}

public boolean offer(E e) {
synchronized (this) {
return queue.offer(e);
}
}

public E poll() {
synchronized (this) {
return queue.poll();
}
}

public E peek() {
synchronized (this) {
return queue.peek();
}
}

public boolean isEmpty() {
synchronized (this) {
return queue.isEmpty();
}
}

public boolean contains(Object o) {
synchronized (this) {
return queue.contains(o);
}
}

public Object[] toArray() {
synchronized (this) {
return queue.toArray();
}
}

public <T> T[] toArray(T[] a) {
synchronized (this) {
return queue.toArray(a);
}
}

public boolean add(E e) {
synchronized (this) {
return queue.add(e);
}
}

public boolean remove(Object o) {
synchronized (this) {
return queue.remove(o);
}
}

public boolean containsAll(Collection<?> c) {
synchronized (this) {
return queue.containsAll(c);
}
}

public boolean addAll(Collection<? extends E> c) {
synchronized (this) {
return queue.addAll(c);
}
}

public boolean removeAll(Collection<?> c) {
synchronized (this) {
return queue.removeAll(c);
}
}

public boolean retainAll(Collection<?> c) {
synchronized (this) {
return queue.retainAll(c);
}
}

public void clear() {
synchronized (this) {
queue.clear();
}
}

public E remove() {
synchronized (this) {
return queue.remove();
}
}

public E element() {
synchronized (this) {
return queue.element();
}
}

public boolean equals(Object other) {
if (other == null) {
return false;
}

if (!other.getClass().isInstance(this)) {
return false;
}

SynchronizedBoundedPriorityQueue<E> other_synced =
(SynchronizedBoundedPriorityQueue<E>) other;

synchronized (this) {
return queue.equals(other_synced.queue);
}
}

public String toString() {
synchronized (this) {
return queue.toString();
}
}
}
4 changes: 2 additions & 2 deletions src/test/java/info/debatty/java/graphs/GraphTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ public void testStronglyConnectedComponents() {
* Test of stronglyConnectedComponents method, of class Graph.
*/
public void testStronglyConnectedComponents2() {
System.out.println("Strongly connected components");
System.out.println("=============================");
System.out.println("Strongly connected components 2");
System.out.println("===============================");

// Generate two series of nodes
ArrayList<Integer> nodes = new ArrayList<Integer>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public double similarity(Integer value1, Integer value2) {

Integer first_node = graph.first();
System.out.println(threaded_graph.getNeighbors(first_node));
assertEquals(graph.getNeighbors(first_node).countCommons(threaded_graph.getNeighbors(first_node)), k);
assertEquals(k, graph.getNeighbors(first_node).countCommons(threaded_graph.getNeighbors(first_node)));

int correct_edges = threaded_graph.compare(graph);
double correct_ratio = 1.0 * correct_edges / (count * k);
Expand All @@ -87,4 +87,45 @@ public double similarity(Integer value1, Integer value2) {
assertTrue("Too many wrong edges!", correct_ratio >= MIN_CORRECT_RATIO);
}

/**
* Test that the threaded nndescent algorithms produces neighborlists of
* the correct size (might fail because of missing synchronization).
*/
public void testK() {
System.out.println("test K");

int count = 10;
int k = 5;
int trials = 10;

// Generate some nodes
Random r = new Random();
LinkedList<Integer> nodes = new LinkedList<Integer>();
for (int i = 0; i < count; i++) {
nodes.add(r.nextInt());
}

// Define the similarity
SimilarityInterface<Integer> similarity =
new SimilarityInterface<Integer>() {

public double similarity(final Integer value1, final Integer value2) {
return 1.0 / (1.0 + Math.abs(value1 - value2));
}
};

for (int i = 0; i < trials; i++) {
System.out.println("NNdescent threaded graph builder...");
ThreadedNNDescent<Integer> threaded_builder =
new ThreadedNNDescent<Integer>();
threaded_builder.setK(k);
threaded_builder.setSimilarity(similarity);
Graph<Integer> threaded_graph = threaded_builder.computeGraph(nodes);

for (Integer value : threaded_graph.getNodes()) {
assertEquals(k, threaded_graph.getNeighbors(value).size());
}
}
}

}

0 comments on commit f605635

Please sign in to comment.