|
package org.fupfin.insight.event1b; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.concurrent.RecursiveAction; |
|
import java.util.LinkedList; |
|
import java.util.List; |
|
import java.util.concurrent.ForkJoinPool; |
|
|
|
public class SetPartitioner { |
|
|
|
ForkJoinPool pool = new ForkJoinPool(); |
|
|
|
public void partition(int n, ResultHandler handler) { |
|
pool.invoke(new Partitioner(new int[0][], generateSet(n), handler)); |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
class Partitioner extends RecursiveAction{ |
|
|
|
private static final int FORK_THRESHOLD = 10; |
|
|
|
private int[][] initialPrefix; |
|
private int[][] initialWorkSet; |
|
|
|
private ResultHandler handler; |
|
|
|
Partitioner(int[][] prefix, int[][] workSet, ResultHandler handler) { |
|
this.initialPrefix = prefix; |
|
this.initialWorkSet = workSet; |
|
this.handler = handler; |
|
} |
|
|
|
@Override |
|
protected void compute() { |
|
partition(this.initialPrefix, this.initialWorkSet); |
|
} |
|
|
|
private void partition(int[][] prefix, int[][] workSet) { |
|
handler.handle(prefix, workSet); |
|
discoverSubPartitions(prefix, workSet); |
|
} |
|
|
|
private void discoverSubPartitions(int[][] prefix, int[][] workSet) { |
|
while(workSet.length > 1) { |
|
|
|
int[] head = workSet[0]; |
|
int[][] tail = Arrays.copyOfRange(workSet, 1, workSet.length); |
|
|
|
composeNewPartitionAndDiscover(prefix, head, tail); |
|
|
|
prefix = mergeLists(prefix, new int[][]{head}); |
|
workSet = tail; |
|
} |
|
} |
|
|
|
private void composeNewPartitionAndDiscover(int[][] prefix, int[] first, int[][] rest) { |
|
|
|
List<Partitioner> subtasks = new LinkedList<Partitioner>(); |
|
|
|
int mostHighestNumber = first[first.length - 1]; |
|
|
|
for(int j = 0; j < rest.length; j++) { |
|
|
|
if(rest[j][0] <= mostHighestNumber) |
|
continue; |
|
int[] second = rest[j]; |
|
int[][] nextWorkingSet = mergeLists( |
|
new int[][]{unite(first, second)}, |
|
Arrays.copyOfRange(rest, 0, j), |
|
Arrays.copyOfRange(rest, j+1, rest.length)); |
|
|
|
if(nextWorkingSet.length < FORK_THRESHOLD) |
|
partition(prefix, nextWorkingSet); |
|
else { |
|
subtasks.add(new Partitioner(prefix, nextWorkingSet, this.handler)); |
|
} |
|
} |
|
|
|
if(subtasks.size() > 0) |
|
invokeAll(subtasks); |
|
} |
|
} |
|
|
|
private int[] unite(int[] first, int[] second) { |
|
int[] union = new int[first.length + second.length]; |
|
System.arraycopy(first, 0, union, 0, first.length); |
|
System.arraycopy(second, 0, union, first.length, second.length); |
|
return union; |
|
} |
|
|
|
private int[][] mergeLists(int[][] ... lists) { |
|
int len = 0; |
|
for(int[][] list: lists) |
|
len += list.length; |
|
int[][] result = new int[len][]; |
|
|
|
int idx = 0; |
|
for(int[][] list:lists) { |
|
System.arraycopy(list, 0, result, idx, list.length); |
|
idx += list.length; |
|
} |
|
return result; |
|
} |
|
|
|
private int[][] generateSet(int n) { |
|
int[][] result = new int[n][]; |
|
for(int i=0; i < n; i++) |
|
result[i] = new int[]{i}; |
|
return result; |
|
} |
|
|
|
|
|
static interface ResultHandler { |
|
public void handle(int[][] prefix, int[][] rest); |
|
} |
|
|
|
public static void main(String[] args) { |
|
|
|
Counter counter = new Counter(); |
|
|
|
ResultHandler handler = new SilenceResultHandler(counter); |
|
int setSize = 0; |
|
|
|
|
|
if(args.length <= 0) { |
|
printUsage(); |
|
return; |
|
} |
|
|
|
if(args.length > 1) { |
|
if(args[0].equals("-v")) |
|
handler = new SetPrintingResultHandler(counter); |
|
else if(args[0].equals("-d")) |
|
handler = new DotPrintingResultHandler(counter); |
|
else { |
|
printUsage(); |
|
return; |
|
} |
|
} |
|
|
|
Long startTime = System.currentTimeMillis(); |
|
|
|
setSize = Integer.valueOf(args[args.length > 1 ? 1 : 0]); |
|
new SetPartitioner().partition(setSize, handler); |
|
|
|
System.out.println("Bell number for " + setSize + " : " + counter.count); |
|
System.out.println("Run time: " + (System.currentTimeMillis() - startTime) / 1000.0 + " secs"); |
|
} |
|
|
|
private static void printUsage() { |
|
System.out.println("java SetPartitioner [-v|-d] set_size\n" + |
|
"\t-v: verbose output\n" + |
|
"\t-d: dot pregression output\n" + |
|
"\tset_size : size of set. greater than 0"); |
|
} |
|
|
|
static class Counter { |
|
long count; |
|
|
|
synchronized void inc() { |
|
count ++; |
|
} |
|
} |
|
|
|
static class SilenceResultHandler implements ResultHandler { |
|
|
|
private Counter counter; |
|
|
|
public SilenceResultHandler(Counter counter) { |
|
this.counter = counter; |
|
} |
|
|
|
public void handle(int[][] prefix, int[][] rest) { |
|
this.counter.inc(); |
|
} |
|
} |
|
|
|
static class DotPrintingResultHandler implements ResultHandler { |
|
|
|
private Counter counter; |
|
|
|
public DotPrintingResultHandler(Counter counter) { |
|
this.counter = counter; |
|
} |
|
|
|
@Override |
|
public synchronized void handle(int[][] prefix, int[][] rest) { |
|
|
|
if(counter.count % 100000 == 0) { |
|
System.out.print("\n"); System.out.print(counter.count); System.out.print(": "); |
|
} |
|
|
|
if(counter.count % 1000 == 0) |
|
System.out.print('.'); |
|
|
|
counter.inc(); |
|
} |
|
} |
|
|
|
static class SetPrintingResultHandler implements ResultHandler { |
|
|
|
private Counter counter; |
|
|
|
public SetPrintingResultHandler(Counter counter) { |
|
this.counter = counter; |
|
} |
|
|
|
public synchronized void handle(int[][] prefix, int[][] rest) { |
|
this.counter.inc(); |
|
printResult(prefix); |
|
printResult(rest); |
|
System.out.println(""); |
|
} |
|
|
|
private void printResult(int[][] result) { |
|
StringBuilder buf = new StringBuilder(); |
|
for(int i=0; i<result.length; i++) { |
|
int[] set = result[i]; |
|
buf.append('{'); |
|
for(int j=0; j<set.length; j++) |
|
buf.append(j > 0 ? ", " : "").append(set[j]); |
|
buf.append('}'); |
|
} |
|
System.out.print(buf.toString()); |
|
} |
|
} |
|
} |