Add optimized permutation algo

WIP, needs more tests, comments, clean up....
This commit is contained in:
chimp1984 2020-04-28 00:40:41 -05:00
parent 18476e48b2
commit 54e280c78d
No known key found for this signature in database
GPG key ID: 9801B4EC591F90E3
3 changed files with 104 additions and 19 deletions

View file

@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.function.BiFunction;
import lombok.extern.slf4j.Slf4j;
@ -53,8 +54,53 @@ public class PermutationUtil {
return altered;
}
public static <T, R> List<T> findMatchingPermutation(R targetValue,
List<T> list,
BiFunction<R, List<T>, Boolean> predicate,
int maxIterations) {
if (predicate.apply(targetValue, list)) {
return list;
} else {
return findMatchingPermutation(targetValue,
list,
new ArrayList<>(),
predicate,
maxIterations);
}
}
private static <T, R> List<T> findMatchingPermutation(R targetValue,
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);
}
}
}
List<T> nextList = lists.remove(0);
return findMatchingPermutation(targetValue, nextList, lists, predicate, maxIterations);
}
//TODO optimize algorithm so that it starts from all objects and goes down instead starting with from the bottom.
// That should help that we are not hitting the iteration limit so easily.
/**
* Returns a list of all possible permutations of a give sorted list ignoring duplicates.
* E.g. List [A,B,C] results in this list of permutations: [[A], [B], [A,B], [C], [A,C], [B,C], [A,B,C]]

View file

@ -21,15 +21,19 @@ import java.util.ArrayList;
import java.util.Arrays;
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 {
@Test
// @Test
public void testGetPartialList() {
String blindVote0 = "blindVote0";
String blindVote1 = "blindVote1";
@ -96,6 +100,34 @@ public class PermutationTest {
}
@Test
public void testFindMatchingPermutation() {
String a = "A";
String b = "B";
String c = "C";
String d = "D";
String e = "E";
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(a);
result = PermutationUtil.findMatchingPermutation(expected.toString(), list, predicate, limit);
assertTrue(expected.toString().equals(result.toString()));
expected = Arrays.asList(a, c, e);
result = PermutationUtil.findMatchingPermutation(expected.toString(), list, predicate, limit);
assertTrue(expected.toString().equals(result.toString()));
}
// @Test
public void testFindAllPermutations() {
String blindVote0 = "blindVote0";
String blindVote1 = "blindVote1";
@ -107,18 +139,23 @@ public class PermutationTest {
// findAllPermutations took 580 ms for 20 items and 1048575 iterations
// findAllPermutations took 10 ms for 15 items and 32767 iterations
// findAllPermutations took 0 ms for 10 items and 1023 iterations
int limit = 1048575;
// int limit = 1048575;
int limit = 1048575000;
List<String> list;
List<List<String>> expected;
List<List<String>> result;
List<String> subList;
/* list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
list.add("blindVote"+i);
log.error("prep");
list = new ArrayList<>();
for (int i = 0; i < 4; i++) {
list.add("blindVote" + i);
}
PermutationUtil.findAllPermutations(list, limit);*/
log.error("start");
PermutationUtil.findAllPermutations(list, limit);
log.error("end");
list = new ArrayList<>();

View file

@ -77,6 +77,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -486,20 +487,20 @@ public class VoteResultService implements DaoStateListener, DaoSetupService {
private Optional<List<BlindVote>> findPermutatedListMatchingMajority(byte[] majorityVoteListHash) {
List<BlindVote> list = BlindVoteConsensus.getSortedBlindVoteListOfCycle(blindVoteListService);
long ts = System.currentTimeMillis();
List<List<BlindVote>> result = PermutationUtil.findAllPermutations(list, 1000000);
for (List<BlindVote> variation : result) {
if (isListMatchingMajority(majorityVoteListHash, variation, false)) {
log.info("We found a variation of the blind vote list which matches the majority hash. variation={}",
variation);
log.info("findPermutatedListMatchingMajority for {} items took {} ms.",
list.size(), (System.currentTimeMillis() - ts));
return Optional.of(variation);
}
}
log.info("We did not find a variation of the blind vote list which matches the majority hash.");
BiFunction<byte[], List<BlindVote>, Boolean> predicate = (hash, variation) ->
isListMatchingMajority(hash, variation, false);
List<BlindVote> result = PermutationUtil.findMatchingPermutation(majorityVoteListHash, list, predicate, 1000000);
log.info("findPermutatedListMatchingMajority for {} items took {} ms.",
list.size(), (System.currentTimeMillis() - ts));
return Optional.empty();
if (result.isEmpty()) {
log.info("We did not find a variation of the blind vote list which matches the majority hash.");
return Optional.empty();
} else {
log.info("We found a variation of the blind vote list which matches the majority hash. variation={}", result);
return Optional.of(result);
}
}
private boolean isListMatchingMajority(byte[] majorityVoteListHash, List<BlindVote> list, boolean doLog) {
@ -513,7 +514,8 @@ public class VoteResultService implements DaoStateListener, DaoSetupService {
return Arrays.equals(majorityVoteListHash, hashOfBlindVoteList);
}
private Set<EvaluatedProposal> getEvaluatedProposals(Set<DecryptedBallotsWithMerits> decryptedBallotsWithMeritsSet, int chainHeight) {
private Set<EvaluatedProposal> getEvaluatedProposals(Set<DecryptedBallotsWithMerits> decryptedBallotsWithMeritsSet,
int chainHeight) {
// We reorganize the data structure to have a map of proposals with a list of VoteWithStake objects
Map<Proposal, List<VoteWithStake>> resultListByProposalMap = getVoteWithStakeListByProposalMap(decryptedBallotsWithMeritsSet);