Line data Source code
1 : #include "Dynamic/Policy/DoubleQLearner.hpp"
2 :
3 : #include <random>
4 :
5 : #include "Dynamic/Policy/Policy.hpp"
6 : #include "Dynamic/Policy/QLearner.hpp"
7 :
8 : using namespace std;
9 : using namespace Dynamic;
10 :
11 0 : DoubleQLearner::PolicyFactory::PolicyFactory(
12 : Env::Env& env_,
13 : const SUMO::NetworkTAZs& sumo_,
14 : const Dynamic::SUMOAdapter& adapter_,
15 : random_device::result_type seed,
16 : optional<reference_wrapper<QLearner::Logger>> policyLogger_
17 0 : ):
18 : QLearner::Policy::Factory(
19 : env_,
20 : sumo_,
21 : adapter_,
22 : seed,
23 : policyLogger_
24 0 : ) {}
25 :
26 0 : shared_ptr<Dynamic::Policy> DoubleQLearner::PolicyFactory::create(
27 : Vehicle::ID id,
28 : Time,
29 : const Env::TAZ&,
30 : const Env::TAZ& toTAZ
31 : ) {
32 0 : auto it = qLearners.find(toTAZ.id);
33 0 : if(it == qLearners.end()) {
34 : // clang-format off
35 0 : it = qLearners.emplace(
36 0 : toTAZ.id,
37 0 : DoubleQLearner(
38 : env,
39 0 : sumo.network,
40 : adapter,
41 : toTAZ,
42 0 : gen,
43 : policyLogger
44 : )
45 0 : ).first;
46 : // clang-format on
47 : }
48 :
49 0 : QLearner& qLearner = it->second;
50 :
51 0 : return make_shared<QLearner::Policy>(qLearner, id, gen);
52 : }
53 :
54 0 : DoubleQLearner::DoubleQLearner(
55 : Env::Env& env_,
56 : const SUMO::Network& network_,
57 : const Dynamic::SUMOAdapter& adapter_,
58 : const Env::TAZ& destinationTAZ_,
59 : mt19937& gen_,
60 : optional<reference_wrapper<QLearner::Logger>> policyLogger_,
61 : Reward alpha_,
62 : Reward gamma_,
63 : Reward xi_,
64 : Reward eta_,
65 : float epsilon_
66 0 : ):
67 : QLearner(
68 : env_,
69 : network_,
70 : adapter_,
71 : destinationTAZ_,
72 : policyLogger_,
73 : alpha_,
74 : gamma_,
75 : xi_,
76 : eta_,
77 : epsilon_
78 : ),
79 0 : gen(gen_) {
80 0 : }
81 :
82 0 : [[noreturn]] QLearner::Reward DoubleQLearner::estimateOptimalValue(const State&) const {
83 0 : throw logic_error(__PRETTY_FUNCTION__ + string(": not implemented"));
84 : }
85 :
86 0 : [[noreturn]] QLearner::Reward DoubleQLearner::estimateOptimalFutureValue(const State&, const Action&) const {
87 0 : throw logic_error(__PRETTY_FUNCTION__ + string(": not implemented"));
88 : }
89 :
90 0 : [[noreturn]] QLearner::Reward& DoubleQLearner::Qref(const State&, const Action&) {
91 0 : throw logic_error(__PRETTY_FUNCTION__ + string(": not implemented"));
92 : }
93 :
94 0 : QLearner::Reward DoubleQLearner::Q(const State& s, const Action& a) const {
95 0 : return (QA(s, a) + QB(s, a)) / 2.0;
96 : }
97 :
98 0 : void DoubleQLearner::updateMatrix(const State& s, const Action& a, Reward r) {
99 0 : uniform_real_distribution<double> distribution(0.0, 1.0);
100 :
101 0 : const double x = distribution(gen);
102 0 : if(x < 0.5) {
103 0 : Reward& qA = QA(s, a);
104 :
105 0 : Reward qPrev = qA;
106 0 : Reward fB = estimateOptimalFutureValueA(s, a);
107 :
108 0 : Reward qNew = (r + gamma * fB);
109 :
110 0 : qA += alpha * (qNew - qA);
111 :
112 0 : if(policyLogger.has_value()) {
113 0 : auto& logger = policyLogger.value().get();
114 0 : auto &D = logger.D, &DA = logger.DA;
115 :
116 0 : const double Delta = qA - qPrev;
117 0 : D += Logger::ALPHA_D * (Delta - D);
118 0 : DA += Logger::ALPHA_D * (abs(Delta) - DA);
119 : }
120 : } else {
121 0 : Reward& qB = QB(s, a);
122 :
123 0 : Reward qPrev = qB;
124 0 : Reward fA = estimateOptimalFutureValueB(s, a);
125 :
126 0 : Reward qNew = (r + gamma * fA);
127 :
128 0 : qB += alpha * (qNew - qB);
129 :
130 0 : if(policyLogger.has_value()) {
131 0 : auto& logger = policyLogger.value().get();
132 0 : auto &D = logger.D, &DA = logger.DA;
133 :
134 0 : const double Delta = qB - qPrev;
135 0 : D += Logger::ALPHA_D * (Delta - D);
136 0 : DA += Logger::ALPHA_D * (abs(Delta) - DA);
137 : }
138 : }
139 0 : }
140 :
141 0 : QLearner::Reward& DoubleQLearner::QA(const State& s, const Action& a) {
142 0 : auto& q = QMatrixA[s];
143 :
144 0 : auto it = q.find(a);
145 0 : if(it != q.end()) return it->second;
146 :
147 0 : return q[a] = estimateInitialValue(s, a);
148 : }
149 :
150 0 : QLearner::Reward DoubleQLearner::QA(const State& s, const Action& a) const {
151 0 : auto it = QMatrixA.find(s);
152 0 : if(it == QMatrixA.end()) return 0.0;
153 :
154 0 : auto it2 = it->second.find(a);
155 0 : if(it2 == it->second.end()) return 0.0;
156 :
157 0 : return it2->second;
158 : }
159 :
160 0 : QLearner::Reward& DoubleQLearner::QB(const State& s, const Action& a) {
161 0 : auto& q = QMatrixB[s];
162 :
163 0 : auto it = q.find(a);
164 0 : if(it != q.end()) return it->second;
165 :
166 0 : return q[a] = estimateInitialValue(s, a);
167 : }
168 :
169 0 : QLearner::Reward DoubleQLearner::QB(const State& s, const Action& a) const {
170 0 : auto it = QMatrixB.find(s);
171 0 : if(it == QMatrixB.end()) return 0.0;
172 :
173 0 : auto it2 = it->second.find(a);
174 0 : if(it2 == it->second.end()) return 0.0;
175 :
176 0 : return it2->second;
177 : }
178 :
179 0 : QLearner::Reward DoubleQLearner::estimateOptimalValueA(const State& s) const {
180 0 : vector<Action> actions = s.possibleActions();
181 :
182 0 : vector<pair<Reward, Action>> actionRewards;
183 0 : for(const Action& a: actions) {
184 0 : actionRewards.emplace_back(QB(s, a), a);
185 : }
186 :
187 0 : auto [_, a] = *max_element(
188 : actionRewards.begin(),
189 : actionRewards.end()
190 0 : );
191 :
192 0 : return QA(s, a);
193 : }
194 :
195 0 : QLearner::Reward DoubleQLearner::estimateOptimalValueB(const State& s) const {
196 0 : vector<Action> actions = s.possibleActions();
197 :
198 0 : vector<pair<Reward, Action>> actionRewards;
199 0 : for(const Action& a: actions) {
200 0 : actionRewards.emplace_back(QA(s, a), a);
201 : }
202 :
203 0 : auto [_, a] = *max_element(
204 : actionRewards.begin(),
205 : actionRewards.end()
206 0 : );
207 :
208 0 : return QB(s, a);
209 : }
210 :
211 0 : QLearner::Reward DoubleQLearner::estimateOptimalFutureValueA(const State& s, const Action& a) const {
212 0 : State sNew = s.apply(a);
213 :
214 0 : return estimateOptimalValueA(sNew);
215 : }
216 :
217 0 : QLearner::Reward DoubleQLearner::estimateOptimalFutureValueB(const State& s, const Action& a) const {
218 0 : State sNew = s.apply(a);
219 :
220 0 : return estimateOptimalValueB(sNew);
221 : }
|