1 | package agents.anac.y2015.AgentHP;
|
---|
2 |
|
---|
3 | import java.util.HashMap;
|
---|
4 | import java.util.List;
|
---|
5 |
|
---|
6 | import genius.core.AgentID;
|
---|
7 | import genius.core.Bid;
|
---|
8 | import genius.core.actions.Accept;
|
---|
9 | import genius.core.actions.Action;
|
---|
10 | import genius.core.actions.ActionWithBid;
|
---|
11 | import genius.core.actions.Inform;
|
---|
12 | import genius.core.actions.Offer;
|
---|
13 | import genius.core.issue.Issue;
|
---|
14 | import genius.core.issue.IssueDiscrete;
|
---|
15 | import genius.core.issue.ValueDiscrete;
|
---|
16 | import genius.core.parties.AbstractNegotiationParty;
|
---|
17 | import genius.core.parties.NegotiationInfo;
|
---|
18 | import genius.core.utility.AdditiveUtilitySpace;
|
---|
19 | import genius.core.utility.EvaluatorDiscrete;
|
---|
20 |
|
---|
21 | /**
|
---|
22 | * This is your negotiation party.
|
---|
23 | */
|
---|
24 | public class AgentHP extends AbstractNegotiationParty {
|
---|
25 |
|
---|
26 | // 提案保存数最大
|
---|
27 | private int logMax = 500;
|
---|
28 |
|
---|
29 | /* ここまではコンストラクタ内で初期化必要なし */
|
---|
30 |
|
---|
31 | // 交渉参加者合計人数
|
---|
32 | private int partyNum = 0;
|
---|
33 |
|
---|
34 | // 論点数
|
---|
35 | private int issueNum = 0;
|
---|
36 |
|
---|
37 | // 判断対象の提案
|
---|
38 | private Bid targetBid = null;
|
---|
39 |
|
---|
40 | // 予約値
|
---|
41 | private double reservationValue = 0.0;
|
---|
42 |
|
---|
43 | // 効用値の下限値(時間で変化)
|
---|
44 | private double underlimitUtility = 1.0;
|
---|
45 |
|
---|
46 | // 現在の提案保存数
|
---|
47 | private int logNum[];
|
---|
48 |
|
---|
49 | // 提案ログの論点ごとの項目出現数格納Hash用テンプレ
|
---|
50 | private HashMap<String, Integer>[] TemplateLogBidCountHash;
|
---|
51 |
|
---|
52 | // 提案ログから作成した予測効用空間用テンプレ
|
---|
53 | private HashMap<String, Double>[] TemplateLogBidValueHash;
|
---|
54 |
|
---|
55 | // 提案ログ保存ハッシュ
|
---|
56 | private Bid[][] logBid;
|
---|
57 |
|
---|
58 | // 提案ログの論点ごとの項目出現数格納Hash
|
---|
59 | private HashMap<String, Integer>[][] logBidCountHash;
|
---|
60 |
|
---|
61 | // 提案ログから作成した予測効用空間格納Hash
|
---|
62 | private HashMap<String, Double>[][] logBidValueHash;
|
---|
63 |
|
---|
64 | // 参加者名と配列要素数の対応格納Hash
|
---|
65 | private HashMap<String, Integer> participantList;
|
---|
66 |
|
---|
67 | // 一対比較段数
|
---|
68 | private int compareSize = 0;
|
---|
69 |
|
---|
70 | // 一対比較結果用配列
|
---|
71 | private double compareResultArray[];
|
---|
72 |
|
---|
73 | // 予測した相手の論点ごとの重み格納用配列
|
---|
74 | private double issueWeightArray[][];
|
---|
75 |
|
---|
76 | // 予測の更新回数
|
---|
77 | private int estimateCount[];
|
---|
78 |
|
---|
79 | // 効用空間合算時の自分の重み
|
---|
80 | private double weightUtilSpace = 0.0;
|
---|
81 |
|
---|
82 | // 合算効用空間Hash
|
---|
83 | private HashMap<String, Double>[] addupValueHash;
|
---|
84 |
|
---|
85 | // 合算論点間重み配列
|
---|
86 | private double addupWeightArray[];
|
---|
87 |
|
---|
88 | // 直近の合算タイミング
|
---|
89 | private int prevAddupTiming = 0;
|
---|
90 |
|
---|
91 | // 相手の提案の自分にとっての効用値合計&効用値2乗合計
|
---|
92 | private double sumUtility[];
|
---|
93 | private double sumUtility2[];
|
---|
94 |
|
---|
95 | // 承諾確率計算用
|
---|
96 | private double estimateMax = 0.0;
|
---|
97 | private double utilityBarometer = 0.0;
|
---|
98 |
|
---|
99 | /**
|
---|
100 | * コンストラクタ(geniusから呼び出し)
|
---|
101 | *
|
---|
102 | * @param utilitySpace
|
---|
103 | * 自分の効用空間
|
---|
104 | * @param deadlines
|
---|
105 | * 交渉の制限時間
|
---|
106 | * @param timeline
|
---|
107 | * 経過時間(0~1)
|
---|
108 | * @param randomSeed
|
---|
109 | * 乱数用シード
|
---|
110 | */
|
---|
111 | @Override
|
---|
112 | public void init(NegotiationInfo info) {
|
---|
113 |
|
---|
114 | // 親クラスコンストラクタ
|
---|
115 | super.init(info);
|
---|
116 |
|
---|
117 | // 予約値取得
|
---|
118 | reservationValue = utilitySpace.getReservationValueUndiscounted();
|
---|
119 |
|
---|
120 | // 初期化
|
---|
121 | partyNum = 0;
|
---|
122 | issueNum = 0;
|
---|
123 | targetBid = null;
|
---|
124 | underlimitUtility = 0.0;
|
---|
125 | logNum = null;
|
---|
126 | TemplateLogBidCountHash = null;
|
---|
127 | TemplateLogBidValueHash = null;
|
---|
128 | logBid = null;
|
---|
129 | logBidCountHash = null;
|
---|
130 | logBidValueHash = null;
|
---|
131 | participantList = null;
|
---|
132 | compareSize = 0;
|
---|
133 | compareResultArray = null;
|
---|
134 | issueWeightArray = null;
|
---|
135 | estimateCount = null;
|
---|
136 | weightUtilSpace = 0.0;
|
---|
137 | addupValueHash = null;
|
---|
138 | addupWeightArray = null;
|
---|
139 | prevAddupTiming = 0;
|
---|
140 | sumUtility = null;
|
---|
141 | sumUtility2 = null;
|
---|
142 | estimateMax = 0.0;
|
---|
143 | utilityBarometer = 0.0;
|
---|
144 |
|
---|
145 | // 論点数取得
|
---|
146 | issueNum = utilitySpace.getDomain().getIssues().size();
|
---|
147 |
|
---|
148 | // 提案保存Hashテンプレ&合算効用空間保存Hash作成
|
---|
149 | TemplateLogBidCountHash = new HashMap[issueNum];
|
---|
150 | TemplateLogBidValueHash = new HashMap[issueNum];
|
---|
151 | addupValueHash = new HashMap[issueNum];
|
---|
152 | for (Issue tmp : utilitySpace.getDomain().getIssues()) {
|
---|
153 |
|
---|
154 | int issue_num = tmp.getNumber(); // 論点番号
|
---|
155 | IssueDiscrete tmpDiscrete = (IssueDiscrete) tmp;
|
---|
156 |
|
---|
157 | TemplateLogBidValueHash[issue_num
|
---|
158 | - 1] = new HashMap<String, Double>();
|
---|
159 | TemplateLogBidCountHash[issue_num
|
---|
160 | - 1] = new HashMap<String, Integer>();
|
---|
161 | addupValueHash[issue_num - 1] = new HashMap<String, Double>();
|
---|
162 | for (int j = 0; j < tmpDiscrete.getNumberOfValues(); j++) {
|
---|
163 | TemplateLogBidValueHash[issue_num - 1]
|
---|
164 | .put(tmpDiscrete.getValue(j).toString(), 0.0);
|
---|
165 | TemplateLogBidCountHash[issue_num - 1]
|
---|
166 | .put(tmpDiscrete.getValue(j).toString(), 0);
|
---|
167 | addupValueHash[issue_num - 1]
|
---|
168 | .put(tmpDiscrete.getValue(j).toString(), 0.0);
|
---|
169 | }
|
---|
170 | }
|
---|
171 |
|
---|
172 | // 参加者名と配列要素数対応Hash作成
|
---|
173 | participantList = new HashMap<String, Integer>();
|
---|
174 |
|
---|
175 | // 提案作成最低効用値初期値
|
---|
176 | underlimitUtility = 1.0;
|
---|
177 |
|
---|
178 | // 効用空間合算の自分の重み初期値
|
---|
179 | weightUtilSpace = 1.0;
|
---|
180 | }
|
---|
181 |
|
---|
182 | /**
|
---|
183 | * 自分の番に呼ばれ,AcceptかOfferか選択
|
---|
184 | *
|
---|
185 | * @param validActions
|
---|
186 | * 選べる行動のクラスが格納されている(Accept or
|
---|
187 | * Offer)
|
---|
188 | * @return 選んだ行動のクラス(Accept or Offer)
|
---|
189 | */
|
---|
190 | @Override
|
---|
191 | public Action chooseAction(List<Class<? extends Action>> validActions) {
|
---|
192 |
|
---|
193 | if (isEstimated(partyNum)) {
|
---|
194 |
|
---|
195 | // 歩み寄り用係数作成
|
---|
196 | makeConcession();
|
---|
197 |
|
---|
198 | // 予測効用空間を合算
|
---|
199 | addupUtilSpace(weightUtilSpace);
|
---|
200 | }
|
---|
201 |
|
---|
202 | // 承諾が可能な時
|
---|
203 | if (validActions.contains(Accept.class)) {
|
---|
204 |
|
---|
205 | // 承諾判断
|
---|
206 | if (getAcceptableProbability() > Math.random()) {
|
---|
207 | return new Accept(getPartyId(),
|
---|
208 | ((ActionWithBid) getLastReceivedAction()).getBid());
|
---|
209 | }
|
---|
210 | }
|
---|
211 |
|
---|
212 | // 提案作成
|
---|
213 | Bid nextBid = null;
|
---|
214 | if (isEstimated(partyNum) && underlimitUtility < 1.0) {
|
---|
215 |
|
---|
216 | // Bid作成
|
---|
217 | nextBid = generateOfferBid();
|
---|
218 |
|
---|
219 | // 予測作成前&譲歩前は最大効用Bid
|
---|
220 | } else {
|
---|
221 | try {
|
---|
222 | nextBid = utilitySpace.getMaxUtilityBid();
|
---|
223 | } catch (Exception e) {
|
---|
224 | e.printStackTrace();
|
---|
225 | }
|
---|
226 | }
|
---|
227 |
|
---|
228 | // 判断対象に自分のOfferBidを設定
|
---|
229 | targetBid = nextBid;
|
---|
230 |
|
---|
231 | // ログ
|
---|
232 | // System.out.println("Time = "+timeline.getTime());
|
---|
233 | // System.out.println("UnderLimitUtil = "+underlimitUtility);
|
---|
234 | // System.out.println("AddupWeight = "+weightUtilSpace);
|
---|
235 | // System.out.println("Util(UnDiscount) = "+getUtility(nextBid));
|
---|
236 | // System.out.println("Util(Discount) =
|
---|
237 | // "+getUtilityWithDiscount(nextBid));
|
---|
238 |
|
---|
239 | // 提案
|
---|
240 | return new Offer(getPartyId(), nextBid);
|
---|
241 | }
|
---|
242 |
|
---|
243 | /**
|
---|
244 | * 他の参加者のすべての行動(Accept or
|
---|
245 | * Offer)がメッセージとして受信
|
---|
246 | *
|
---|
247 | * @param sender
|
---|
248 | * 行動者の情報
|
---|
249 | * @param action
|
---|
250 | * 行動内容(Accept,Offer,Inform)
|
---|
251 | */
|
---|
252 | @Override
|
---|
253 | public void receiveMessage(AgentID sender, Action action) {
|
---|
254 |
|
---|
255 | // オーバーライドのため
|
---|
256 | super.receiveMessage(sender, action);
|
---|
257 |
|
---|
258 | // 初回のみ呼び出し
|
---|
259 | if (action.getClass() == Inform.class) {
|
---|
260 |
|
---|
261 | // 交渉参加合計人数取得
|
---|
262 | partyNum = (Integer) ((Inform) action).getValue();
|
---|
263 |
|
---|
264 | // 配列&Hash初期化
|
---|
265 | initHashArray(partyNum);
|
---|
266 |
|
---|
267 | } else {
|
---|
268 |
|
---|
269 | // 参加者に対応する配列要素番号取得
|
---|
270 | int partyID = getSenderID(sender.toString());
|
---|
271 | if (partyID < 0) {
|
---|
272 | partyID = participantList.size();
|
---|
273 | participantList.put(sender.toString(), partyID);
|
---|
274 | estimateCount[partyID] = 0;
|
---|
275 | }
|
---|
276 |
|
---|
277 | // senderが誰かの提案を拒否してofferした時
|
---|
278 | if (action.getClass() == Offer.class) {
|
---|
279 |
|
---|
280 | // 相手の提案を取得し判断対象に設定
|
---|
281 | Offer received_offer = (Offer) action;
|
---|
282 | targetBid = received_offer.getBid();
|
---|
283 | }
|
---|
284 |
|
---|
285 | // 提案ログ更新
|
---|
286 | // senderがacceptした時はtargetBidを提案したとする
|
---|
287 | if (logNum[partyID] < logMax) {
|
---|
288 |
|
---|
289 | logBid[partyID][logNum[partyID]] = targetBid;
|
---|
290 | logNum[partyID]++;
|
---|
291 | }
|
---|
292 |
|
---|
293 | // 効用値合計更新
|
---|
294 | double util = getUtility(targetBid);
|
---|
295 | sumUtility[partyID] += util;
|
---|
296 | sumUtility2[partyID] += util * util;
|
---|
297 |
|
---|
298 | // 効用空間予測
|
---|
299 | if (logNum[partyID] == logMax) {
|
---|
300 |
|
---|
301 | // 出現数一時格納Hash作成
|
---|
302 | HashMap<String, Integer>[] TmpCountHash = new HashMap[issueNum];
|
---|
303 | for (int i = 0; i < issueNum; i++) {
|
---|
304 | TmpCountHash[i] = new HashMap<String, Integer>(
|
---|
305 | TemplateLogBidCountHash[i]);
|
---|
306 | }
|
---|
307 |
|
---|
308 | // ログから相手のValueの回数計測
|
---|
309 | for (int i = 0; i < logMax; i++) {
|
---|
310 | for (int j = 1; j <= issueNum; j++) {
|
---|
311 | try {
|
---|
312 | if (TmpCountHash[j - 1]
|
---|
313 | .containsKey(logBid[partyID][i].getValue(j)
|
---|
314 | .toString())) {
|
---|
315 | int tmp = TmpCountHash[j - 1]
|
---|
316 | .get(logBid[partyID][i].getValue(j)
|
---|
317 | .toString());
|
---|
318 | TmpCountHash[j - 1].put(logBid[partyID][i]
|
---|
319 | .getValue(j).toString(), tmp + 1);
|
---|
320 | }
|
---|
321 | } catch (Exception e) {
|
---|
322 | System.out.println("getValue Error !\n");
|
---|
323 | }
|
---|
324 | ;
|
---|
325 | }
|
---|
326 | }
|
---|
327 |
|
---|
328 | // 偏りのあるデータを一部改変
|
---|
329 | for (int i = 0; i < issueNum; i++) {
|
---|
330 | int tmp = 0;
|
---|
331 | for (String key : logBidCountHash[partyID][i].keySet()) {
|
---|
332 | int count = TmpCountHash[i].get(key);
|
---|
333 | if (tmp < count) {
|
---|
334 | tmp = count;
|
---|
335 | }
|
---|
336 | }
|
---|
337 |
|
---|
338 | if (tmp >= logMax) {
|
---|
339 | for (String key : logBidCountHash[partyID][i]
|
---|
340 | .keySet()) {
|
---|
341 | int count = TmpCountHash[i].get(key);
|
---|
342 | if (count < logMax) {
|
---|
343 | TmpCountHash[i].put(key,
|
---|
344 | logMax / compareSize + 1);
|
---|
345 | }
|
---|
346 | }
|
---|
347 | }
|
---|
348 | }
|
---|
349 |
|
---|
350 | // 合計出現数に加算&issueごとの最大値も取得
|
---|
351 | int itemCountMax[] = new int[issueNum];
|
---|
352 | for (int i = 0; i < issueNum; i++) {
|
---|
353 | int tmpMax = 0;
|
---|
354 | for (String key : logBidCountHash[partyID][i].keySet()) {
|
---|
355 |
|
---|
356 | int now_count = TmpCountHash[i].get(key);
|
---|
357 | int sum_count = logBidCountHash[partyID][i].get(key);
|
---|
358 | logBidCountHash[partyID][i].put(key,
|
---|
359 | (now_count + sum_count));
|
---|
360 |
|
---|
361 | if (tmpMax < (now_count + sum_count)) {
|
---|
362 | tmpMax = (now_count + sum_count);
|
---|
363 | }
|
---|
364 | }
|
---|
365 | itemCountMax[i] = tmpMax;
|
---|
366 | }
|
---|
367 |
|
---|
368 | // 論点内項目の一対比較
|
---|
369 | for (int i = 0; i < issueNum; i++) {
|
---|
370 |
|
---|
371 | // 一対比較閾値格納用配列作成(段階数+1が閾値の数)
|
---|
372 | int compareArray[] = new int[compareSize + 1];
|
---|
373 | for (int j = 0; j <= compareSize; j++) {
|
---|
374 | compareArray[j] = (int) (itemCountMax[i]
|
---|
375 | * ((double) j / (double) compareSize));
|
---|
376 | }
|
---|
377 |
|
---|
378 | // 一対比較結果をHashに格納
|
---|
379 | for (String key : logBidCountHash[partyID][i].keySet()) {
|
---|
380 | int tmp = logBidCountHash[partyID][i].get(key);
|
---|
381 | for (int k = 0; k < compareSize; k++) {
|
---|
382 | if (tmp >= compareArray[k]
|
---|
383 | && tmp <= compareArray[k + 1]) {
|
---|
384 | logBidValueHash[partyID][i].put(key,
|
---|
385 | compareResultArray[k]);
|
---|
386 | break;
|
---|
387 | }
|
---|
388 | }
|
---|
389 | }
|
---|
390 | }
|
---|
391 |
|
---|
392 | // 論点ごとの重み作成のための一対比較
|
---|
393 | int tmpMax = 0;
|
---|
394 | for (int i = 0; i < issueNum; i++) {
|
---|
395 | if (tmpMax < itemCountMax[i]) {
|
---|
396 | tmpMax = itemCountMax[i];
|
---|
397 | }
|
---|
398 | }
|
---|
399 | int compareArray[] = new int[compareSize + 1];
|
---|
400 | for (int i = 0; i <= compareSize; i++) {
|
---|
401 | compareArray[i] = (int) (tmpMax
|
---|
402 | * ((double) i / (double) compareSize));
|
---|
403 | }
|
---|
404 | double tmpWeightArray[] = new double[issueNum];
|
---|
405 | for (int i = 0; i < issueNum; i++) {
|
---|
406 | int tmp = itemCountMax[i];
|
---|
407 | for (int j = 0; j < compareSize; j++) {
|
---|
408 | if (tmp >= compareArray[j]
|
---|
409 | && tmp <= compareArray[j + 1]) {
|
---|
410 | tmpWeightArray[i] = compareResultArray[j];
|
---|
411 | break;
|
---|
412 | }
|
---|
413 | }
|
---|
414 | }
|
---|
415 |
|
---|
416 | // 幾何平均で論点ごとの重み作成
|
---|
417 | double averageMatrix[][] = new double[issueNum][issueNum];
|
---|
418 | for (int i = 0; i < issueNum; i++) {
|
---|
419 | for (int j = 0; j < issueNum; j++) {
|
---|
420 | averageMatrix[i][j] = tmpWeightArray[j]
|
---|
421 | / tmpWeightArray[i];
|
---|
422 | }
|
---|
423 | }
|
---|
424 | double sumMultiply = 0.0;
|
---|
425 | for (int i = 0; i < issueNum; i++) {
|
---|
426 | double multiply = 1.0;
|
---|
427 | for (int j = 0; j < issueNum; j++) {
|
---|
428 | multiply *= averageMatrix[i][j];
|
---|
429 | }
|
---|
430 | multiply = Math.pow(multiply, 1.0 / issueNum);
|
---|
431 | sumMultiply += multiply;
|
---|
432 | issueWeightArray[partyID][i] = multiply;
|
---|
433 | }
|
---|
434 | for (int i = 0; i < issueNum; i++) {
|
---|
435 | issueWeightArray[partyID][i] /= sumMultiply;
|
---|
436 | }
|
---|
437 |
|
---|
438 | // 次のログ採取へ移行
|
---|
439 | logNum[partyID] = 0;
|
---|
440 | estimateCount[partyID]++;
|
---|
441 | }
|
---|
442 | }
|
---|
443 | }
|
---|
444 |
|
---|
445 | /**
|
---|
446 | * 同意確率を計算
|
---|
447 | *
|
---|
448 | * @return double 同意確率
|
---|
449 | */
|
---|
450 | private double getAcceptableProbability() {
|
---|
451 |
|
---|
452 | double probability = 0.0;
|
---|
453 | double time = timeline.getTime();
|
---|
454 | double offeredUtility = getUtility(targetBid);
|
---|
455 |
|
---|
456 | // 自分にとって好条件 or
|
---|
457 | // 時間ギリギリなら他条件に関わらず承諾確定
|
---|
458 | if (offeredUtility >= 0.90 || time >= 0.95) {
|
---|
459 | return 1.0;
|
---|
460 | }
|
---|
461 |
|
---|
462 | // 効用空間予測が完了している時
|
---|
463 | if (isEstimated(partyNum)) {
|
---|
464 |
|
---|
465 | // 譲歩率を元に承諾確率計算
|
---|
466 | double tmp1 = (Math.pow(time, 5.0) / 5.0);
|
---|
467 | tmp1 += (offeredUtility - estimateMax)
|
---|
468 | + (offeredUtility - utilityBarometer);
|
---|
469 |
|
---|
470 | // AHP評価値を元に承諾確率を計算
|
---|
471 | double tmp2 = (Math.pow(time, 5.0) / 5.0);
|
---|
472 | double ahpResult = getAHPEvaluation(targetBid);
|
---|
473 | tmp2 += (ahpResult - estimateMax) + (ahpResult - utilityBarometer);
|
---|
474 |
|
---|
475 | // 相手の予測効用値を元に承諾確率を計算
|
---|
476 | double tmp3 = 0.0;
|
---|
477 | for (String name : participantList.keySet()) {
|
---|
478 | double otherUtil = getTargetUtility(name, targetBid);
|
---|
479 | if (otherUtil < offeredUtility) {
|
---|
480 | tmp3 += 1.0 / (partyNum - 1.0);
|
---|
481 | } else {
|
---|
482 | tmp3 -= 1.0 / (partyNum - 1.0);
|
---|
483 | }
|
---|
484 | }
|
---|
485 |
|
---|
486 | // 承諾確率を決定
|
---|
487 | probability = tmp1 * 0.4 + tmp2 * 0.4 + tmp3 * 0.2;
|
---|
488 | }
|
---|
489 |
|
---|
490 | return probability;
|
---|
491 | }
|
---|
492 |
|
---|
493 | /**
|
---|
494 | * 提案作成
|
---|
495 | *
|
---|
496 | * @return Bid 提案
|
---|
497 | */
|
---|
498 | private Bid generateOfferBid() {
|
---|
499 |
|
---|
500 | Bid nextBid = null;
|
---|
501 | int bidNum = 10;
|
---|
502 | Bid tmpBid[] = new Bid[bidNum];
|
---|
503 |
|
---|
504 | // 作成Bidの効用値上限
|
---|
505 | double upperLimitUtility = underlimitUtility + 0.2;
|
---|
506 | if (upperLimitUtility > 1.0) {
|
---|
507 | upperLimitUtility = 1.0;
|
---|
508 | }
|
---|
509 |
|
---|
510 | // 効用値が範囲内のBidを複数作成
|
---|
511 | for (int i = 0; i < bidNum; i++) {
|
---|
512 | Bid tmp = null;
|
---|
513 | double util = 0.0;
|
---|
514 | int loop = 100;
|
---|
515 | double tmpUnderlLimit = underlimitUtility;
|
---|
516 | do {
|
---|
517 | tmp = generateRandomBid();
|
---|
518 | util = getUtility(tmp);
|
---|
519 | if (--loop <= 0) {
|
---|
520 | loop = 100;
|
---|
521 | tmpUnderlLimit -= 0.001;
|
---|
522 | }
|
---|
523 | } while (tmp != null
|
---|
524 | && (util < tmpUnderlLimit || util > upperLimitUtility));
|
---|
525 | tmpBid[i] = tmp;
|
---|
526 | }
|
---|
527 |
|
---|
528 | // 作成BidをAHPにて評価し一番評価値の高いものを採用
|
---|
529 | double evalValue = 0.0;
|
---|
530 | for (int i = 0; i < bidNum; i++) {
|
---|
531 | double tmp = getAHPEvaluation(tmpBid[i]);
|
---|
532 | if (tmp > evalValue) {
|
---|
533 | tmp = evalValue;
|
---|
534 | nextBid = tmpBid[i];
|
---|
535 | }
|
---|
536 | }
|
---|
537 |
|
---|
538 | return nextBid;
|
---|
539 | }
|
---|
540 |
|
---|
541 | /**
|
---|
542 | * Hashと配列初期化用
|
---|
543 | *
|
---|
544 | * @param int
|
---|
545 | * 交渉参加人数
|
---|
546 | */
|
---|
547 | private void initHashArray(int partyNum) {
|
---|
548 |
|
---|
549 | // 自分以外の参加人数
|
---|
550 | int otherCount = partyNum - 1;
|
---|
551 |
|
---|
552 | // 提案ログ現状数格納二次元配列作成
|
---|
553 | logNum = new int[otherCount];
|
---|
554 |
|
---|
555 | // 提案ログ格納用二次元配列作成
|
---|
556 | logBid = new Bid[otherCount][logMax];
|
---|
557 |
|
---|
558 | // 提案内出現回数カウントHash配列作成
|
---|
559 | logBidCountHash = new HashMap[otherCount][issueNum];
|
---|
560 | for (int i = 0; i < otherCount; i++) {
|
---|
561 | for (int j = 0; j < issueNum; j++) {
|
---|
562 | logBidCountHash[i][j] = new HashMap<String, Integer>(
|
---|
563 | TemplateLogBidCountHash[j]);
|
---|
564 | }
|
---|
565 | }
|
---|
566 |
|
---|
567 | // 提案内出現回数カウントHash配列作成
|
---|
568 | logBidValueHash = new HashMap[otherCount][issueNum];
|
---|
569 | for (int i = 0; i < otherCount; i++) {
|
---|
570 | for (int j = 0; j < issueNum; j++) {
|
---|
571 | logBidValueHash[i][j] = new HashMap<String, Double>(
|
---|
572 | TemplateLogBidValueHash[j]);
|
---|
573 | }
|
---|
574 | }
|
---|
575 |
|
---|
576 | // 予測効用空間の論点間重み格納配列作成
|
---|
577 | issueWeightArray = new double[otherCount][issueNum];
|
---|
578 |
|
---|
579 | // 一対比較の段階数設定&結果配列作成
|
---|
580 | compareSize = issueNum;
|
---|
581 | compareResultArray = new double[compareSize];
|
---|
582 | for (int j = 1; j <= compareSize; j++) {
|
---|
583 | compareResultArray[j - 1] = (2.0 * j - 1.0)
|
---|
584 | / (2.0 * compareSize - 1.0);
|
---|
585 | }
|
---|
586 |
|
---|
587 | // 予測の更新回数格納配列作成
|
---|
588 | estimateCount = new int[otherCount];
|
---|
589 | for (int i = 0; i < otherCount; i++) {
|
---|
590 | estimateCount[i] = 0;
|
---|
591 | }
|
---|
592 |
|
---|
593 | // 合算した論点間重み格納配列作成
|
---|
594 | addupWeightArray = new double[issueNum];
|
---|
595 |
|
---|
596 | // 相手提案の効用値合計格納配列作成
|
---|
597 | sumUtility = new double[otherCount];
|
---|
598 | sumUtility2 = new double[otherCount];
|
---|
599 | for (int i = 0; i < otherCount; i++) {
|
---|
600 | sumUtility[i] = 0.0;
|
---|
601 | sumUtility2[i] = 0.0;
|
---|
602 | }
|
---|
603 | }
|
---|
604 |
|
---|
605 | /**
|
---|
606 | * 参加者名から対応する配列要素数を取得
|
---|
607 | *
|
---|
608 | * @param String
|
---|
609 | * 参加者名
|
---|
610 | * @return int 配列要素数
|
---|
611 | */
|
---|
612 | private int getSenderID(String name) {
|
---|
613 |
|
---|
614 | int id = -1;
|
---|
615 | if (participantList.containsKey(name)) {
|
---|
616 | id = participantList.get(name);
|
---|
617 | }
|
---|
618 |
|
---|
619 | return id;
|
---|
620 | }
|
---|
621 |
|
---|
622 | /**
|
---|
623 | * 参加者全員分の予測が作成済みであるかどうか
|
---|
624 | *
|
---|
625 | * @param int
|
---|
626 | * 交渉参加人数
|
---|
627 | * @return boolean 作成済み=true
|
---|
628 | */
|
---|
629 | private boolean isEstimated(int partyNum) {
|
---|
630 |
|
---|
631 | int otherCount = partyNum - 1;
|
---|
632 | boolean flag = true;
|
---|
633 | for (int i = 0; i < otherCount; i++) {
|
---|
634 | if (estimateCount[i] <= 0) {
|
---|
635 | flag = false;
|
---|
636 | break;
|
---|
637 | }
|
---|
638 | }
|
---|
639 |
|
---|
640 | return flag;
|
---|
641 | }
|
---|
642 |
|
---|
643 | /**
|
---|
644 | * 効用空間合算
|
---|
645 | *
|
---|
646 | * @param double
|
---|
647 | * 自分の重み
|
---|
648 | */
|
---|
649 | private void addupUtilSpace(double myWeight) {
|
---|
650 |
|
---|
651 | // 合算更新の必要がない
|
---|
652 | // &予測が作成済みでない場合はreturn
|
---|
653 | int timing = 0;
|
---|
654 | for (int i = 0; i < partyNum - 1; i++) {
|
---|
655 | timing += estimateCount[i];
|
---|
656 | }
|
---|
657 | if (timing == prevAddupTiming || !isEstimated(partyNum)) {
|
---|
658 | return;
|
---|
659 | } else {
|
---|
660 | prevAddupTiming = timing;
|
---|
661 | }
|
---|
662 |
|
---|
663 | // 自分以外の参加者の重み
|
---|
664 | double otherWeight = (1.0 - myWeight) / (partyNum - 1);
|
---|
665 |
|
---|
666 | // 自分の効用空間値取得
|
---|
667 | for (Issue tmp : utilitySpace.getDomain().getIssues()) {
|
---|
668 |
|
---|
669 | // 論点番号取得
|
---|
670 | int issue_num = tmp.getNumber();
|
---|
671 |
|
---|
672 | // 論点の重み取得し重み付き格納
|
---|
673 | addupWeightArray[issue_num
|
---|
674 | - 1] = ((AdditiveUtilitySpace) utilitySpace)
|
---|
675 | .getWeight(issue_num) * myWeight;
|
---|
676 |
|
---|
677 | // 論点内の項目事の値を取得
|
---|
678 | IssueDiscrete tmpDiscrete = (IssueDiscrete) tmp;
|
---|
679 | EvaluatorDiscrete evaluator = (EvaluatorDiscrete) ((AdditiveUtilitySpace) utilitySpace)
|
---|
680 | .getEvaluator(issue_num);
|
---|
681 | for (int j = 0; j < tmpDiscrete.getNumberOfValues(); j++) {
|
---|
682 |
|
---|
683 | ValueDiscrete value = tmpDiscrete.getValue(j);
|
---|
684 | try {
|
---|
685 | addupValueHash[issue_num - 1].put(value.toString(),
|
---|
686 | evaluator.getEvaluation(value) * myWeight);
|
---|
687 | } catch (Exception e) {
|
---|
688 | e.printStackTrace();
|
---|
689 | }
|
---|
690 | }
|
---|
691 | }
|
---|
692 |
|
---|
693 | // 他参加者の情報を重み付き格納
|
---|
694 | for (int i = 0; i < partyNum - 1; i++) {
|
---|
695 | for (int j = 0; j < issueNum; j++) {
|
---|
696 |
|
---|
697 | // 論点間の重みを重み付き格納
|
---|
698 | addupWeightArray[j] += issueWeightArray[i][j] * otherWeight;
|
---|
699 |
|
---|
700 | // 論点内の項目事の値を重み付き格納
|
---|
701 | for (String key : logBidValueHash[i][j].keySet()) {
|
---|
702 | double tmp1 = addupValueHash[j].get(key);
|
---|
703 | double tmp2 = logBidValueHash[i][j].get(key);
|
---|
704 | addupValueHash[j].put(key, tmp1 + tmp2 * otherWeight);
|
---|
705 | }
|
---|
706 | }
|
---|
707 | }
|
---|
708 | }
|
---|
709 |
|
---|
710 | /**
|
---|
711 | * 自分以外の参加者の効用値予測を取得
|
---|
712 | *
|
---|
713 | * @param String
|
---|
714 | * 参加者名
|
---|
715 | * @param Bid
|
---|
716 | * 予測対象提案
|
---|
717 | * @return double 予測効用値
|
---|
718 | */
|
---|
719 | private double getTargetUtility(String name, Bid targetBid) {
|
---|
720 |
|
---|
721 | int partyID = getSenderID(name);
|
---|
722 | double utility = 0.0;
|
---|
723 | if (targetBid != null && partyID >= 0) {
|
---|
724 |
|
---|
725 | for (int i = 1; i <= issueNum; i++) {
|
---|
726 |
|
---|
727 | try {
|
---|
728 | // 相手の提案を元に予測効用空間から効用を取得し重み掛けて加算
|
---|
729 | String valName = targetBid.getValue(i).toString();
|
---|
730 | utility += (logBidValueHash[partyID][i - 1].get(valName)
|
---|
731 | * issueWeightArray[partyID][i - 1]);
|
---|
732 |
|
---|
733 | } catch (Exception e) {
|
---|
734 | System.out.println("getValue Error !\n");
|
---|
735 | }
|
---|
736 | ;
|
---|
737 | }
|
---|
738 | }
|
---|
739 |
|
---|
740 | return utility;
|
---|
741 | }
|
---|
742 |
|
---|
743 | /**
|
---|
744 | * AHPによる提案の評価値を取得
|
---|
745 | *
|
---|
746 | * @param Bid
|
---|
747 | * 予測対象提案
|
---|
748 | * @return double 予測評価値(効用値)
|
---|
749 | */
|
---|
750 | private double getAHPEvaluation(Bid targetBid) {
|
---|
751 |
|
---|
752 | double utility = 0.0;
|
---|
753 | if (targetBid != null && isEstimated(partyNum)) {
|
---|
754 |
|
---|
755 | for (int i = 1; i <= issueNum; i++) {
|
---|
756 |
|
---|
757 | try {
|
---|
758 | // 合算した効用空間から効用を取得
|
---|
759 | String valName = targetBid.getValue(i).toString();
|
---|
760 | utility += (addupValueHash[i - 1].get(valName)
|
---|
761 | * addupWeightArray[i - 1]);
|
---|
762 |
|
---|
763 | } catch (Exception e) {
|
---|
764 | System.out.println("getValue Error !\n");
|
---|
765 | }
|
---|
766 | ;
|
---|
767 | }
|
---|
768 | }
|
---|
769 |
|
---|
770 | return utility;
|
---|
771 | }
|
---|
772 |
|
---|
773 | /**
|
---|
774 | * 譲歩度合い設定
|
---|
775 | */
|
---|
776 | private void makeConcession() {
|
---|
777 |
|
---|
778 | int otherCount = partyNum - 1;
|
---|
779 | double time = timeline.getTime();
|
---|
780 | double tremor = 1.0; // 行動のゆらぎ幅
|
---|
781 | double gt = 0.2; // 最高でどの程度まで譲歩するか(1.0-gt)まで
|
---|
782 |
|
---|
783 | // 参加者全員の効用値合計
|
---|
784 | double allSum = 0.0;
|
---|
785 | double allSum2 = 0.0;
|
---|
786 | for (int i = 0; i < otherCount; i++) {
|
---|
787 | allSum += sumUtility[i];
|
---|
788 | allSum2 += sumUtility2[i];
|
---|
789 | }
|
---|
790 |
|
---|
791 | // 現在の相手全員からの合計提案数
|
---|
792 | int round = 0;
|
---|
793 | for (int i = 0; i < otherCount; i++) {
|
---|
794 | round += estimateCount[i] * logMax + logNum[i];
|
---|
795 | }
|
---|
796 |
|
---|
797 | // 平均
|
---|
798 | double mean = allSum / round;
|
---|
799 |
|
---|
800 | // 分散
|
---|
801 | double variance = Math.sqrt(((allSum2) / round) - (mean * mean));
|
---|
802 | if (Double.isNaN(variance)) {
|
---|
803 | variance = 0.0;
|
---|
804 | }
|
---|
805 |
|
---|
806 | // 行動の幅(論文でのd(t))
|
---|
807 | double width = Math.sqrt(12) * variance;
|
---|
808 | if (Double.isNaN(width)) {
|
---|
809 | width = 0.0;
|
---|
810 | }
|
---|
811 |
|
---|
812 | // 最大効用の推定値
|
---|
813 | estimateMax = mean + ((1.0 - mean) * width);
|
---|
814 |
|
---|
815 | // 歩み寄り速度調整用
|
---|
816 | double alpha = 1.0 + tremor + (7.0 * mean) - (2.0 * tremor * mean);
|
---|
817 | double beta = alpha + (Math.random() * tremor) - (tremor / 2);
|
---|
818 |
|
---|
819 | // 歩み寄り後の最低効用値(仮)
|
---|
820 | // 1:承諾判断用,2:提案作成用
|
---|
821 | double tmpConsession1 = 1.0
|
---|
822 | - (Math.pow(time, alpha) * (1.0 - estimateMax));
|
---|
823 | double tmpConsession2 = 1.0
|
---|
824 | - (Math.pow(time, beta) * (1.0 - estimateMax));
|
---|
825 |
|
---|
826 | // 歩み寄り度合い
|
---|
827 | double ratio1 = (width + gt) / (1.0 - tmpConsession1);
|
---|
828 | if (Double.isNaN(ratio1) || ratio1 > 2.0) {
|
---|
829 | ratio1 = 2.0;
|
---|
830 | }
|
---|
831 | double ratio2 = (width + gt) / (1.0 - tmpConsession2);
|
---|
832 | if (Double.isNaN(ratio2) || ratio2 > 2.0) {
|
---|
833 | ratio2 = 2.0;
|
---|
834 | }
|
---|
835 |
|
---|
836 | // 提案作成用最低効用値作成
|
---|
837 | // 作成提案最低効用値と効用空間合算時の自分の重みに利用
|
---|
838 | double tmp = ratio2 * tmpConsession2 + (1.0 - ratio2);
|
---|
839 | if (tmp < underlimitUtility) {
|
---|
840 | underlimitUtility = tmp;
|
---|
841 | if (underlimitUtility < reservationValue) {
|
---|
842 | underlimitUtility = reservationValue;
|
---|
843 | }
|
---|
844 | weightUtilSpace = 1.0 - ((1.0 - tmp) * 2);
|
---|
845 | if (weightUtilSpace < 0.4) {
|
---|
846 | weightUtilSpace = 0.4;
|
---|
847 | }
|
---|
848 | }
|
---|
849 |
|
---|
850 | // 承諾判断用効用値指標作成
|
---|
851 | utilityBarometer = ratio1 * tmpConsession1 + (1.0 - ratio1);
|
---|
852 | }
|
---|
853 |
|
---|
854 | @Override
|
---|
855 | public String getDescription() {
|
---|
856 | return "ANAC2015";
|
---|
857 | }
|
---|
858 | }
|
---|