1 | package genius.core.utility;
|
---|
2 |
|
---|
3 | import java.util.List;
|
---|
4 |
|
---|
5 | import java.util.Enumeration;
|
---|
6 | import java.util.HashMap;
|
---|
7 | import java.util.Map;
|
---|
8 | import java.util.Map.Entry;
|
---|
9 | import java.util.Set;
|
---|
10 | import java.util.Vector;
|
---|
11 |
|
---|
12 | import java.io.BufferedReader;
|
---|
13 | import java.io.File;
|
---|
14 | import java.io.FileReader;
|
---|
15 | import java.io.IOException;
|
---|
16 |
|
---|
17 | import genius.core.Bid;
|
---|
18 | import genius.core.Domain;
|
---|
19 | import genius.core.DomainImpl;
|
---|
20 | import genius.core.issue.Issue;
|
---|
21 | import genius.core.issue.IssueDiscrete;
|
---|
22 | import genius.core.issue.Objective;
|
---|
23 | import genius.core.xml.SimpleDOMParser;
|
---|
24 | import genius.core.xml.SimpleElement;
|
---|
25 |
|
---|
26 | /**
|
---|
27 | * The additive utility space couples all objectives to weights and evaluators.
|
---|
28 | *
|
---|
29 | * @author D. Tykhonov, K. Hindriks, W. Pasman
|
---|
30 | */
|
---|
31 |
|
---|
32 | public class AdditiveUtilitySpace extends AbstractUtilitySpace {
|
---|
33 |
|
---|
34 | /**
|
---|
35 | *
|
---|
36 | */
|
---|
37 | private static final long serialVersionUID = 8746748105840831474L;
|
---|
38 |
|
---|
39 | private final Map<Objective, Evaluator> fEvaluators;
|
---|
40 |
|
---|
41 | /**
|
---|
42 | * Creates an empty utility space.
|
---|
43 | */
|
---|
44 | public AdditiveUtilitySpace() {
|
---|
45 | this(new DomainImpl(), new HashMap<Objective, Evaluator>());
|
---|
46 | }
|
---|
47 |
|
---|
48 | /**
|
---|
49 | * Creates a new utilityspace of the given domain.
|
---|
50 | *
|
---|
51 | * @param domain
|
---|
52 | * for which the utilityspace should be specified.
|
---|
53 | */
|
---|
54 | public AdditiveUtilitySpace(Domain domain) {
|
---|
55 | this(domain, new HashMap<Objective, Evaluator>());
|
---|
56 | }
|
---|
57 |
|
---|
58 | public AdditiveUtilitySpace(Domain domain,
|
---|
59 | Map<Objective, Evaluator> fEvaluators) {
|
---|
60 | super(domain);
|
---|
61 | this.fEvaluators = fEvaluators;
|
---|
62 | normalizeWeights();
|
---|
63 | }
|
---|
64 |
|
---|
65 | /**
|
---|
66 | * Create new default util space for a given domain.
|
---|
67 | *
|
---|
68 | * @param domain
|
---|
69 | * @param fileName
|
---|
70 | * to read domain from. Set fileName to "" if no file available,
|
---|
71 | * in which case default evaluators are loaded..
|
---|
72 | * @throws IOException
|
---|
73 | * if error occurs, e.g. if domain does not match the util
|
---|
74 | * space, or file not found.
|
---|
75 | */
|
---|
76 | public AdditiveUtilitySpace(Domain domain, String fileName)
|
---|
77 | throws IOException {
|
---|
78 | super(domain);
|
---|
79 | this.fileName = fileName;
|
---|
80 | fEvaluators = new HashMap<Objective, Evaluator>();
|
---|
81 | if (!fileName.equals(""))
|
---|
82 | loadTreeFromFile(fileName);
|
---|
83 | else { // add evaluator to all objectives
|
---|
84 | List<Objective> objectives = domain.getObjectives();
|
---|
85 | for (Objective obj : objectives) {
|
---|
86 | Evaluator eval = defaultEvaluator(obj);
|
---|
87 | fEvaluators.put(obj, eval);
|
---|
88 | }
|
---|
89 |
|
---|
90 | }
|
---|
91 | }
|
---|
92 |
|
---|
93 | /**
|
---|
94 | * Copies the data from another UtilitySpace.
|
---|
95 | *
|
---|
96 | * @param us
|
---|
97 | * utility space to be cloned.
|
---|
98 | */
|
---|
99 | public AdditiveUtilitySpace(AdditiveUtilitySpace us) {
|
---|
100 | super(us.getDomain());
|
---|
101 | fileName = us.getFileName();
|
---|
102 | fEvaluators = new HashMap<Objective, Evaluator>();
|
---|
103 | setReservationValue(us.getReservationValue());
|
---|
104 | // and clone the evaluators
|
---|
105 | for (Objective obj : getDomain().getObjectives()) {
|
---|
106 | Evaluator e = us.getEvaluator(obj.getNumber());
|
---|
107 | if (e != null)
|
---|
108 | fEvaluators.put(obj, e.clone());
|
---|
109 | /*
|
---|
110 | * else incomplete. But that seems allowed. especially, objectives
|
---|
111 | * (the non-Issues) won't generally have an evlauator
|
---|
112 | */
|
---|
113 | }
|
---|
114 | setDiscount(us.getDiscountFactor());
|
---|
115 | }
|
---|
116 |
|
---|
117 | /**************** implements UtilitySpace ****************/
|
---|
118 |
|
---|
119 | @Override
|
---|
120 | public double getUtility(Bid bid) {
|
---|
121 | double utility = 0;
|
---|
122 |
|
---|
123 | Objective root = getDomain().getObjectivesRoot();
|
---|
124 | Enumeration<Objective> issueEnum = root.getPreorderIssueEnumeration();
|
---|
125 | while (issueEnum.hasMoreElements()) {
|
---|
126 | Objective is = issueEnum.nextElement();
|
---|
127 | Evaluator eval = fEvaluators.get(is);
|
---|
128 | if (eval == null) {
|
---|
129 | throw new IllegalArgumentException(
|
---|
130 | "UtilitySpace does not contain evaluator for issue "
|
---|
131 | + is + ". ");
|
---|
132 | }
|
---|
133 |
|
---|
134 | switch (eval.getType()) {
|
---|
135 | case DISCRETE:
|
---|
136 | case INTEGER:
|
---|
137 | case REAL:
|
---|
138 | utility += eval.getWeight()
|
---|
139 | * eval.getEvaluation(this, bid, is.getNumber());
|
---|
140 | break;
|
---|
141 | case OBJECTIVE:
|
---|
142 | // we ignore OBJECTIVE. Not clear what it is and why.
|
---|
143 | break;
|
---|
144 | }
|
---|
145 | }
|
---|
146 | double result = utility;
|
---|
147 | if (result > 1)
|
---|
148 | return 1;
|
---|
149 | return result;
|
---|
150 | }
|
---|
151 |
|
---|
152 | @Override
|
---|
153 | public SimpleElement toXML() throws IOException {
|
---|
154 | SimpleElement root = (getDomain().getObjectivesRoot()).toXML();
|
---|
155 | root = toXMLrecurse(root);
|
---|
156 | SimpleElement rootWrapper = new SimpleElement("utility_space");
|
---|
157 | rootWrapper.addChildElement(root);
|
---|
158 |
|
---|
159 | SimpleElement discountFactor = new SimpleElement("discount_factor");
|
---|
160 | discountFactor.setAttribute("value", getDiscountFactor() + "");
|
---|
161 | rootWrapper.addChildElement(discountFactor);
|
---|
162 |
|
---|
163 | SimpleElement reservationValue = new SimpleElement(RESERVATION);
|
---|
164 | reservationValue.setAttribute("value",
|
---|
165 | getReservationValueUndiscounted() + "");
|
---|
166 | rootWrapper.addChildElement(reservationValue);
|
---|
167 |
|
---|
168 | return rootWrapper;
|
---|
169 | }
|
---|
170 |
|
---|
171 | @Override
|
---|
172 | public String isComplete() {
|
---|
173 | /**
|
---|
174 | * This function *should* check that the domainSubtreeP is a subtree of
|
---|
175 | * the utilSubtreeP, and that all leaf nodes are complete. However
|
---|
176 | * currently we only check that all the leaf nodes are complete, We
|
---|
177 | * don't have the domain template here anymore. so we can only check
|
---|
178 | * that all fields are filled.
|
---|
179 | */
|
---|
180 | List<Issue> issues = getDomain().getIssues();
|
---|
181 | if (issues == null)
|
---|
182 | return "Utility space is not complete, in fact it is empty!";
|
---|
183 | String mess;
|
---|
184 | for (Issue issue : issues) {
|
---|
185 | Evaluator ev = getEvaluator(issue.getNumber());
|
---|
186 | if (ev == null)
|
---|
187 | return "issue " + issue.getName() + " has no evaluator";
|
---|
188 | mess = (ev.isComplete(issue));
|
---|
189 | if (mess != null)
|
---|
190 | return mess;
|
---|
191 | }
|
---|
192 | return null;
|
---|
193 | }
|
---|
194 |
|
---|
195 | @Override
|
---|
196 | public String toString() {
|
---|
197 | String result = "";
|
---|
198 | for (Entry<Objective, Evaluator> entry : fEvaluators.entrySet()) {
|
---|
199 | result += ("Issue weight " + entry.getValue().getWeight() + "\n");
|
---|
200 | result += ("Values " + entry.getKey().getName() + ": "
|
---|
201 | + entry.getValue().toString() + "\n");
|
---|
202 | }
|
---|
203 | return result;
|
---|
204 | }
|
---|
205 |
|
---|
206 | @Override
|
---|
207 | public boolean equals(Object obj) {
|
---|
208 | if (!(obj instanceof AdditiveUtilitySpace))
|
---|
209 | return false;
|
---|
210 | AdditiveUtilitySpace obj2 = (AdditiveUtilitySpace) obj;
|
---|
211 | if (!getDomain().equals(obj2.getDomain()))
|
---|
212 | return false;
|
---|
213 | for (Entry<Objective, Evaluator> entry : fEvaluators.entrySet()) {
|
---|
214 | Evaluator eval2 = obj2.getEvaluator(entry.getKey().getNumber());
|
---|
215 | if (!entry.getValue().equals(eval2)) {
|
---|
216 | return false;
|
---|
217 | }
|
---|
218 | }
|
---|
219 | return true;
|
---|
220 | }
|
---|
221 |
|
---|
222 | @Override
|
---|
223 | public UtilitySpace copy() {
|
---|
224 | return new AdditiveUtilitySpace(this);
|
---|
225 | }
|
---|
226 |
|
---|
227 | /************ Additive-specific functions *****************/
|
---|
228 |
|
---|
229 | /**
|
---|
230 | * @return number of issues. This can only be used for linear utility
|
---|
231 | * functions.
|
---|
232 | */
|
---|
233 | public final int getNrOfEvaluators() {
|
---|
234 | return fEvaluators.size();
|
---|
235 | }
|
---|
236 |
|
---|
237 | /**
|
---|
238 | * Returns the evaluator of an issue for the given index. This can only be
|
---|
239 | * used for linear utility functions.
|
---|
240 | *
|
---|
241 | * @param index
|
---|
242 | * The IDnumber of the Objective or Issue
|
---|
243 | * @return An Evaluator for the Objective or Issue.
|
---|
244 | */
|
---|
245 | public Evaluator getEvaluator(int index) {
|
---|
246 | Objective obj = getDomain().getObjectivesRoot().getObjective(index);
|
---|
247 | if (obj != null) {
|
---|
248 | return fEvaluators.get(obj);
|
---|
249 | } else
|
---|
250 | return null;
|
---|
251 | }
|
---|
252 |
|
---|
253 | /**
|
---|
254 | * @param obj
|
---|
255 | * the objective for which an evaluator is needed
|
---|
256 | * @return evaluator for given objective, or null if no such objective.
|
---|
257 | */
|
---|
258 | public Evaluator getEvaluator(Objective obj) {
|
---|
259 | return fEvaluators.get(obj);
|
---|
260 | }
|
---|
261 |
|
---|
262 | /**
|
---|
263 | * Returns the utility of one issue in the bid. Note that this value is in
|
---|
264 | * the range [0,1] as it is not normalized by the issue weight. Only works
|
---|
265 | * with linear utility spaces.
|
---|
266 | *
|
---|
267 | * @param pIssueIndex
|
---|
268 | * of the issue.
|
---|
269 | * @param bid
|
---|
270 | * @return evaluation of the value of the issue of the given bid.
|
---|
271 | */
|
---|
272 | public final double getEvaluation(int pIssueIndex, Bid bid) {
|
---|
273 | Object lObj = getDomain().getObjectivesRoot().getObjective(pIssueIndex);
|
---|
274 | Evaluator lEvaluator = fEvaluators.get(lObj);
|
---|
275 |
|
---|
276 | return lEvaluator.getEvaluation(this, bid, pIssueIndex);
|
---|
277 | }
|
---|
278 |
|
---|
279 | /**
|
---|
280 | *
|
---|
281 | * @param issueID
|
---|
282 | * The Issue or Objective to get the weight from
|
---|
283 | * @return The weight, or 0 if the objective doesn't exist. Only works with
|
---|
284 | * linear utility spaces.
|
---|
285 | */
|
---|
286 | public double getWeight(int issueID)
|
---|
287 | {
|
---|
288 | Objective ob = getDomain().getObjectivesRoot().getObjective(issueID);
|
---|
289 | if (ob != null) {
|
---|
290 | Evaluator ev = fEvaluators.get(ob);
|
---|
291 | if (ev != null) {
|
---|
292 | return ev.getWeight();
|
---|
293 | }
|
---|
294 | }
|
---|
295 |
|
---|
296 | // System.out.println("Objective of issue #" + issueID + " not found. Weight 0 returned.");
|
---|
297 | return 0.0;
|
---|
298 | }
|
---|
299 |
|
---|
300 | public double getWeight(Objective obj) {
|
---|
301 |
|
---|
302 | Evaluator ev = fEvaluators.get(obj);
|
---|
303 | if (ev != null) {
|
---|
304 | return ev.getWeight();
|
---|
305 | } else
|
---|
306 | return 0.0;
|
---|
307 | }
|
---|
308 |
|
---|
309 | /**
|
---|
310 | * Method used to set the weight of the given objective. Only works if the
|
---|
311 | * objective has been unlockeed.
|
---|
312 | *
|
---|
313 | * @param objective
|
---|
314 | * of which the weights must be set.
|
---|
315 | * @param weight
|
---|
316 | * to which the weight of the objective must be set.
|
---|
317 | * @return the new weight of the issue after normalization.
|
---|
318 | */
|
---|
319 | public double setWeight(Objective objective, double weight) {
|
---|
320 | try {
|
---|
321 | Evaluator ev = fEvaluators.get(objective);
|
---|
322 | double oldWt = ev.getWeight();
|
---|
323 | if (!ev.weightLocked()) {
|
---|
324 | ev.setWeight(weight); // set weight
|
---|
325 | }
|
---|
326 | this.normalizeChildren(objective.getParent());
|
---|
327 | if (this.checkTreeNormalization()) {
|
---|
328 | return fEvaluators.get(objective).getWeight();
|
---|
329 | } else {
|
---|
330 | ev.setWeight(oldWt); // set the old weight back.
|
---|
331 | return fEvaluators.get(objective).getWeight();
|
---|
332 | }
|
---|
333 | } catch (NullPointerException npe) {
|
---|
334 | return -1;
|
---|
335 | }
|
---|
336 | }
|
---|
337 |
|
---|
338 | public void setWeights(List<Issue> issues, double[] weights) {
|
---|
339 | try {
|
---|
340 | for (int i = 0; i < issues.size(); i++) {
|
---|
341 | Evaluator ev = fEvaluators.get(issues.get(i));
|
---|
342 | ev.setWeight(weights[i]); // set weight
|
---|
343 | }
|
---|
344 | } catch (NullPointerException npe) {
|
---|
345 | }
|
---|
346 | }
|
---|
347 |
|
---|
348 | /**
|
---|
349 | * Helper function, evaluator values need to be normalized
|
---|
350 | */
|
---|
351 | public void normalizeWeights() {
|
---|
352 | double sum = 0.0;
|
---|
353 | for (Objective obj : fEvaluators.keySet()) {
|
---|
354 | sum += fEvaluators.get(obj).getWeight();
|
---|
355 | }
|
---|
356 |
|
---|
357 | for (Objective obj : fEvaluators.keySet()) {
|
---|
358 | fEvaluators.get(obj)
|
---|
359 | .setWeight(fEvaluators.get(obj).getWeight() / sum);
|
---|
360 | }
|
---|
361 | }
|
---|
362 |
|
---|
363 | /**
|
---|
364 | * @deprecated Use getObjective
|
---|
365 | *
|
---|
366 | * @param index
|
---|
367 | * The index of the issue to
|
---|
368 | * @return the indexed objective or issue
|
---|
369 | */
|
---|
370 | @Deprecated
|
---|
371 | public final Objective getIssue(int index) {
|
---|
372 | return getDomain().getIssues().get(index);
|
---|
373 | }
|
---|
374 |
|
---|
375 | /**
|
---|
376 | * Sets an [Objective, evaluator] pair. Replaces old evaluator for
|
---|
377 | * objective.
|
---|
378 | *
|
---|
379 | * @param obj
|
---|
380 | * The Objective to attach an Evaluator to.
|
---|
381 | * @param ev
|
---|
382 | * The Evaluator to attach.
|
---|
383 | * @return The given evaluator.
|
---|
384 | */
|
---|
385 | public final Evaluator addEvaluator(Objective obj, Evaluator ev) {
|
---|
386 | fEvaluators.put(obj, ev);
|
---|
387 | return ev;
|
---|
388 | }
|
---|
389 |
|
---|
390 | /**
|
---|
391 | * @return The set with all pairs of evaluators and objectives in this
|
---|
392 | * utility space.
|
---|
393 | */
|
---|
394 | public final Set<Map.Entry<Objective, Evaluator>> getEvaluators() {
|
---|
395 | return fEvaluators.entrySet();
|
---|
396 | }
|
---|
397 |
|
---|
398 | /**
|
---|
399 | * Place a lock on the weight of an objective or issue. Mainly used to guide
|
---|
400 | * the normalization procedure.
|
---|
401 | *
|
---|
402 | * @param obj
|
---|
403 | * The objective or issue that is about to have it's weight
|
---|
404 | * locked.
|
---|
405 | * @return <code>true</code> if successful, <code>false</code> If the
|
---|
406 | * objective doesn't have an evaluator yet.
|
---|
407 | */
|
---|
408 | public final boolean lock(Objective obj) {
|
---|
409 | try {
|
---|
410 | fEvaluators.get(obj).lockWeight();
|
---|
411 | } catch (Exception e) {
|
---|
412 | e.printStackTrace();
|
---|
413 | return false;
|
---|
414 | }
|
---|
415 | return true;
|
---|
416 | }
|
---|
417 |
|
---|
418 | /**
|
---|
419 | * Clear a lock on the weight of an objective or issue. Mainly used to guide
|
---|
420 | * the normalization procedure.
|
---|
421 | *
|
---|
422 | * @param obj
|
---|
423 | * The objective or issue that is having it's lock cleared.
|
---|
424 | * @return <code>true</code> If the lock is cleared, <code>false</code> if
|
---|
425 | * the objective or issue doesn't have an evaluator yet.
|
---|
426 | */
|
---|
427 | public final boolean unlock(Objective obj) {
|
---|
428 | try {
|
---|
429 | fEvaluators.get(obj).unlockWeight();
|
---|
430 | } catch (Exception e) {
|
---|
431 | e.printStackTrace();
|
---|
432 | return false;
|
---|
433 | }
|
---|
434 | return true;
|
---|
435 | }
|
---|
436 |
|
---|
437 | /**
|
---|
438 | * Normalizes the weights of non-locked objectives of the given objective so
|
---|
439 | * that all objective weights they sum up to one.
|
---|
440 | *
|
---|
441 | * @param obj
|
---|
442 | * of which the weights must be normalized.
|
---|
443 | * @return all evaluators using getEvaluators().
|
---|
444 | */
|
---|
445 | public final Set<Map.Entry<Objective, Evaluator>> normalizeChildren(
|
---|
446 | Objective obj) {
|
---|
447 | Enumeration<Objective> childs = obj.children();
|
---|
448 | double RENORMALCORR = 0.05;
|
---|
449 | /*
|
---|
450 | * we add this to all weight sliders to solve the slider-stuck-at-0
|
---|
451 | * problem.
|
---|
452 | */
|
---|
453 | double weightSum = 0;
|
---|
454 | double lockedWeightSum = 0;
|
---|
455 | int freeCount = 0;
|
---|
456 | int lockedCount = 0;
|
---|
457 | while (childs.hasMoreElements()) {
|
---|
458 | Objective tmpObj = childs.nextElement();
|
---|
459 | try {
|
---|
460 | if (!fEvaluators.get(tmpObj).weightLocked()) {
|
---|
461 | weightSum += fEvaluators.get(tmpObj).getWeight();
|
---|
462 | freeCount++;
|
---|
463 | } else {
|
---|
464 | lockedWeightSum += fEvaluators.get(tmpObj).getWeight();
|
---|
465 | lockedCount++;
|
---|
466 | }
|
---|
467 | } catch (Exception e) {
|
---|
468 |
|
---|
469 | // do nothing, we can encounter Objectives/issues without
|
---|
470 | // Evaluators.
|
---|
471 | }
|
---|
472 | }
|
---|
473 | if (freeCount + lockedCount == 1) {
|
---|
474 | Enumeration<Objective> singleChild = obj.children();
|
---|
475 | while (singleChild.hasMoreElements()) {
|
---|
476 | Objective tmpObj = singleChild.nextElement();
|
---|
477 | fEvaluators.get(tmpObj).setWeight(1.0);
|
---|
478 | }
|
---|
479 | }
|
---|
480 |
|
---|
481 | if (freeCount > 1) {
|
---|
482 | Enumeration<Objective> normalChilds = obj.children();
|
---|
483 | while (normalChilds.hasMoreElements()) {
|
---|
484 | Objective tmpObj = normalChilds.nextElement();
|
---|
485 | double diff = (lockedWeightSum + weightSum) - 1.0;
|
---|
486 | // because of RENORMALCORR, total weight will get larger.
|
---|
487 | double correctedWeightSum = weightSum
|
---|
488 | + RENORMALCORR * freeCount;
|
---|
489 | try {
|
---|
490 |
|
---|
491 | if (!fEvaluators.get(tmpObj).weightLocked()) {
|
---|
492 | double currentWeight = fEvaluators.get(tmpObj)
|
---|
493 | .getWeight();
|
---|
494 | double newWeight = currentWeight
|
---|
495 | - (diff * (currentWeight + RENORMALCORR)
|
---|
496 | / correctedWeightSum);
|
---|
497 | if (newWeight < 0) {
|
---|
498 | newWeight = 0;
|
---|
499 | }
|
---|
500 | fEvaluators.get(tmpObj).setWeight(newWeight);
|
---|
501 | }
|
---|
502 | } catch (Exception e) {
|
---|
503 | // do nothing, we can encounter Objectives/issues without
|
---|
504 | // Evaluators.
|
---|
505 | }
|
---|
506 |
|
---|
507 | }
|
---|
508 |
|
---|
509 | }
|
---|
510 |
|
---|
511 | return getEvaluators();
|
---|
512 | }
|
---|
513 |
|
---|
514 | /****************** private internal stuff *******************/
|
---|
515 |
|
---|
516 | /**
|
---|
517 | * @param filename
|
---|
518 | * The name of the xml file to parse.
|
---|
519 | * @throws IOException
|
---|
520 | * if error occurs, e.g. file not found
|
---|
521 | */
|
---|
522 | protected boolean loadTreeFromFile(String filename) throws IOException {
|
---|
523 | SimpleDOMParser parser = new SimpleDOMParser();
|
---|
524 | BufferedReader file = new BufferedReader(
|
---|
525 | new FileReader(new File(filename)));
|
---|
526 | SimpleElement root = parser.parse(file);
|
---|
527 | return loadTreeRecursive(root);
|
---|
528 | }
|
---|
529 |
|
---|
530 | /**
|
---|
531 | * Loads the weights and issues for the evaluators.
|
---|
532 | *
|
---|
533 | * @param root
|
---|
534 | * The current root of the XML structure.
|
---|
535 | * @return true iff error occured
|
---|
536 | */
|
---|
537 | protected boolean loadTreeRecursive(SimpleElement currentRoot) {
|
---|
538 | int nrOfWeights = 0;
|
---|
539 |
|
---|
540 | int index;
|
---|
541 | // load reservation value
|
---|
542 | try {
|
---|
543 | if ((currentRoot.getChildByTagName(RESERVATION) != null)
|
---|
544 | && (currentRoot
|
---|
545 | .getChildByTagName(RESERVATION).length > 0)) {
|
---|
546 | SimpleElement xmlReservation = (SimpleElement) (currentRoot
|
---|
547 | .getChildByTagName(RESERVATION)[0]);
|
---|
548 | setReservationValue(
|
---|
549 | Double.valueOf(xmlReservation.getAttribute("value")));
|
---|
550 | }
|
---|
551 | } catch (Exception e) {
|
---|
552 | System.out.println("Utility space has no reservation value");
|
---|
553 | }
|
---|
554 | // load discount factor
|
---|
555 | try {
|
---|
556 | if ((currentRoot.getChildByTagName("discount_factor") != null)
|
---|
557 | && (currentRoot
|
---|
558 | .getChildByTagName("discount_factor").length > 0)) {
|
---|
559 | SimpleElement xmlReservation = (SimpleElement) (currentRoot
|
---|
560 | .getChildByTagName("discount_factor")[0]);
|
---|
561 | double df = Double
|
---|
562 | .parseDouble(xmlReservation.getAttribute("value"));
|
---|
563 | setDiscount(validateDiscount(df));
|
---|
564 | }
|
---|
565 | } catch (Exception e) {
|
---|
566 | System.out.println("Utility space has no discount factor;");
|
---|
567 | }
|
---|
568 |
|
---|
569 | Vector<Evaluator> tmpEvaluator = new Vector<Evaluator>();
|
---|
570 | /*
|
---|
571 | * tmp vector with all Evaluators at this level. Used to normalize
|
---|
572 | * weigths.
|
---|
573 | */
|
---|
574 | EVALUATORTYPE evalType;
|
---|
575 | String type, etype;
|
---|
576 | Evaluator lEvaluator = null;
|
---|
577 |
|
---|
578 | // Get the weights of the current children
|
---|
579 | Object[] xml_weights = currentRoot.getChildByTagName("weight");
|
---|
580 | nrOfWeights = xml_weights.length; // assuming each
|
---|
581 | HashMap<Integer, Double> tmpWeights = new HashMap<Integer, Double>();
|
---|
582 | for (int i = 0; i < nrOfWeights; i++) {
|
---|
583 | index = Integer.valueOf(
|
---|
584 | ((SimpleElement) xml_weights[i]).getAttribute("index"));
|
---|
585 | Double dval = Double.parseDouble(
|
---|
586 | ((SimpleElement) xml_weights[i]).getAttribute("value"));
|
---|
587 | tmpWeights.put(index, dval);
|
---|
588 | }
|
---|
589 |
|
---|
590 | // Collect evaluations for each of the issue values from file.
|
---|
591 | // Assumption: Discrete-valued issues.
|
---|
592 | Object[] xml_issues = currentRoot.getChildByTagName("issue");
|
---|
593 | Object[] xml_objectives = currentRoot.getChildByTagName("objective");
|
---|
594 | Object[] xml_obj_issues = new Object[xml_issues.length
|
---|
595 | + xml_objectives.length];
|
---|
596 | int i_ind;
|
---|
597 | for (i_ind = 0; i_ind < xml_issues.length; i_ind++) {
|
---|
598 | xml_obj_issues[i_ind] = xml_issues[i_ind];
|
---|
599 | }
|
---|
600 | for (int o_ind = 0; (o_ind + i_ind) < xml_obj_issues.length; o_ind++) {
|
---|
601 | xml_obj_issues[(o_ind + i_ind)] = xml_objectives[o_ind];
|
---|
602 | }
|
---|
603 |
|
---|
604 | for (int i = 0; i < xml_obj_issues.length; i++) {
|
---|
605 | index = Integer.valueOf(
|
---|
606 | ((SimpleElement) xml_obj_issues[i]).getAttribute("index"));
|
---|
607 | type = ((SimpleElement) xml_obj_issues[i]).getAttribute("type");
|
---|
608 | etype = ((SimpleElement) xml_obj_issues[i]).getAttribute("etype");
|
---|
609 | if (type == null) { // No value type specified.
|
---|
610 | evalType = EVALUATORTYPE.DISCRETE;
|
---|
611 | } else if (type.equals(etype)) {
|
---|
612 | evalType = EVALUATORTYPE.convertToType(type);
|
---|
613 | } else if (type != null && etype == null) {
|
---|
614 | evalType = EVALUATORTYPE.convertToType(type);
|
---|
615 | } else {
|
---|
616 | System.out.println(
|
---|
617 | "Conflicting value types specified for evaluators in utility template file.");
|
---|
618 | evalType = EVALUATORTYPE.convertToType(type);
|
---|
619 | }
|
---|
620 | if (tmpWeights.get(index) != null) {
|
---|
621 | switch (evalType) {
|
---|
622 | case DISCRETE:
|
---|
623 | lEvaluator = new EvaluatorDiscrete();
|
---|
624 | break;
|
---|
625 | case INTEGER:
|
---|
626 | lEvaluator = new EvaluatorInteger();
|
---|
627 | break;
|
---|
628 | case REAL:
|
---|
629 | lEvaluator = new EvaluatorReal();
|
---|
630 | break;
|
---|
631 | case OBJECTIVE:
|
---|
632 | lEvaluator = new EvaluatorObjective();
|
---|
633 | break;
|
---|
634 | }
|
---|
635 | lEvaluator.loadFromXML((SimpleElement) (xml_obj_issues[i]));
|
---|
636 |
|
---|
637 | try {
|
---|
638 | fEvaluators.put(
|
---|
639 | getDomain().getObjectivesRoot().getObjective(index),
|
---|
640 | lEvaluator);
|
---|
641 | /*
|
---|
642 | * get the Objective or Issue.
|
---|
643 | */
|
---|
644 | } catch (Exception e) {
|
---|
645 | System.out.println("Domain-utilityspace mismatch");
|
---|
646 | e.printStackTrace();
|
---|
647 | return false;
|
---|
648 | }
|
---|
649 | }
|
---|
650 | try {
|
---|
651 | if (nrOfWeights != 0) {
|
---|
652 | double tmpdwt = tmpWeights.get(index).doubleValue();
|
---|
653 | Objective tmpob = getDomain().getObjectivesRoot()
|
---|
654 | .getObjective(index);
|
---|
655 | fEvaluators.get(tmpob).setWeight(tmpdwt);
|
---|
656 | }
|
---|
657 | } catch (Exception e) {
|
---|
658 | System.out.println(
|
---|
659 | "Evaluator-weight mismatch or no weight for this issue or objective.");
|
---|
660 | }
|
---|
661 | tmpEvaluator.add(lEvaluator); // for normalisation purposes.
|
---|
662 | }
|
---|
663 |
|
---|
664 | // Recurse over all children:
|
---|
665 | boolean returnval = false;
|
---|
666 | Object[] objArray = currentRoot.getChildElements();
|
---|
667 | for (int i = 0; i < objArray.length; i++)
|
---|
668 | returnval = loadTreeRecursive((SimpleElement) objArray[i]);
|
---|
669 | return returnval;
|
---|
670 | }
|
---|
671 |
|
---|
672 | /**
|
---|
673 | * Adds the utilities (weights) from this utility space to a given domain.
|
---|
674 | * It modifies the currentLevel so the return value is superfluous.
|
---|
675 | *
|
---|
676 | * @param currentLevel
|
---|
677 | * is pointer to a XML tree describing the domain.
|
---|
678 | * @return XML tree with the weights. NOTE: currentLevel is modified anyway.
|
---|
679 | */
|
---|
680 | private SimpleElement toXMLrecurse(SimpleElement currentLevel) {
|
---|
681 | // go through all tags.
|
---|
682 |
|
---|
683 | Object[] Objectives = currentLevel.getChildByTagName("objective");
|
---|
684 |
|
---|
685 | for (int objInd = 0; objInd < Objectives.length; objInd++) {
|
---|
686 | SimpleElement currentChild = (SimpleElement) Objectives[objInd];
|
---|
687 | int childIndex = Integer
|
---|
688 | .valueOf(currentChild.getAttribute("index"));
|
---|
689 | try {
|
---|
690 | Evaluator ev = fEvaluators.get(getDomain().getObjectivesRoot()
|
---|
691 | .getObjective(childIndex));
|
---|
692 | SimpleElement currentChildWeight = new SimpleElement("weight");
|
---|
693 | currentChildWeight.setAttribute("index", "" + childIndex);
|
---|
694 | currentChildWeight.setAttribute("value", "" + ev.getWeight());
|
---|
695 | currentLevel.addChildElement(currentChildWeight);
|
---|
696 | } catch (Exception e) {
|
---|
697 | // do nothing, not every node has an evaluator.
|
---|
698 | }
|
---|
699 | currentChild = toXMLrecurse(currentChild);
|
---|
700 | }
|
---|
701 |
|
---|
702 | Object[] Issues = currentLevel.getChildByTagName("issue");
|
---|
703 |
|
---|
704 | for (int issInd = 0; issInd < Issues.length; issInd++) {
|
---|
705 | SimpleElement issueL = (SimpleElement) Issues[issInd];
|
---|
706 |
|
---|
707 | // set the weight
|
---|
708 | int childIndex = Integer.valueOf(issueL.getAttribute("index"));
|
---|
709 | Objective tmpEvObj = getDomain().getObjectivesRoot()
|
---|
710 | .getObjective(childIndex);
|
---|
711 | try {
|
---|
712 |
|
---|
713 | Evaluator ev = fEvaluators.get(tmpEvObj);
|
---|
714 |
|
---|
715 | SimpleElement currentChildWeight = new SimpleElement("weight");
|
---|
716 | currentChildWeight.setAttribute("index", "" + childIndex);
|
---|
717 | currentChildWeight.setAttribute("value", "" + ev.getWeight());
|
---|
718 | currentLevel.addChildElement(currentChildWeight);
|
---|
719 |
|
---|
720 | String evtype_str = issueL.getAttribute("etype");
|
---|
721 | EVALUATORTYPE evtype = EVALUATORTYPE.convertToType(evtype_str);
|
---|
722 | switch (evtype) {
|
---|
723 | case DISCRETE:
|
---|
724 | // fill this issue with the relevant weights to items.
|
---|
725 | Object[] items = issueL.getChildByTagName("item");
|
---|
726 | for (int itemInd = 0; itemInd < items.length; itemInd++) {
|
---|
727 | IssueDiscrete theIssue = (IssueDiscrete) getDomain()
|
---|
728 | .getObjectivesRoot().getObjective(childIndex);
|
---|
729 |
|
---|
730 | EvaluatorDiscrete dev = (EvaluatorDiscrete) ev;
|
---|
731 | Double eval = dev
|
---|
732 | .getDoubleValue(theIssue.getValue(itemInd));
|
---|
733 | ((SimpleElement) items[itemInd])
|
---|
734 | .setAttribute("evaluation", "" + eval);
|
---|
735 | }
|
---|
736 | break;
|
---|
737 | case INTEGER:
|
---|
738 | EvaluatorInteger iev = (EvaluatorInteger) ev;
|
---|
739 | issueL.setAttribute("lowerbound", "" + iev.getLowerBound());
|
---|
740 | issueL.setAttribute("upperbound", "" + iev.getUpperBound());
|
---|
741 |
|
---|
742 | SimpleElement thisIntEval = new SimpleElement("evaluator");
|
---|
743 | thisIntEval.setAttribute("ftype", "linear");
|
---|
744 | thisIntEval.setAttribute("slope", "" + iev.getSlope());
|
---|
745 | thisIntEval.setAttribute("offset", "" + iev.getOffset());
|
---|
746 | issueL.addChildElement(thisIntEval);
|
---|
747 | break;
|
---|
748 | case REAL:
|
---|
749 | EvaluatorReal rev = (EvaluatorReal) ev;
|
---|
750 | SimpleElement thisRealEval = new SimpleElement("evaluator");
|
---|
751 | EVALFUNCTYPE revtype = rev.getFuncType();
|
---|
752 | if (revtype == EVALFUNCTYPE.LINEAR) {
|
---|
753 | thisRealEval.setAttribute("ftype", "linear");
|
---|
754 | thisRealEval.setAttribute("parameter1",
|
---|
755 | "" + rev.getLinearParam());
|
---|
756 | } else if (revtype == EVALFUNCTYPE.CONSTANT) {
|
---|
757 | thisRealEval.setAttribute("ftype", "constant");
|
---|
758 | thisRealEval.setAttribute("parameter0",
|
---|
759 | "" + rev.getConstantParam());
|
---|
760 | }
|
---|
761 | issueL.addChildElement(thisRealEval);
|
---|
762 | break;
|
---|
763 | }
|
---|
764 | } catch (Exception e) {
|
---|
765 | // do nothing, it could be that this objective/issue doesn't
|
---|
766 | // have an evaluator yet.
|
---|
767 | }
|
---|
768 |
|
---|
769 | }
|
---|
770 |
|
---|
771 | return currentLevel;
|
---|
772 | }
|
---|
773 |
|
---|
774 | /**
|
---|
775 | * createFrom a default evaluator for a given Objective. This function is
|
---|
776 | * placed here, and not in Objective, because the Objectives should not be
|
---|
777 | * loaded with utility space functionality. The price we pay for that is
|
---|
778 | * that we now have an ugly switch inside the code, losing some modularity.
|
---|
779 | *
|
---|
780 | * @param obj
|
---|
781 | * the objective to createFrom an evaluator for
|
---|
782 | * @return the default evaluator
|
---|
783 | */
|
---|
784 | private Evaluator defaultEvaluator(Objective obj) {
|
---|
785 | if (obj.isObjective())
|
---|
786 | return new EvaluatorObjective();
|
---|
787 | // if not an objective then it must be an issue.
|
---|
788 | switch (((Issue) obj).getType()) {
|
---|
789 | case DISCRETE:
|
---|
790 | return new EvaluatorDiscrete();
|
---|
791 | case INTEGER:
|
---|
792 | return new EvaluatorInteger();
|
---|
793 | case REAL:
|
---|
794 | return new EvaluatorReal();
|
---|
795 | default:
|
---|
796 | System.out.println("INTERNAL ERROR: issue of type "
|
---|
797 | + ((Issue) obj).getType() + "has no default evaluator");
|
---|
798 | }
|
---|
799 | return null;
|
---|
800 | }
|
---|
801 |
|
---|
802 | /**
|
---|
803 | * Checks the normalization throughout the tree. Will eventually replace
|
---|
804 | * checkNormalization
|
---|
805 | *
|
---|
806 | * @return true if the weigths are indeed normalized, false if they aren't.
|
---|
807 | */
|
---|
808 | private boolean checkTreeNormalization() {
|
---|
809 | return checkTreeNormalizationRecursive(getDomain().getObjectivesRoot());
|
---|
810 | }
|
---|
811 |
|
---|
812 | /**
|
---|
813 | * Private helper function to check the normalisation throughout the tree.
|
---|
814 | *
|
---|
815 | * @param currentRoot
|
---|
816 | * The current parent node of the subtree we are going to check
|
---|
817 | * @return True if the weights are indeed normalized, false if they aren't.
|
---|
818 | */
|
---|
819 | private boolean checkTreeNormalizationRecursive(Objective currentRoot) {
|
---|
820 | boolean normalised = true;
|
---|
821 | double lSum = 0;
|
---|
822 |
|
---|
823 | Enumeration<Objective> children = currentRoot.children();
|
---|
824 |
|
---|
825 | while (children.hasMoreElements() && normalised) {
|
---|
826 |
|
---|
827 | Objective tmpObj = children.nextElement();
|
---|
828 | lSum += (fEvaluators.get(tmpObj)).getWeight();
|
---|
829 |
|
---|
830 | }
|
---|
831 | return (normalised && lSum > .98 && lSum < 1.02);
|
---|
832 | }
|
---|
833 |
|
---|
834 | public Map<Objective, Evaluator> getfEvaluators() {
|
---|
835 | return fEvaluators;
|
---|
836 | }
|
---|
837 | }
|
---|