Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/router/FareModul.h
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2002-2025 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
explicit ZoneCounter(unsigned int ct) :
38
myCount(ct) {
39
40
}
41
42
inline void addZone(int zoneNumber) {
43
zoneNumber = getOverlayZone(zoneNumber);
44
if (zoneNumber == 0) {
45
return;
46
}
47
long long int repNum = fareZoneToRep[zoneNumber];
48
//assert power of 2
49
if (bitcount(repNum) == 0) {
50
return;
51
}
52
myCount = myCount | repNum;
53
}
54
55
56
int numZones() const {
57
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
while (counter != 0) {
67
counter = counter & (counter - 1);
68
++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
explicit FareState():
92
myFareToken(FareToken::None),
93
myCounter(std::numeric_limits<int>::max()),
94
myTravelledDistance(std::numeric_limits<double>::max()),
95
myVisistedStops(std::numeric_limits<int>::max()),
96
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
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
FareModul() :
164
myFareStates()
165
{};
166
167
/**Implementation of EffortCalculator **/
168
void init(const std::vector<std::string>& edges) override {
169
myEdges = edges;
170
myFareStates.resize(edges.size());
171
}
172
173
void addStop(const int stopEdge, const Parameterised& params) override {
174
myStopFareZone[stopEdge] = StringUtils::toInt(params.getParameter("fareZone"));
175
myStopFareToken[stopEdge] = FareUtil::stringToToken(params.getParameter("fareToken"));
176
myStopStartToken[stopEdge] = FareUtil::stringToToken(params.getParameter("startToken"));
177
}
178
179
/**Implementation of EffortCalculator **/
180
double getEffort(const int numericalID) const override {
181
double effort = 0;
182
FareState const& state = myFareStates.at(numericalID);
183
if (state.isValid()) {
184
effort = state.myPriceDiff;
185
} else {
186
effort = std::numeric_limits<double>::max();
187
}
188
return effort;
189
}
190
191
/** Implementation of EffortCalculator **/
192
void update(const int edge, const int prev, const double length) override {
193
194
std::string const& edgeType = myEdges[edge];
195
196
//get propagated fare state
197
FareState& state = myFareStates.at(prev);
198
199
double oldPr;
200
if (state.myFareToken == FareToken::START) {
201
oldPr = 0;
202
} else {
203
oldPr = computePrice(state);
204
}
205
//treat public transport edges
206
if (edgeType.c_str()[0] != '!') {
207
updateFareStatePublic(state, edge, length);
208
} else if (edgeType == "!stop") {
209
updateFareStateStop(state, edge);
210
} else if (edgeType == "!ped") {
211
updateFareStatePedestrian(state, edge);
212
} else if (edgeType == "!access") {
213
updateFareStateAccess(state, edge, prev);
214
} else {
215
updateFareState(state, edge);
216
}
217
FareState& stateAtE = myFareStates[edge];
218
double newPr = computePrice(stateAtE);
219
stateAtE.myPriceDiff = newPr - oldPr;
220
221
assert(stateAtE.myPriceDiff >= 0);
222
223
}
224
225
/** Implementation of EffortCalculator
226
* _IntermodalEdge should be an Connector Edge **/
227
void setInitialState(const int edge) override {
228
// assert( edge->getLine() == "!connector");
229
230
myFareStates[edge] = FareState(FareToken::START);
231
232
}
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
double computePrice(FareState const& fareState) const {
255
switch (fareState.myFareToken) {
256
case FareToken ::H:
257
return prices.halle;
258
case FareToken ::L:
259
return prices.leipzig;
260
case FareToken ::T1:
261
return prices.t1;
262
case FareToken ::T2:
263
return prices.t2;
264
case FareToken ::T3:
265
return prices.t3;
266
case FareToken::U:
267
return prices.zonePrices[0];
268
case FareToken ::Z:
269
return prices.zonePrices[fareState.myCounter.numZones() - 1];
270
case FareToken ::M:
271
return prices.maxPrice;
272
case FareToken ::K:
273
return prices.shortTrip;
274
case FareToken ::KL:
275
case FareToken ::KLZ:
276
case FareToken ::KLU:
277
return prices.shortTripLeipzig;
278
case FareToken ::KH:
279
case FareToken ::KHU:
280
case FareToken ::KHZ:
281
return prices.shortTripHalle;
282
case FareToken::Free:
283
return 1.4;
284
case FareToken ::START:
285
return 0;
286
case FareToken::ZU:
287
case FareToken::None:
288
assert(false);
289
290
}
291
return std::numeric_limits<double>::max();
292
}
293
294
295
296
std::string output(const int edge) const override {
297
298
FareState const& my = myFareStates[edge];
299
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
msg << FareUtil::tokenToTicket(my.myFareToken) << " ";
309
if (my.myFareToken == FareToken::Z) {
310
msg << my.myCounter.numZones() << " ";
311
if (my.myCounter.numZones() == 1) {
312
msg << "Zone";
313
} else {
314
msg << "Zonen";
315
}
316
317
} else if (my.myFareToken == FareToken::U) {
318
msg << my.myCounter.numZones() << "1 Zone";
319
320
}
321
msg << ":" << computePrice(my);
322
return msg.str();
323
}
324
325
void updateFareStateStop(FareState const& currentFareState, const int stopEdge) {
326
327
FareToken collectedToken = myStopFareToken[stopEdge];
328
329
//if station has no fare information, just propagate
330
if (collectedToken == FareToken::None) {
331
std::cout << "Propagating fare state for stop w/o a price!" << std::endl;
332
return;
333
}
334
335
FareToken const& token = currentFareState.myFareToken;
336
337
FareState& stateAtE = myFareStates[stopEdge];
338
339
stateAtE = currentFareState;
340
341
stateAtE.myCounter.addZone(myStopFareZone[stopEdge]);
342
343
stateAtE.myVisistedStops++;
344
345
switch (token) {
346
case FareToken ::Free:
347
stateAtE.myFareToken = myStopStartToken[stopEdge];
348
break;
349
case FareToken::M :
350
break;
351
352
case FareToken::Z :
353
if (stateAtE.myCounter.numZones() > 6) {
354
stateAtE.myFareToken = FareToken::M;
355
}
356
break;
357
358
case FareToken::T1 :
359
case FareToken::T2 :
360
case FareToken::T3 :
361
if (collectedToken == FareToken::Z) {
362
stateAtE.myFareToken = stateAtE.myTravelledDistance <= 4000 ? FareToken::K : FareToken::Z;
363
}
364
break;
365
case FareToken::U :
366
if (collectedToken == FareToken::H) {
367
stateAtE.myFareToken = FareToken::H;
368
}
369
if (collectedToken == FareToken::L) {
370
stateAtE.myFareToken = FareToken::L;
371
}
372
if (collectedToken == FareToken::Z) {
373
stateAtE.myFareToken = FareToken::Z;
374
}
375
break;
376
case FareToken::H:
377
case FareToken::L:
378
if (collectedToken == FareToken::Z) {
379
stateAtE.myFareToken = FareToken::Z;
380
}
381
break;
382
case FareToken::KH:
383
if (stateAtE.myVisistedStops <= 4) {
384
if (collectedToken == FareToken::U) {
385
stateAtE.myFareToken = FareToken::KHU;
386
}
387
if (collectedToken == FareToken::Z) {
388
stateAtE.myFareToken = FareToken::KHZ;
389
}
390
} else {
391
if (collectedToken == FareToken::H) {
392
stateAtE.myFareToken = FareToken ::H;
393
}
394
if (collectedToken == FareToken::Z) {
395
stateAtE.myFareToken = FareToken ::Z;
396
}
397
if (collectedToken == FareToken::U) {
398
stateAtE.myFareToken = FareToken ::U;
399
}
400
}
401
break;
402
case FareToken::KL:
403
if (stateAtE.myVisistedStops <= 4) {
404
if (collectedToken == FareToken::U) {
405
stateAtE.myFareToken = FareToken::KLU;
406
}
407
if (collectedToken == FareToken::Z) {
408
stateAtE.myFareToken = FareToken::KLZ;
409
}
410
} else {
411
if (collectedToken == FareToken::L) {
412
stateAtE.myFareToken = FareToken ::L;
413
}
414
if (collectedToken == FareToken::Z) {
415
stateAtE.myFareToken = FareToken ::Z;
416
}
417
if (collectedToken == FareToken::U) {
418
stateAtE.myFareToken = FareToken ::U;
419
}
420
}
421
break;
422
case FareToken::K:
423
if (stateAtE.myTravelledDistance > 4000) {
424
if (collectedToken == FareToken::U) {
425
stateAtE.myFareToken = FareToken ::U;
426
}
427
if (collectedToken == FareToken::Z) {
428
stateAtE.myFareToken = FareToken ::Z;
429
}
430
}
431
break;
432
case FareToken::KHU :
433
case FareToken::KLU :
434
if (stateAtE.myVisistedStops > 4) {
435
if (collectedToken == FareToken::U) {
436
stateAtE.myFareToken = FareToken::U;
437
}
438
}
439
break;
440
441
case FareToken::KLZ:
442
case FareToken::KHZ:
443
if (stateAtE.myVisistedStops > 4) {
444
if (collectedToken == FareToken::Z) {
445
stateAtE.myFareToken = FareToken::Z;
446
}
447
}
448
break;
449
case FareToken::ZU :
450
assert(false);
451
if (collectedToken == FareToken::U) {
452
stateAtE.myFareToken = FareToken::U;
453
} else {
454
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
stateAtE = currentFareState;
471
472
if (currentFareState.myFareToken == FareToken::START) {
473
stateAtE.myFareToken = FareToken::Free;
474
}
475
476
}
477
478
479
void updateFareStatePublic(FareState const& currentFareState, const int publicTransportEdge, const double length) {
480
481
482
if (currentFareState.myFareToken == FareToken::None) {
483
return;
484
}
485
486
FareState& stateAtE = myFareStates[publicTransportEdge];
487
488
stateAtE = currentFareState;
489
stateAtE.myTravelledDistance += length;
490
}
491
492
void updateFareState(FareState const& currentFareState, const int intermodalEdge) {
493
494
if (currentFareState.myFareToken == FareToken::None) {
495
return;
496
}
497
498
FareState& stateAtE = myFareStates[intermodalEdge];
499
500
stateAtE = currentFareState;
501
502
if (currentFareState.myFareToken == FareToken::START) {
503
stateAtE.myFareToken = FareToken::Free;
504
}
505
506
}
507
508
void updateFareStateAccess(FareState const& currentFareState, const int accessEdge, const int prev) {
509
510
FareToken const& token = currentFareState.myFareToken;
511
512
FareState& stateAtE = myFareStates[accessEdge];
513
514
stateAtE = currentFareState;
515
516
if (currentFareState.myFareToken == FareToken::START) {
517
stateAtE.myFareToken = FareToken::Free;
518
}
519
520
if (myEdges[prev] == "!ped") {
521
switch (token) {
522
523
case FareToken::Free ://we have not yet taken public transport
524
break;
525
case FareToken::K :
526
if (currentFareState.myCounter.numZones() == 0) {
527
stateAtE.myFareToken = FareToken::U;
528
} else {
529
stateAtE.myFareToken = FareToken::Z;
530
}
531
break;
532
case FareToken::KH :
533
stateAtE.myFareToken = FareToken::H;
534
break;
535
case FareToken::KL :
536
stateAtE.myFareToken = FareToken::L;
537
break;
538
case FareToken::KLU :
539
stateAtE.myFareToken = FareToken::L;
540
break;
541
case FareToken::KHU:
542
stateAtE.myFareToken = FareToken::H;
543
break;
544
case FareToken::KLZ :
545
stateAtE.myFareToken = FareToken::Z;
546
break;
547
case FareToken::KHZ:
548
stateAtE.myFareToken = FareToken::Z;
549
break;
550
default:
551
return;
552
}
553
}
554
555
}
556
};
557
558