Index: voting/pom.xml
===================================================================
--- voting/pom.xml	(revision 27)
+++ voting/pom.xml	(revision 28)
@@ -6,5 +6,5 @@
 	<groupId>geniusweb</groupId>
 	<artifactId>voting</artifactId>
-	<version>1.5.6</version> <!-- must equal ${geniusweb.version} -->
+	<version>1.5.7</version> <!-- must equal ${geniusweb.version} -->
 	<packaging>jar</packaging>
 
@@ -17,5 +17,5 @@
 		<passwd>${env.ARTIFACTORY_PASS}</passwd>
 		<jackson-2-version>2.9.10</jackson-2-version>
-		<geniusweb.version>1.5.6</geniusweb.version>
+		<geniusweb.version>1.5.7</geniusweb.version>
 	</properties>
 
Index: voting/src/main/java/geniusweb/voting/CollectedVotes.java
===================================================================
--- voting/src/main/java/geniusweb/voting/CollectedVotes.java	(revision 27)
+++ voting/src/main/java/geniusweb/voting/CollectedVotes.java	(revision 28)
@@ -2,8 +2,11 @@
 
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.PriorityQueue;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import geniusweb.actions.PartyId;
@@ -137,4 +140,58 @@
 
 	/**
+	 * Breath-first optimized search, similar as {@link #getMaxPowerGroup(Set)}
+	 * but more efficient on average (remains to be proven). Notice that this
+	 * algorithm may be more expensive particularly if there is no consensus at
+	 * all, because of the added overhead of the breath-first search
+	 * 
+	 * @param allvotes a list of all votes for a particular bid.
+	 * @return a consensus-group with maximum power, so there is no other
+	 *         consensus group that has more power (but there may be other
+	 *         groups with same power). returns empty set if no consensus found
+	 */
+	protected Set<PartyId> getMaxPowerGroupBreathFirst(Set<Vote> allvotes) {
+		/**
+		 * queue that keeps the options for the breath-first search sorted from
+		 * highest to lowest power of the voters.
+		 */
+		PriorityQueue<Set<Vote>> queue = new PriorityQueue<>(
+				new Comparator<Set<Vote>>() {
+					@Override
+					public int compare(Set<Vote> vs1, Set<Vote> vs2) {
+						Set<PartyId> parties1 = vs1.stream()
+								.map(vote -> vote.getActor())
+								.collect(Collectors.toSet());
+						Set<PartyId> parties2 = vs2.stream()
+								.map(vote -> vote.getActor())
+								.collect(Collectors.toSet());
+						return getTotalPower(parties1)
+								.compareTo(getTotalPower(parties2));
+					}
+				});
+		queue.add(allvotes);
+
+		while (!queue.isEmpty()) {
+			// try one with the highest power
+			Set<Vote> vs = queue.poll();
+			if (isViable(vs))
+				return getParties(vs);
+			if (vs.size() > 1) {
+				// vote can be splitted. push all new subsets
+				for (Vote vote : vs) {
+					Set<Vote> subvotes = new HashSet<>(vs);
+					subvotes.remove(vote);
+					// avoid duplicate work. Since this has a removed party,
+					// and assuming power of each party >=1,
+					// we can not already have checked subvotes
+					if (!queue.contains(subvotes))
+						queue.add(subvotes);
+				}
+			}
+
+		}
+		return Collections.emptySet();
+	}
+
+	/**
 	 * 
 	 * @param votes a list of all votes for a particular bid. The parties that
@@ -142,5 +199,5 @@
 	 * @return a consensus-group with maximum power, so there is no other
 	 *         consensus group that has more power (but there may be other
-	 *         groups with same power).
+	 *         groups with same power). returns empty set if no consensus found
 	 */
 	protected Set<PartyId> getMaxPowerGroup(Set<Vote> votes) {
@@ -179,13 +236,24 @@
 				new FixedList<Vote>(votes));
 		// check each possible subset.
+		// TODO stream this
 		for (ImmutableList<Vote> voteList : allVotePermutations) {
-			Set<PartyId> parties = getParties(voteList);
-			Integer totalpower = getTotalPower(parties);
-			if (parties.size() >= 2 && totalpower >= getMinPower(voteList)
-					&& totalpower <= getMaxPower(voteList)) {
-				groups.add(parties);
+			if (isViable(voteList)) {
+				groups.add(getParties(voteList));
 			}
 		}
 		return groups;
+	}
+
+	/**
+	 * 
+	 * @param voteList a list of votes for a single bid.
+	 * @return true if this votelist satisfies the requirements of all
+	 *         participants and there are &ge; 2 parties
+	 */
+	private boolean isViable(Iterable<Vote> voteList) {
+		Set<PartyId> parties = getParties(voteList);
+		Integer totalpower = getTotalPower(parties);
+		return parties.size() >= 2 && totalpower >= getMinPower(voteList)
+				&& totalpower <= getMaxPower(voteList);
 	}
 
@@ -194,5 +262,5 @@
 	 * @return all parties that did a vote
 	 */
-	public static Set<PartyId> getParties(ImmutableList<Vote> voteList) {
+	public static Set<PartyId> getParties(Iterable<Vote> voteList) {
 		Set<PartyId> parties = new HashSet<>();
 		for (Vote vote : voteList) {
@@ -209,5 +277,5 @@
 	 *         accept. This is equal to the max of the vote.getMinPower
 	 */
-	private Integer getMinPower(ImmutableList<Vote> votes) {
+	private Integer getMinPower(Iterable<Vote> votes) {
 		int max = 0;
 		for (Vote vote : votes) {
@@ -224,5 +292,5 @@
 	 *         accept. This is equal to the min of the vote.getMaxPower
 	 */
-	private Integer getMaxPower(ImmutableList<Vote> votes) {
+	private Integer getMaxPower(Iterable<Vote> votes) {
 		int min = Integer.MAX_VALUE;
 		for (Vote vote : votes) {
Index: voting/src/test/java/geniusweb/voting/CollectedVotesTest.java
===================================================================
--- voting/src/test/java/geniusweb/voting/CollectedVotesTest.java	(revision 27)
+++ voting/src/test/java/geniusweb/voting/CollectedVotesTest.java	(revision 28)
@@ -2,4 +2,5 @@
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
@@ -10,4 +11,5 @@
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -40,4 +42,5 @@
 	private final Vote votePA2 = new Vote(partyP, bidA, 2, 9);
 	private final Vote voteQA2 = new Vote(partyQ, bidA, 2, 9);
+	private final Vote voteQA3 = new Vote(partyQ, bidA, 3, 9);
 	private final Vote voteQB3 = new Vote(partyQ, bidB, 3, 9);
 	private final Vote voteQB2 = new Vote(partyQ, bidB, 2, 9);
@@ -100,4 +103,9 @@
 		Set<PartyId> parties = cv.getMaxPowerGroup(votes);
 		assertEquals(new HashSet<>(Arrays.asList(partyP, partyQ)), parties);
+
+		// test the optimized code similarly
+		parties = cv.getMaxPowerGroupBreathFirst(votes);
+		assertEquals(new HashSet<>(Arrays.asList(partyP, partyQ)), parties);
+
 	}
 
@@ -111,4 +119,8 @@
 		Set<PartyId> parties = cv.getMaxPowerGroup(votes);
 		// party R wants 4 votes so we can't satisfy
+		assertEquals(new HashSet<>(Arrays.asList(partyP, partyQ)), parties);
+
+		// test the optimized code similarly
+		parties = cv.getMaxPowerGroupBreathFirst(votes);
 		assertEquals(new HashSet<>(Arrays.asList(partyP, partyQ)), parties);
 	}
@@ -124,4 +136,19 @@
 		assertEquals(new HashSet<>(Arrays.asList(partyP, partyQ, partyR)),
 				parties);
+
+		// test the optimized code similarly
+		parties = cv.getMaxPowerGroupBreathFirst(votes);
+		assertEquals(new HashSet<>(Arrays.asList(partyP, partyQ, partyR)),
+				parties);
+	}
+
+	@Test
+	public void testNoConsensus() {
+		Set<Vote> votes = new HashSet<>(Arrays.asList(voteQA3, voteRA3));
+		CollectedVotes cv = new CollectedVotes(Collections.emptyMap(),
+				allpowers);
+		assertEquals(Collections.emptySet(), cv.getMaxPowerGroup(votes));
+		assertEquals(Collections.emptySet(),
+				cv.getMaxPowerGroupBreathFirst(votes));
 	}
 
@@ -298,3 +325,19 @@
 	}
 
+	@Test
+	public void testRandomOrderOfSet() {
+		// this test that a Set of parties does not have
+		// the fixed order of the list #1878
+		// not really testing our code but crucial for proper working.
+		List<PartyId> list = Arrays.asList(partyQ, partyR, partyS);
+		// #1878 does Set randomize somewhat?
+		Set<PartyId> parties = new HashSet<>(list);
+		assertNotEquals(list, new LinkedList<>(parties));
+
+		LinkedList<PartyId> list2 = new LinkedList<>(list);
+		list2.add(partyP);
+		parties = new HashSet<>(list2);
+		assertNotEquals(list2, new LinkedList<>(parties));
+
+	}
 }
