Index: bidspace/src/main/java/geniusweb/bidspace/AllBidsList.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/AllBidsList.java	(revision 53)
+++ bidspace/src/main/java/geniusweb/bidspace/AllBidsList.java	(revision 1)
@@ -26,8 +26,6 @@
 
 	/**
-	 * This object contains s list containing all bids in the space. This is an
-	 * ImmutableList so it can contain all bids without pre-computing them.
-	 * 
-	 * @param domain the {@link Domain}
+	 * A list containing all bids in the space. This is an ImmutableList so it
+	 * can contain all bids without pre-computing them.
 	 * 
 	 */
Index: bidspace/src/main/java/geniusweb/bidspace/AllPartialBidsList.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/AllPartialBidsList.java	(revision 53)
+++ bidspace/src/main/java/geniusweb/bidspace/AllPartialBidsList.java	(revision 1)
@@ -32,5 +32,4 @@
 	 * pre-computing them.
 	 * 
-	 * @param domain the {@link Domain}
 	 */
 	public AllPartialBidsList(Domain domain) {
Index: bidspace/src/main/java/geniusweb/bidspace/BidsWithUtility.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/BidsWithUtility.java	(revision 53)
+++ 	(revision )
@@ -1,278 +1,0 @@
-package geniusweb.bidspace;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import geniusweb.issuevalue.Bid;
-import geniusweb.issuevalue.Domain;
-import geniusweb.issuevalue.Value;
-import geniusweb.profile.utilityspace.LinearAdditive;
-import tudelft.utilities.immutablelist.AbstractImmutableList;
-import tudelft.utilities.immutablelist.FixedList;
-import tudelft.utilities.immutablelist.ImmutableList;
-import tudelft.utilities.immutablelist.JoinedList;
-import tudelft.utilities.immutablelist.MapList;
-import tudelft.utilities.immutablelist.Tuple;
-
-/**
- * Tool class containing functions dealing with utilities of all bids in a given
- * {@link LinearAdditive}. This class caches previously computed values to
- * accelerate the calls and subsequent calls. Re-use the object to keep/reuse
- * the cache.
- * <h2>Rounding</h2> Internally, utilities of bids are rounded to the given
- * precision. This may cause inclusion/exclusion of some bids in the results.
- * See {@link #BidsWithUtility(LinearAdditive, int)} for more details
- */
-public class BidsWithUtility {
-
-	private final List<IssueInfo> issueInfo;
-	private final int precision; // #digits used for Intervals
-
-	/**
-	 * cache. Key = call arguments for {@link #get(int, Interval)}. Value=return
-	 * value of that call.
-	 */
-	private final Map<Tuple<Integer, Interval>, ImmutableList<Bid>> cache = new HashMap<>();
-	private ImmutableList<Bid> emptylist = new FixedList<>(
-			Collections.emptyList());
-
-	/**
-	 * Default constructor, uses default precision 6. This value seems practical
-	 * for the common range of issues, utilities and weights. See
-	 * {@link #BidsWithUtility(LinearAdditive, int)} for more details on the
-	 * precision.
-	 * 
-	 * @param space the {@link LinearAdditive} to analyze
-	 */
-	public BidsWithUtility(LinearAdditive space) {
-		this(space, 6);
-	}
-
-	/**
-	 * 
-	 * @param space     the {@link LinearAdditive} to analyze
-	 * @param precision the number of digits to use for computations. In
-	 *                  practice, 6 seems a good default value.
-	 *                  <p>
-	 *                  All utilities * weight are rounded to this number of
-	 *                  digits. This value should match the max number of
-	 *                  (digits used in the weight of an issue + number of
-	 *                  digits used in the issue utility). To determine the
-	 *                  optimal value, one may consider the step size of the
-	 *                  issues, and the range of interest. For instance if the
-	 *                  utility function has values 1/3 and 2/3, then these have
-	 *                  an 'infinite' number of relevant digits. But if the goal
-	 *                  is to search bids between utility 0.1 and 0.2, then
-	 *                  computing in 2 digits might already be sufficient.
-	 *                  <p>
-	 *                  This algorithm has memory and space complexity O(
-	 *                  |nissues| 10^precision ). For spaces up to 7 issues, 7
-	 *                  digits should be feasible; for 9 issues, 6 digits may be
-	 *                  the maximum.
-	 */
-	public BidsWithUtility(LinearAdditive space, int precision) {
-		this(getInfo(space, precision), precision);
-	}
-
-	/**
-	 * 
-	 * @param issuesInfo List of the relevant issues (in order of relevance) and
-	 *                   all info of each issue.
-	 * @param precision  the number of digits used in Intervals.
-	 */
-	public BidsWithUtility(List<IssueInfo> issuesInfo, int precision) {
-		if (issuesInfo == null || issuesInfo.isEmpty()) {
-			throw new IllegalArgumentException(
-					"sortedissues list must contain at least 1 element");
-		}
-
-		this.issueInfo = issuesInfo;
-		this.precision = precision;
-
-	}
-
-	/**
-	 * @return the (rounded) utility {@link Interval} of this space: minimum and
-	 *         maximum achievable utility.
-	 */
-	public Interval getRange() {
-		return getRange(issueInfo.size() - 1);
-	}
-
-	/**
-	 * 
-	 * @param range the minimum and maximum utility required of the bids. to be
-	 *              included (both ends inclusive).
-	 * @return a list with bids that have a (rounded) utility inside range.
-	 *         possibly empty.
-	 */
-	public ImmutableList<Bid> getBids(Interval range) {
-		return get(issueInfo.size() - 1, range.round(precision));
-	}
-
-	public List<IssueInfo> getInfo() {
-		return Collections.unmodifiableList(issueInfo);
-	}
-
-	/**
-	 * 
-	 * @param isMax the extreme bid required
-	 * @return the extreme bid, either the minimum if isMax=false or maximum if
-	 *         isMax=true
-	 */
-	public Bid getExtremeBid(boolean isMax) {
-		Map<String, Value> map = new HashMap<>();
-		for (IssueInfo info : issueInfo) {
-			map.put(info.getName(), info.getExtreme(isMax));
-		}
-		return new Bid(map);
-	}
-
-	/**
-	 * Create partial BidsWithUtil list considering only issues 0..n, with
-	 * utilities in given range.
-	 * <h2>Memory use</h2> Memory use of the return value can be large, if large
-	 * domains are given and the requested interval contains large numbers of
-	 * bids. To give some idea, here are some typical memory uses:
-	 * <table border="1">
-	 * <tr>
-	 * <td>domain</td>
-	 * <td>mem use (MB) of returned object</td>
-	 * <td>nr. of selected bids</td>
-	 * </tr>
-	 * <tr>
-	 * <td>jobs1</td>
-	 * <td>0.028</td>
-	 * <td>23</td>
-	 * </tr>
-	 * <tr>
-	 * <td>7issues1</td>
-	 * <td>34</td>
-	 * <td>346327</td>
-	 * </tr>
-	 * <tr>
-	 * <td>9issues1</td>
-	 * <td>98</td>
-	 * <td>37160666</td>
-	 * </tr>
-	 * </table>
-	 * 
-	 * @param n    the number of issueRanges to consider, we consider 0..n here.
-	 *             The recursion decreases n until n=0
-	 * @param goal the minimum and maximum utility required of the bids. to be
-	 *             included (both ends inclusive)
-	 * @return BidsWithUtil list, possibly empty.
-	 */
-	protected ImmutableList<Bid> get(int n, Interval goal) {
-		if (goal == null) {
-			throw new NullPointerException("Interval=null");
-		}
-
-		// clamp goal into what is reachable. Avoid caching empty
-		goal = goal.intersect(getRange(n));
-		if (goal.isEmpty()) {
-			return new FixedList<>(Collections.emptyList());
-		}
-
-		Tuple<Integer, Interval> cachetuple = new Tuple<>(n, goal);
-		ImmutableList<Bid> cached = cache.get(cachetuple);
-		if (cached != null) {
-			// hits++;
-			return cached;
-		}
-
-		ImmutableList<Bid> result = checkedGet(n, goal);
-		cache.put(cachetuple, result);
-		return result;
-	}
-
-	private static List<IssueInfo> getInfo(LinearAdditive space2,
-			int precision) {
-		Domain dom = space2.getDomain();
-		return space2.getDomain().getIssues().stream()
-				.map(issue -> new IssueInfo(issue, dom.getValues(issue),
-						space2.getUtilities().get(issue),
-						space2.getWeight(issue), precision))
-				.collect(Collectors.toList());
-	}
-
-	private ImmutableList<Bid> checkedGet(int n, Interval goal) {
-		IssueInfo info = issueInfo.get(n);
-		// issue is the first issuesWithRange.
-		String issue = info.getName();
-
-		if (n == 0)
-			return new OneIssueSubset(info, goal);
-
-		// make new list, joining all sub-lists
-		ImmutableList<Bid> fulllist = emptylist;
-		for (Value val : info.getValues()) {
-			BigDecimal weightedutil = info.getWeightedUtil(val);
-			Interval subgoal = goal.subtract(weightedutil);
-			// recurse: get list of bids for the subspace
-			ImmutableList<Bid> partialbids = get(n - 1, subgoal);
-
-			ImmutableList<Bid> fullbids = new MapList<Bid, Bid>(
-					pbid -> pbid.merge(new Bid(issue, val)), partialbids);
-			if (!fullbids.size().equals(BigInteger.ZERO))
-				fulllist = new JoinedList<Bid>(
-						Arrays.asList(fullbids, fulllist));
-		}
-		return fulllist;
-	}
-
-	/**
-	 * @param n the maximum issuevalue utility to include. Use n=index of last
-	 *          issue s= (#issues in the domain - 1) for the full range of this
-	 *          domain.
-	 * @return Interval (min, max) of the total weighted utility Interval of
-	 *         issues 0..n. All weighted utilities have been rounded to the set
-	 *         {@link #precision}
-	 */
-	private Interval getRange(int n) {
-		Interval value = Interval.ZERO;
-		for (int i = 0; i <= n; i++) {
-			value = value.add(issueInfo.get(i).getInterval());
-		}
-		return value;
-	}
-
-}
-
-/**
- * List of all one-issue bids that have utility inside given interval.
- */
-class OneIssueSubset extends AbstractImmutableList<Bid> {
-	private final IssueInfo info;
-	private final Interval interval;
-	private BigInteger size;
-
-	/**
-	 * 
-	 * @param info     the {@link IssueInfo}
-	 * @param interval a utility interval (weighted)
-	 */
-	OneIssueSubset(IssueInfo info, Interval interval) {
-		this.info = info;
-		this.interval = interval;
-		this.size = BigInteger.valueOf(info.subsetSize(interval));
-	}
-
-	@Override
-	public Bid get(BigInteger index) {
-		return new Bid(info.getName(),
-				info.subset(interval).get(index.intValue()));
-	}
-
-	@Override
-	public BigInteger size() {
-		return size;
-	}
-
-}
Index: bidspace/src/main/java/geniusweb/bidspace/FrequencyOpponentModel.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/FrequencyOpponentModel.java	(revision 1)
+++ bidspace/src/main/java/geniusweb/bidspace/FrequencyOpponentModel.java	(revision 1)
@@ -0,0 +1,194 @@
+package geniusweb.bidspace;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import geniusweb.issuevalue.Bid;
+import geniusweb.issuevalue.Domain;
+import geniusweb.issuevalue.NumberValue;
+import geniusweb.issuevalue.Value;
+import geniusweb.profile.utilityspace.NumberValueSetUtilities;
+
+/**
+ * implements an {@link OpponentModel} by counting frequencies of bids placed by
+ * the opponent.
+ * <p>
+ * NOTE: {@link NumberValue}s are also treated as 'discrete', so the frequency
+ * of one value does not influence the influence the frequency of nearby values
+ * (as you might expect as {@link NumberValueSetUtilities} is only affected by
+ * the endpoints).
+ *
+ */
+public class FrequencyOpponentModel implements OpponentModel {
+
+	private static final int DECIMALS = 4; // accuracy of our computations.
+	private final Domain domain;
+	private final Map<String, Map<Value, Integer>> bidFrequencies;
+	private final BigDecimal totalBids;
+	private static int serial = 1; // counter for auto name generation
+
+	public FrequencyOpponentModel(Domain domain) {
+		// map with empth hashmap for each issue.
+		this(domain,
+				domain.getIssues().stream().collect(
+						Collectors.toMap(iss -> iss, iss -> new HashMap<>())),
+				BigDecimal.ZERO);
+	}
+
+	@Override
+	public BigDecimal getUtility(Bid bid) {
+		String err = domain.isComplete(bid);
+		if (err != null) {
+			throw new IllegalArgumentException(err);
+		}
+		if (totalBids == BigDecimal.ZERO) {
+			return BigDecimal.ONE;
+		}
+		BigDecimal sum = BigDecimal.ZERO;
+		// Assume all issues have equal weight.
+		for (String issue : domain.getIssues()) {
+			sum = sum.add(getFraction(issue, bid.getValue(issue)));
+		}
+		return sum.divide(new BigDecimal(bidFrequencies.size()), DECIMALS,
+				BigDecimal.ROUND_HALF_UP);
+	}
+
+	@Override
+	public String getName() {
+		return "FreqOppModel" + (serial++) + "For" + domain;
+	}
+
+	/**
+	 * 
+	 * @param issue the issue to check
+	 * @param value the value to check
+	 * @return the fraction of the total cases that bids contained given value
+	 *         for the issue.
+	 */
+	private BigDecimal getFraction(String issue, Value value) {
+		if (totalBids == BigDecimal.ZERO) {
+			return BigDecimal.ONE;
+		}
+		Integer freq = bidFrequencies.get(issue).get(value);
+		if (freq == null) {
+			freq = 0;
+		}
+		return new BigDecimal(freq).divide(totalBids, DECIMALS,
+				BigDecimal.ROUND_HALF_UP);
+	}
+
+	@Override
+	public Domain getDomain() {
+		return domain;
+	}
+
+	@Override
+	public OpponentModel update(Bid bid) {
+		String err = domain.isComplete(bid);
+		if (err != null) {
+			throw new IllegalArgumentException(err);
+		}
+		Map<String, Map<Value, Integer>> newFreqs = cloneMap(bidFrequencies);
+		for (String issue : domain.getIssues()) {
+			Map<Value, Integer> freqs = newFreqs.get(issue);
+			Value value = bid.getValue(issue);
+			Integer oldfreq = freqs.get(value);
+			if (oldfreq == null) {
+				oldfreq = 0;
+			}
+			freqs.put(value, oldfreq + 1);
+		}
+
+		return new FrequencyOpponentModel(domain, newFreqs,
+				totalBids.add(BigDecimal.ONE));
+	}
+
+	/**
+	 * internal constructor. Assumes the freqs keyset is equal to the available
+	 * issues.
+	 * 
+	 * @param domain the domain
+	 * @param freqs  the observed frequencies for all issue values. This map is
+	 *               assumed to be a fresh private-access only copy.
+	 * @param total  the total number of bids contained in the freqs map. This
+	 *               must be equal to the sum of the Integer values in the
+	 *               {@link #bidFrequencies} for each issue (this is not
+	 *               checked).
+	 */
+	private FrequencyOpponentModel(Domain domain,
+			Map<String, Map<Value, Integer>> freqs, BigDecimal total) {
+		if (domain == null) {
+			throw new NullPointerException("domain=null");
+		}
+		this.domain = domain;
+		this.bidFrequencies = freqs;
+		this.totalBids = total;
+	}
+
+	/**
+	 * 
+	 * @param freqs
+	 * @return deep copy of freqs map.
+	 */
+	private static Map<String, Map<Value, Integer>> cloneMap(
+			Map<String, Map<Value, Integer>> freqs) {
+		Map<String, Map<Value, Integer>> map = new HashMap<>();
+		for (String issue : freqs.keySet()) {
+			map.put(issue, new HashMap<Value, Integer>(freqs.get(issue)));
+		}
+		return map;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((bidFrequencies == null) ? 0 : bidFrequencies.hashCode());
+		result = prime * result + ((domain == null) ? 0 : domain.hashCode());
+		result = prime * result
+				+ ((totalBids == null) ? 0 : totalBids.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;
+		FrequencyOpponentModel other = (FrequencyOpponentModel) obj;
+		if (bidFrequencies == null) {
+			if (other.bidFrequencies != null)
+				return false;
+		} else if (!bidFrequencies.equals(other.bidFrequencies))
+			return false;
+		if (domain == null) {
+			if (other.domain != null)
+				return false;
+		} else if (!domain.equals(other.domain))
+			return false;
+		if (totalBids == null) {
+			if (other.totalBids != null)
+				return false;
+		} else if (!totalBids.equals(other.totalBids))
+			return false;
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "FrequencyOpponentModel[" + totalBids + "," + bidFrequencies
+				+ "]";
+	}
+
+	@Override
+	public Bid getReservationBid() {
+		throw new UnsupportedOperationException();
+	}
+
+}
Index: bidspace/src/main/java/geniusweb/bidspace/Interval.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/Interval.java	(revision 53)
+++ 	(revision )
@@ -1,161 +1,0 @@
-package geniusweb.bidspace;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-
-/**
- * An interval [min, max].
- *
- */
-public class Interval {
-	public static Interval ZERO = new Interval(BigDecimal.ZERO,
-			BigDecimal.ZERO);
-
-	private final BigDecimal min;
-	private final BigDecimal max;
-
-	/**
-	 * AN interval [min,max]. If min &gt; max, then there are no values in this
-	 * interval.
-	 * 
-	 * @param min the minimum value of the interval (inclusive)
-	 * @param max the maximum value of the interval (inclusive)
-	 */
-	public Interval(BigDecimal min, BigDecimal max) {
-		if (min == null || max == null) {
-			throw new NullPointerException("min and max must contain not null");
-		}
-		this.min = min;
-		this.max = max;
-	}
-
-	/**
-	 * 
-	 * @return the minimum value of the interval
-	 */
-	public BigDecimal getMin() {
-		return min;
-	}
-
-	/**
-	 * 
-	 * @return the maximum value of the interval
-	 */
-	public BigDecimal getMax() {
-		return max;
-	}
-
-	/**
-	 * 
-	 * @return true iff this range does not contain any element.
-	 */
-	public boolean isEmpty() {
-		return min.compareTo(max) > 0;
-	}
-
-	/**
-	 * 
-	 * @param value the value to test
-	 * @return true iff min &le; value &le; max
-	 */
-	public boolean contains(BigDecimal value) {
-		return min.compareTo(value) <= 0 && max.compareTo(value) >= 0;
-	}
-
-	/**
-	 * 
-	 * @param other {@link Interval} to be added to this
-	 * @return new interval [ this.min + other.min , this.max + other.max ]
-	 */
-	public Interval add(Interval other) {
-		return new Interval(min.add(other.min), max.add(other.max));
-	}
-
-	/**
-	 * 
-	 * @param other another {@link Interval} intersect with
-	 * @return intersection of this with other. returns null if intersection is
-	 *         empty.
-	 */
-	public Interval intersect(Interval other) {
-		return new Interval(min.max(other.min), max.min(other.max));
-	}
-
-	/**
-	 * 
-	 * @param other the other minmax to deal with
-	 * @return the range of values that, when added to a value from other, will
-	 *         possibly get in our range. effectively, [min-other.max,
-	 *         max-other.min]. Returns null if the resulting range is empty.
-	 */
-	public Interval invert(Interval other) {
-		BigDecimal newmin = min.subtract(other.max);
-		BigDecimal newmax = max.subtract(other.min);
-		if (newmin.compareTo(newmax) > 0)
-			return null;
-		return new Interval(newmin, newmax);
-	}
-
-	/**
-	 * 
-	 * @param value the value to subtract
-	 * @return Interval with both min and max reduced by value.
-	 */
-	public Interval subtract(BigDecimal value) {
-		return new Interval(min.subtract(value), max.subtract(value));
-	}
-
-	public Interval multiply(BigDecimal weight) {
-		return new Interval(min.multiply(weight), max.multiply(weight));
-	}
-
-	@Override
-	public String toString() {
-		return "Interval[" + min + "," + max + "]";
-	}
-
-	/**
-	 * @param precision number of digits required
-	 * @return this but with modified precision. The interval is rounded so that
-	 *         the new interval is inside the old one.
-	 */
-	public Interval round(int precision) {
-		return new Interval(min.setScale(precision, RoundingMode.UP),
-				max.setScale(precision, RoundingMode.DOWN));
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		result = prime * result + ((max == null) ? 0 : max.hashCode());
-		result = prime * result + ((min == null) ? 0 : min.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;
-		Interval other = (Interval) obj;
-		if (max == null) {
-			if (other.max != null)
-				return false;
-
-		} else if (max.compareTo(other.max) != 0)
-			// THIS WAS FIXED MANUALLY TO USE COMPARETO
-			return false;
-		if (min == null) {
-			if (other.min != null)
-				return false;
-		} else if (min.compareTo(other.min) != 0)
-			// THIS WAS FIXED MANUALLY TO USE COMPARETO
-			return false;
-		return true;
-	}
-
-}
Index: bidspace/src/main/java/geniusweb/bidspace/IssueInfo.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/IssueInfo.java	(revision 53)
+++ 	(revision )
@@ -1,165 +1,0 @@
-package geniusweb.bidspace;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import geniusweb.issuevalue.Value;
-import geniusweb.issuevalue.ValueSet;
-import geniusweb.profile.utilityspace.ValueSetUtilities;
-
-/**
- * Tool class to collect all relevant info about one issue (from LinearAdditive)
- * in one class. Used for internally grouping data for more efficient
- * processing. This class may change in the future, not recommended for direct
- * use.
- * <p>
- * immutable
- */
-public class IssueInfo {
-	private final String name;
-	private final ValueSet values;
-	private final Interval interval;
-	private final Map<Value, BigDecimal> weightedUtils;
-
-	/**
-	 * 
-	 * @param name      the issue name
-	 * @param values    the {@link ValueSet} of the issue
-	 * @param utils     the {@link ValueSetUtilities} of the issue profile
-	 * @param weight    the weight of the {@link ValueSetUtilities}
-	 * @param precision the precision to compute with. Basically the number of
-	 *                  decimal places used for the computations.
-	 * 
-	 */
-	public IssueInfo(String name, ValueSet values, ValueSetUtilities utils,
-			BigDecimal weight, int precision) {
-		this.name = name;
-		this.values = values;
-		this.weightedUtils = computeWeightedUtils(utils, weight, precision);
-		this.interval = getRange();
-	}
-
-	public ValueSet getValues() {
-		return values;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * 
-	 * @return weighted minimum and maximum utility achievable with this issue,
-	 *         rounded to the requested precision.
-	 */
-	public Interval getInterval() {
-		return interval;
-	}
-
-	/**
-	 * 
-	 * @param isMax if true the max {@link Value} is returned, else the min is
-	 *              returned.
-	 * @return the extreme value, either the minimum if isMax=false or maximum
-	 *         if isMax=true
-	 */
-	public Value getExtreme(boolean isMax) {
-		BigDecimal extremeutil = null;
-		Value extremeval = null;
-		for (Value val : values) {
-			BigDecimal util = weightedUtils.get(val);
-			if (extremeval == null) {
-				extremeutil = weightedUtils.get(val);
-				extremeval = val;
-			} else {
-				if (isMax) {
-					if (util.compareTo(extremeutil) > 0) {
-						extremeutil = util;
-						extremeval = val;
-					}
-				} else {
-					if (util.compareTo(extremeutil) < 0) {
-						extremeutil = util;
-						extremeval = val;
-					}
-
-				}
-			}
-		}
-		return extremeval;
-	}
-
-	/**
-	 * @param val the issue value to be evaluated
-	 * @return weighted utility of given value, rounded to nearest value with
-	 *         the requested precision number of digits.
-	 */
-	public BigDecimal getWeightedUtil(Value val) {
-		return weightedUtils.get(val);
-	}
-
-	/**
-	 * 
-	 * @param interval an {@link Interval} of utility values.
-	 * @return all values that are inside the interval.
-	 */
-	protected List<Value> subset(Interval interval) {
-
-		List<Value> selection = new ArrayList<>();
-		for (Value value : values) {
-			if (interval.contains(getWeightedUtil(value)))
-				selection.add(value);
-		}
-		return selection;
-	}
-
-	/**
-	 * Faster way to determine subset size, it does not create a list
-	 * 
-	 * @param interval an {@link Interval} of utility values.
-	 * @return size of the subset that you will get from calling subset
-	 */
-	protected int subsetSize(Interval interval) {
-		int n = 0;
-		for (Value value : values)
-			if (interval.contains(getWeightedUtil(value)))
-				n++;
-		return n;
-	}
-
-	/**
-	 * @return the {@link Interval} (minimum and maximum) of the utility of the
-	 *         weighted utility of this issue, properly rounded to the
-	 *         {@link #precision}/
-	 * 
-	 */
-	private Interval getRange() {
-		BigDecimal min = BigDecimal.ONE;
-		BigDecimal max = BigDecimal.ZERO;
-		for (Value value : values) {
-			BigDecimal util = getWeightedUtil(value);
-			if (util.compareTo(min) < 0)
-				min = util;
-			if (util.compareTo(max) > 0)
-				max = util;
-		}
-		return new Interval(min, max);
-
-	}
-
-	private Map<Value, BigDecimal> computeWeightedUtils(
-			ValueSetUtilities utilities, BigDecimal w, int prec) {
-		Map<Value, BigDecimal> map = new HashMap<>();
-
-		for (Value val : values) {
-			map.put(val, utilities.getUtility(val).multiply(w).setScale(prec,
-					RoundingMode.HALF_UP));
-		}
-		return map;
-	}
-
-}
Index: bidspace/src/main/java/geniusweb/bidspace/OpponentModel.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/OpponentModel.java	(revision 1)
+++ bidspace/src/main/java/geniusweb/bidspace/OpponentModel.java	(revision 1)
@@ -0,0 +1,18 @@
+package geniusweb.bidspace;
+
+import geniusweb.issuevalue.Bid;
+import geniusweb.profile.utilityspace.UtilitySpace;
+
+/**
+ * An opponentmodel estimates a {@link UtilitySpace} from received opponent
+ * bids.
+ */
+public interface OpponentModel extends UtilitySpace {
+	/**
+	 *
+	 * @param bid the next bid that was received
+	 * @return a new {@link OpponentModel} that takes the next bid into account.
+	 */
+	OpponentModel update(Bid bid);
+
+}
Index: bidspace/src/main/java/geniusweb/bidspace/PartialSpaceFromUtility.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/PartialSpaceFromUtility.java	(revision 53)
+++ 	(revision )
@@ -1,96 +1,0 @@
-package geniusweb.bidspace;
-
-import java.math.BigInteger;
-import java.security.SecureRandom;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import geniusweb.issuevalue.Bid;
-import geniusweb.profile.DefaultPartialOrdering;
-import geniusweb.profile.PartialOrdering;
-import geniusweb.profile.utilityspace.UtilitySpace;
-import tudelft.utilities.immutablelist.ListWithRemove;
-import tudelft.utilities.immutablelist.Tuple;
-import tudelft.utilities.immutablelist.Tuples;
-
-/**
- * Simple demo converting a {@link UtilitySpace} into a {@link PartialOrdering}.
- * Notice, a UtilitySpace IS a PartialOrdering, but a special one that is in
- * fact a full ordering. This converter makes it a space that really has all
- * info removed except for a few basic "isBetter" informations.
- */
-public class PartialSpaceFromUtility extends DefaultPartialOrdering {
-	public PartialSpaceFromUtility(UtilitySpace space, int nRankings) {
-		super(space.getName() + "_" + nRankings, space.getDomain(),
-				space.getReservationBid(), pickBetter(space, nRankings));
-	}
-
-	/**
-	 * Pick subset of static isbetter rankings. Notice, ShuffledList currently
-	 * can't handle really large lists which also limits this. This has to be
-	 * fixed.
-	 * 
-	 * @param space     the space to sample from
-	 * @param nRankings the number of rankings to be placed in the
-	 *                  PartialOrdering.
-	 * @return a subset creating a partial profile of the geiven UtilitySpace
-	 */
-	private static Map<Bid, Set<Bid>> pickBetter(UtilitySpace space,
-			int nRankings) {
-		Map<Bid, Set<Bid>> eqOrBetter = new HashMap<>();
-
-		AllBidsList allbids = new AllBidsList(space.getDomain());
-		ListWithRemove<Tuple<Bid, Bid>> available = new ListWithRemove<>(
-				new Tuples<Bid, Bid>(allbids, allbids), Collections.emptySet());
-		for (int n = 0; n < nRankings; n++) {
-			BigInteger sel = rnd(available.size());
-			Tuple<Bid, Bid> tuple = available.get(sel);
-			Bid bid1 = tuple.get1();
-			Bid bid2 = tuple.get2();
-			switch (space.getUtility(bid1).compareTo(space.getUtility(bid2))) {
-			case -1: // bid1 is worse
-				add(eqOrBetter, bid2, bid1);
-				break;
-			case 0:
-				add(eqOrBetter, bid2, bid1);
-				add(eqOrBetter, bid1, bid2);
-				break;
-			case 1:// bid1 is better
-				add(eqOrBetter, bid1, bid2);
-				break;
-			}
-			available = available.remove(sel);
-		}
-		return eqOrBetter;
-	}
-
-	/**
-	 * 
-	 * @param eqOrBetter map to be extended with (key=bid1, value=bid2)
-	 * @param bid1       the key to add a value to
-	 * @param bid2       the value to be added
-	 */
-	private static void add(Map<Bid, Set<Bid>> eqOrBetter, Bid bid1, Bid bid2) {
-		Set<Bid> set = eqOrBetter.get(bid1);
-		if (set == null) {
-			set = new HashSet<Bid>();
-		}
-		set.add(bid2);
-		eqOrBetter.put(bid1, set);
-	}
-
-	/**
-	 * Bit simplistic way to generate random in [0,n>. Simplistic because the
-	 * mod() operator that we use causes bias in the random numbers.
-	 * 
-	 * @param n the maximum value for the random number
-	 * @return random in [0,n>
-	 * 
-	 */
-	private static final BigInteger rnd(BigInteger n) {
-		return new BigInteger(n.bitLength(), new SecureRandom()).mod(n);
-	}
-}
Index: bidspace/src/main/java/geniusweb/bidspace/SumOfGroupsLinAdditiveAdapter.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/SumOfGroupsLinAdditiveAdapter.java	(revision 53)
+++ 	(revision )
@@ -1,337 +1,0 @@
-package geniusweb.bidspace;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.math.RoundingMode;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import geniusweb.bidspace.pareto.ParetoLinearAdditive;
-import geniusweb.issuevalue.Bid;
-import geniusweb.issuevalue.DiscreteValue;
-import geniusweb.issuevalue.Domain;
-import geniusweb.issuevalue.Value;
-import geniusweb.issuevalue.ValueSet;
-import geniusweb.profile.utilityspace.DiscreteValueSetUtilities;
-import geniusweb.profile.utilityspace.LinearAdditive;
-import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace;
-import geniusweb.profile.utilityspace.PartsUtilities;
-import geniusweb.profile.utilityspace.ProductOfValue;
-import geniusweb.profile.utilityspace.SumOfGroupsUtilitySpace;
-import geniusweb.profile.utilityspace.ValueSetUtilities;
-import tudelft.utilities.immutablelist.ArrayListSet;
-
-/**
- * ValueSet with ProductOfValue objects as elements. Otherwise just a
- * DiscreteValueSet. Storing the ProductOfValues here directly (instead of
- * strings) makes it easier to map back and forth
- *
- */
-class GroupValueSet implements ValueSet {
-
-	/*
-	 * final, must be immutable so do not provide external access to this list.
-	 * ArrayList (instead of List) to help Jackson serializer which avoids
-	 * per-field type annotations.
-	 */
-	private final ArrayListSet<ProductOfValue> values = new ArrayListSet<>();
-
-	public GroupValueSet(Collection<ProductOfValue> issuevalues) {
-		this.values.addAll(issuevalues);
-	}
-
-	public List<ProductOfValue> getValues() {
-		return Collections.unmodifiableList(values);
-	}
-
-	@Override
-	public Boolean contains(Value value) {
-		return values.contains(value);
-	}
-
-	@Override
-	public ProductOfValue get(BigInteger index) {
-		return values.get(index.intValue());
-	}
-
-	@Override
-	public BigInteger size() {
-		return BigInteger.valueOf(values.size());
-	}
-
-	@Override
-	public ProductOfValue get(long index) {
-		return values.get((int) index);
-	}
-
-	@Override
-	public Iterator iterator() {
-		return values.iterator();
-	}
-
-	@Override
-	public String toString() {
-		return values.toString();
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		result = prime * result + ((values == null) ? 0 : values.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;
-		GroupValueSet other = (GroupValueSet) obj;
-		if (values == null) {
-			if (other.values != null)
-				return false;
-		} else if (!values.equals(other.values))
-			return false;
-		return true;
-	}
-}
-
-/**
- * As {@link DiscreteValueSetUtilities} but with ProductOfValue instead of Value
- */
-class GroupValueSetUtilities implements ValueSetUtilities {
-	private final Map<ProductOfValue, BigDecimal> valueUtilities = new HashMap<>();
-
-	public GroupValueSetUtilities(Map<ProductOfValue, BigDecimal> utilities) {
-		valueUtilities.putAll(utilities);
-	}
-
-	@Override
-	public BigDecimal getUtility(Value value) {
-		if (!valueUtilities.containsKey(value)) {
-			return BigDecimal.ZERO;
-		}
-		return valueUtilities.get(value);
-	}
-
-	@Override
-	public String isFitting(ValueSet valueset) {
-		if (!(valueset instanceof GroupValueSet)) {
-			return "The utilities are for a GroupValueSet valueset but the given values are "
-					+ valueset;
-		}
-		GroupValueSet discvalueset = (GroupValueSet) valueset;
-		if (!valueUtilities.keySet()
-				.equals(new HashSet<>(discvalueset.getValues())))
-			return "The values in the set " + valueset
-					+ " do not match the values mapped to utilities "
-					+ valueUtilities.keySet();
-		return null;
-	}
-
-	@Override
-	public String toString() {
-		return valueUtilities.toString();
-	}
-}
-
-/**
- * Creates a {@link LinearAdditive} profile matching a
- * {@link SumOfGroupsUtilitySpace}. THe {@link LinearAdditive} can then be used
- * with tools like {@link ParetoLinearAdditive} or linear parties. Note that
- * TimeDependentParty and all derivatives use this already and thus seamlessly
- * support {@link SumOfGroupsUtilitySpace}.
- * 
- * <p>
- * 
- * The domain, issues values and utilities are all different from the
- * {@link SumOfGroupsUtilitySpace}. The methods {@link #toLinearBid(Bid)} and
- * {@link #toGroupBid(Bid)} can be used to convert back and forth. The space is
- * made such that there is a constant scaling between utilities in the
- * {@link SumOfGroupsUtilitySpace} and those in the adapted
- * {@link LinearAdditive} space.
- * 
- */
-public class SumOfGroupsLinAdditiveAdapter extends LinearAdditiveUtilitySpace {
-
-	/*
-	 * special character, used as separator char in constructed issue names.
-	 * Must not be used in any original issue names. can be a non-printable
-	 * char, as this class does not serialize but for debugging it's nice to get
-	 * something readable
-	 */
-	private final static String SEP = "~";
-	private final static MathContext mc = new MathContext(10,
-			RoundingMode.DOWN);
-	private static final DiscreteValue WCVALUE = new DiscreteValue("C");
-	private static final ProductOfValue WC = new ProductOfValue(
-			Arrays.asList(WCVALUE));
-	private static final ValueSet WEIGHTCORRECTION = new GroupValueSet(
-			Collections.singletonList(WC));
-	private static final Map<ProductOfValue, BigDecimal> WEIGHTCORRUTIL = Collections
-			.singletonMap(WC, BigDecimal.ZERO);
-
-	private final SumOfGroupsUtilitySpace groupspace;
-
-	/**
-	 * Basically LinearAdditive constructor plus the original group space. Use
-	 * {@link #create(SumOfGroupsUtilitySpace)} to create a
-	 * {@link SumOfGroupsLinAdditiveAdapter}
-	 */
-	private SumOfGroupsLinAdditiveAdapter(SumOfGroupsUtilitySpace groupspace,
-			LinearAdditiveUtilitySpace lin) {
-		super(lin.getDomain(), groupspace.getName(), lin.getUtilities(),
-				lin.getWeights(), lin.getReservationBid());
-		this.groupspace = groupspace;
-	}
-
-	public static SumOfGroupsLinAdditiveAdapter create(
-			SumOfGroupsUtilitySpace groupspace) {
-		checkSpecialCharacter(groupspace);
-
-		final HashMap<String, ValueSetUtilities> linIssueUtilities = new HashMap<>();
-		final HashMap<String, BigDecimal> weights = new HashMap<>();
-		final Map<String, ValueSet> issueValues = new HashMap<>();
-		final BigDecimal SIZE = BigDecimal
-				.valueOf(groupspace.getPartsUtilities().size());
-		final BigDecimal weight = BigDecimal.ONE.divide(SIZE, mc);
-
-		// compute the joned-issue-names, values and utility maps
-		for (final PartsUtilities part : groupspace.getPartsUtilities()
-				.values()) {
-
-			// part is a group, containing a set of issues and
-			// ProductOfValue for every possible combination.
-			final String joinedissue = String.join(SEP, part.getIssues());
-			weights.put(joinedissue, weight);
-
-			issueValues.put(joinedissue,
-					new GroupValueSet(part.getUtilities().keySet()));
-			linIssueUtilities.put(joinedissue,
-					new GroupValueSetUtilities(part.getUtilities()));
-
-		}
-
-		// weight correction. Add issue with name SEP filling the remainder
-		issueValues.put(SEP, WEIGHTCORRECTION);
-		linIssueUtilities.put(SEP, new GroupValueSetUtilities(WEIGHTCORRUTIL));
-		weights.put(SEP, BigDecimal.ONE.subtract(weight.multiply(SIZE)));
-
-		final Domain lindomain = new Domain(groupspace.getDomain().getName(),
-				issueValues);
-		final Bid resbid = toLinearBid(groupspace.getReservationBid(),
-				groupspace);
-		final LinearAdditiveUtilitySpace linspace = new LinearAdditiveUtilitySpace(
-				lindomain, groupspace.getName(), linIssueUtilities, weights,
-				resbid);
-		return new SumOfGroupsLinAdditiveAdapter(groupspace, linspace);
-
-	}
-
-	/**
-	 * Check for occurences of {@link #SEP} in this space.
-	 * 
-	 * @param space2 the space to check
-	 */
-	private static void checkSpecialCharacter(SumOfGroupsUtilitySpace space2) {
-		Domain dom = space2.getDomain();
-		for (String issue : dom.getIssues()) {
-			checkString(issue);
-			for (Value val : dom.getValues(issue)) {
-				if (val instanceof DiscreteValue) {
-					checkString(((DiscreteValue) val).getValue());
-				}
-			}
-		}
-	}
-
-	/**
-	 * check that name does not contain the {@link #SEP} characte to avoid
-	 * problems later. This ensures 1-1 mapping between original names and names
-	 * in converted space.
-	 * 
-	 * @param name the name to check
-	 */
-	private static void checkString(String name) {
-		if (name.contains(SEP))
-			throw new IllegalArgumentException("space should not use  " + name
-					+ " : character '" + SEP + "' is reserved");
-	}
-
-	@Override
-	public String toString() {
-		return "LinearAdditiveAdapter[" + super.toString() + "]";
-	}
-
-	/**
-	 * 
-	 * @param bid
-	 * @param groupspace
-	 * @return bid converted to {@link LinearAdditiveUtilitySpace.
-	 */
-	public static Bid toLinearBid(Bid bid, SumOfGroupsUtilitySpace groupspace) {
-		if (bid == null)
-			return null;
-
-		final Map<String, Value> map = new HashMap<>();
-
-		for (PartsUtilities part : groupspace.getPartsUtilities().values()) {
-			String linissue = String.join(SEP, part.getIssues());
-			List<Value> values = part.getIssues().stream()
-					.map(iss -> bid.getValue(iss)).collect(Collectors.toList());
-			map.put(linissue, new ProductOfValue(values));
-		}
-		return new Bid(map);
-	}
-
-	/**
-	 * 
-	 * @param bid possibly partial {@link Bid} from {@link LinearAdditive} space
-	 * @return a possibly partial Bid in the {@link SumOfGroupsUtilitySpace}.
-	 */
-	public Bid toGroupBid(Bid bid) {
-		if (bid == null)
-			return null;
-
-		final Map<String, Value> allvalues = new HashMap<>();
-
-		for (String linissue : bid.getIssues()) {
-			allvalues.putAll(toGroupValues(linissue,
-					(ProductOfValue) bid.getValue(linissue)));
-		}
-		return new Bid(allvalues);
-	}
-
-	/**
-	 * 
-	 * @param linissue an issue in the {@link LinearAdditive} space
-	 * @param value    a value in the {@link LinearAdditive} space
-	 * @return a map of issue-value pairs in the {@link SumOfGroupsUtilitySpace}
-	 */
-	private Map<String, Value> toGroupValues(String linissue,
-			ProductOfValue value) {
-		if (linissue.equals(SEP))
-			// ignore the weight-balancer issue
-			return Collections.emptyMap();
-
-		final Map<String, Value> values = new HashMap<>();
-		final String[] issues = linissue.split(SEP);
-		for (int n = 0; n < issues.length; n = n + 1) {
-			values.put(issues[n], value.getValues().get(n));
-		}
-
-		return values;
-	}
-}
Index: bidspace/src/main/java/geniusweb/bidspace/pareto/GenericPareto.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/pareto/GenericPareto.java	(revision 53)
+++ bidspace/src/main/java/geniusweb/bidspace/pareto/GenericPareto.java	(revision 1)
@@ -1,6 +1,4 @@
 package geniusweb.bidspace.pareto;
 
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -16,11 +14,10 @@
 /**
  * A set of all pareto points associated with a set of profiles. Generally
- * applicable but slow. It is recommended to use {@link ParetoLinearAdditive} if
- * applicable.
+ * applicable but slow.
  */
 public class GenericPareto implements ParetoFrontier {
 
 	private final List<? extends PartialOrdering> profiles;
-	private transient Set<Bid> paretobids = null; // cache
+	private Set<Bid> paretobids = null;
 
 	/**
@@ -38,5 +35,5 @@
 					"at least 2 profiles are needed");
 		}
-		if (profiles.contains(null)) {
+		if (profiles.stream().anyMatch(profile -> profile == null)) {
 			throw new IllegalArgumentException("Profiles must not be null");
 		}
@@ -49,10 +46,10 @@
 			}
 		}
-		this.profiles = new ArrayList<>(profiles);
+		this.profiles = profiles;
 	}
 
 	@Override
-	public List<Profile> getProfiles() {
-		return Collections.unmodifiableList(profiles);
+	public List<? extends Profile> getProfiles() {
+		return profiles;
 	}
 
@@ -61,5 +58,5 @@
 		if (paretobids == null)
 			computePareto();
-		return Collections.unmodifiableSet(paretobids);
+		return paretobids;
 	}
 
Index: bidspace/src/main/java/geniusweb/bidspace/pareto/ParetoLinearAdditive.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/pareto/ParetoLinearAdditive.java	(revision 53)
+++ bidspace/src/main/java/geniusweb/bidspace/pareto/ParetoLinearAdditive.java	(revision 1)
@@ -10,13 +10,13 @@
 import geniusweb.issuevalue.Domain;
 import geniusweb.profile.Profile;
-import geniusweb.profile.utilityspace.LinearAdditive;
+import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace;
 
 /**
- * pareto frontier implementation for {@link LinearAdditive}. This is a highly
- * optimized pareto method for {@link LinearAdditive} spaces
+ * pareto frontier implementation for {@link LinearAdditiveUtilitySpace}.
+ * Simplistic implementation that iterates over all bids.
  */
 public class ParetoLinearAdditive implements ParetoFrontier {
 
-	private final List<LinearAdditive> utilSpaces;
+	private final List<LinearAdditiveUtilitySpace> utilSpaces;
 	private Set<Bid> points = null;
 	// all issues in a deterministic order
@@ -24,8 +24,9 @@
 	/**
 	 * 
-	 * @param utilSpaces. Must contain at least two {@link LinearAdditive}s and
-	 *                    all must be defined on the same donain.
+	 * @param utilSpaces. Must contain at least two
+	 *                    {@link LinearAdditiveUtilitySpace}s and all must be
+	 *                    defined on the same donain.
 	 */
-	public ParetoLinearAdditive(List<LinearAdditive> utilSpaces) {
+	public ParetoLinearAdditive(List<LinearAdditiveUtilitySpace> utilSpaces) {
 		if (utilSpaces == null || utilSpaces.size() < 2) {
 			throw new IllegalArgumentException(
@@ -33,5 +34,5 @@
 		}
 		Domain domain = utilSpaces.get(0).getDomain();
-		for (LinearAdditive space : utilSpaces) {
+		for (LinearAdditiveUtilitySpace space : utilSpaces) {
 			if (!space.getDomain().equals(domain)) {
 				throw new IllegalArgumentException(
Index: bidspace/src/main/java/geniusweb/bidspace/pareto/ParetoPoint.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/pareto/ParetoPoint.java	(revision 53)
+++ bidspace/src/main/java/geniusweb/bidspace/pareto/ParetoPoint.java	(revision 1)
@@ -3,9 +3,12 @@
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
 import geniusweb.issuevalue.Bid;
-import geniusweb.profile.utilityspace.LinearAdditive;
+import geniusweb.issuevalue.Value;
+import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace;
 
 /**
@@ -23,10 +26,10 @@
 	 * 
 	 * @param bid    a (possibly partial) {@link Bid}
-	 * @param spaces the {@link LinearAdditive}s to consider
+	 * @param spaces the {@link LinearAdditiveUtilitySpace}s to consider
 	 */
-	public ParetoPoint(Bid bid, List<LinearAdditive> spaces) {
+	public ParetoPoint(Bid bid, List<LinearAdditiveUtilitySpace> spaces) {
 		this.bid = bid;
 		utilities = new ArrayList<>();
-		for (LinearAdditive space : spaces) {
+		for (LinearAdditiveUtilitySpace space : spaces) {
 			utilities.add(space.getUtility(bid));
 		}
@@ -46,4 +49,11 @@
 	 */
 	public ParetoPoint merge(ParetoPoint otherpoint) {
+		Map<String, Value> issuevalues = new HashMap<>();
+		for (String issue : bid.getIssues()) {
+			issuevalues.put(issue, bid.getValue(issue));
+		}
+		for (String issue : otherpoint.bid.getIssues()) {
+			issuevalues.put(issue, otherpoint.bid.getValue(issue));
+		}
 		List<BigDecimal> summedutils = new LinkedList<>();
 		for (int n = 0; n < utilities.size(); n++) {
@@ -51,5 +61,5 @@
 		}
 
-		return new ParetoPoint(summedutils, bid.merge(otherpoint.getBid()));
+		return new ParetoPoint(summedutils, new Bid(issuevalues));
 	}
 
Index: bidspace/src/main/java/geniusweb/bidspace/pareto/PartialPareto.java
===================================================================
--- bidspace/src/main/java/geniusweb/bidspace/pareto/PartialPareto.java	(revision 53)
+++ bidspace/src/main/java/geniusweb/bidspace/pareto/PartialPareto.java	(revision 1)
@@ -8,5 +8,5 @@
 import geniusweb.issuevalue.Bid;
 import geniusweb.issuevalue.Value;
-import geniusweb.profile.utilityspace.LinearAdditive;
+import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace;
 
 /**
@@ -28,5 +28,5 @@
 	 * implemented recursively (O(log(#issues))).
 	 * 
-	 * @param utilSpaces the {@link LinearAdditive}s
+	 * @param utilSpaces the {@link LinearAdditiveUtilitySpace}s
 	 * @param issues     the issues (subset of all issues in the space) to be
 	 *                   used for this pareto
@@ -34,6 +34,6 @@
 	 *         given issues.
 	 */
-	public static PartialPareto create(List<LinearAdditive> utilSpaces,
-			List<String> issues) {
+	public static PartialPareto create(
+			List<LinearAdditiveUtilitySpace> utilSpaces, List<String> issues) {
 
 		if (issues.size() == 1) {
