package org.aksw.combinatorics.algos; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import java.util.function.BinaryOperator; import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.aksw.combinatorics.collections.Combination; import org.aksw.combinatorics.collections.CombinationStack; import org.aksw.commons.collections.lists.LinkedListNode; import com.google.common.base.Stopwatch; import com.google.common.collect.Iterators; public class StateCombinatoric<A, B, S> { //protected Stack<Entry<A, B>> stack = new Stack<Entry<A, B>>(); protected LinkedListNode<A> remainingA; protected LinkedListNode<B> remainingB; protected BiFunction<A, B, S> computeSolutionContribution; protected BinaryOperator<S> solutionCombiner; protected Predicate<S> isUnsatisfiable; //protected BiConsumer<Stack<Entry<A, B>>, S> completeMatch; public StateCombinatoric( LinkedListNode<A> remainingA, LinkedListNode<B> remainingB, BiFunction<A, B, S> computeSolutionContribution, BinaryOperator<S> solutionCombiner, Predicate<S> isUnsatisfiable) { super(); this.remainingA = remainingA; this.remainingB = remainingB; this.computeSolutionContribution = computeSolutionContribution; this.solutionCombiner = solutionCombiner; this.isUnsatisfiable = isUnsatisfiable; } public static <A, B> Stream<CombinationStack<A, B, Void>> createKPermutationsOfN(Collection<A> ks, Collection<B> ns) { LinkedListNode<A> nas = LinkedListNode.create(ks); LinkedListNode<B> nbs = LinkedListNode.create(ns); //int[] i = new int[]{0}; Void nil = null; StateCombinatoric<A, B, Void> runner = new StateCombinatoric<>( nas, nbs, (a, b) -> nil, (a, b) -> nil, (s) -> false); Iterator<CombinationStack<A, B, Void>> iterator = runner.stream(nil); Iterable<CombinationStack<A, B, Void>> iterable = () -> iterator; Stream<CombinationStack<A, B, Void>> result = StreamSupport.stream(iterable.spliterator(), false); return result; } public Iterator<CombinationStack<A, B, S>> stream(S baseSolution) { Iterator<CombinationStack<A, B, S>> result = streamA(baseSolution, null, () -> {}); return result; } // [a b c] [1 2 3 4 5] -> [1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 4], ... //Stream<Stack<Entry<A, B>>> public Iterator<CombinationStack<A, B, S>> streamA(S baseSolution, CombinationStack<A, B, S> stack, Runnable closeAction) { Iterator<Iterator<CombinationStack<A, B, S>>> it = new Iterator<Iterator<CombinationStack<A, B, S>>>() { LinkedListNode<A> curr = remainingA.successor; boolean next = true; @Override public boolean hasNext() { if(!next) { closeAction.run(); } return next; } @Override public Iterator<CombinationStack<A, B, S>> next() { next = false; Iterator<CombinationStack<A, B, S>> r; if(!curr.isTail()) { LinkedListNode<A> pick = curr; A a = pick.data; pick.unlink(); curr = pick.successor; //System.out.println("as unlink: " + remainingA + "; " + a); // recurse r = nextB(baseSolution, a, stack, () -> { // restore pick.relink(); }); } else { //@SuppressWarnings("unchecked") //Stack<Entry<A, B>> copy = (Stack<Entry<A, B>>)stack.clone(); //r = Stream.of(new Combination<A, B, S>(copy, baseSolution)); r = Collections.singleton(stack).iterator();//Stream.of(stack); } return r; //System.out.println("picked " + a); } }; Iterator<CombinationStack<A, B, S>> result = Iterators.concat(it); return result; } public Iterator<CombinationStack<A, B, S>> nextB(S baseSolution, A a, CombinationStack<A, B, S> stack, Runnable closeAction) { Iterator<Iterator<CombinationStack<A, B, S>>> it = new Iterator<Iterator<CombinationStack<A, B, S>>>() { LinkedListNode<B> curr = remainingB.successor; @Override public boolean hasNext() { boolean r = !curr.isTail(); if(r == false) { closeAction.run(); } return r; } @Override public Iterator<CombinationStack<A, B, S>> next() { Iterator<CombinationStack<A, B, S>> r = null; LinkedListNode<B> pick = curr; B b = pick.data; pick.unlink(); curr = pick.successor; S solutionContribution = computeSolutionContribution.apply(a, b); S combined = null; boolean unsatisfiable; unsatisfiable = isUnsatisfiable.test(solutionContribution); if(!unsatisfiable) { combined = solutionCombiner.apply(baseSolution, solutionContribution); unsatisfiable = isUnsatisfiable.test(combined); } if(!unsatisfiable) { Combination<A, B, S> c = new Combination<>(a, b, combined); //stack.push(new SimpleEntry<>(a, b)); CombinationStack<A, B, S> newStack = new CombinationStack<>(stack, c); //System.out.println("push: " + stack); // recurse r = streamA(combined, newStack, () -> { // restore pick.relink(); }); } else { r = Collections.emptyIterator(); } return r; } }; Iterator<CombinationStack<A, B, S>> result = Iterators.concat(it); return result; } public static void main(String[] args) { List<String> as = new ArrayList<String>(Arrays.asList("a", "b", "c", "d", "e", "f", "g")); List<Integer> bs = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); // List<String> as = new ArrayList<String>(Arrays.asList("a", "b", "c")); // List<Integer> bs = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5)); // Collection<String> strs = new ArrayList<String>(); for(int i = 0; i < 1; ++i) { Stopwatch sw = Stopwatch.createStarted(); Stream<?> stream = null; stream = StateCombinatoricCallback.createKPermutationsOfN2(as, bs); //System.out.println("huh"); //stream = createKPermutationsOfN(as, bs); //IntStream stream = IntStream.range(0, 181440000); //stream = IntStream.range(0, 181440).mapToObj(x -> "mystr" + x); if(true) { stream = stream.limit(1); com.codepoetics.protonpack.StreamUtils.zipWithIndex(stream).forEach(y -> System.out.println(y.getIndex() + " - " + y.getValue())); } else { long count = stream != null ? stream.count() : 0; System.out.println("Time taken for " + count + " items: " + sw.stop().elapsed(TimeUnit.MILLISECONDS)); } } } }