Test permutations level by level

This commit is contained in:
sqrrm 2020-04-29 01:00:53 +02:00 committed by Christoph Atteneder
parent 61838920ed
commit 96575dcad7
No known key found for this signature in database
GPG key ID: CD5DC1C529CDFD3B
2 changed files with 59 additions and 25 deletions

View file

@ -21,8 +21,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@ -65,7 +67,7 @@ public class PermutationUtil {
list,
new ArrayList<>(),
predicate,
maxIterations);
new AtomicInteger(maxIterations));
}
}
@ -73,29 +75,49 @@ public class PermutationUtil {
List<T> list,
List<List<T>> lists,
BiFunction<R, List<T>, Boolean> predicate,
int maxIterations) {
if (maxIterations == 0) {
return new ArrayList<>();
}
maxIterations--;
for (int i = 0; i < list.size(); i++) {
List<T> newList = new ArrayList<>(list);
newList.remove(i);
// We want to avoid testing duplicates
if (!lists.contains(newList)) {
if (predicate.apply(targetValue, newList)) {
return newList;
} else {
lists.add(newList);
}
AtomicInteger maxIterations) {
for (int level = 0; level < list.size(); level++) {
// Test one level at a time
var result = checkLevel(targetValue, list, predicate, level, 0, maxIterations);
if (!result.isEmpty()) {
return result;
}
}
List<T> nextList = lists.remove(0);
return findMatchingPermutation(targetValue, nextList, lists, predicate, maxIterations);
return new ArrayList<>();
}
@NonNull
private static <T, R> List<T> checkLevel(R targetValue,
List<T> previousLevel,
BiFunction<R, List<T>, Boolean> predicate,
int level,
int permutationIndex,
AtomicInteger maxIterations) {
if (previousLevel.size() == 1) {
return new ArrayList<>();
}
for (int i = permutationIndex; i < previousLevel.size(); i++) {
if (maxIterations.get() <= 0) {
return new ArrayList<>();
}
List<T> newList = new ArrayList<>(previousLevel);
newList.remove(i);
if (level == 0) {
maxIterations.decrementAndGet();
// Check all permutations on this level
if (predicate.apply(targetValue, newList)) {
return newList;
}
} else {
// Test next level
var result = checkLevel(targetValue, newList, predicate, level - 1, i, maxIterations);
if (!result.isEmpty()) {
return result;
}
}
}
return new ArrayList<>();
}
//TODO optimize algorithm so that it starts from all objects and goes down instead starting with from the bottom.

View file

@ -23,13 +23,11 @@ import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
@Slf4j
public class PermutationTest {
@ -109,13 +107,12 @@ public class PermutationTest {
int limit = 1048575;
List<String> result;
List<String> list;
String targetValue;
List<String> expected;
BiFunction<String, List<String>, Boolean> predicate = (target, variationList) -> variationList.toString().equals(target);
list = Arrays.asList(a, b, c, d, e);
expected = Arrays.asList("-");
expected = Arrays.asList(a);
result = PermutationUtil.findMatchingPermutation(expected.toString(), list, predicate, limit);
assertTrue(expected.toString().equals(result.toString()));
@ -123,7 +120,22 @@ public class PermutationTest {
expected = Arrays.asList(a, c, e);
result = PermutationUtil.findMatchingPermutation(expected.toString(), list, predicate, limit);
assertTrue(expected.toString().equals(result.toString()));
}
@Test
public void testBreakAtLimit() {
BiFunction<String, List<String>, Boolean> predicate =
(target, variationList) -> variationList.toString().equals(target);
var list = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o");
var expected = Arrays.asList("b", "g", "m");
// Takes around 32508 tries starting from longer strings
var limit = 100000;
var result = PermutationUtil.findMatchingPermutation(expected.toString(), list, predicate, limit);
assertTrue(expected.toString().equals(result.toString()));
limit = 1000;
result = PermutationUtil.findMatchingPermutation(expected.toString(), list, predicate, limit);
assertTrue(result.isEmpty());
}