Index: voting/src/main/java/geniusweb/voting/CollectedVotesWithValue.java
===================================================================
--- voting/src/main/java/geniusweb/voting/CollectedVotesWithValue.java	(revision 30)
+++ voting/src/main/java/geniusweb/voting/CollectedVotesWithValue.java	(revision 30)
@@ -0,0 +1,305 @@
+package geniusweb.voting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import geniusweb.actions.PartyId;
+import geniusweb.actions.VoteWithValue;
+import geniusweb.actions.Votes;
+import geniusweb.actions.VotesWithValue;
+import geniusweb.ip.inputOutput.Input;
+import geniusweb.ip.inputOutput.Output;
+import geniusweb.ip.ipSolver.IPSolver;
+import geniusweb.ip.mainSolver.Result;
+import geniusweb.issuevalue.Bid;
+import tudelft.utilities.immutablelist.Tuple;
+
+/**
+ * Utility class. Typically contains all the votes collected from 1 round. Can
+ * find the best combinations of votes, eg to get the maximum consensus group.
+ * Basically a copy of {@link CollectedVotesWithValue} but for
+ * {@link VotesWithValue}.
+ * <p>
+ * immutable.
+ */
+public class CollectedVotesWithValue {
+	private final Map<PartyId, VotesWithValue> allvotes;
+	private final Map<PartyId, Integer> powers;
+
+	// caching
+	private transient Map<Bid, Set<VoteWithValue>> allBids = null;
+	private transient Map<PartyId, Bid> maxAgreements = null;
+	// parties must have fixed order.
+	private transient List<PartyId> parties;
+
+	/**
+	 * 
+	 * @param votesMap the {@link Votes} done for each party
+	 * @param power    the power of each party. The power is an integer number.
+	 *                 In the voting process, the party powers add up to form
+	 *                 the total voting power. This set may contain parties that
+	 *                 are not in newmap. The maximum number of parties is 32
+	 *                 (memory constraints)
+	 */
+	public CollectedVotesWithValue(Map<PartyId, VotesWithValue> votesMap,
+			Map<PartyId, Integer> power) {
+		this.allvotes = new HashMap<>(votesMap);
+		this.powers = new HashMap<>(power);
+		// respect insertion order of votesMap, useful
+		// for testing in combination with LinkedHashMap
+		parties = new ArrayList<PartyId>(votesMap.keySet());
+
+		if (!powers.keySet().containsAll(allvotes.keySet())) {
+			throw new IllegalArgumentException(
+					"All voting parties must have a power");
+		}
+		if (parties.size() > 32)
+			throw new IllegalArgumentException(
+					"Exceeded max number of 32 parties- won't fit in memory");
+	}
+
+	/**
+	 * @return all the votes placed so far
+	 */
+	public Map<PartyId, VotesWithValue> getVotes() {
+		return Collections.unmodifiableMap(allvotes);
+	}
+
+	/**
+	 * @return the powers of all parties
+	 */
+	public Map<PartyId, Integer> getPowers() {
+		return Collections.unmodifiableMap(powers);
+	}
+
+	/**
+	 * @return a map containing for each {@link Bid}s a subset of
+	 *         {@link PartyId}s that placed a satisfied vote for that bid, such
+	 *         that the subset has maximum power. Maximum power means that there
+	 *         is no other subset of satisfied votes for that bid with more
+	 *         group power. There may be other subsets of equal power for the
+	 *         bid. If there are no concensus possibilities at all for a bid,
+	 *         the bid is not placed in the map.
+	 */
+	public Map<PartyId, Bid> getMaxAgreements() {
+		if (maxAgreements == null)
+			maxAgreements = getMaxAgreements1();
+		return maxAgreements;
+	}
+
+	/**
+	 * @return all bids that were voted on and the votes for that bid. This
+	 *         basically reverses keys and values in {@link #allvotes}
+	 */
+	public Map<Bid, Set<VoteWithValue>> getAllBids() {
+		if (allBids == null)
+			allBids = getAllBids1();
+		return allBids;
+	}
+
+	/**
+	 * @return the list of all parties, in the exact order as used internally
+	 */
+	public List<PartyId> getParties() {
+		return Collections.unmodifiableList(parties);
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((allvotes == null) ? 0 : allvotes.hashCode());
+		result = prime * result + ((powers == null) ? 0 : powers.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		CollectedVotesWithValue other = (CollectedVotesWithValue) obj;
+		if (allvotes == null) {
+			if (other.allvotes != null)
+				return false;
+		} else if (!allvotes.equals(other.allvotes))
+			return false;
+		if (powers == null) {
+			if (other.powers != null)
+				return false;
+		} else if (!powers.equals(other.powers))
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "CollectedVotesWithValue[" + allvotes + "," + powers + "]";
+	}
+
+	/**
+	 * @see #getMaxAgreements()
+	 */
+	private Map<PartyId, Bid> getMaxAgreements1() {
+		int numOfAgents = parties.size();
+		if (numOfAgents == 0)
+			return Collections.emptyMap();
+
+		double[] coalitionValues = getCoalitionValues();
+		double acceptableRatio = 100;
+		Input input = new Input(numOfAgents, coalitionValues, acceptableRatio);
+		Result result = new Result(input);
+		Output output = new Output(input);
+
+		IPSolver ipSolver = new IPSolver();
+		ipSolver.solve(input, output, result);
+		int[][] coalitions = result.get_ipBestCSFound();
+
+		// coalitions now contains array like [[3, 4], [1, 2]]
+		// indicating which parties are in coalitions.
+		Map<PartyId, Bid> agreements = new HashMap<>();
+		for (int n = 0; n < coalitions.length; n++) {
+			Set<PartyId> active = getParties(coalitions[n]);
+			Tuple<Bid, Integer> bestcoalition = getBestCoalition(active);
+			if (bestcoalition != null) {
+				Bid bestbid = bestcoalition.get1();
+				for (PartyId party : active) {
+					agreements.put(party, bestbid);
+				}
+			}
+		}
+		return agreements;
+	}
+
+	/**
+	 * @return array of the maximum goalition value for each possible coalition,
+	 *         structured as required for the IP algorithm: arrey element k
+	 *         contains the best coalition with members
+	 *         {@link #getActiveParties(int)}
+	 */
+	protected double[] getCoalitionValues() {
+		int numOfAgents = parties.size();
+		double[] coalitionValues = new double[1 << numOfAgents];
+
+		for (int n = 0; n < 1 << numOfAgents; n++) {
+			Tuple<Bid, Integer> best = getBestCoalition(getActiveParties(n));
+			coalitionValues[n] = best == null ? 0 : best.get2();
+		}
+		return coalitionValues;
+	}
+
+	/**
+	 * @param active the set of active parties to consider for a coalition.
+	 * @return the Bid and the coalition value of the bid. This searches the bid
+	 *         that all parties can accept and has the highest sum of values.
+	 *         Returns null if there is no coalition possible
+	 */
+	protected Tuple<Bid, Integer> getBestCoalition(Set<PartyId> active) {
+		if (active.isEmpty())
+			return null;
+		PartyId firstparty = active.iterator().next();
+		if (!allvotes.containsKey(firstparty))
+			return null;
+		Integer power = getPower(active);
+		Bid bestBid = null;
+		Integer bestValue = 0;
+		for (VoteWithValue vote : allvotes.get(firstparty).getVotes()) {
+			Integer val = getBidValue(active, vote.getBid(), power);
+			if (val > bestValue) {
+				bestBid = vote.getBid();
+				bestValue = val;
+			}
+		}
+		if (bestBid == null)
+			return null;
+		return new Tuple<Bid, Integer>(bestBid, bestValue);
+	}
+
+	/***
+	 * 
+	 * @param active the active parties
+	 * @param bid    the bid to evaluate
+	 * @param power  the power of the set of active parties
+	 * @return the sum of the values for this bid, or 0 if this bid is
+	 *         unacceptable: a party did not vote for that bid, or if the actual
+	 *         power of the active parties is outside the acceptable range for a
+	 *         vote.
+	 */
+	private Integer getBidValue(Set<PartyId> active, Bid bid, int power) {
+		int value = 0;
+		for (PartyId party : active) {
+			VoteWithValue vote = allvotes.get(party).getVote(bid);
+			if (vote == null || power < vote.getMinPower()
+					|| power > vote.getMaxPower())
+				return 0;
+			value = value + vote.getValue();
+		}
+		return value;
+	}
+
+	/**
+	 * @param n a coalition number, where 1 at bit position k indicates party k
+	 *          is active.
+	 * @return the active parties in the n bit-indicator
+	 */
+	protected Set<PartyId> getActiveParties(int n) {
+		Set<PartyId> activeparties = new HashSet<>();
+		for (PartyId party : parties) {
+			if ((n & 1) == 1) {
+				activeparties.add(party);
+			}
+			n = n >> 1;
+		}
+		return activeparties;
+	}
+
+	/**
+	 * 
+	 * @param partynrs the party numbers in the coalition. WARNING the first
+	 *                 party number is assumed to be 1, instead of the usual 0.
+	 *                 This to match the working of the IP library that starts
+	 *                 counting at 1.
+	 * @return list of {@link PartyId}s
+	 */
+	protected Set<PartyId> getParties(int[] partynrs) {
+		Set<PartyId> active = new HashSet<PartyId>(partynrs.length);
+		for (int n = 0; n < partynrs.length; n++) {
+			active.add(parties.get(partynrs[n] - 1));
+		}
+		return active;
+	}
+
+	private Map<Bid, Set<VoteWithValue>> getAllBids1() {
+		Map<Bid, Set<VoteWithValue>> bids = new HashMap<>();
+		for (VotesWithValue votes : allvotes.values()) {
+			for (VoteWithValue vote : votes.getVotes()) {
+				Bid bid = vote.getBid();
+				Set<VoteWithValue> list = bids.get(bid);
+				if (list == null)
+					list = new HashSet<VoteWithValue>();
+				list.add(vote);
+				bids.put(bid, list);
+			}
+		}
+		return bids;
+	}
+
+	/**
+	 * 
+	 * @param activeparties a list of parties
+	 * @return total voting power of the parties
+	 */
+	protected Integer getPower(Set<PartyId> activeparties) {
+		return activeparties.stream().map(p -> powers.get(p)).reduce(0,
+				Integer::sum);
+	}
+}
Index: voting/src/main/java/geniusweb/voting/VotingEvaluator.java
===================================================================
--- voting/src/main/java/geniusweb/voting/VotingEvaluator.java	(revision 29)
+++ voting/src/main/java/geniusweb/voting/VotingEvaluator.java	(revision 30)
@@ -34,7 +34,8 @@
 	 * </ul>
 	 * 
-	 * @param votes the Votes made by parties. All active parties in the
-	 *              negotiation must be available, even if they did not vote, to
-	 *              ensure that {@link #isFinished()} can work properly.
+	 * @param votes the Votes made by parties in the round to be evaluated.. All
+	 *              active parties in the negotiation must be available, even if
+	 *              they did not vote, to ensure that {@link #isFinished()} can
+	 *              work properly.
 	 * 
 	 * @return new VotingEvaluation object containing the given votes.
Index: voting/src/main/java/geniusweb/voting/VotingEvaluatorWithValue.java
===================================================================
--- voting/src/main/java/geniusweb/voting/VotingEvaluatorWithValue.java	(revision 30)
+++ voting/src/main/java/geniusweb/voting/VotingEvaluatorWithValue.java	(revision 30)
@@ -0,0 +1,56 @@
+package geniusweb.voting;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+
+import geniusweb.inform.Agreements;
+import geniusweb.voting.evaluatorwithvalue.LargestAgreementWithValue;
+
+/**
+ * Evaluates the {@link CollectedVotes}, determining the agreements and if the
+ * negotiation should continue.
+ * 
+ * Implementations should be immutable and not serialize internal variables (eg
+ * &#64;JsonIgnore them).
+ */
+@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE)
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.WRAPPER_OBJECT)
+@JsonSubTypes({ @JsonSubTypes.Type(value = LargestAgreementWithValue.class) })
+public interface VotingEvaluatorWithValue {
+	/**
+	 * This function is the effective constructor. This mechanism serves several
+	 * purposes:
+	 * <ul>
+	 * <li>It defines the constructor at interface level, so that we can ensure
+	 * it's available and can call it given an instance,
+	 * <li>We can use a (typically blank) instance of this to make more
+	 * instances
+	 * <li>You can cache intermediate results in the object for caching
+	 * </ul>
+	 * 
+	 * @param votes the Votes made by parties in the round to be evaluated.. All
+	 *              active parties in the negotiation must be available, even if
+	 *              they did not vote, to ensure that {@link #isFinished()} can
+	 *              work properly.
+	 * 
+	 * @return new VotingEvaluation object containing the given votes.
+	 */
+	VotingEvaluatorWithValue create(CollectedVotesWithValue votes);
+
+	/**
+	 * 
+	 * @return the agreements that is contained in the current available votes.
+	 *         The exact procedure varies with the implementation.
+	 */
+	Agreements getAgreements();
+
+	/**
+	 * 
+	 * @return true iff the negotiation is finished after taking the agreement
+	 *         returned by {@link #getAgreements()}
+	 */
+	boolean isFinished();
+}
Index: voting/src/main/java/geniusweb/voting/evaluatorwithvalue/LargestAgreementWithValue.java
===================================================================
--- voting/src/main/java/geniusweb/voting/evaluatorwithvalue/LargestAgreementWithValue.java	(revision 30)
+++ voting/src/main/java/geniusweb/voting/evaluatorwithvalue/LargestAgreementWithValue.java	(revision 30)
@@ -0,0 +1,81 @@
+package geniusweb.voting.evaluatorwithvalue;
+
+import java.util.Collections;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import geniusweb.inform.Agreements;
+import geniusweb.voting.CollectedVotesWithValue;
+import geniusweb.voting.VotingEvaluatorWithValue;
+
+/**
+ * Take the first possible agreement, and take the largest possible agreement.
+ * Stop after first agreement.
+ */
+public class LargestAgreementWithValue implements VotingEvaluatorWithValue {
+	@JsonIgnore
+	private final CollectedVotesWithValue allVotes;
+
+	// caching
+	@JsonIgnore
+	private Agreements maxAgreements = null;
+
+	@JsonCreator
+	public LargestAgreementWithValue() {
+		this(new CollectedVotesWithValue(Collections.emptyMap(),
+				Collections.emptyMap()));
+	}
+
+	protected LargestAgreementWithValue(CollectedVotesWithValue votes) {
+		this.allVotes = votes;
+	}
+
+	@Override
+	public Agreements getAgreements() {
+		if (maxAgreements == null)
+			maxAgreements = new Agreements(allVotes.getMaxAgreements());
+		return maxAgreements;
+	}
+
+	@Override
+	public boolean isFinished() {
+		return getAgreements().getMap().isEmpty();
+	}
+
+	@Override
+	public VotingEvaluatorWithValue create(CollectedVotesWithValue votes) {
+		return new LargestAgreementWithValue(votes);
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((allVotes == null) ? 0 : allVotes.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		LargestAgreementWithValue other = (LargestAgreementWithValue) obj;
+		if (allVotes == null) {
+			if (other.allVotes != null)
+				return false;
+		} else if (!allVotes.equals(other.allVotes))
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "LargestAgreement";
+	}
+}
