[1] | 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 | }
|
---|