Reputation: 168
when I solve the Subset Sum problem or "P = NP" it takes 5 minutes with the following code. I am really curious to know how much faster it would be if I were using .parallelStream. however I don't understand how to convert the code.
public class MainActivity {
final static Integer[] POPS = {8897109, 12828837, 9461105, 6371773, 5965343, 5946800, 5582170, 5564635, 5268860, 4552402, 4335391, 4296250, 4224851, 4192887, 3439809, 3279833, 3095313, 2812896, 2783243, 2710489, 2543482, 2356285, 2226009, 2149127, 2142508, 2134411};
final static int TOTAL = 100000000;
/**
* @param args
*/
public static void main(String[] args) {
Combinations c = new Combinations(POPS, TOTAL);
c.chooser();
}
}
import java.util.ArrayList;
import org.paukov.combinatorics.Factory;
import org.paukov.combinatorics.Generator;
import org.paukov.combinatorics.ICombinatoricsVector;
public class Combinations {
private Integer[] POPS;
private int TOTAL;
public combinations(Integer[] pops, int total){
this.POPS = pops;
this.TOTAL = total;
}
public void chooser(){
for(int i = 1; i<=POPS.length; i++){
System.out.println(i);
ICombinatoricsVector<Integer> initialVector = Factory.createVector(POPS);
Generator<Integer> gen = Factory.createSimpleCombinationGenerator(initialVector, i);
for (ICombinatoricsVector<Integer> combination : gen) {
String temp = combination.toString();
int size = temp.indexOf("size");
temp = temp.substring(22, size-3);
int sum = Adder(temp);
if (sum == TOTAL){
System.out.println(temp);
}
}
}
}
public int adder(String combos){
int total = 0;
String[] parts = combos.split(", ");
ArrayList<Integer> nums = new ArrayList<>();
for(int i = 0; i<parts.length; i++){
nums.add(Integer.parseInt(parts[i]));
}
for(int temp : nums){
total += temp;
}
return total;
}
}
Here is the code with the string stuff taken out. It only takes about 15 seconds now. I realize that .parallelStream() will not reduce its time much, but could someone still at least give me some hints on how to do it.
import java.util.ArrayList;
import java.util.List;
import org.paukov.combinatorics.Factory;
import org.paukov.combinatorics.Generator;
import org.paukov.combinatorics.ICombinatoricsVector;
public class Combinations {
private Integer[] POPS;
private int TOTAL;
public Combinations(Integer[] pops, int total){
this.POPS = pops;
this.TOTAL = total;
}
public void chooser(){
for(int i = 1; i<=POPS.length; i++){
System.out.println(i);
ICombinatoricsVector<Integer> initialVector = Factory.createVector(POPS);
Generator<Integer> gen = Factory.createSimpleCombinationGenerator(initialVector, i);
for (ICombinatoricsVector<Integer> combination : gen) {
List<Integer> temp = combination.getVector();
int sum = adder(temp);
if (sum == TOTAL){
System.out.println(temp);
}
}
}
}
public int adder(List<Integer> combos){
int total = 0;
for(Integer temp : combos){
total+=temp;
}
return total;
}
}
Upvotes: 0
Views: 714
Reputation: 3453
This runs about three times as fast on my box (i7-2600 with hyper-threading, 8 virtual cores):
public class Combinations {
private Integer[] POPS;
private int TOTAL;
public Combinations(Integer[] pops, int total) {
this.POPS = pops;
this.TOTAL = total;
}
public void chooser() {
ICombinatoricsVector<Integer> initialVector = Factory.createVector(POPS);
IntStream.range(1, POPS.length + 1).parallel()
.peek(System.out::println)
.mapToObj(i -> Factory.createSimpleCombinationGenerator(initialVector, i))
.flatMap(gen -> genToStream(gen, false)
.map(ICombinatoricsVector::getVector)
.filter(v -> adder(v) == TOTAL))
.forEach(System.out::println);
}
public static int adder(Iterable<Integer> combos) {
int total = 0;
for (Integer temp : combos) {
total += temp;
}
return total;
}
public static <E> Stream<ICombinatoricsVector<E>> genToStream(Generator<E> gen, boolean parallel) {
return StreamSupport.stream(Spliterators.spliterator(gen.iterator(),
gen.getNumberOfGeneratedObjects(), Spliterator.ORDERED), parallel);
}
}
This uses a parallel stream for the outer loop, a regular stream for the inner loop, and avoids using a stream to sum the list (for speed). You can try a parallel inner stream with genToStream(gen, true)
, but I didn't see any difference in speed.
Also, if you want a List<List<Integer>>
of matches, just change the forEach line to .collect(Collectors.toList());
.
Upvotes: 2