LCOV - code coverage report
Current view: top level - src/router - RORouteDef.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 183 188 97.3 %
Date: 2024-05-08 15:29:52 Functions: 12 13 92.3 %

          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    RORouteDef.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Michael Behrisch
      17             : /// @author  Jakob Erdmann
      18             : /// @date    Sept 2002
      19             : ///
      20             : // Base class for a vehicle's route definition
      21             : /****************************************************************************/
      22             : #include <config.h>
      23             : 
      24             : #include <string>
      25             : #include <iterator>
      26             : #include <algorithm>
      27             : #include <utils/common/StringUtils.h>
      28             : #include <utils/common/ToString.h>
      29             : #include <utils/common/Named.h>
      30             : #include <utils/common/StringUtils.h>
      31             : #include <utils/common/MsgHandler.h>
      32             : #include <utils/common/RandHelper.h>
      33             : #include <utils/iodevices/OutputDevice.h>
      34             : #include <utils/options/OptionsCont.h>
      35             : #include "ROEdge.h"
      36             : #include "RORoute.h"
      37             : #include <utils/router/SUMOAbstractRouter.h>
      38             : #include <utils/router/RouteCostCalculator.h>
      39             : #include "RORouteDef.h"
      40             : #include "ROVehicle.h"
      41             : 
      42             : // ===========================================================================
      43             : // static members
      44             : // ===========================================================================
      45             : bool RORouteDef::myUsingJTRR(false);
      46             : 
      47             : // ===========================================================================
      48             : // method definitions
      49             : // ===========================================================================
      50      280506 : RORouteDef::RORouteDef(const std::string& id, const int lastUsed,
      51      280506 :                        const bool tryRepair, const bool mayBeDisconnected) :
      52      561012 :     Named(StringUtils::convertUmlaute(id)),
      53      280506 :     myPrecomputed(nullptr), myLastUsed(lastUsed), myTryRepair(tryRepair),
      54      280506 :     myMayBeDisconnected(mayBeDisconnected),
      55      280506 :     myDiscardSilent(false) {
      56      280506 : }
      57             : 
      58             : 
      59      561012 : RORouteDef::~RORouteDef() {
      60      870378 :     for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
      61             :         if (myRouteRefs.count(*i) == 0) {
      62      589868 :             delete *i;
      63             :         }
      64             :     }
      65      561012 : }
      66             : 
      67             : 
      68             : void
      69      562275 : RORouteDef::addLoadedAlternative(RORoute* alt) {
      70      562275 :     myAlternatives.push_back(alt);
      71      562275 : }
      72             : 
      73             : 
      74             : void
      75           4 : RORouteDef::addAlternativeDef(const RORouteDef* alt) {
      76             :     std::copy(alt->myAlternatives.begin(), alt->myAlternatives.end(),
      77           4 :               back_inserter(myAlternatives));
      78             :     std::copy(alt->myAlternatives.begin(), alt->myAlternatives.end(),
      79           4 :               std::inserter(myRouteRefs, myRouteRefs.end()));
      80           4 : }
      81             : 
      82             : 
      83             : RORoute*
      84      276172 : RORouteDef::buildCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
      85             :                               SUMOTime begin, const ROVehicle& veh) const {
      86      276172 :     if (myPrecomputed == nullptr) {
      87      276172 :         preComputeCurrentRoute(router, begin, veh);
      88             :     }
      89      276172 :     return myPrecomputed;
      90             : }
      91             : 
      92             : 
      93             : void
      94      276172 : RORouteDef::preComputeCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
      95             :                                    SUMOTime begin, const ROVehicle& veh) const {
      96      276172 :     myNewRoute = false;
      97      276172 :     const OptionsCont& oc = OptionsCont::getOptions();
      98      276172 :     const bool ignoreErrors = oc.getBool("ignore-errors");
      99             :     assert(myAlternatives[0]->getEdgeVector().size() > 0);
     100      276172 :     MsgHandler* mh = ignoreErrors ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance();
     101      552373 :     if (myAlternatives[0]->getFirst()->prohibits(&veh) && (!oc.getBool("repair.from")
     102             :             // do not try to reassign starting edge for trip input
     103           9 :             || myMayBeDisconnected || myAlternatives[0]->getEdgeVector().size() < 2)) {
     104          42 :         mh->inform("Vehicle '" + veh.getID() + "' is not allowed to depart on edge '" +
     105          42 :                    myAlternatives[0]->getFirst()->getID() + "'.");
     106          14 :         return;
     107      552342 :     } else if (myAlternatives[0]->getLast()->prohibits(&veh) && (!oc.getBool("repair.to")
     108             :                // do not try to reassign destination edge for trip input
     109           9 :                || myMayBeDisconnected || myAlternatives[0]->getEdgeVector().size() < 2)) {
     110             :         // this check is not strictly necessary unless myTryRepair is set.
     111             :         // However, the error message is more helpful than "no connection found"
     112          33 :         mh->inform("Vehicle '" + veh.getID() + "' is not allowed to arrive on edge '" +
     113          33 :                    myAlternatives[0]->getLast()->getID() + "'.");
     114          11 :         return;
     115             :     }
     116      842362 :     const bool skipTripRouting = (oc.exists("write-trips") && oc.getBool("write-trips")
     117      298677 :                                   && RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().skipRouteCalculation());
     118      276147 :     if ((myTryRepair && !skipTripRouting) || myUsingJTRR) {
     119             :         ConstROEdgeVector newEdges;
     120      189046 :         if (repairCurrentRoute(router, begin, veh, myAlternatives[0]->getEdgeVector(), newEdges)) {
     121       93690 :             if (myAlternatives[0]->getEdgeVector() != newEdges) {
     122       88260 :                 if (!myMayBeDisconnected) {
     123         102 :                     WRITE_WARNINGF(TL("Repaired route of vehicle '%'."), veh.getID());
     124             :                 }
     125       88260 :                 myNewRoute = true;
     126       88260 :                 RGBColor* col = myAlternatives[0]->getColor() != nullptr ? new RGBColor(*myAlternatives[0]->getColor()) : nullptr;
     127       88260 :                 myPrecomputed = new RORoute(myID, 0, myAlternatives[0]->getProbability(), newEdges, col, myAlternatives[0]->getStops());
     128             :             } else {
     129        5430 :                 myPrecomputed = myAlternatives[0];
     130             :             }
     131             :         }
     132             :         return;
     133             :     }
     134      181624 :     if ((RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().skipRouteCalculation()
     135      362400 :             || OptionsCont::getOptions().getBool("remove-loops"))
     136      181680 :             && (skipTripRouting || myAlternatives[myLastUsed]->isValid(veh, ignoreErrors))) {
     137         956 :         myPrecomputed = myAlternatives[myLastUsed];
     138             :     } else {
     139             :         // build a new route to test whether it is better
     140             :         ConstROEdgeVector oldEdges;
     141      180668 :         oldEdges.push_back(myAlternatives[0]->getFirst());
     142      180668 :         oldEdges.push_back(myAlternatives[0]->getLast());
     143             :         ConstROEdgeVector edges;
     144      180668 :         repairCurrentRoute(router, begin, veh, oldEdges, edges);
     145             :         // check whether the same route was already used
     146             :         int cheapest = -1;
     147      260903 :         for (int i = 0; i < (int)myAlternatives.size(); i++) {
     148      233214 :             if (edges == myAlternatives[i]->getEdgeVector()) {
     149             :                 cheapest = i;
     150             :                 break;
     151             :             }
     152             :         }
     153      180668 :         if (cheapest >= 0) {
     154      152979 :             myPrecomputed = myAlternatives[cheapest];
     155             :         } else {
     156       27689 :             RGBColor* col = myAlternatives[0]->getColor() != nullptr ? new RGBColor(*myAlternatives[0]->getColor()) : nullptr;
     157       27689 :             myPrecomputed = new RORoute(myID, 0, 1, edges, col, myAlternatives[0]->getStops());
     158       27689 :             myNewRoute = true;
     159             :         }
     160             :     }
     161             : }
     162             : 
     163             : 
     164             : bool
     165      275191 : RORouteDef::repairCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
     166             :                                SUMOTime begin, const ROVehicle& veh,
     167             :                                ConstROEdgeVector oldEdges, ConstROEdgeVector& newEdges) const {
     168      550382 :     MsgHandler* mh = (OptionsCont::getOptions().getBool("ignore-errors") ?
     169      275191 :                       MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
     170      275191 :     const int initialSize = (int)oldEdges.size();
     171      275191 :     if (initialSize == 1) {
     172        8515 :         if (myUsingJTRR) {
     173             :             /// only ROJTRRouter is supposed to handle this type of input
     174        8508 :             bool ok = router.compute(oldEdges.front(), nullptr, &veh, begin, newEdges);
     175       13965 :             myDiscardSilent = ok && newEdges.size() == 0;
     176             :         } else {
     177           7 :             newEdges = oldEdges;
     178             :         }
     179             :     } else {
     180      533352 :         if (oldEdges.front()->prohibits(&veh)) {
     181             :             // option repair.from is in effect
     182             :             const std::string& frontID = oldEdges.front()->getID();
     183          18 :             for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) {
     184          30 :                 if ((*i)->prohibits(&veh) || (*i)->isInternal()) {
     185             :                     i = oldEdges.erase(i);
     186             :                 } else {
     187           6 :                     WRITE_MESSAGE("Changing invalid starting edge '" + frontID
     188             :                                   + "' to '" + (*i)->getID() + "' for vehicle '" + veh.getID() + "'.");
     189           3 :                     break;
     190             :                 }
     191             :             }
     192             :         }
     193      266676 :         if (oldEdges.size() == 0) {
     194           6 :             mh->inform("Could not find new starting edge for vehicle '" + veh.getID() + "'.");
     195         833 :             return false;
     196             :         }
     197      533346 :         if (oldEdges.back()->prohibits(&veh)) {
     198             :             // option repair.to is in effect
     199             :             const std::string& backID = oldEdges.back()->getID();
     200             :             // oldEdges cannot get empty here, otherwise we would have left the stage when checking "from"
     201           6 :             while (oldEdges.back()->prohibits(&veh) || oldEdges.back()->isInternal()) {
     202             :                 oldEdges.pop_back();
     203             :             }
     204           6 :             WRITE_MESSAGE("Changing invalid destination edge '" + backID
     205             :                           + "' to edge '" + oldEdges.back()->getID() + "' for vehicle '" + veh.getID() + "'.");
     206             :         }
     207      266673 :         ConstROEdgeVector mandatory = veh.getMandatoryEdges(oldEdges.front(), oldEdges.back());
     208             :         std::set<ConstROEdgeVector::const_iterator> jumpStarts;
     209      266673 :         veh.collectJumps(mandatory, jumpStarts);
     210             :         assert(mandatory.size() >= 2);
     211             :         // removed prohibited
     212      833621 :         for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) {
     213     1133896 :             if ((*i)->prohibits(&veh) || (*i)->isInternal()) {
     214             :                 // no need to check the mandatories here, this was done before
     215             :                 i = oldEdges.erase(i);
     216             :             } else {
     217             :                 ++i;
     218             :             }
     219             :         }
     220             :         // reconnect remaining edges
     221      266673 :         if (mandatory.size() > oldEdges.size() && initialSize > 2) {
     222           0 :             WRITE_MESSAGEF(TL("There are stop edges which were not part of the original route for vehicle '%'."), veh.getID());
     223             :         }
     224      266673 :         const ConstROEdgeVector& targets = mandatory.size() > oldEdges.size() ? mandatory : oldEdges;
     225      266673 :         newEdges.push_back(targets.front());
     226             :         ConstROEdgeVector::iterator nextMandatory = mandatory.begin() + 1;
     227             :         int lastMandatory = 0;
     228      266673 :         for (ConstROEdgeVector::const_iterator i = targets.begin() + 1;
     229      564405 :                 i != targets.end() && nextMandatory != mandatory.end(); ++i) {
     230      298562 :             const ROEdge* prev = *(i - 1);
     231      298562 :             const ROEdge* cur = *i;
     232      319320 :             if (prev->isConnectedTo(*cur, veh.getVClass()) && (!isRailway(veh.getVClass()) || prev->getBidiEdge() != cur)) {
     233       20754 :                 newEdges.push_back(cur);
     234             :             } else {
     235      277808 :                 if (initialSize > 2) {
     236             :                     // only inform if the input is (probably) not a trip
     237      164020 :                     WRITE_MESSAGEF(TL("Edge '%' not connected to edge '%' for vehicle '%'."), (*(i - 1))->getID(), (*i)->getID(), veh.getID());
     238             :                 }
     239      277808 :                 const ROEdge* last = newEdges.back();
     240             :                 newEdges.pop_back();
     241      277808 :                 if (last->isTazConnector() && newEdges.size() > 1) {
     242             :                     // assume this was a viaTaz
     243          24 :                     last = newEdges.back();
     244             :                     newEdges.pop_back();
     245             :                 }
     246      277808 :                 if (veh.hasJumps() && jumpStarts.count(nextMandatory - 1) != 0) {
     247          24 :                     while (*i != *nextMandatory) {
     248             :                         ++i;
     249             :                     }
     250          24 :                     newEdges.push_back(last);
     251          24 :                     newEdges.push_back(*i);
     252             :                     //std::cout << " skipJump mIndex=" << (nextMandatory - 1 - mandatory.begin()) << " last=" << last->getID() << " next=" << (*i)->getID() << " newEdges=" << toString(newEdges) << "\n";
     253             :                 } else {
     254             : 
     255             :                     //                router.setHint(targets.begin(), i, &veh, begin);
     256      277784 :                     if (!router.compute(last, *i, &veh, begin, newEdges)) {
     257             :                         // backtrack: try to route from last mandatory edge to next mandatory edge
     258             :                         // XXX add option for backtracking in smaller increments
     259             :                         // (i.e. previous edge to edge after *i)
     260             :                         // we would then need to decide whether we have found a good
     261             :                         // tradeoff between faithfulness to the input data and detour-length
     262             :                         ConstROEdgeVector edges;
     263         833 :                         if (lastMandatory >= (int)newEdges.size() || last == newEdges[lastMandatory] || !router.compute(newEdges[lastMandatory], *nextMandatory, &veh, begin, edges)) {
     264        1660 :                             mh->inform("Mandatory edge '" + (*i)->getID() + "' not reachable by vehicle '" + veh.getID() + "'.");
     265             :                             return false;
     266             :                         }
     267           6 :                         while (*i != *nextMandatory) {
     268             :                             ++i;
     269             :                         }
     270             :                         newEdges.erase(newEdges.begin() + lastMandatory + 1, newEdges.end());
     271             :                         std::copy(edges.begin() + 1, edges.end(), back_inserter(newEdges));
     272             :                     }
     273             : 
     274             :                 }
     275             :             }
     276      297732 :             if (*i == *nextMandatory) {
     277             :                 nextMandatory++;
     278      292558 :                 lastMandatory = (int)newEdges.size() - 1;
     279             :             }
     280             :         }
     281             :     }
     282             :     return true;
     283             : }
     284             : 
     285             : 
     286             : void
     287      272764 : RORouteDef::addAlternative(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
     288             :                            const ROVehicle* const veh, RORoute* current, SUMOTime begin) {
     289      272764 :     if (myTryRepair || myUsingJTRR) {
     290       91148 :         if (myNewRoute) {
     291       85710 :             delete myAlternatives[0];
     292       85710 :             myAlternatives[0] = current;
     293             :         }
     294      182296 :         if (!router.isValid(current->getEdgeVector(), veh)) {
     295           0 :             throw ProcessError("Route '" + getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
     296             :         }
     297       91148 :         double costs = router.recomputeCosts(current->getEdgeVector(), veh, begin);
     298       91148 :         if (veh->hasJumps()) {
     299             :             // @todo: jumpTime should be applied in recomputeCost to ensure the
     300             :             // correctness of time-dependent traveltimes
     301          20 :             costs += STEPS2TIME(veh->getJumpTime());
     302             :         }
     303       91148 :         current->setCosts(costs);
     304       91148 :         return;
     305             :     }
     306             :     // add the route when it's new
     307      181616 :     if (myNewRoute) {
     308       27689 :         myAlternatives.push_back(current);
     309             :     }
     310             :     // recompute the costs and (when a new route was added) scale the probabilities
     311      181616 :     const double scale = double(myAlternatives.size() - 1) / double(myAlternatives.size());
     312      673219 :     for (RORoute* const alt : myAlternatives) {
     313      491619 :         if (!router.isValid(alt->getEdgeVector(), veh)) {
     314          32 :             throw ProcessError("Route '" + current->getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
     315             :         }
     316             :         // recompute the costs for all routes
     317      491603 :         const double newCosts = router.recomputeCosts(alt->getEdgeVector(), veh, begin);
     318             :         assert(myAlternatives.size() != 0);
     319      491603 :         if (myNewRoute) {
     320       67196 :             if (alt == current) {
     321             :                 // set initial probability and costs
     322       27673 :                 alt->setProbability(1. / (double) myAlternatives.size());
     323       27673 :                 alt->setCosts(newCosts);
     324             :             } else {
     325             :                 // rescale probs for all others
     326       39523 :                 alt->setProbability(alt->getProbability() * scale);
     327             :             }
     328             :         }
     329      491603 :         RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().setCosts(alt, newCosts, alt == myAlternatives[myLastUsed]);
     330             :     }
     331             :     assert(myAlternatives.size() != 0);
     332      181600 :     RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().calculateProbabilities(myAlternatives, veh, veh->getDepartureTime());
     333      181600 :     const bool keepRoute = RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().keepRoute();
     334      181600 :     if (!RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().keepAllRoutes() && !keepRoute) {
     335             :         // remove with probability of 0 (not mentioned in Gawron)
     336      642743 :         for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end();) {
     337      469469 :             if ((*i)->getProbability() == 0) {
     338           0 :                 delete *i;
     339             :                 i = myAlternatives.erase(i);
     340             :             } else {
     341             :                 i++;
     342             :             }
     343             :         }
     344             :     }
     345      181600 :     int maxNumber = RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().getMaxRouteNumber();
     346      181600 :     if ((int)myAlternatives.size() > maxNumber) {
     347          96 :         const RORoute* last = myAlternatives[myLastUsed];
     348             :         // only keep the routes with highest probability
     349          96 :         sort(myAlternatives.begin(), myAlternatives.end(), [](const RORoute * const a, const RORoute * const b) {
     350             :             return a->getProbability() > b->getProbability();
     351             :         });
     352          96 :         if (keepRoute) {
     353          18 :             for (int i = 0; i < (int)myAlternatives.size(); i++) {
     354          18 :                 if (myAlternatives[i] == last) {
     355          12 :                     myLastUsed = i;
     356          12 :                     break;
     357             :                 }
     358             :             }
     359          12 :             if (myLastUsed >= maxNumber) {
     360           6 :                 std::swap(myAlternatives[maxNumber - 1], myAlternatives[myLastUsed]);
     361           6 :                 myLastUsed = maxNumber - 1;
     362             :             }
     363             :         }
     364         192 :         for (std::vector<RORoute*>::iterator i = myAlternatives.begin() + maxNumber; i != myAlternatives.end(); i++) {
     365          96 :             delete *i;
     366             :         }
     367             :         myAlternatives.erase(myAlternatives.begin() + maxNumber, myAlternatives.end());
     368             :     }
     369             :     // rescale probabilities
     370             :     double newSum = 0.;
     371      673107 :     for (const RORoute* const alt : myAlternatives) {
     372      491507 :         newSum += alt->getProbability();
     373             :     }
     374             :     assert(newSum > 0);
     375             :     // @note newSum may be larger than 1 for numerical reasons
     376      673107 :     for (RORoute* const alt : myAlternatives) {
     377      491507 :         alt->setProbability(alt->getProbability() / newSum);
     378             :     }
     379             : 
     380             :     // find the route to use
     381      181600 :     if (!keepRoute) {
     382      173274 :         double chosen = RandHelper::rand();
     383      173274 :         myLastUsed = 0;
     384      302633 :         for (const RORoute* const alt : myAlternatives) {
     385      302633 :             chosen -= alt->getProbability();
     386      302633 :             if (chosen <= 0) {
     387             :                 return;
     388             :             }
     389      129359 :             myLastUsed++;
     390             :         }
     391             :     }
     392             : }
     393             : 
     394             : 
     395             : const ROEdge*
     396           0 : RORouteDef::getDestination() const {
     397           0 :     return myAlternatives[0]->getLast();
     398             : }
     399             : 
     400             : 
     401             : OutputDevice&
     402      458150 : RORouteDef::writeXMLDefinition(OutputDevice& dev, const ROVehicle* const veh,
     403             :                                bool asAlternatives, bool withExitTimes, bool withCost, bool withLength) const {
     404      458150 :     if (asAlternatives) {
     405      207687 :         dev.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, myLastUsed);
     406      725284 :         for (int i = 0; i != (int)myAlternatives.size(); i++) {
     407     1035194 :             myAlternatives[i]->writeXMLDefinition(dev, veh, true, true, withExitTimes, withLength);
     408             :         }
     409      207687 :         dev.closeTag();
     410      207687 :         return dev;
     411             :     } else {
     412      500926 :         return myAlternatives[myLastUsed]->writeXMLDefinition(dev, veh, withCost, false, withExitTimes, withLength);
     413             :     }
     414             : }
     415             : 
     416             : 
     417             : RORouteDef*
     418       36135 : RORouteDef::copy(const std::string& id, const SUMOTime stopOffset) const {
     419       36135 :     RORouteDef* result = new RORouteDef(id, 0, myTryRepair, myMayBeDisconnected);
     420       73150 :     for (const RORoute* const route : myAlternatives) {
     421       37015 :         RGBColor* col = route->getColor() != nullptr ? new RGBColor(*route->getColor()) : nullptr;
     422       37015 :         RORoute* newRoute = new RORoute(id, route->getCosts(), route->getProbability(), route->getEdgeVector(), col, route->getStops());
     423             :         newRoute->addStopOffset(stopOffset);
     424       37015 :         result->addLoadedAlternative(newRoute);
     425             :     }
     426       36135 :     return result;
     427             : }
     428             : 
     429             : 
     430             : double
     431      178303 : RORouteDef::getOverallProb() const {
     432             :     double sum = 0.;
     433      638071 :     for (std::vector<RORoute*>::const_iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
     434      459768 :         sum += (*i)->getProbability();
     435             :     }
     436      178303 :     return sum;
     437             : }
     438             : 
     439             : 
     440             : /****************************************************************************/

Generated by: LCOV version 1.14