source: src/main/java/genius/core/Bid.java@ 305

Last change on this file since 305 was 305, checked in by Adel Magra, 5 years ago

Added new functions in Bid and BidRanking to compute a certain distance between bids and a Total Variational Distance associated with it.

File size: 8.8 KB
Line 
1package genius.core;
2
3import java.util.List;
4
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.HashMap;
8import java.util.Iterator;
9import java.util.Map;
10import java.util.Map.Entry;
11import java.util.Set;
12
13import java.io.Serializable;
14
15import javax.xml.bind.annotation.XmlAttribute;
16import javax.xml.bind.annotation.XmlElement;
17import javax.xml.bind.annotation.XmlElementRef;
18import javax.xml.bind.annotation.XmlRootElement;
19import javax.xml.bind.annotation.adapters.XmlAdapter;
20import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
21
22import genius.core.analysis.pareto.IssueValue;
23import genius.core.issue.Issue;
24import genius.core.issue.Value;
25
26/**
27 * A bid is a set of tuples [idnumber,value], where idnumber is the unique
28 * number of the issue, and value is the picked alternative.
29 * <p>
30 * Bid is a immutable. But you can create modified copies using
31 * {@link #putValue(int, Value)}.
32 *
33 * Bid should be considered final so do not extend this.
34 *
35 * @author Dmytro Tykhonov, Koen Hindriks
36 */
37@XmlRootElement
38public class Bid implements Serializable {
39
40 /**
41 *
42 */
43 private static final long serialVersionUID = -7723017380013100614L;
44
45 private final Domain fDomain;
46
47 /**
48 * the bid values for each IssueID
49 */
50 @XmlElement(name = "values")
51 @XmlJavaTypeAdapter(MyMapAdapter.class)
52 private HashMap<Integer, Value> fValues;
53
54 /**
55 * Only for (de)serialization
56 */
57 private Bid() {
58 fDomain = null; // keep Java happy. Serializer shall overwrite anyway
59 }
60
61 /**
62 * Create a new empty bid of which the values still must be set.
63 *
64 * @param domain
65 * the domain for this bid
66 */
67 public Bid(Domain domain) {
68 fDomain = domain;
69 fValues = new HashMap<Integer, Value>();
70 }
71
72 /**
73 * createFrom a new bid in a domain. There is only this constructor because we require that ALL
74 * values in the domain get assigned a value.
75 *
76 * @param domainP
77 * the domain in which the bid is done
78 * @param bidP
79 * HashMap, which is a set of pairs [issueID,value]
80 */
81 public Bid(Domain domainP, HashMap<Integer, Value> bidP) {
82 this.fDomain = domainP;
83 fValues = bidP;
84 }
85
86 /**
87 * create bid from set of {@link IssueValue}s
88 *
89 * @param domain
90 * the {@link Domain}
91 * @param values
92 * a {@link Collection} of {@link IssueValue}s
93 */
94 public Bid(Domain domain, Collection<IssueValue> values) {
95 if (domain == null)
96 throw new NullPointerException("null domain");
97 if (values == null)
98 throw new NullPointerException("null values");
99
100 this.fDomain = domain;
101 fValues = new HashMap<>();
102 for (IssueValue iv : values) {
103 fValues.put(iv.getIssue().getNumber(), iv.getValue());
104 }
105 }
106
107 /**
108 * This method clones the given bid.
109 *
110 * @param bid
111 * the bid to clone
112 */
113 public Bid(Bid bid) {
114
115 fDomain = bid.fDomain;
116 fValues = (HashMap<Integer, Value>) bid.fValues.clone();
117 }
118
119 /**
120 * @param issueNr
121 * number of an issue.
122 * @return the picked value for given issue idnumber
123 * @throws IllegalArgumentException
124 * if there exist no issue with the given number.
125 */
126 public Value getValue(int issueNr) {
127 Value v = fValues.get(issueNr);
128 if (v == null) {
129 if (fDomain.getIssues().get(issueNr) == null)
130 throw new IllegalArgumentException("Bid.getValue: issue " + issueNr + " does not exist at all");
131 throw new IllegalStateException("There is no evaluator for issue " + issueNr);
132 }
133 return v;
134 }
135
136 /**
137 * @param issue the issue
138 * @return the picked value for given issue
139 * @throws IllegalArgumentException
140 * if there exist no issue with the given number.
141 */
142 public Value getValue(Issue issue)
143 {
144 return getValue(issue.getNumber());
145 }
146
147 /**
148 * @param issue the issue corresponding to the value.
149 * This is needed because the same values can occur multiple times in a bid
150 * @param value
151 * @return Whether this bid has a value selected for an issue
152 */
153 public boolean containsValue(Issue issue, Value value)
154 {
155 return getValue(issue).equals(value);
156 }
157
158 /**
159 * @param issueId
160 * unique ID of an issue.
161 * @param pValue
162 * value of the issue.
163 * @return new Bid as the current bid but with the value of the issue with
164 * the given issueID to the given value
165 * @throws IllegalArgumentException
166 * if there exist no issue with the given number.
167 */
168 public Bid putValue(int issueId, Value pValue) {
169 if (fValues.get(issueId).getType() != pValue.getType()) {
170 // FIXME
171 // if (fDomain.getIssue(issueId).getType() != pValue.getType()) {
172 throw new IllegalArgumentException("expected value of type " + fDomain.getIssues().get(issueId).getType()
173 + " but got " + pValue + " of type " + pValue.getType());
174 }
175 HashMap<Integer, Value> newValues = new HashMap<Integer, Value>(fValues);
176 newValues.put(issueId, pValue);
177 return new Bid(fDomain, newValues);
178 }
179
180
181 public String toString() {
182 String s = "Bid[";
183 Set<Entry<Integer, Value>> value_set = fValues.entrySet();
184 Iterator<Entry<Integer, Value>> value_it = value_set.iterator();
185 int i = 0;
186 while (value_it.hasNext()) {
187 int ind = ((Entry<Integer, Value>) value_it.next()).getKey();
188 Object tmpobj = fDomain.getObjectivesRoot().getObjective(ind);
189 if (tmpobj != null) {
190 String issueName = fDomain.getObjectivesRoot().getObjective(ind).getName();
191 s += (i++ > 0 ? ", " : "") + issueName + ": " + fValues.get(ind);
192 } else {
193 System.out.println("objective with index " + ind + " does not exist");
194 }
195 }
196 s = s + "]";
197 return s;
198 }
199
200 /**
201 * @return A CSV version of the bid, useful for logging.
202 */
203 public String toStringCSV()
204 {
205 String s = "";
206 Set<Entry<Integer, Value>> value_set = fValues.entrySet();
207 Iterator<Entry<Integer, Value>> value_it = value_set.iterator();
208 int i = 0;
209 while (value_it.hasNext())
210 {
211 int ind = ((Entry<Integer, Value>) value_it.next()).getKey();
212 s += (i++ > 0 ? ";" : "") + fValues.get(ind);
213 }
214 return s;
215 }
216
217 /**
218 * @param pBid
219 * to which this bid must be compared.
220 * @return true if the values of this and the given bid are equal.
221 */
222 public boolean equals(Bid pBid) {
223 if (pBid == null)
224 return false;
225 return fValues.equals(pBid.fValues);
226 }
227
228 /*
229 * (non-Javadoc)
230 *
231 * @see java.lang.Object#equals(java.lang.Object)
232 */
233 @Override
234 public boolean equals(Object obj) {
235 if (obj instanceof Bid)
236 return equals((Bid) obj);
237 return false;
238 }
239
240 /**
241 * @return a (copy of ) the list of all values in this bid. FIXME we really
242 * should return an immutable {@link Map} here but that may break
243 * many agents.
244 */
245
246 public HashMap<Integer, Value> getValues() {
247 return new HashMap<Integer, Value>(fValues);
248 }
249
250 // Reyhan: add this method
251 public List<Issue> getIssues() {
252 return fDomain.getIssues();
253 }
254
255 public Domain getDomain() {
256 return fDomain;
257 }
258
259 /**
260 * Counts the number of equal values with another bid (assuming they are defined on the same domain)
261 */
262 public int countEqualValues(Bid b)
263 {
264 int count = 0;
265 for (Integer v : fValues.keySet())
266 {
267 if (this.fValues.get(v).equals(b.fValues.get(v)))
268 count++;
269 }
270 return count;
271 }
272
273 /**
274 * Computes a basic distance function between 2 bids defined on the same domain:
275 * The average of their # of unequal values.
276 * @param b
277 * @return double in [0,1].
278 */
279
280 public double getDistance(Bid b) {
281 double nrOfIssues = this.getIssues().size();
282 double unequalValues = nrOfIssues - this.countEqualValues(b);
283 return unequalValues/nrOfIssues;
284 }
285
286
287 @Override
288 public int hashCode() {
289 int code = 0;
290 for (Entry<Integer, Value> lEntry : fValues.entrySet()) {
291 code = code + lEntry.getValue().hashCode();
292 }
293 return code;// fValues.hashCode();
294 }
295
296}
297
298class MyMapAdapter extends XmlAdapter<Temp, Map<Integer, Value>> {
299
300 @Override
301 public Temp marshal(Map<Integer, Value> arg0) throws Exception {
302 Temp temp = new Temp();
303 for (Entry<Integer, Value> entry : arg0.entrySet()) {
304 temp.entry.add(new Item(entry.getKey(), entry.getValue()));
305 }
306 return temp;
307 }
308
309 @Override
310 public Map<Integer, Value> unmarshal(Temp arg0) throws Exception {
311 Map<Integer, Value> map = new HashMap<Integer, Value>();
312 for (Item item : arg0.entry) {
313 map.put(item.key, item.value);
314 }
315 return map;
316 }
317
318}
319
320class Temp {
321 @XmlElement(name = "issue")
322 public List<Item> entry;
323
324 public Temp() {
325 entry = new ArrayList<Item>();
326 }
327
328}
329
330@XmlRootElement
331class Item {
332 @XmlAttribute(name = "index")
333 public Integer key;
334
335 @XmlElementRef
336 public Value value;
337
338 public Item() {
339 }
340
341 public Item(Integer key, Value val) {
342 this.key = key;
343 this.value = val;
344 }
345}
Note: See TracBrowser for help on using the repository browser.