Index: exampleparties/timedependentparty/pom.xml
===================================================================
--- exampleparties/timedependentparty/pom.xml	(revision 3)
+++ exampleparties/timedependentparty/pom.xml	(revision 4)
@@ -158,4 +158,16 @@
 			</plugin>
 
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-source-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>attach-sources</id>
+						<goals>
+							<goal>jar</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
 
 			<plugin>
Index: exampleparties/timedependentparty/src/main/java/geniusweb/exampleparties/timedependentparty/ExtendedUtilSpace.java
===================================================================
--- exampleparties/timedependentparty/src/main/java/geniusweb/exampleparties/timedependentparty/ExtendedUtilSpace.java	(revision 4)
+++ exampleparties/timedependentparty/src/main/java/geniusweb/exampleparties/timedependentparty/ExtendedUtilSpace.java	(revision 4)
@@ -0,0 +1,102 @@
+package geniusweb.exampleparties.timedependentparty;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.LinkedList;
+
+import geniusweb.bidspace.BidsWithUtility;
+import geniusweb.bidspace.Interval;
+import geniusweb.bidspace.IssueInfo;
+import geniusweb.issuevalue.Bid;
+import geniusweb.issuevalue.Value;
+import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace;
+import tudelft.utilities.immutablelist.ImmutableList;
+
+/**
+ * Inner class for TimeDependentParty, made public for testing purposes. This
+ * class may change in the future, use at your own risk.
+ *
+ */
+public class ExtendedUtilSpace {
+	private LinearAdditiveUtilitySpace utilspace;
+	private BigDecimal tolerance; // utility tolerance for a bid.
+	private BidsWithUtility bidutils;
+	// min and max achievable utility
+	private BigDecimal minUtil;
+	private BigDecimal maxUtil;
+
+	public ExtendedUtilSpace(LinearAdditiveUtilitySpace space) {
+		this.utilspace = space;
+		bidutils = new BidsWithUtility(utilspace);
+		computeMinMax();
+		this.tolerance = computeTolerance();
+
+	}
+
+	/**
+	 * Computes the fields minutil and maxUtil.
+	 * <p>
+	 * TODO this is simplistic, very expensive method and may cause us to run
+	 * out of time on large domains.
+	 * <p>
+	 * Assumes that utilspace and bidutils have been set properly.
+	 */
+	private void computeMinMax() {
+		Interval range = bidutils.getRange();
+		this.minUtil = range.getMin();
+		this.maxUtil = range.getMax();
+
+		Bid rvbid = utilspace.getReservationBid();
+		if (rvbid != null) {
+			BigDecimal rv = utilspace.getUtility(rvbid);
+			if (rv.compareTo(minUtil) > 0)
+				minUtil = rv;
+		}
+	}
+
+	/**
+	 * Tolerance is the Interval we need when searching bids. When we are close
+	 * to the maximum utility, this value has to be the distance between the
+	 * best and one-but-best utility.
+	 * 
+	 * @return the minimum tolerance required, which is the minimum difference
+	 *         between the weighted utility of the best and one-but-best issue
+	 *         value.
+	 */
+	protected BigDecimal computeTolerance() {
+		BigDecimal tolerance = BigDecimal.ONE;
+		for (IssueInfo iss : bidutils.getInfo()) {
+			if (iss.getValues().size().compareTo(BigInteger.ONE) > 0) {
+				// we have at least 2 values.
+				LinkedList<BigDecimal> values = new LinkedList<BigDecimal>();
+				for (Value val : iss.getValues()) {
+					values.add(iss.getWeightedUtil(val));
+				}
+				Collections.sort(values);
+				Collections.reverse(values);
+				tolerance = tolerance
+						.min(values.get(0).subtract(values.get(1)));
+			}
+		}
+		return tolerance;
+	}
+
+	public BigDecimal getMin() {
+		return minUtil;
+	}
+
+	public BigDecimal getMax() {
+		return maxUtil;
+	}
+
+	/**
+	 * @param utilityGoal
+	 * @return bids with utility inside [utilitygoal-tolerance, utilitygoal]
+	 */
+	public ImmutableList<Bid> getBids(BigDecimal utilityGoal) {
+		return bidutils.getBids(
+				new Interval(utilityGoal.subtract(tolerance), utilityGoal));
+	}
+
+}
Index: exampleparties/timedependentparty/src/main/java/geniusweb/exampleparties/timedependentparty/TimeDependentParty.java
===================================================================
--- exampleparties/timedependentparty/src/main/java/geniusweb/exampleparties/timedependentparty/TimeDependentParty.java	(revision 3)
+++ exampleparties/timedependentparty/src/main/java/geniusweb/exampleparties/timedependentparty/TimeDependentParty.java	(revision 4)
@@ -3,4 +3,5 @@
 import java.io.IOException;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -14,6 +15,4 @@
 import geniusweb.actions.Offer;
 import geniusweb.actions.PartyId;
-import geniusweb.bidspace.AllBidsList;
-import geniusweb.bidspace.BidsWithUtility;
 import geniusweb.issuevalue.Bid;
 import geniusweb.party.Capabilities;
@@ -24,6 +23,6 @@
 import geniusweb.party.inform.Settings;
 import geniusweb.party.inform.YourTurn;
+import geniusweb.profile.Profile;
 import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace;
-import geniusweb.profile.utilityspace.UtilitySpace;
 import geniusweb.profileconnection.ProfileConnectionFactory;
 import geniusweb.profileconnection.ProfileInterface;
@@ -31,4 +30,5 @@
 import geniusweb.progress.ProgressRounds;
 import geniusweb.references.ProtocolRef;
+import tudelft.utilities.immutablelist.ImmutableList;
 import tudelft.utilities.logging.Reporter;
 
@@ -41,10 +41,12 @@
 public abstract class TimeDependentParty extends DefaultParty {
 
+	private static final BigDecimal DEC0001 = new BigDecimal("0.0001");
+	private static final BigDecimal DEC100 = new BigDecimal("100");
 	private ProfileInterface profileint;
+	private LinearAdditiveUtilitySpace utilspace = null; // last received space
 	private PartyId me;
 	private Progress progress;
-	private Double minUtil = null, maxUtil = null;
 	private Bid lastReceivedBid = null;
-	private double tolerance;
+	private ExtendedUtilSpace extendedspace;
 
 	public TimeDependentParty() {
@@ -77,5 +79,4 @@
 				this.me = settings.getID();
 				this.progress = settings.getProgress();
-				computeMinMax();
 			} else if (info instanceof ActionDone) {
 				Action otheract = ((ActionDone) info).getAction();
@@ -117,13 +118,15 @@
 
 	private void myTurn() throws IOException {
-		Action myAction = null;
+		updateUtilSpace();
 		Bid bid = makeBid();
-		UtilitySpace utilspace = getUtilSpace();
 
-		if (lastReceivedBid != null && utilspace.getUtility(lastReceivedBid)
-				.compareTo(utilspace.getUtility(bid)) >= 0) {
+		Action myAction;
+		if (bid == null || lastReceivedBid != null
+				&& utilspace.getUtility(lastReceivedBid)
+						.compareTo(utilspace.getUtility(bid)) >= 0) {
+			// if bid==null we failed to suggest next bid.
 			myAction = new Accept(me, lastReceivedBid);
 		} else {
-			myAction = new Offer(me, makeBid());
+			myAction = new Offer(me, bid);
 		}
 		getConnection().send(myAction);
@@ -131,51 +134,23 @@
 	}
 
-	private UtilitySpace getUtilSpace() {
-		return (LinearAdditiveUtilitySpace) profileint.getProfile();
+	private LinearAdditiveUtilitySpace updateUtilSpace() {
+		Profile newutilspace = profileint.getProfile();
+		if (!newutilspace.equals(utilspace)) {
+			utilspace = (LinearAdditiveUtilitySpace) newutilspace;
+			extendedspace = new ExtendedUtilSpace(utilspace);
+		}
+		return utilspace;
 	}
 
 	/**
-	 * Computes the fields minutil and maxUtil if not yet computed. minutil is
-	 * the minimum utility of any bid, but at least the utility of the
-	 * reservation bid. maxUtil is the maximum util of any bid.
-	 * <p>
-	 * TODO this is simplistic, very expensive method and may cause us to run
-	 * out of time on large domains.
-	 * <p>
-	 * Can be called only after profileint has been set.
+	 * @return next possible bid with current target utility, or null if no such
+	 *         bid.
 	 */
-	private void computeMinMax() {
-		if (this.maxUtil != null && this.minUtil != null)
-			return;
-		this.minUtil = 1d;
-		this.maxUtil = 0d;
-		UtilitySpace utilspace = getUtilSpace();
-		AllBidsList allbidslist = new AllBidsList(
-				profileint.getProfile().getDomain());
-		for (Bid bid : allbidslist) {
-			double util = utilspace.getUtility(bid).doubleValue();
-			if (util < minUtil)
-				minUtil = util;
-			if (util > maxUtil)
-				maxUtil = util;
-		}
-
-		Bid rvbid = utilspace.getReservationBid();
-		if (rvbid != null) {
-			double rv = utilspace.getUtility(rvbid).doubleValue();
-			if (rv > minUtil)
-				minUtil = rv;
-		}
-		tolerance = 100 / allbidslist.size().longValue();
-		tolerance = Math.max(tolerance, 0.1);
-	}
-
 	private Bid makeBid() {
 		double time = progress.get(System.currentTimeMillis());
-		double utilityGoal = utilityGoal(time, getE());
-		BidsWithUtility options = new BidsWithUtility(
-				(LinearAdditiveUtilitySpace) profileint.getProfile(),
-				BigDecimal.valueOf(utilityGoal),
-				BigDecimal.valueOf(utilityGoal + tolerance));
+		BigDecimal utilityGoal = utilityGoal(time, getE());
+		ImmutableList<Bid> options = extendedspace.getBids(utilityGoal);
+		if (options.size() == BigInteger.ZERO)
+			return null;
 		// pick a random one.
 		return options.get(new Random().nextInt(options.size().intValue()));
@@ -190,10 +165,15 @@
 	 * @return the utility goal for this time and e value
 	 */
-	private double utilityGoal(double t, double e) {
+	private BigDecimal utilityGoal(double t, double e) {
+		BigDecimal minUtil = extendedspace.getMin();
+		BigDecimal maxUtil = extendedspace.getMax();
+
 		double ft = 0;
 		if (e != 0)
 			ft = Math.pow(t, 1 / e);
-		// we subtract 0.000001 to correct possibly small round-up errors
-		return minUtil + (maxUtil - minUtil) * (1 - ft) - 0.000001;
+		// we subtract epsilon to correct possibly small round-up errors
+		return new BigDecimal(minUtil.doubleValue()
+				+ (maxUtil.doubleValue() - minUtil.doubleValue()) * (1 - ft))
+						.min(maxUtil).max(minUtil);
 	}
 }
Index: exampleparties/timedependentparty/src/test/java/geniusweb/exampleparties/timedependentparty/ExtendedUtilSpaceTest.java
===================================================================
--- exampleparties/timedependentparty/src/test/java/geniusweb/exampleparties/timedependentparty/ExtendedUtilSpaceTest.java	(revision 4)
+++ exampleparties/timedependentparty/src/test/java/geniusweb/exampleparties/timedependentparty/ExtendedUtilSpaceTest.java	(revision 4)
@@ -0,0 +1,63 @@
+package geniusweb.exampleparties.timedependentparty;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import geniusweb.profile.Profile;
+import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace;
+
+@RunWith(Parameterized.class)
+public class ExtendedUtilSpaceTest {
+	private final static ObjectMapper jackson = new ObjectMapper();
+	private final static BigDecimal SMALL = new BigDecimal("0.0001");
+
+	@Parameters
+	public static Collection<Object[]> data() {
+		return Arrays.asList(new Object[][] {
+				{ "src/test/resources/jobs/jobs1.json", 0.02 },
+				{ "src/test/resources/7issues/7issues1.json", 0.0055 },
+				{ "src/test/resources/9issues/9issues1.json", 0.0013 } });
+	}
+
+	private String filename;
+	private BigDecimal expectedTolerance;
+	private ExtendedUtilSpace space;
+
+	public ExtendedUtilSpaceTest(String filename, double expectedTolerance) {
+		this.filename = filename;
+		this.expectedTolerance = BigDecimal.valueOf(expectedTolerance);
+	}
+
+	@Before
+	public void before() throws IOException {
+		String file = new String(Files.readAllBytes(Paths.get(filename)));
+		LinearAdditiveUtilitySpace profile = (LinearAdditiveUtilitySpace) jackson
+				.readValue(file, Profile.class);
+		space = new ExtendedUtilSpace(profile);
+	}
+
+	@Test
+	public void smokeTest() {
+
+	}
+
+	@Test
+	public void testTolerance() {
+		assertTrue(space.computeTolerance().subtract(expectedTolerance).abs()
+				.compareTo(SMALL) < 0);
+	}
+}
Index: exampleparties/timedependentparty/src/test/resources/7issues/7issues1.json
===================================================================
--- exampleparties/timedependentparty/src/test/resources/7issues/7issues1.json	(revision 4)
+++ exampleparties/timedependentparty/src/test/resources/7issues/7issues1.json	(revision 4)
@@ -0,0 +1,105 @@
+{
+	"LinearAdditiveUtilitySpace": {
+		"name": "7issues1",
+		"issueUtilities": {
+			"i1": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.11,
+					"highValue": 9,
+					"highUtility": 0.99
+
+				}
+			},
+			"i2": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.12,
+					"highValue": 9,
+					"highUtility": 0.97
+
+				}
+			},
+			"i3": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.13,
+					"highValue": 9,
+					"highUtility": 0.96
+
+				}
+			},
+			"i4": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.14,
+					"highValue": 9,
+					"highUtility": 0.94
+
+				}
+			},
+			"i5": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.15,
+					"highValue": 9,
+					"highUtility": 0.93
+
+				}
+			},
+			"i6": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.16,
+					"highValue": 9,
+					"highUtility": 0.92
+
+				}
+			},
+			"i7": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.16,
+					"highValue": 9,
+					"highUtility": 0.91
+
+				}
+			}
+		},
+		"issueWeights": {
+			"i1": 0.07531677352656704,
+			"i2": 0.18148468268008364,
+			"i3": 0.13035193969082373,
+			"i4": 0.24649985443378972,
+			"i5": 0.16931694966873587,
+			"i6": 0.131353,
+			"i7": 0.0656768
+		},
+		"domain": {
+			"name": "7issues",
+			"issuesValues": {
+				"i1": {
+					"range": ["0", "9", "1"]
+				},
+				"i2": {
+					"range": ["0", "9", "1"]
+				},
+				"i3": {
+					"range": ["0", "9", "1"]
+				},
+				"i4": {
+					"range": ["0", "9", "1"]
+				},
+				"i5": {
+					"range": ["0", "9", "1"]
+				},
+				"i6": {
+					"range": ["0", "9", "1"]
+				},
+				"i7": {
+					"range": ["0", "9", "1"]
+				}
+			}
+		}
+	}
+}
Index: exampleparties/timedependentparty/src/test/resources/9issues/9issues1.json
===================================================================
--- exampleparties/timedependentparty/src/test/resources/9issues/9issues1.json	(revision 4)
+++ exampleparties/timedependentparty/src/test/resources/9issues/9issues1.json	(revision 4)
@@ -0,0 +1,134 @@
+{
+	"LinearAdditiveUtilitySpace": {
+		"name": "9issues1",
+		"issueUtilities": {
+			"i1": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.11,
+					"highValue": 9,
+					"highUtility": 0.99
+
+				}
+			},
+			"i2": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.12,
+					"highValue": 9,
+					"highUtility": 0.97
+
+				}
+			},
+			"i3": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.13,
+					"highValue": 9,
+					"highUtility": 0.96
+
+				}
+			},
+			"i4": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.14,
+					"highValue": 9,
+					"highUtility": 0.94
+
+				}
+			},
+			"i5": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.15,
+					"highValue": 9,
+					"highUtility": 0.93
+
+				}
+			},
+			"i6": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.16,
+					"highValue": 9,
+					"highUtility": 0.92
+
+				}
+			},
+			"i7": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.16,
+					"highValue": 9,
+					"highUtility": 0.91
+
+				}
+			},
+			"i8": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.7664,
+					"highValue": 9,
+					"highUtility": 0.183
+
+				}
+			},
+
+			"i9": {
+				"numberutils": {
+					"lowValue": 0,
+					"lowUtility": 0.191,
+					"highValue": 9,
+					"highUtility": 0.891
+
+				}
+			}
+
+		},
+		"issueWeights": {
+			"i1": 0.07531677352656704,
+			"i2": 0.18148468268008364,
+			"i3": 0.12035193969082373,
+			"i4": 0.21649985443378972,
+			"i5": 0.15621694966873587,
+			"i6": 0.111253,
+			"i7": 0.0656768,
+			"i8": 0.0201,
+			"i9": 0.0531
+		},
+		"domain": {
+			"name": "9issues",
+			"issuesValues": {
+				"i1": {
+					"range": ["0", "9", "1"]
+				},
+				"i2": {
+					"range": ["0", "9", "1"]
+				},
+				"i3": {
+					"range": ["0", "9", "1"]
+				},
+				"i4": {
+					"range": ["0", "9", "1"]
+				},
+				"i5": {
+					"range": ["0", "9", "1"]
+				},
+				"i6": {
+					"range": ["0", "9", "1"]
+				},
+				"i7": {
+					"range": ["0", "9", "1"]
+				},
+				"i8": {
+					"range": ["0", "9", "1"]
+				},
+				"i9": {
+					"range": ["0", "9", "1"]
+				}
+
+			}
+		}
+	}
+}
Index: exampleparties/timedependentparty/src/test/resources/jobs/jobs1.json
===================================================================
--- exampleparties/timedependentparty/src/test/resources/jobs/jobs1.json	(revision 4)
+++ exampleparties/timedependentparty/src/test/resources/jobs/jobs1.json	(revision 4)
@@ -0,0 +1,116 @@
+{
+	"LinearAdditiveUtilitySpace": {
+		"issueUtilities": {
+			"salary": {
+				"discreteutils": {
+					"valueUtilities": {
+						"2000": 0,
+						"2500": 0.25,
+						"3000": 0.3,
+						"3500": 0.75,
+						"4000": 1.0
+					}
+				}
+			},
+			"fte": {
+				"discreteutils": {
+					"valueUtilities": {
+						"0.6": 0.25,
+						"0.8": 0.5,
+						"1.0": 0.75
+					}
+				}
+			},
+			"work from home": {
+				"discreteutils": {
+					"valueUtilities": {
+						"0": 0.333333333,
+						"1": 0.5,
+						"2": 0.666666666666
+					}
+				}
+			},
+			"lease car": {
+				"discreteutils": {
+					"valueUtilities": {
+						"yes":1,
+						"no":0
+					}
+				}
+			},
+			"permanent contract": {
+				"discreteutils": {
+					"valueUtilities": {
+						"yes":1,
+						"no":0
+					}
+				}
+			},
+			"career development opportunities": {
+				"discreteutils": {
+					"valueUtilities": {
+						"low":0,
+						"medium":0.5,
+						"high":1
+					}
+				}
+			}
+		},
+		"issueWeights": {
+			"salary": 0.24,
+			"fte": 0.32,
+			"work from home": 0.18,
+			"lease car": 0.06,
+			"permanent contract": 0.16,
+			"career development opportunities": 0.04
+		},
+		"domain": {
+			"name": "jobs",
+			"issuesValues": {
+				"salary": {
+					"values": [
+						"2000",
+						"2500",
+						"3000",
+						"3500",
+						"4000"
+					]
+				},
+				"fte": {
+					"values": [
+						"0.6",
+						"0.8",
+						"1.0"
+					]
+				},
+				"work from home": {
+					"values": [
+						"0",
+						"1",
+						"2"
+					]
+				},
+				"lease car": {
+					"values": [
+						"yes",
+						"no"
+					]
+				},
+				"permanent contract": {
+					"values": [
+						"yes",
+						"no"
+					]
+				},
+				"career development opportunities": {
+					"values": [
+						"low",
+						"medium",
+						"high"
+					]
+				}
+			}
+		},
+		"name": "jobs1"
+	}
+}
