1 | package genius.core.uncertainty;
|
---|
2 |
|
---|
3 | import java.util.ArrayList;
|
---|
4 | import java.util.Collections;
|
---|
5 | import java.util.List;
|
---|
6 | import java.util.Map;
|
---|
7 | import java.util.TreeMap;
|
---|
8 |
|
---|
9 | import genius.core.Bid;
|
---|
10 | import genius.core.Domain;
|
---|
11 | import genius.core.issue.IssueDiscrete;
|
---|
12 | import genius.core.issue.ValueDiscrete;
|
---|
13 | import genius.core.utility.AbstractUtilitySpace;
|
---|
14 | import genius.core.utility.AdditiveUtilitySpace;
|
---|
15 | import genius.core.utility.EvaluatorDiscrete;
|
---|
16 | import java.util.Random;
|
---|
17 |
|
---|
18 | /**
|
---|
19 | * This class is a helper for the fitnessCross_SAGA function in EstimateUtilityLibrary.
|
---|
20 | */
|
---|
21 |
|
---|
22 | public class Helper_SAGA {
|
---|
23 |
|
---|
24 | private Domain domain;
|
---|
25 | private BidRanking bidRank;
|
---|
26 | private Random rnd;
|
---|
27 |
|
---|
28 | public Helper_SAGA(Domain domain, BidRanking bidRank, Random rnd){
|
---|
29 | this.domain = domain;
|
---|
30 | this.bidRank = bidRank;
|
---|
31 | this.rnd = rnd;
|
---|
32 | }
|
---|
33 | public AbstractUtilitySpace generateRandomUtilitySpace() {
|
---|
34 | AdditiveUtilitySpaceFactory additiveUtilitySpaceFactory = new AdditiveUtilitySpaceFactory(domain);
|
---|
35 | List<IssueDiscrete> issues = additiveUtilitySpaceFactory.getIssues();
|
---|
36 | for (IssueDiscrete i : issues) {
|
---|
37 | additiveUtilitySpaceFactory.setWeight(i, rnd.nextDouble());
|
---|
38 | for (ValueDiscrete v : i.getValues())
|
---|
39 | additiveUtilitySpaceFactory.setUtility(i, v, rnd.nextDouble());
|
---|
40 | }
|
---|
41 |
|
---|
42 | // Normalize the weights, since we picked them randomly in [0, 1]
|
---|
43 | additiveUtilitySpaceFactory.normalizeWeights();
|
---|
44 |
|
---|
45 | // The factory is done with setting all parameters, now return the estimated utility space
|
---|
46 | return additiveUtilitySpaceFactory.getUtilitySpace();
|
---|
47 | }
|
---|
48 |
|
---|
49 | // 交叉と突然変異を行います
|
---|
50 | public AbstractUtilitySpace crossover(AdditiveUtilitySpace parent1, AdditiveUtilitySpace parent2) {
|
---|
51 | double alpha = 0.3; // BLX-alphaの値
|
---|
52 | double mutateProb = 0.005; // 突然変異確率
|
---|
53 | double low, high;
|
---|
54 | double w1, w2, wChild;
|
---|
55 |
|
---|
56 | AdditiveUtilitySpaceFactory additiveUtilitySpaceFactory = new AdditiveUtilitySpaceFactory(domain);
|
---|
57 | List<IssueDiscrete> issues = additiveUtilitySpaceFactory.getIssues();
|
---|
58 | for (IssueDiscrete i : issues) {
|
---|
59 | // 論点の重み
|
---|
60 | w1 = parent1.getWeight(i);
|
---|
61 | w2 = parent2.getWeight(i);
|
---|
62 | low = Math.min(w1, w2) - alpha * Math.abs(w1 - w2);
|
---|
63 | high = Math.max(w1, w2) + alpha * Math.abs(w1 - w2);
|
---|
64 | wChild = rnd.nextDouble() * (high - low) + low;
|
---|
65 | if (wChild < 0.01) wChild = 0.01;
|
---|
66 | additiveUtilitySpaceFactory.setWeight(i, wChild);
|
---|
67 | //突然変異
|
---|
68 | if (rnd.nextDouble() < mutateProb)
|
---|
69 | additiveUtilitySpaceFactory.setWeight(i, rnd.nextDouble());
|
---|
70 |
|
---|
71 | for (ValueDiscrete v : i.getValues()) {
|
---|
72 | // 選択肢の評価値
|
---|
73 | w1 = ((EvaluatorDiscrete) parent1.getEvaluator(i)).getDoubleValue(v);
|
---|
74 | w2 = ((EvaluatorDiscrete) parent2.getEvaluator(i)).getDoubleValue(v);
|
---|
75 | low = Math.min(w1, w2) - alpha * Math.abs(w1 - w2);
|
---|
76 | high = Math.max(w1, w2) + alpha * Math.abs(w1 - w2);
|
---|
77 | wChild = rnd.nextDouble() * (high - low) + low;
|
---|
78 | if (wChild < 0.01) wChild = 0.01;
|
---|
79 | additiveUtilitySpaceFactory.setUtility(i, v, wChild);
|
---|
80 | //突然変異
|
---|
81 | if (rnd.nextDouble() < mutateProb)
|
---|
82 | additiveUtilitySpaceFactory.setUtility(i, v, rnd.nextDouble());
|
---|
83 | }
|
---|
84 |
|
---|
85 | /* 正規分布で交叉
|
---|
86 | if (rnd.nextBoolean())
|
---|
87 | wChild = rnd.nextGaussian() * Math.abs(w1 - w2) + Math.min(w1, w2);
|
---|
88 | else
|
---|
89 | wChild = rnd.nextGaussian() * Math.abs(w1 - w2) + Math.max(w1, w2);
|
---|
90 | */
|
---|
91 | }
|
---|
92 |
|
---|
93 | // Normalize the weights
|
---|
94 | additiveUtilitySpaceFactory.normalizeWeights();
|
---|
95 |
|
---|
96 | return additiveUtilitySpaceFactory.getUtilitySpace();
|
---|
97 | }
|
---|
98 |
|
---|
99 | // 適応度関数
|
---|
100 | public double fitness(AbstractUtilitySpace individual, boolean print) {
|
---|
101 | List<Double> utilList = new ArrayList<>(); // ランキング下位から上位の予測効用値
|
---|
102 |
|
---|
103 | for (Bid b : bidRank.getBidOrder()) {
|
---|
104 | utilList.add(individual.getUtility(b));
|
---|
105 | }
|
---|
106 |
|
---|
107 | // {予測効用値:予測順位} の辞書
|
---|
108 | TreeMap<Double, Integer> map = new TreeMap<>(Collections.reverseOrder());
|
---|
109 | for (double util : utilList) {
|
---|
110 | map.put(util, 1);
|
---|
111 | }
|
---|
112 | int rank = 1;
|
---|
113 | for (Map.Entry<Double, Integer> entry : map.entrySet()) {
|
---|
114 | rank += entry.setValue(rank);
|
---|
115 | }
|
---|
116 |
|
---|
117 | List<Integer> rankList = new ArrayList<>();
|
---|
118 | for (double util : utilList) {
|
---|
119 | rankList.add(map.get(util));
|
---|
120 | }
|
---|
121 | Collections.reverse(rankList); // ランキング上位から下位のBidの予測順位(1,2,3,...って並んでるとうれしい)
|
---|
122 |
|
---|
123 | int sqSum = 0;
|
---|
124 | for (int i = 0; i < rankList.size(); i++) {
|
---|
125 | int diff = i + 1 - rankList.get(i);
|
---|
126 | sqSum += diff * diff;
|
---|
127 | }
|
---|
128 | double spearman = 1.0 - 6.0 * (double) sqSum / (Math.pow(rankList.size(), 3) - rankList.size());
|
---|
129 | double lowDiff = Math.abs(bidRank.getLowUtility() - individual.getUtility(bidRank.getMinimalBid()));
|
---|
130 | double highDiff = Math.abs(bidRank.getHighUtility() - individual.getUtility(bidRank.getMaximalBid()));
|
---|
131 |
|
---|
132 | if (print) {
|
---|
133 | System.out.println("spearman = " + spearman + ", lowDiff = " + lowDiff + ", highDiff = " + highDiff);
|
---|
134 | }
|
---|
135 |
|
---|
136 | return spearman * 10 + (1 - lowDiff) + (1 - highDiff);
|
---|
137 | }
|
---|
138 |
|
---|
139 | // ルーレット選択
|
---|
140 | public List<AbstractUtilitySpace> selectByRoulette(List<AbstractUtilitySpace> population, List<Double> fitnessList, int popSize) {
|
---|
141 | List<AbstractUtilitySpace> nextGeneration = new ArrayList<>();
|
---|
142 |
|
---|
143 | // 適応度が最大の要素を求める
|
---|
144 | double maxFit = -1.0;
|
---|
145 | int maxIndex = -1;
|
---|
146 |
|
---|
147 | double fitSum = 0.0;
|
---|
148 | for (int i = 0; i < fitnessList.size(); i++) {
|
---|
149 | double fit = fitnessList.get(i);
|
---|
150 | if (maxFit < fit) {
|
---|
151 | maxFit = fit;
|
---|
152 | maxIndex = i;
|
---|
153 | }
|
---|
154 | fitSum += fit;
|
---|
155 | }
|
---|
156 |
|
---|
157 | ////System.out.print("average = " + fitSum / population.size() + ", max = " + maxFit + ", ");
|
---|
158 | ////fitness(population.get(maxIndex), true);
|
---|
159 |
|
---|
160 | nextGeneration.add(population.get(maxIndex));
|
---|
161 |
|
---|
162 | for (int i = 0; i < popSize - 1; i++) {
|
---|
163 | double randomNum = rnd.nextDouble() * fitSum;
|
---|
164 | double count = 0.0;
|
---|
165 | for (int n = 0; n < population.size(); n++) {
|
---|
166 | count += fitnessList.get(n);
|
---|
167 | if (count > randomNum) {
|
---|
168 | nextGeneration.add(population.get(n));
|
---|
169 | break;
|
---|
170 | }
|
---|
171 | }
|
---|
172 | }
|
---|
173 |
|
---|
174 | return nextGeneration;
|
---|
175 | }
|
---|
176 |
|
---|
177 | }
|
---|