Line data Source code
1 : #include <catch2/catch_get_random_seed.hpp>
2 : #include <catch2/catch_test_macros.hpp>
3 : #include <catch2/matchers/catch_matchers_floating_point.hpp>
4 : #include <chrono>
5 : #include <fstream>
6 : #include <ios>
7 : #include <iostream>
8 : #include <thread>
9 :
10 : #include "Alg/ShortestPath/DijkstraMany.hpp"
11 : #include "Dynamic/Demand/UniformDemandLoader.hpp"
12 : #include "Dynamic/Env/Env.hpp"
13 : #include "Dynamic/Env/Loader.hpp"
14 : #include "Dynamic/Env/Vehicle.hpp"
15 : #include "Dynamic/Policy/DoubleQLearner.hpp"
16 : #include "Dynamic/Policy/PathPolicy.hpp"
17 : #include "Dynamic/Policy/QLearner.hpp"
18 : #include "Dynamic/Policy/RandomPolicy.hpp"
19 : #include "Dynamic/Policy/RewardFunction/RewardFunction.hpp"
20 : #include "Dynamic/Policy/RewardFunction/RewardFunctionDifference.hpp"
21 : #include "Dynamic/Policy/RewardFunction/RewardFunctionGreedy.hpp"
22 : #include "Dynamic/Policy/RewardFunction/RewardFunctionLocal.hpp"
23 : #include "Log/ProgressLogger.hpp"
24 : #include "Log/ProgressLoggerTableOStream.hpp"
25 : #include "Static/Demand.hpp"
26 : #include "Static/supply/Network.hpp"
27 : #include "data/SUMO/EdgeData.hpp"
28 : #include "data/SUMO/NetState.hpp"
29 : #include "data/SUMO/Routes.hpp"
30 : #include "data/VISUM/OFormatDemand.hpp"
31 :
32 : using namespace std;
33 : using Catch::Matchers::WithinRel;
34 :
35 : extern string baseDir;
36 : extern string benchmarkDir;
37 :
38 : typedef chrono::steady_clock clk;
39 :
40 : const size_t MATRIX_9_10_TOTAL_DEMAND_HOUR = 102731;
41 :
42 0 : TEST_CASE("Dynamic - shortest path", "[dynamic][dynamic-sp][!benchmark]") {
43 0 : utils::stringify::stringify<float>::PRECISION = 3;
44 0 : utils::stringify::stringify<double>::PRECISION = 3;
45 :
46 0 : Log::ProgressLoggerTableOStream logger;
47 :
48 : // logger << std::fixed << std::setprecision(6);
49 :
50 : // clang-format off
51 0 : Dynamic::Env::Loader<
52 : const SUMO::NetworkTAZs &,
53 : Dynamic::RewardFunction &
54 0 : > loader;
55 : // clang-format on
56 :
57 : // Environment
58 0 : shared_ptr<SUMO::Network> sumoNetwork = SUMO::Network::loadFromFile(benchmarkDir + "data/dynaminator-data/porto.net.xml");
59 0 : SUMO::TAZs sumoTAZs = SUMO::TAZ::loadFromFile(benchmarkDir + "data/dynaminator-data/porto.taz.xml");
60 0 : SUMO::NetworkTAZs sumo{*sumoNetwork, sumoTAZs};
61 :
62 0 : Dynamic::RewardFunction &rewardFunction = Dynamic::RewardFunctionGreedy::INSTANCE;
63 :
64 0 : shared_ptr<Dynamic::Env::Env> env = loader.load(sumo, rewardFunction);
65 :
66 : // loader.adapter.dump();
67 :
68 : // Demand
69 0 : VISUM::OFormatDemand oDemand = VISUM::OFormatDemand::loadFromFile(benchmarkDir + "data/dynaminator-data/matrix.9.0.10.0.2.fma");
70 : // clang-format off
71 0 : Static::Demand::Loader<
72 : const VISUM::OFormatDemand &,
73 : const Static::SUMOAdapter &
74 : > staticDemandLoader;
75 : // clang-format on
76 0 : Static::Demand staticDemand = staticDemandLoader.load(
77 : oDemand,
78 : (Static::SUMOAdapter &)loader.adapter
79 0 : );
80 :
81 : // loader.adapter.dump();
82 :
83 : // Policy
84 0 : Alg::Graph G = env->toGraph();
85 :
86 0 : vector<Dynamic::Env::Node> startNodes;
87 0 : for(const Static::Network::Node &u: staticDemand.getStartNodes()) {
88 0 : SUMO::TAZ::ID fromTAZ = loader.adapter.toSumoTAZ(u);
89 0 : list<SUMO::TAZ::Source> sourcesList = loader.adapter.toTAZEdges(fromTAZ).first;
90 0 : for(const SUMO::TAZ::Source &source: sourcesList)
91 0 : if(source.weight > 0.0) {
92 0 : Dynamic::Env::Edge::ID edgeID = loader.adapter.toEdge(source.id);
93 0 : Dynamic::Env::Node nodeID = env->getEdge(edgeID).u;
94 0 : startNodes.push_back(nodeID);
95 : }
96 : }
97 :
98 0 : Alg::ShortestPath::DijkstraMany sp;
99 0 : sp.solve(G, startNodes);
100 :
101 0 : Dynamic::PathPolicy::ShortestPathFactory policyFactory(*env, 0);
102 :
103 : // Demand
104 0 : const double SCALE = 0.1;
105 :
106 0 : Dynamic::UniformDemandLoader demandLoader(SCALE, 0.0, 3600.0, policyFactory, 0);
107 0 : Dynamic::Demand demand = demandLoader.load(staticDemand, *env, loader.adapter).first;
108 :
109 0 : REQUIRE_THAT(demand.getVehicles().size(), WithinRel(MATRIX_9_10_TOTAL_DEMAND_HOUR * SCALE, 1e-2));
110 :
111 : // Load demand into environment
112 0 : env->addDemand(demand);
113 :
114 0 : env->initializeTrafficLights(0);
115 :
116 0 : env->log(logger, 0, 3600, 30);
117 :
118 0 : SUMO::NetState netState(baseDir + "data/out/netstate.xml", ios_base::out);
119 :
120 0 : list<thread> threads;
121 0 : const size_t MAX_NUMBER_THREADS = 64;
122 :
123 : // Run simulation
124 : // clang-format off
125 0 : SUMO::NetState::Timestep::Loader<
126 : Dynamic::Env::Env &,
127 : const Dynamic::SUMOAdapter &,
128 : Dynamic::Time
129 : > timestepLoader;
130 : // clang-format on
131 :
132 0 : for(Dynamic::Time t = 0.0; t <= 3600.0; t += 1.0) {
133 0 : env->runUntil(t);
134 :
135 0 : SUMO::NetState::Timestep timestep = timestepLoader.load(*env, loader.adapter, t);
136 :
137 : // clang-format off
138 0 : threads.emplace_back(
139 : [&netState](SUMO::NetState::Timestep ts) -> void {
140 : netState << ts;
141 : },
142 : timestep
143 0 : );
144 : // clang-format on
145 :
146 0 : while(threads.size() > MAX_NUMBER_THREADS) {
147 0 : threads.front().join();
148 0 : threads.pop_front();
149 : }
150 : }
151 :
152 0 : while(!threads.empty()) {
153 0 : threads.front().join();
154 0 : threads.pop_front();
155 : }
156 :
157 0 : env->runUntil(3600.0);
158 :
159 : // clang-format off
160 0 : SUMO::Routes::Loader<
161 : const std::list<std::reference_wrapper<const Dynamic::Env::Vehicle>> &,
162 : const SUMO::TAZs &,
163 : const Dynamic::SUMOAdapter &
164 : > routesLoader;
165 : // clang-format on
166 :
167 0 : const Dynamic::Env::Env &envConst = *env;
168 :
169 0 : SUMO::Routes routes = routesLoader.load(envConst.getVehicles(), sumo.tazs, loader.adapter);
170 :
171 0 : routes.saveToFile(baseDir + "data/out/sp.rou.xml");
172 0 : }
173 :
174 0 : void dynamic(Dynamic::RewardFunction &rewardFunction) {
175 0 : utils::stringify::stringify<float>::PRECISION = 3;
176 0 : utils::stringify::stringify<double>::PRECISION = 3;
177 :
178 0 : Log::ProgressLoggerTableOStream logger;
179 :
180 : // logger << std::fixed << std::setprecision(6);
181 :
182 : // clang-format off
183 0 : Dynamic::Env::Loader<
184 : const SUMO::NetworkTAZs &,
185 : Dynamic::RewardFunction &
186 0 : > loader;
187 : // clang-format on
188 :
189 : // Environment
190 0 : shared_ptr<SUMO::Network> sumoNetwork = SUMO::Network::loadFromFile(benchmarkDir + "data/dynaminator-data/porto.net.xml");
191 0 : SUMO::TAZs sumoTAZs = SUMO::TAZ::loadFromFile(benchmarkDir + "data/dynaminator-data/porto.taz.xml");
192 0 : SUMO::NetworkTAZs sumo{*sumoNetwork, sumoTAZs};
193 :
194 0 : shared_ptr<Dynamic::Env::Env> env = loader.load(sumo, rewardFunction);
195 :
196 : // loader.adapter.dump();
197 :
198 : // Demand
199 0 : VISUM::OFormatDemand oDemand = VISUM::OFormatDemand::loadFromFile(benchmarkDir + "data/dynaminator-data/matrix.9.0.10.0.2.fma");
200 : // clang-format off
201 0 : Static::Demand::Loader<
202 : const VISUM::OFormatDemand &,
203 : const Static::SUMOAdapter &
204 : > staticDemandLoader;
205 : // clang-format on
206 0 : Static::Demand staticDemand = staticDemandLoader.load(
207 : oDemand,
208 : (Static::SUMOAdapter &)loader.adapter
209 0 : );
210 :
211 0 : ofstream adapterDumpFile(baseDir + "data/out/adapter-dynamic.dump.txt");
212 0 : loader.adapter.dump(adapterDumpFile);
213 :
214 0 : const double HOUR2SEC = 3600.0;
215 :
216 : // Policy
217 0 : Dynamic::QLearner::Logger policyLogger(0.5);
218 :
219 0 : std::shared_ptr<Dynamic::Policy::Factory> policyFactory = make_shared<Dynamic::QLearner::Policy::Factory>(
220 0 : *env,
221 : sumo,
222 : loader.adapter,
223 0 : 0,
224 : policyLogger
225 0 : );
226 :
227 : // Demand
228 : // clang-format off
229 0 : std::vector<std::tuple<float, Dynamic::Time, Dynamic::Time>> demandSpecs = {
230 : {0.010, 0, 1},
231 : {0.100, 1, 10},
232 : {0.200, 10, 30},
233 : {0.300, 30, 43},
234 : {0.350, 43, 55},
235 : {0.375, 55, 75},
236 : {0.400, 75, 90},
237 : {0.425, 90, 100},
238 : {0.450, 100, 200},
239 :
240 0 : };
241 : // clang-format off
242 :
243 : // double END_SIMULATION = get<2>(demandSpecs.back()) * HOUR2SEC;
244 0 : double END_SIMULATION = 105 * HOUR2SEC;
245 :
246 0 : Dynamic::Vehicle::ID nextID = 0;
247 :
248 0 : for(auto &[scale, begin, end]: demandSpecs) {
249 0 : Dynamic::UniformDemandLoader demandLoader(scale, begin * HOUR2SEC, end * HOUR2SEC, *policyFactory, 0);
250 0 : auto p = demandLoader.load(staticDemand, *env, loader.adapter, nextID);
251 0 : auto [demand, id] = p;
252 0 : nextID = id;
253 0 : env->addDemand(demand);
254 : }
255 :
256 : // Load demand into environment
257 :
258 0 : env->initializeTrafficLights(5);
259 :
260 0 : env->log(logger, 0, END_SIMULATION, 600, policyLogger);
261 :
262 0 : env->setDiscardVehicles(true);
263 :
264 0 : env->setDespawnTime(5*60);
265 :
266 0 : SUMO::NetState netState(baseDir + "data/out/netstate.xml", ios_base::out);
267 :
268 : // env->dump(netState, loader.adapter, 0.0, 1.0, 5 * 3600);
269 :
270 0 : env->dump(netState, loader.adapter, 102 * HOUR2SEC, 0.25, 4 * 2 * HOUR2SEC, true);
271 :
272 0 : env->runUntil(END_SIMULATION);
273 :
274 0 : list<reference_wrapper<Dynamic::Env::Vehicle>> vehiclesList = env->getVehicles();
275 :
276 : // Create edgedata file
277 0 : SUMO::EdgeData edgeData;
278 :
279 0 : SUMO::EdgeData::Interval &interval = edgeData.createInterval(0.0, END_SIMULATION);
280 :
281 0 : for(const Dynamic::Env::Vehicle &vehicle: vehiclesList) {
282 0 : if(vehicle.state != Dynamic::Env::Vehicle::State::STOPPED) continue;
283 :
284 0 : SUMO::Network::Edge::ID edgeID = loader.adapter.toSumoEdge(vehicle.position.lane.edge.id);
285 0 : SUMO::Network::Edge::Lane::ID laneID = edgeID + "_" + to_string(vehicle.position.lane.index);
286 :
287 0 : if(!interval.hasEdge(edgeID)) {
288 0 : SUMO::EdgeData::Interval::Edge &edge = interval.createEdge(edgeID);
289 0 : edge.attributes.setAttribute("hasQueue", true);
290 : }
291 :
292 0 : SUMO::EdgeData::Interval::Edge &edge = interval.getEdge(edgeID);
293 :
294 0 : if(!edge.hasLane(laneID)) {
295 0 : SUMO::EdgeData::Interval::Edge::Lane &lane = edge.createLane(laneID);
296 :
297 0 : lane.attributes.setAttribute("queueSize", vehicle.position.lane.stopped.size());
298 : }
299 : }
300 :
301 0 : edgeData.saveToFile(benchmarkDir + "data/out/edgedata-ql-queues.xml");
302 :
303 : // policyFactory.dump();
304 :
305 : // // clang-format off
306 : // SUMO::Routes::Loader<
307 : // const std::list<std::reference_wrapper<const Dynamic::Env::Vehicle>> &,
308 : // const SUMO::TAZs &,
309 : // const Dynamic::SUMOAdapter &
310 : // > routesLoader;
311 : // // clang-format on
312 :
313 : // const Dynamic::Env::Env &envConst = env;
314 :
315 : // SUMO::Routes routes = routesLoader.load(envConst.getVehicles(), sumo.tazs, loader.adapter);
316 :
317 : // routes.saveToFile(baseDir + "data/out/routes-ql.xml");
318 0 : }
319 :
320 0 : TEST_CASE("Dynamic - Q-learning", "[dynamic][q-learn][!benchmark]") {
321 0 : SECTION("w=0.0") {
322 0 : Dynamic::RewardFunction &rewardFunction = Dynamic::RewardFunctionGreedy::INSTANCE;
323 0 : dynamic(rewardFunction);
324 : }
325 0 : SECTION("w=0.1") {
326 0 : Dynamic::RewardFunctionDifference rewardFunction(0.1);
327 0 : dynamic(rewardFunction);
328 : }
329 0 : SECTION("w=0.5") {
330 0 : Dynamic::RewardFunctionDifference rewardFunction(0.5);
331 0 : dynamic(rewardFunction);
332 : }
333 0 : SECTION("w=0.75") {
334 0 : Dynamic::RewardFunctionDifference rewardFunction(0.75);
335 0 : dynamic(rewardFunction);
336 : }
337 0 : SECTION("w=0.9") {
338 0 : Dynamic::RewardFunctionDifference rewardFunction(0.9);
339 0 : dynamic(rewardFunction);
340 : }
341 0 : SECTION("w=1.0") {
342 0 : Dynamic::RewardFunctionDifference rewardFunction(1.0);
343 0 : dynamic(rewardFunction);
344 : }
345 0 : SECTION("w=1.1") {
346 0 : Dynamic::RewardFunctionDifference rewardFunction(1.1);
347 0 : dynamic(rewardFunction);
348 : }
349 0 : }
350 :
351 0 : TEST_CASE("Dynamic - Q-learners - small", "[dynamic][q-learn-small][!benchmark]") {
352 0 : utils::stringify::stringify<float>::PRECISION = 3;
353 0 : utils::stringify::stringify<double>::PRECISION = 3;
354 :
355 0 : Log::ProgressLoggerTableOStream logger;
356 :
357 : // logger << std::fixed << std::setprecision(6);
358 :
359 : // clang-format off
360 0 : Dynamic::Env::Loader<
361 : const SUMO::NetworkTAZs &,
362 : Dynamic::RewardFunction &
363 0 : > loader;
364 : // clang-format on
365 :
366 : // Environment
367 0 : shared_ptr<SUMO::Network> sumoNetwork = SUMO::Network::loadFromFile(benchmarkDir + "data/dynaminator-data/porto.net.xml");
368 0 : SUMO::TAZs sumoTAZs = SUMO::TAZ::loadFromFile(benchmarkDir + "data/dynaminator-data/porto.taz.xml");
369 0 : SUMO::NetworkTAZs sumo{*sumoNetwork, sumoTAZs};
370 :
371 0 : shared_ptr<Dynamic::Env::Env> env = loader.load(sumo, Dynamic::RewardFunctionGreedy::INSTANCE);
372 :
373 : // loader.adapter.dump();
374 :
375 : // Demand
376 0 : VISUM::OFormatDemand oDemand = VISUM::OFormatDemand::loadFromFile(benchmarkDir + "data/dynaminator-data/matrix.9.0.10.0.2.fma");
377 : // clang-format off
378 0 : Static::Demand::Loader<
379 : const VISUM::OFormatDemand &,
380 : const Static::SUMOAdapter &
381 : > staticDemandLoader;
382 : // clang-format on
383 0 : Static::Demand staticDemand = staticDemandLoader.load(
384 : oDemand,
385 : (Static::SUMOAdapter &)loader.adapter
386 0 : );
387 :
388 0 : ofstream adapterDumpFile(baseDir + "data/out/adapter-dynamic.dump.txt");
389 0 : loader.adapter.dump(adapterDumpFile);
390 :
391 0 : const double HOUR2SEC = 3600.0;
392 :
393 : // Policy
394 0 : Dynamic::QLearner::Logger policyLogger(0.5);
395 :
396 0 : std::shared_ptr<Dynamic::Policy::Factory> policyFactory = make_shared<Dynamic::QLearner::Policy::Factory>(
397 0 : *env,
398 : sumo,
399 : loader.adapter,
400 0 : 0,
401 : policyLogger
402 0 : );
403 :
404 : // Demand
405 : // clang-format off
406 0 : std::vector<std::tuple<float, Dynamic::Time, Dynamic::Time>> demandSpecs = {
407 : {0.2, 0, 1},
408 0 : };
409 : // clang-format off
410 :
411 0 : double END_SIMULATION = get<2>(demandSpecs.back()) * HOUR2SEC;
412 : // double END_SIMULATION = 130 * HOUR2SEC;
413 :
414 0 : Dynamic::Vehicle::ID nextID = 0;
415 :
416 0 : for(auto &[scale, begin, end]: demandSpecs) {
417 0 : Dynamic::UniformDemandLoader demandLoader(scale, begin * HOUR2SEC, end * HOUR2SEC, *policyFactory, 0);
418 0 : auto p = demandLoader.load(staticDemand, *env, loader.adapter, nextID);
419 0 : auto [demand, id] = p;
420 0 : nextID = id;
421 0 : env->addDemand(demand);
422 : }
423 :
424 : // Load demand into environment
425 :
426 0 : env->initializeTrafficLights(0);
427 :
428 0 : env->log(logger, 0, END_SIMULATION, 600, policyLogger);
429 :
430 0 : env->runUntil(END_SIMULATION);
431 :
432 0 : list<reference_wrapper<Dynamic::Env::Vehicle>> vehiclesList = env->getVehicles();
433 :
434 : // Create edgedata file
435 0 : SUMO::EdgeData edgeData;
436 :
437 0 : SUMO::EdgeData::Interval &interval = edgeData.createInterval(0.0, END_SIMULATION);
438 :
439 0 : for(const Dynamic::Env::Vehicle &vehicle: vehiclesList) {
440 0 : if(vehicle.state != Dynamic::Env::Vehicle::State::STOPPED) continue;
441 :
442 0 : SUMO::Network::Edge::ID edgeID = loader.adapter.toSumoEdge(vehicle.position.lane.edge.id);
443 0 : SUMO::Network::Edge::Lane::ID laneID = edgeID + "_" + to_string(vehicle.position.lane.index);
444 :
445 0 : if(!interval.hasEdge(edgeID)) {
446 0 : SUMO::EdgeData::Interval::Edge &edge = interval.createEdge(edgeID);
447 0 : edge.attributes.setAttribute("hasQueue", true);
448 : }
449 :
450 0 : SUMO::EdgeData::Interval::Edge &edge = interval.getEdge(edgeID);
451 :
452 0 : if(!edge.hasLane(laneID)) {
453 0 : SUMO::EdgeData::Interval::Edge::Lane &lane = edge.createLane(laneID);
454 :
455 0 : lane.attributes.setAttribute("queueSize", vehicle.position.lane.stopped.size());
456 : }
457 : }
458 :
459 0 : edgeData.saveToFile(benchmarkDir + "data/out/edgedata-ql-queues.xml");
460 :
461 : // policyFactory.dump();
462 :
463 : // clang-format off
464 0 : SUMO::Routes::Loader<
465 : const std::list<std::reference_wrapper<const Dynamic::Env::Vehicle>> &,
466 : const SUMO::TAZs &,
467 : const Dynamic::SUMOAdapter &
468 : > routesLoader;
469 : // clang-format on
470 :
471 0 : const Dynamic::Env::Env &envConst = *env;
472 :
473 0 : SUMO::Routes routes = routesLoader.load(envConst.getVehicles(), sumo.tazs, loader.adapter);
474 :
475 0 : routes.saveToFile(baseDir + "data/out/routes-ql.xml");
476 0 : }
|