source: domaineditor/src/main/java/geniusweb/domaineditor/model/profile/LinearAdditiveUtilitySpaceModel.java@ 52

Last change on this file since 52 was 52, checked in by ruud, 14 months ago

Fixed small issues in domaineditor.

File size: 8.6 KB
Line 
1package geniusweb.domaineditor.model.profile;
2
3import java.math.BigDecimal;
4import java.math.RoundingMode;
5import java.util.Collections;
6import java.util.HashMap;
7import java.util.Map;
8import java.util.stream.Collectors;
9
10import geniusweb.domaineditor.model.BidModel;
11import geniusweb.domaineditor.model.DiscreteValueSetModel;
12import geniusweb.domaineditor.model.DomainModel;
13import geniusweb.domaineditor.model.NumberValueSetModel;
14import geniusweb.domaineditor.model.SimpleStringModel;
15import geniusweb.domaineditor.model.ValueSetModel;
16import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace;
17import geniusweb.profile.utilityspace.ValueSetUtilities;
18import tudelft.utilities.listener.DefaultListenable;
19import tudelft.utilities.logging.Reporter;
20import tudelft.utilities.mvc.model.ListModel;
21import tudelft.utilities.mvc.model.MapFromKeys;
22import tudelft.utilities.mvc.model.MapModel;
23import tudelft.utilities.mvc.model.NumberModel;
24import tudelft.utilities.mvc.model.RestrictedNumberModel;
25import tudelft.utilities.mvc.model.StringModel;
26import tudelft.utilities.mvc.model.TypedModel;
27import tudelft.utilities.mvc.model.events.Event;
28import tudelft.utilities.mvc.panels.PopupReporter;
29
30/**
31 * Model containing a {@link LinearAdditiveUtilitySpace}
32 */
33public class LinearAdditiveUtilitySpaceModel extends DefaultListenable<Event>
34 implements ProfileModel, TypedModel<LinearAdditiveUtilitySpace> {
35 private final SimpleStringModel name;
36 /**
37 * the key is the issue, the value is the valuesetutilities for this issue.
38 * Should be immutable so do not return direct access to this field.
39 */
40 private final MapModel<StringModel, ValueSetUtilitiesModel> issueUtilities;
41
42 /**
43 * The key is the issue, the value is the weight of the utilities for that
44 * issue (utility as returned from the ValueSetUtilities for that issue).
45 */
46 private final MapModel<StringModel, RestrictedNumberModel> issueWeights;
47
48 private final DomainModel domain;
49
50 private final BidModel reservationBid;
51 private Reporter log;
52
53 /**
54 * @param name the name for the profile.
55 * @param issueUtilities a map of issue-values. Issues are
56 * {@link StringModel}.
57 * @param weights the issue weights. RestrictedNumberModel with
58 * minimum 0 and max 1. The set of keys (issue
59 * {@link StringModel}) must equal the issueUtilities
60 * keyMap
61 * @param domain the {@link DomainModel}. Issues in the domain must
62 * equal to issueUtities keys.
63 * @param reservationBid the {#link BidModel} holding the reservation bid
64 * @param log the {@link Reporter}
65 */
66 public LinearAdditiveUtilitySpaceModel(SimpleStringModel name,
67 MapModel<StringModel, ValueSetUtilitiesModel> issueUtilities,
68 MapModel<StringModel, RestrictedNumberModel> weights,
69 DomainModel domain, BidModel reservationBid, Reporter log) {
70 if (!domain.getIssues().getKeys().equals(issueUtilities.getKeys()))
71 throw new IllegalArgumentException(
72 "issues in domain and isseuUtilities are not equal");
73 if (!domain.getIssues().getKeys().equals(weights.getKeys()))
74 throw new IllegalArgumentException(
75 "issues in domain and weight map are not equal");
76 this.name = name;
77 this.issueUtilities = issueUtilities;
78 this.issueWeights = weights;
79 this.domain = domain;
80 this.reservationBid = reservationBid;
81 this.log = log;
82 }
83
84 protected static final BigDecimal N05 = new BigDecimal("0.5");
85 // dummylog is for events that should never happen.
86 private static Reporter dummylog = new PopupReporter(null);
87 // we should never allow editing of these constants.
88 protected static final NumberModel CONSTANT0 = new NumberModel(
89 BigDecimal.ZERO, dummylog);
90 protected static final NumberModel CONSTANT1 = new NumberModel(
91 BigDecimal.ONE, dummylog);
92
93 public LinearAdditiveUtilitySpaceModel(DomainModel domain,
94 final Reporter log) {
95 this(new SimpleStringModel("profilename", log),
96 createUtilsMap(domain, log), createWeightMap(domain, log),
97 domain, new BidModel(domain.getIssues(), log), log);
98 }
99
100 /**
101 * creates a initial weight map for domain
102 *
103 * @param domain2
104 * @return MapModel with issue-weight pairs. Map keys are issues from the
105 * domain.
106 */
107 private static MapModel<StringModel, RestrictedNumberModel> createWeightMap(
108 final DomainModel domain2, final Reporter log) {
109 return new MapFromKeys<StringModel, RestrictedNumberModel>(
110 domain2.getIssues().getKeys(), log, true) {
111
112 @Override
113 public RestrictedNumberModel create(StringModel key) {
114 return new RestrictedNumberModel(N05, CONSTANT0, CONSTANT1,
115 log);
116 }
117
118 @Override
119 public String getColumnName(int n) {
120 return n == 0 ? "issue" : "weight";
121 }
122
123 };
124 }
125
126 private static MapModel<StringModel, ValueSetUtilitiesModel> createUtilsMap(
127 final DomainModel domain2, final Reporter log) {
128 // do not retain old values, issues may be removed and replaced with
129 // different type
130 return new MapFromKeys<StringModel, ValueSetUtilitiesModel>(
131 domain2.getIssues().getKeys(), log, false) {
132 @Override
133 public ValueSetUtilitiesModel create(StringModel key) {
134 ValueSetModel val = domain2.getIssues().getValue(key);
135 if (val instanceof DiscreteValueSetModel)
136 return new DiscreteValueSetUtilitiesModel(
137 (DiscreteValueSetModel) val, log);
138 if (val instanceof NumberValueSetModel)
139 return new NumberValueSetUtilitiesModel(
140 (NumberValueSetModel) val, log);
141 throw new RuntimeException(
142 "Unsupported type " + val + "for key" + key);
143 }
144
145 @Override
146 public String getColumnName(int n) {
147 return n == 0 ? "value" : "utility";
148 }
149
150 };
151 }
152
153 /**
154 *
155 * @return the {@link DomainModel}
156 */
157 public DomainModel getDomain() {
158 return domain;
159 }
160
161 /**
162 *
163 * @return {@link StringModel} containing the domain name
164 */
165 public StringModel getName() {
166 return name;
167 }
168
169 /**
170 *
171 * @return {@link BidModel} containing the reservation bid
172 */
173 public BidModel getReservationBid() {
174 return reservationBid;
175 }
176
177 /**
178 * @return the weights map, but all weights are NOT NORMALIZED.
179 */
180 public MapModel<StringModel, RestrictedNumberModel> getWeights() {
181 return issueWeights;
182 }
183
184 /**
185 *
186 * @return the issue utilities map
187 */
188 public MapModel<StringModel, ValueSetUtilitiesModel> getIssueUtilities() {
189 return issueUtilities;
190 }
191
192 @Override
193 public LinearAdditiveUtilitySpace getCurrentValue()
194 throws IllegalStateException {
195 return new LinearAdditiveUtilitySpace(domain.getCurrentValue(),
196 name.getValue(), getUtilitiesMap(), getNormalizedWeightMap(),
197 reservationBid.getCurrentValue());
198 }
199
200 /**
201 *
202 * @return a Utilities map as contained in the current settings
203 */
204 private Map<String, ValueSetUtilities> getUtilitiesMap() {
205 Map<String, ValueSetUtilities> map = new HashMap<>();
206 for (int n = 0; n < issueUtilities.getKeys().getSize(); n++) {
207 StringModel issuem = issueUtilities.getKeys().get(n);
208 map.put(issuem.getValue(),
209 issueUtilities.getValue(issuem).getCurrentValue());
210 }
211 return map;
212 }
213
214 @Override
215 public void setCurrentValue(LinearAdditiveUtilitySpace obj)
216 throws IllegalArgumentException {
217 LinearAdditiveUtilitySpace space = obj;
218 name.setValue(space.getName());
219 domain.setCurrentValue(space.getDomain());
220 reservationBid.setCurrentValue(space.getReservationBid());
221
222 ListModel<StringModel> issuesm = domain.getIssues().getKeys();
223 for (int n = 0; n < issuesm.getSize(); n++) {
224 StringModel issuem = issuesm.get(n);
225 String issue = issuem.getValue();
226 issueWeights.getValue(issuem).setValue(space.getWeight(issue));
227 issueUtilities.getValue(issuem)
228 .setCurrentValue(space.getUtilities().get(issue));
229 }
230
231 }
232
233 /**
234 *
235 * @return normalized weight map
236 */
237 protected Map<String, BigDecimal> getNormalizedWeightMap() {
238 Map<String, BigDecimal> weights = new HashMap<>();
239 for (int n = 0; n < issueWeights.getKeys().getSize(); n++) {
240 StringModel key = issueWeights.getKeys().get(n);
241 weights.put(key.getValue(), issueWeights.getValue(key).getValue());
242 }
243
244 BigDecimal sum = weights.values().stream().reduce(BigDecimal.ZERO,
245 BigDecimal::add);
246 // weights1 may still contain rounding errors
247 Map<String, BigDecimal> normap = weights.entrySet().stream()
248 .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()
249 .divide(sum, 6, RoundingMode.HALF_UP)));
250 BigDecimal err = normap.values().stream()
251 .reduce(BigDecimal.ZERO, BigDecimal::add)
252 .subtract(BigDecimal.ONE);
253 // just subtract err from the biggest value
254 String maxkey = Collections
255 .max(normap.entrySet(), Map.Entry.comparingByValue()).getKey();
256 normap.put(maxkey, normap.get(maxkey).subtract(err));
257 return normap;
258 }
259
260}
Note: See TracBrowser for help on using the repository browser.