Index: profile/src/main/java/geniusweb/profile/DefaultPartialOrdering.java
===================================================================
--- profile/src/main/java/geniusweb/profile/DefaultPartialOrdering.java	(revision 2)
+++ profile/src/main/java/geniusweb/profile/DefaultPartialOrdering.java	(revision 2)
@@ -0,0 +1,156 @@
+package geniusweb.profile;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonGetter;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import geniusweb.issuevalue.Bid;
+import geniusweb.issuevalue.Domain;
+
+/**
+ * Default implementation of partial ordering that stores all is-better
+ * relations explicitly in a map.
+ * 
+ * NOTICE this can handle profiles of max size Integer. This is because various
+ * functions used here rely on basic java functions that can handle only int.
+ * Besides, the size of partial maps grows very rapidly so this approach is
+ * limited anyway.
+ */
+public class DefaultPartialOrdering extends DefaultProfile implements PartialOrdering {
+
+	/**
+	 * Set is sparsely filled. If a Bid is not a key, it is not better than any
+	 * other bid.
+	 */
+	private final Map<Bid, Set<Bid>> isBetter;
+
+	/**
+	 * 
+	 * @param name
+	 * @param domain
+	 * @param reservationbid
+	 * @param bids
+	 * @param isbetterList   a list of tuples [bid1index, bid2index]. It indicates
+	 *                       that bids[bid1index] isbetterthan bids[bid2index].
+	 */
+	@JsonCreator
+	public DefaultPartialOrdering(@JsonProperty("name") String name, @JsonProperty("domain") Domain domain,
+			@JsonProperty("reservationBid") Bid reservationbid, @JsonProperty("bids") List<Bid> bids,
+			@JsonProperty("better") List<List<Integer>> isbetterList) {
+		this(name, domain, reservationbid, makeBidMap(bids, isbetterList));
+	}
+
+	/**
+	 * @param name           the name for the profile
+	 * @param domain         the {@link Domain} description
+	 * @param reservationbid the reservation {@link Bid}
+	 * @param isBetterMap    a map with keys = a better bid and value=a less good
+	 *                       bid.
+	 */
+	public DefaultPartialOrdering(String name, Domain domain, Bid reservationbid, Map<Bid, Set<Bid>> isBetterMap) {
+		super(name, domain, reservationbid);
+		this.isBetter = isBetterMap;
+	}
+
+	@Override
+	public boolean isPreferredOrEqual(Bid bid1, Bid bid2) {
+		if (!isBetter.containsKey(bid1))
+			return false;
+		return isBetter.get(bid1).contains(bid2);
+	}
+
+	/**
+	 * 
+	 * @return a list with all the bids
+	 */
+	@JsonGetter
+	public List<Bid> getBids() {
+		// FIXME the iteration order may not be guaranteed!
+		Set<Bid> bids = new HashSet<>();
+		for (Bid bid : isBetter.keySet()) {
+			bids.add(bid);
+			bids.addAll(isBetter.get(bid));
+		}
+		return new ArrayList<Bid>(bids);
+	}
+
+	@JsonGetter
+	/**
+	 * 
+	 * @return a list of tuples [bid1index, bid2index]. It indicates that
+	 *         bids[bid1index] isbetterthan bids[bid2index].
+	 */
+	public List<List<Integer>> getBetter() {
+		List<List<Integer>> betterlist = new LinkedList<>();
+		List<Bid> bidslist = getBids();
+
+		for (Bid bid : bidslist) {
+			if (isBetter.containsKey(bid)) {
+				for (Bid worsebid : isBetter.get(bid)) {
+					betterlist.add(Arrays.asList(bidslist.indexOf(bid), bidslist.indexOf(worsebid)));
+				}
+			}
+		}
+
+		return betterlist;
+	}
+
+	@Override
+	public String toString() {
+		return "DefaultPartialOrdering[" + getValuesString() + "," + isBetter + "]";
+	}
+
+	private static Map<Bid, Set<Bid>> makeBidMap(List<Bid> bids, List<List<Integer>> isBetterList) {
+		Map<Bid, Set<Bid>> betterMap = new HashMap<>();
+
+		for (List<Integer> tuple : isBetterList) {
+			if (tuple.size() != 2) {
+				throw new IllegalArgumentException("Expected tuple but found " + tuple + "in " + isBetterList);
+			}
+			Bid betterbid = bids.get(tuple.get(0));
+			Set<Bid> map = betterMap.get(betterbid);
+			if (map == null) {
+				map = new HashSet<>();
+				betterMap.put(betterbid, map);
+			}
+			map.add(bids.get(tuple.get(1)));
+		}
+
+		return betterMap;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = super.hashCode();
+		result = prime * result + ((isBetter == null) ? 0 : isBetter.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (!super.equals(obj))
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		DefaultPartialOrdering other = (DefaultPartialOrdering) obj;
+		if (isBetter == null) {
+			if (other.isBetter != null)
+				return false;
+		} else if (!isBetter.equals(other.isBetter))
+			return false;
+		return true;
+	}
+
+}
Index: profile/src/main/java/geniusweb/profile/DefaultProfile.java
===================================================================
--- profile/src/main/java/geniusweb/profile/DefaultProfile.java	(revision 2)
+++ profile/src/main/java/geniusweb/profile/DefaultProfile.java	(revision 2)
@@ -0,0 +1,93 @@
+package geniusweb.profile;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import geniusweb.issuevalue.Bid;
+import geniusweb.issuevalue.Domain;
+
+/**
+ * Set up such that jackson can look at the getters.
+ *
+ */
+public abstract class DefaultProfile implements Profile {
+	private final String name;
+	private final Domain domain;
+	private final Bid reservationbid;
+
+	/**
+	 * 
+	 * @param name           the name for the profile
+	 * @param domain         the {@link Domain} description
+	 * @param reservationbid the reservation {@link Bid}
+	 */
+	@JsonCreator
+	public DefaultProfile(String name, Domain domain, Bid reservationbid) {
+		this.name = name;
+		this.domain = domain;
+		this.reservationbid = reservationbid;
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public Domain getDomain() {
+		return domain;
+	}
+
+	@Override
+	public Bid getReservationBid() {
+		return reservationbid;
+	}
+
+	/**
+	 * 
+	 * @return string of values contained in here. Useful to make derived toString
+	 *         functions
+	 */
+	@JsonIgnore
+	public String getValuesString() {
+		return name + "," + domain + "," + reservationbid;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((domain == null) ? 0 : domain.hashCode());
+		result = prime * result + ((name == null) ? 0 : name.hashCode());
+		result = prime * result + ((reservationbid == null) ? 0 : reservationbid.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;
+		DefaultProfile other = (DefaultProfile) obj;
+		if (domain == null) {
+			if (other.domain != null)
+				return false;
+		} else if (!domain.equals(other.domain))
+			return false;
+		if (name == null) {
+			if (other.name != null)
+				return false;
+		} else if (!name.equals(other.name))
+			return false;
+		if (reservationbid == null) {
+			if (other.reservationbid != null)
+				return false;
+		} else if (!reservationbid.equals(other.reservationbid))
+			return false;
+		return true;
+	}
+
+}
Index: profile/src/main/java/geniusweb/profile/Profile.java
===================================================================
--- profile/src/main/java/geniusweb/profile/Profile.java	(revision 1)
+++ profile/src/main/java/geniusweb/profile/Profile.java	(revision 2)
@@ -16,5 +16,6 @@
  */
 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
-@JsonSubTypes({ @JsonSubTypes.Type(value = LinearAdditiveUtilitySpace.class) })
+@JsonSubTypes({ @JsonSubTypes.Type(value = LinearAdditiveUtilitySpace.class),
+		@JsonSubTypes.Type(value = DefaultPartialOrdering.class) })
 public interface Profile {
 
@@ -32,9 +33,8 @@
 	/**
 	 * 
-	 * @return a (hypothetical) bid that is the best alternative to a
-	 *         non-agreement. Only bids that are
-	 *         {@link #isPreferredOrEqual(Bid, Bid)} should be accepted. If a
-	 *         negotiation does not reach an agreement, the party can get this
-	 *         offer somewhere else. This replaces the older notion of a
+	 * @return a (hypothetical) bid that is the best alternative to a non-agreement.
+	 *         Only bids that are {@link #isPreferredOrEqual(Bid, Bid)} should be
+	 *         accepted. If a negotiation does not reach an agreement, the party can
+	 *         get this offer somewhere else. This replaces the older notion of a
 	 *         "reservation value" and is more general. If null, there is no
 	 *         reservation bid and any agreement is better than no agreement.
Index: profile/src/test/java/geniusweb/profile/DefaultPartialOrderingTest.java
===================================================================
--- profile/src/test/java/geniusweb/profile/DefaultPartialOrderingTest.java	(revision 2)
+++ profile/src/test/java/geniusweb/profile/DefaultPartialOrderingTest.java	(revision 2)
@@ -0,0 +1,105 @@
+package geniusweb.profile;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+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 org.junit.Before;
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import geniusweb.issuevalue.Bid;
+import geniusweb.issuevalue.DiscreteValue;
+import geniusweb.issuevalue.DiscreteValueSet;
+import geniusweb.issuevalue.Domain;
+import geniusweb.issuevalue.ValueSet;
+import tudelft.utilities.junit.GeneralTests;
+
+public class DefaultPartialOrderingTest extends GeneralTests<DefaultPartialOrdering> {
+
+	private final String serialized = "{\"DefaultPartialOrdering\":{" + "\"name\":\"ordering1\","
+			+ "\"domain\":{\"name\":\"dom1\",\"issuesValues\":{\"iss1\":{\"values\":[\"1\",\"2\",\"3\"]}}},"
+			+ "\"reservationBid\":{\"issuevalues\":{\"iss1\":\"1\"}},"
+			+ "\"bids\":[{\"issuevalues\":{\"iss1\":\"1\"}},{\"issuevalues\":{\"iss1\":\"3\"}},{\"issuevalues\":{\"iss1\":\"2\"}}],"
+			+ "\"better\":[[0,2],[1,2]]}}";
+
+	// we need real (not mock) values otherwise serializer crashes..
+	private String issue1 = "iss1";
+	private DefaultPartialOrdering ordering1, ordering1b, ordering2, ordering3, ordering4, ordering5;
+
+	private Bid bid1, bid2, bid3;
+
+	@Before
+	public void before() {
+		Map<String, ValueSet> issues = new HashMap<>();
+		DiscreteValue val1 = new DiscreteValue("1");
+		DiscreteValue val2 = new DiscreteValue("2");
+		DiscreteValue val3 = new DiscreteValue("3");
+		issues.put(issue1, new DiscreteValueSet(new HashSet<>(Arrays.asList(val1, val2, val3))));
+		Domain domain1 = new Domain("dom1", issues);
+		Domain domain2 = new Domain("dom2", issues);
+		bid1 = new Bid(Collections.singletonMap(issue1, val1));
+		bid2 = new Bid(Collections.singletonMap(issue1, val2));
+		bid3 = new Bid(Collections.singletonMap(issue1, val3));
+
+		Map<Bid, Set<Bid>> map1 = new HashMap<>();
+		map1.put(bid1, new HashSet<Bid>(Arrays.asList(bid2)));
+		map1.put(bid3, new HashSet<Bid>(Arrays.asList(bid2)));
+
+		Map<Bid, Set<Bid>> map2 = new HashMap<>();
+		map2.put(bid1, new HashSet<Bid>(Arrays.asList(bid2)));
+		map2.put(bid3, new HashSet<Bid>(Arrays.asList(bid1)));
+
+		ordering1 = new DefaultPartialOrdering("ordering1", domain1, bid1, map1);
+		ordering1b = new DefaultPartialOrdering("ordering1", domain1, bid1, map1);
+		ordering2 = new DefaultPartialOrdering("ordering2", domain1, bid1, map1);
+		ordering3 = new DefaultPartialOrdering("ordering1", domain2, bid1, map1);
+		ordering4 = new DefaultPartialOrdering("ordering1", domain1, bid2, map1);
+		ordering5 = new DefaultPartialOrdering("ordering1", domain1, bid1, map2);
+
+	}
+
+	@Override
+	public List<List<DefaultPartialOrdering>> getGeneralTestData() {
+		return Arrays.asList(Arrays.asList(ordering1, ordering1b), Arrays.asList(ordering2), Arrays.asList(ordering3),
+				Arrays.asList(ordering4), Arrays.asList(ordering5));
+	}
+
+	@Override
+	public List<String> getGeneralTestStrings() {
+		return Arrays.asList("DefaultPartialOrdering.*", "DefaultPartialOrdering.*", "DefaultPartialOrdering.*",
+				"DefaultPartialOrdering.*", "DefaultPartialOrdering.*");
+	}
+
+	@Test
+	public void testSerialize() throws JsonProcessingException {
+		ObjectMapper jackson = new ObjectMapper();
+		assertEquals(serialized, jackson.writeValueAsString(ordering1));
+		System.out.println(serialized);
+	}
+
+	@Test
+	public void testDeserialize() throws IOException {
+		ObjectMapper jackson = new ObjectMapper();
+		assertEquals(ordering1, jackson.readValue(serialized, Profile.class));
+	}
+
+	@Test
+	public void testIsBetter() {
+		assertTrue(ordering1.isPreferredOrEqual(bid1, bid2));
+		assertFalse(ordering1.isPreferredOrEqual(bid1, bid3));
+		assertFalse(ordering1.isPreferredOrEqual(bid2, bid3));
+	}
+
+}
