package org.aksw.combinatorics.algos; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; import org.aksw.combinatorics.collections.Combination; import org.aksw.commons.collections.CartesianProduct; import org.aksw.commons.collections.cache.CachingIterable; /** * kPermutationsOfN implementation with support for solution computation and early bailout should a solution * turn out to be unsatisfiable. * At the core, this implementation notifies clients about results via a callback during a recursion. * * A static utility method is available which collects results into a list and returns a stream. * Hence, all valid permutations will be computed regardless of the number of items consumed from the stream. * However, as this approach is about 5-10 times faster than the recursive stream solution, * this approach is recommended. * * * @author raven * * @param <A> * @param <B> * @param <S> */ public class CartesianProductUtils<A, B, S> { public static <A, B, S> CartesianProduct<Combination<A, B, S>> createOnDemandCartesianProduct( Collection<A> as, Collection<B> bs, BiFunction<A, B, S> pairBasedSolver, Predicate<S> isUnsatisfiable ) { Function<A, Iterator<Combination<A, B, S>>> fn = (a) -> bs.stream() .map(b -> { S s = pairBasedSolver.apply(a, b); boolean unsatisfiable = isUnsatisfiable.test(s); Combination<A, B, S> r = unsatisfiable ? null : new Combination<A, B, S>(a, b, s); return r; }) .filter(x -> x != null) .iterator(); List<Iterable<Combination<A, B, S>>> mappings = new ArrayList<>(as.size()); for(A a : as) { Iterable<Combination<A, B, S>> foo = new CachingIterable<>(fn.apply(a)); mappings.add(foo); } CartesianProduct<Combination<A, B, S>> result = CartesianProduct.create(mappings); return result; } }