Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file FareModul.h
15 : /// @author Ricardo Euler
16 : /// @date Thu, 17 August 2018
17 : ///
18 : // Fare Modul for calculating prices during intermodal routing
19 : /****************************************************************************/
20 : #pragma once
21 : #include <config.h>
22 :
23 : #include <cassert>
24 : #include <string>
25 : #include <vector>
26 : #include "EffortCalculator.h"
27 : #include "FareToken.h"
28 : #include "FareZones.h"
29 :
30 :
31 : // ===========================================================================
32 : // class definitions
33 : // ===========================================================================
34 : class ZoneCounter {
35 : public:
36 :
37 0 : explicit ZoneCounter(unsigned int ct) :
38 0 : myCount(ct) {
39 :
40 : }
41 :
42 0 : inline void addZone(int zoneNumber) {
43 0 : zoneNumber = getOverlayZone(zoneNumber);
44 0 : if (zoneNumber == 0) {
45 : return;
46 : }
47 0 : long long int repNum = fareZoneToRep[zoneNumber];
48 : //assert power of 2
49 0 : if (bitcount(repNum) == 0) {
50 : return;
51 : }
52 0 : myCount = myCount | repNum;
53 : }
54 :
55 :
56 : int numZones() const {
57 0 : return bitcount(myCount);
58 : }
59 :
60 :
61 : private:
62 : inline int bitcount(long long int intVal) const {
63 : int count = 0;
64 : long long int counter = intVal;
65 :
66 0 : while (counter != 0) {
67 0 : counter = counter & (counter - 1);
68 0 : ++count;
69 : }
70 : return count;
71 : }
72 :
73 : private:
74 : long long int myCount;
75 :
76 :
77 : };
78 :
79 :
80 :
81 : /**
82 : * A fare state collects all the information that is necessary to compute the price. Is used as an edge label
83 : * in IntermodalRouter
84 : */
85 : struct FareState {
86 : friend class FareModul;
87 :
88 : public:
89 :
90 : /** default constructor for unlabeled edges**/
91 0 : explicit FareState():
92 0 : myFareToken(FareToken::None),
93 : myCounter(std::numeric_limits<int>::max()),
94 0 : myTravelledDistance(std::numeric_limits<double>::max()),
95 0 : myVisistedStops(std::numeric_limits<int>::max()),
96 0 : myPriceDiff(0) {
97 : };
98 :
99 : /**
100 : *
101 : * @param token
102 : */
103 : explicit FareState(FareToken token):
104 : myFareToken(token),
105 : myCounter(0),
106 : myTravelledDistance(0),
107 : myVisistedStops(0),
108 : myPriceDiff(0) {}
109 :
110 : /** Destructor **/
111 : ~FareState() = default;
112 :
113 : /**
114 : * returns true if fare state is set and not on default
115 : * @return if state is set
116 : */
117 : bool isValid() const {
118 0 : return !(myFareToken == FareToken::None);
119 : }
120 :
121 : private:
122 :
123 : /** fare token **/
124 : FareToken myFareToken;
125 : /** zone counter **/
126 : ZoneCounter myCounter;
127 : /** travelled distance in km**/
128 : double myTravelledDistance;
129 : /**num of visited stops**/
130 : int myVisistedStops;
131 : /** price diff to previous edge **/
132 : double myPriceDiff;
133 :
134 : };
135 :
136 :
137 :
138 : struct Prices {
139 :
140 :
141 :
142 : /** Prices for zones **/
143 : std::vector<double> zonePrices = std::vector<double> {1.9, 3.4, 4.9, 6.2, 7.7, 9.2};
144 : double halle = 2.3;
145 : double leipzig = 2.7;
146 : double t1 = 1.5;
147 : double t2 = 1.6;
148 : double t3 = 1.6;
149 : double shortTrip = 1.6;
150 : double shortTripLeipzig = 1.9;
151 : double shortTripHalle = 1.7;
152 : double maxPrice = 10.6;
153 : };
154 :
155 :
156 : /**
157 : * The fare modul responsible for calculating prices
158 : */
159 : class FareModul : public EffortCalculator {
160 : public:
161 :
162 : /** Constructor ***/
163 0 : FareModul() :
164 0 : myFareStates()
165 0 : {};
166 :
167 : /**Implementation of EffortCalculator **/
168 0 : void init(const std::vector<std::string>& edges) override {
169 0 : myEdges = edges;
170 0 : myFareStates.resize(edges.size());
171 0 : }
172 :
173 0 : void addStop(const int stopEdge, const Parameterised& params) override {
174 0 : myStopFareZone[stopEdge] = StringUtils::toInt(params.getParameter("fareZone"));
175 0 : myStopFareToken[stopEdge] = FareUtil::stringToToken(params.getParameter("fareToken"));
176 0 : myStopStartToken[stopEdge] = FareUtil::stringToToken(params.getParameter("startToken"));
177 0 : }
178 :
179 : /**Implementation of EffortCalculator **/
180 0 : double getEffort(const int numericalID) const override {
181 : double effort = 0;
182 0 : FareState const& state = myFareStates.at(numericalID);
183 0 : if (state.isValid()) {
184 0 : effort = state.myPriceDiff;
185 : } else {
186 : effort = std::numeric_limits<double>::max();
187 : }
188 0 : return effort;
189 : }
190 :
191 : /** Implementation of EffortCalculator **/
192 0 : void update(const int edge, const int prev, const double length) override {
193 :
194 0 : std::string const& edgeType = myEdges[edge];
195 :
196 : //get propagated fare state
197 0 : FareState& state = myFareStates.at(prev);
198 :
199 : double oldPr;
200 0 : if (state.myFareToken == FareToken::START) {
201 : oldPr = 0;
202 : } else {
203 0 : oldPr = computePrice(state);
204 : }
205 : //treat public transport edges
206 0 : if (edgeType.c_str()[0] != '!') {
207 : updateFareStatePublic(state, edge, length);
208 0 : } else if (edgeType == "!stop") {
209 0 : updateFareStateStop(state, edge);
210 0 : } else if (edgeType == "!ped") {
211 : updateFareStatePedestrian(state, edge);
212 0 : } else if (edgeType == "!access") {
213 0 : updateFareStateAccess(state, edge, prev);
214 : } else {
215 : updateFareState(state, edge);
216 : }
217 : FareState& stateAtE = myFareStates[edge];
218 0 : double newPr = computePrice(stateAtE);
219 0 : stateAtE.myPriceDiff = newPr - oldPr;
220 :
221 : assert(stateAtE.myPriceDiff >= 0);
222 :
223 0 : }
224 :
225 : /** Implementation of EffortCalculator
226 : * _IntermodalEdge should be an Connector Edge **/
227 0 : void setInitialState(const int edge) override {
228 : // assert( edge->getLine() == "!connector");
229 :
230 0 : myFareStates[edge] = FareState(FareToken::START);
231 :
232 0 : }
233 :
234 :
235 : private:
236 : /** List of all fare states **/
237 : std::vector<FareState> myFareStates;
238 :
239 : /** List of all edge line attributes **/
240 : std::vector<std::string> myEdges;
241 :
242 : /** the fare zone this stop is a part of **/
243 : std::map<int, int> myStopFareZone;
244 :
245 : /** the faretoken that can be collected at this station **/
246 : std::map<int, FareToken> myStopFareToken;
247 :
248 : /** the faretoken that is used when a trip is started at this station **/
249 : std::map<int, FareToken> myStopStartToken;
250 :
251 : /** List of the prices **/
252 : Prices prices;
253 :
254 0 : double computePrice(FareState const& fareState) const {
255 0 : switch (fareState.myFareToken) {
256 0 : case FareToken ::H:
257 0 : return prices.halle;
258 0 : case FareToken ::L:
259 0 : return prices.leipzig;
260 0 : case FareToken ::T1:
261 0 : return prices.t1;
262 0 : case FareToken ::T2:
263 0 : return prices.t2;
264 0 : case FareToken ::T3:
265 0 : return prices.t3;
266 0 : case FareToken::U:
267 0 : return prices.zonePrices[0];
268 0 : case FareToken ::Z:
269 0 : return prices.zonePrices[fareState.myCounter.numZones() - 1];
270 0 : case FareToken ::M:
271 0 : return prices.maxPrice;
272 0 : case FareToken ::K:
273 0 : return prices.shortTrip;
274 0 : case FareToken ::KL:
275 : case FareToken ::KLZ:
276 : case FareToken ::KLU:
277 0 : return prices.shortTripLeipzig;
278 0 : case FareToken ::KH:
279 : case FareToken ::KHU:
280 : case FareToken ::KHZ:
281 0 : return prices.shortTripHalle;
282 : case FareToken::Free:
283 : return 1.4;
284 0 : case FareToken ::START:
285 0 : return 0;
286 0 : case FareToken::ZU:
287 : case FareToken::None:
288 : assert(false);
289 :
290 : }
291 0 : return std::numeric_limits<double>::max();
292 : }
293 :
294 :
295 :
296 0 : std::string output(const int edge) const override {
297 :
298 0 : FareState const& my = myFareStates[edge];
299 0 : std::stringstream msg;
300 : /*
301 : msg << "Final fare state at edge of type: " << myEdges[edge] << std::endl;
302 : msg << "Faretoken" << FareUtil::tokenToString(my.myFareToken) << std::endl;
303 : msg << "Price:" << computePrice(my) << std::endl;
304 : msg << "Zones " << my.myCounter.numZones() << std::endl;
305 : msg << "Stations: " << my.myVisistedStops << std::endl;
306 : msg << "Distance:" << my.myTravelledDistance << std::endl;
307 : */
308 0 : msg << FareUtil::tokenToTicket(my.myFareToken) << " ";
309 0 : if (my.myFareToken == FareToken::Z) {
310 0 : msg << my.myCounter.numZones() << " ";
311 0 : if (my.myCounter.numZones() == 1) {
312 0 : msg << "Zone";
313 : } else {
314 0 : msg << "Zonen";
315 : }
316 :
317 0 : } else if (my.myFareToken == FareToken::U) {
318 0 : msg << my.myCounter.numZones() << "1 Zone";
319 :
320 : }
321 0 : msg << ":" << computePrice(my);
322 0 : return msg.str();
323 0 : }
324 :
325 0 : void updateFareStateStop(FareState const& currentFareState, const int stopEdge) {
326 :
327 0 : FareToken collectedToken = myStopFareToken[stopEdge];
328 :
329 : //if station has no fare information, just propagate
330 0 : if (collectedToken == FareToken::None) {
331 : std::cout << "Propagating fare state for stop w/o a price!" << std::endl;
332 0 : return;
333 : }
334 :
335 : FareToken const& token = currentFareState.myFareToken;
336 :
337 0 : FareState& stateAtE = myFareStates[stopEdge];
338 :
339 0 : stateAtE = currentFareState;
340 :
341 0 : stateAtE.myCounter.addZone(myStopFareZone[stopEdge]);
342 :
343 0 : stateAtE.myVisistedStops++;
344 :
345 0 : switch (token) {
346 0 : case FareToken ::Free:
347 0 : stateAtE.myFareToken = myStopStartToken[stopEdge];
348 0 : break;
349 : case FareToken::M :
350 : break;
351 :
352 0 : case FareToken::Z :
353 0 : if (stateAtE.myCounter.numZones() > 6) {
354 0 : stateAtE.myFareToken = FareToken::M;
355 : }
356 : break;
357 :
358 0 : case FareToken::T1 :
359 : case FareToken::T2 :
360 : case FareToken::T3 :
361 0 : if (collectedToken == FareToken::Z) {
362 0 : stateAtE.myFareToken = stateAtE.myTravelledDistance <= 4000 ? FareToken::K : FareToken::Z;
363 : }
364 : break;
365 0 : case FareToken::U :
366 0 : if (collectedToken == FareToken::H) {
367 0 : stateAtE.myFareToken = FareToken::H;
368 : }
369 0 : if (collectedToken == FareToken::L) {
370 0 : stateAtE.myFareToken = FareToken::L;
371 : }
372 0 : if (collectedToken == FareToken::Z) {
373 0 : stateAtE.myFareToken = FareToken::Z;
374 : }
375 : break;
376 0 : case FareToken::H:
377 : case FareToken::L:
378 0 : if (collectedToken == FareToken::Z) {
379 0 : stateAtE.myFareToken = FareToken::Z;
380 : }
381 : break;
382 0 : case FareToken::KH:
383 0 : if (stateAtE.myVisistedStops <= 4) {
384 0 : if (collectedToken == FareToken::U) {
385 0 : stateAtE.myFareToken = FareToken::KHU;
386 : }
387 0 : if (collectedToken == FareToken::Z) {
388 0 : stateAtE.myFareToken = FareToken::KHZ;
389 : }
390 : } else {
391 0 : if (collectedToken == FareToken::H) {
392 0 : stateAtE.myFareToken = FareToken ::H;
393 : }
394 0 : if (collectedToken == FareToken::Z) {
395 0 : stateAtE.myFareToken = FareToken ::Z;
396 : }
397 0 : if (collectedToken == FareToken::U) {
398 0 : stateAtE.myFareToken = FareToken ::U;
399 : }
400 : }
401 : break;
402 0 : case FareToken::KL:
403 0 : if (stateAtE.myVisistedStops <= 4) {
404 0 : if (collectedToken == FareToken::U) {
405 0 : stateAtE.myFareToken = FareToken::KLU;
406 : }
407 0 : if (collectedToken == FareToken::Z) {
408 0 : stateAtE.myFareToken = FareToken::KLZ;
409 : }
410 : } else {
411 0 : if (collectedToken == FareToken::L) {
412 0 : stateAtE.myFareToken = FareToken ::L;
413 : }
414 0 : if (collectedToken == FareToken::Z) {
415 0 : stateAtE.myFareToken = FareToken ::Z;
416 : }
417 0 : if (collectedToken == FareToken::U) {
418 0 : stateAtE.myFareToken = FareToken ::U;
419 : }
420 : }
421 : break;
422 0 : case FareToken::K:
423 0 : if (stateAtE.myTravelledDistance > 4000) {
424 0 : if (collectedToken == FareToken::U) {
425 0 : stateAtE.myFareToken = FareToken ::U;
426 : }
427 0 : if (collectedToken == FareToken::Z) {
428 0 : stateAtE.myFareToken = FareToken ::Z;
429 : }
430 : }
431 : break;
432 0 : case FareToken::KHU :
433 : case FareToken::KLU :
434 0 : if (stateAtE.myVisistedStops > 4) {
435 0 : if (collectedToken == FareToken::U) {
436 0 : stateAtE.myFareToken = FareToken::U;
437 : }
438 : }
439 : break;
440 :
441 0 : case FareToken::KLZ:
442 : case FareToken::KHZ:
443 0 : if (stateAtE.myVisistedStops > 4) {
444 0 : if (collectedToken == FareToken::Z) {
445 0 : stateAtE.myFareToken = FareToken::Z;
446 : }
447 : }
448 : break;
449 0 : case FareToken::ZU :
450 : assert(false);
451 0 : if (collectedToken == FareToken::U) {
452 0 : stateAtE.myFareToken = FareToken::U;
453 : } else {
454 0 : stateAtE.myFareToken = FareToken::Z;
455 : }
456 :
457 : break;
458 : default:
459 : std::cout << "Reached invalid position in fareToken selection!" << std::endl;
460 : assert(false);
461 : break;
462 : }
463 : }
464 :
465 : void updateFareStatePedestrian(FareState const& currentFareState, const int pedestrianEdge) {
466 :
467 : //only propagates the fare state
468 : FareState& stateAtE = myFareStates[pedestrianEdge];
469 :
470 0 : stateAtE = currentFareState;
471 :
472 0 : if (currentFareState.myFareToken == FareToken::START) {
473 0 : stateAtE.myFareToken = FareToken::Free;
474 : }
475 :
476 : }
477 :
478 :
479 : void updateFareStatePublic(FareState const& currentFareState, const int publicTransportEdge, const double length) {
480 :
481 :
482 0 : if (currentFareState.myFareToken == FareToken::None) {
483 : return;
484 : }
485 :
486 : FareState& stateAtE = myFareStates[publicTransportEdge];
487 :
488 0 : stateAtE = currentFareState;
489 0 : stateAtE.myTravelledDistance += length;
490 : }
491 :
492 : void updateFareState(FareState const& currentFareState, const int intermodalEdge) {
493 :
494 0 : if (currentFareState.myFareToken == FareToken::None) {
495 : return;
496 : }
497 :
498 : FareState& stateAtE = myFareStates[intermodalEdge];
499 :
500 0 : stateAtE = currentFareState;
501 :
502 0 : if (currentFareState.myFareToken == FareToken::START) {
503 0 : stateAtE.myFareToken = FareToken::Free;
504 : }
505 :
506 : }
507 :
508 0 : void updateFareStateAccess(FareState const& currentFareState, const int accessEdge, const int prev) {
509 :
510 : FareToken const& token = currentFareState.myFareToken;
511 :
512 0 : FareState& stateAtE = myFareStates[accessEdge];
513 :
514 0 : stateAtE = currentFareState;
515 :
516 0 : if (currentFareState.myFareToken == FareToken::START) {
517 0 : stateAtE.myFareToken = FareToken::Free;
518 : }
519 :
520 0 : if (myEdges[prev] == "!ped") {
521 0 : switch (token) {
522 :
523 : case FareToken::Free ://we have not yet taken public transport
524 : break;
525 0 : case FareToken::K :
526 0 : if (currentFareState.myCounter.numZones() == 0) {
527 0 : stateAtE.myFareToken = FareToken::U;
528 : } else {
529 0 : stateAtE.myFareToken = FareToken::Z;
530 : }
531 : break;
532 0 : case FareToken::KH :
533 0 : stateAtE.myFareToken = FareToken::H;
534 0 : break;
535 0 : case FareToken::KL :
536 0 : stateAtE.myFareToken = FareToken::L;
537 0 : break;
538 0 : case FareToken::KLU :
539 0 : stateAtE.myFareToken = FareToken::L;
540 0 : break;
541 0 : case FareToken::KHU:
542 0 : stateAtE.myFareToken = FareToken::H;
543 0 : break;
544 0 : case FareToken::KLZ :
545 0 : stateAtE.myFareToken = FareToken::Z;
546 0 : break;
547 0 : case FareToken::KHZ:
548 0 : stateAtE.myFareToken = FareToken::Z;
549 0 : break;
550 : default:
551 : return;
552 : }
553 : }
554 :
555 : }
556 : };
|