001/*******************************************************************************
002 * Copyright (c) 2017 Pablo Pavon Marino and others.
003 * All rights reserved. This program and the accompanying materials
004 * are made available under the terms of the 2-clause BSD License 
005 * which accompanies this distribution, and is available at
006 * https://opensource.org/licenses/BSD-2-Clause
007 *
008 * Contributors:
009 *     Pablo Pavon Marino and others - initial API and implementation
010 *******************************************************************************/
011package com.net2plan.examples.ocnbook.onlineSim;
012
013
014import cern.colt.matrix.tdouble.DoubleFactory1D;
015import cern.colt.matrix.tdouble.DoubleFactory2D;
016import cern.colt.matrix.tdouble.DoubleMatrix1D;
017import cern.colt.matrix.tdouble.DoubleMatrix2D;
018import com.jom.OptimizationProblem;
019import com.net2plan.interfaces.networkDesign.*;
020import com.net2plan.interfaces.simulation.IEventProcessor;
021import com.net2plan.interfaces.simulation.SimEvent;
022import com.net2plan.utils.Constants.RoutingType;
023import com.net2plan.utils.*;
024
025import java.io.File;
026import java.io.FileOutputStream;
027import java.io.PrintStream;
028import java.util.List;
029import java.util.Map;
030import java.util.Random;
031
032/** 
033 * This module implements a distributed dual-gradient based algorithm, for iteratively adapting the network routing.
034 *
035 * Ths event processor is adapted to permit observing the algorithm performances under user-defined conditions, 
036 * including asynchronous distributed executions, where signaling can be affected by losses and/or delays, and/or measurement errors. 
037 * The time evolution of different metrics can be stored in output files, for later processing. 
038 * As an example, see the <a href="../../../../../../graphGeneratorFiles/fig_sec10_2_adaptiveRoutingDual.m">{@code fig_sec10_2_adaptiveRoutingDual.m}</a> MATLAB file used for generating the graph/s of the case study in the 
039 * <a href="http://eu.wiley.com/WileyCDA/WileyTitle/productCd-1119013356.html">book</a> using this algorithm.
040 * 
041 * To simulate a network with this module, use the {@code Online_evGen_doNothing} generator.
042 * 
043 * @net2plan.keywords Flow assignment (FA), Distributed algorithm, Dual gradient algorithm
044 * @net2plan.ocnbooksections Section 10.2
045 * @net2plan.inputParameters 
046 * @author Pablo Pavon-Marino
047 */
048@SuppressWarnings("unchecked")
049public class Online_evProc_adaptiveRoutingDual extends IEventProcessor
050{
051        private static PrintStream getNulFile () { try { return new PrintStream (new FileOutputStream ("NUL") , false); } catch (Exception e) {e.printStackTrace(); throw new RuntimeException ("Not NUL file"); }   } 
052        private PrintStream log = getNulFile (); //System.err;//new PrintStream (new FileOutputStream ("NUL") , true);
053
054        private InputParameter signaling_isSynchronous = new InputParameter ("signaling_isSynchronous", false , "true if all the distributed agents involved wake up synchronously to send the signaling messages");
055        private InputParameter signaling_averageInterMessageTime = new InputParameter ("signaling_averageInterMessageTime", 1.0 , "Average time between two signaling messages sent by an agent" , 0 , false , Double.MAX_VALUE , true);
056        private InputParameter signaling_maxFluctuationInterMessageTime = new InputParameter ("signaling_maxFluctuationInterMessageTime", 0.5 , "Max fluctuation in time between two signaling messages sent by an agent" , 0 , true , Double.MAX_VALUE , true);
057        private InputParameter signaling_averageDelay = new InputParameter ("signaling_averageDelay", 0.0 , "Average time between signaling message transmission by an agent and its reception by other or others" , 0 , true , Double.MAX_VALUE , true);
058        private InputParameter signaling_maxFluctuationInDelay = new InputParameter ("signaling_maxFluctuationInDelay", 0.0 , "Max fluctuation in time in the signaling delay, in absolute time values. The signaling delays are sampled from a uniform distribution within the given interval" , 0 , true , Double.MAX_VALUE , true);
059        private InputParameter signaling_signalingLossProbability = new InputParameter ("signaling_signalingLossProbability", 0.05 , "Probability that a signaling message transmitted is lost (not received by other or others involved agents)" , 0 , true , Double.MAX_VALUE , true);
060        private InputParameter update_isSynchronous = new InputParameter ("update_isSynchronous", false , "true if all the distributed agents involved wake up synchronousely to update its state");
061        private InputParameter update_averageInterUpdateTime = new InputParameter ("update_averageInterUpdateTime", 1.0 , "Average time between two updates of an agent" , 0 , false , Double.MAX_VALUE , true);
062        private InputParameter update_maxFluctuationInterUpdateTime = new InputParameter ("update_maxFluctuationInterUpdateTime", 0.5 , "Max fluctuation in time in the update interval of an agent, in absolute time values. The update intervals are sampled from a uniform distribution within the given interval" , 0 , true , Double.MAX_VALUE , true);
063        private InputParameter simulation_maxNumberOfUpdateIntervals = new InputParameter ("simulation_maxNumberOfUpdateIntervals", 500.0 , "Maximum number of update intervals in average per agent" , 0 , false , Double.MAX_VALUE , true);
064        private InputParameter simulation_randomSeed = new InputParameter ("simulation_randomSeed", (long) 1 , "Seed of the random number generator");
065        private InputParameter simulation_outFileNameRoot = new InputParameter ("simulation_outFileNameRoot", "adaptiveRoutingDual" , "Root of the file name to be used in the output files. If blank, no output");
066        private InputParameter gradient_maxGradientAbsoluteNoise = new InputParameter ("gradient_maxGradientAbsoluteNoise", 0.0 , "Max value of the added noise to the gradient coordinate in absolute values" , 0 , true , Double.MAX_VALUE , true);
067        private InputParameter gradient_gammaStep = new InputParameter ("gradient_gammaStep", 0.001 , "Gamma step in the gradient algorithm" , 0 , false , Double.MAX_VALUE , true);
068        private InputParameter gradient_heavyBallBetaParameter = new InputParameter ("gradient_heavyBallBetaParameter", 0.0 , "Beta parameter of heavy ball, between 0 and 1. Value 0 means no heavy ball" , 0 , true , 1.0 , true);
069        private InputParameter gradient_maxGradientCoordinateChange = new InputParameter ("gradient_maxGradientCoordinateChange", 1.0e10 , "Maximum change in an iteration of a gradient coordinate" , 0 , false , Double.MAX_VALUE , true);
070        private InputParameter gradient_regularizationEpsilon = new InputParameter ("gradient_regularizationEpsilon", 1.0e-3 , "Regularization factor in the objective function term to make it strictly convex" , 0 , true , Double.MAX_VALUE , true);
071
072        private InputParameter control_maxNumberOfPathsPerDemand = new InputParameter ("control_maxNumberOfPathsPerDemand", (int) 5 , "Number of acceptable paths per demand. Take the k-shortest paths in number of hops" , 1 , Integer.MAX_VALUE);
073        private InputParameter control_initialLinkWeights = new InputParameter ("control_initialLinkWeights", 0.5 , "Initial value of the link weights" , 0 , true , Double.MAX_VALUE , true);
074        
075        private Random rng;
076        private int E , R , N , D;
077
078        private static final int SIGNALING_WAKEUPTOSENDMESSAGE = 300;
079        private static final int SIGNALING_RECEIVEDMESSAGE = 301;
080        private static final int UPDATE_WAKEUPTOUPDATE = 302;
081
082        private NetPlan currentNetPlan;
083        private DoubleMatrix1D routing_price_e;
084        
085        private DoubleMatrix2D routing_mostUpdatedLinkPriceKnownByNode_ne; 
086        private DoubleMatrix1D routing_previousLinkWeight_e;
087        private int [][] control_routeIndexes_d;
088        
089        private TimeTrace stat_traceOf_xp;
090        private TimeTrace stat_traceOf_pie;
091        private TimeTrace stat_traceOf_ye;
092        private TimeTrace stat_traceOf_objFunction;
093
094        @Override
095        public String getDescription()
096        {
097                return "This module implements a distributed dual-gradient based algorithm, for iteratively adapting the network routing.";
098        }
099
100        @Override
101        public List<Triple<String, String, String>> getParameters()
102        {
103                /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
104                return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
105        }
106
107        @Override
108        public void initialize(NetPlan currentNetPlan, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters)
109        {
110                /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
111                InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters);
112
113                if (currentNetPlan.getNumberOfLayers() != 1) throw new Net2PlanException ("This algorithm works in single layer networks");
114
115                this.rng = new Random (simulation_randomSeed.getLong());
116                this.currentNetPlan = currentNetPlan;
117                this.E = currentNetPlan.getNumberOfLinks();
118                this.N = currentNetPlan.getNumberOfNodes();
119                this.D = currentNetPlan.getNumberOfDemands();
120                
121                /* Check all nodes have output links */
122                for (Node n : currentNetPlan.getNodes()) if (n.getOutgoingLinks().isEmpty()) throw new Net2PlanException ("All nodes should have output links");
123
124                /* Set the initial prices in the links to all zeros */
125                this.routing_price_e = DoubleFactory1D.dense.make (E , control_initialLinkWeights.getDouble());
126                this.routing_previousLinkWeight_e = routing_price_e.copy ();
127                for (Link e : currentNetPlan.getLinks ()) e.setAttribute("pi_e" , "" + routing_price_e.get (e.getIndex ()));
128                
129                /* Initialize the information each demand knows of the prices of all the links */
130                this.routing_mostUpdatedLinkPriceKnownByNode_ne = DoubleFactory2D.dense.make (N,E,control_initialLinkWeights.getDouble());
131                
132                /* Sets the initial routing, according to the prices, with all the traffic balanced equally in all the paths of the demand */
133                currentNetPlan.removeAllUnicastRoutingInformation();
134                currentNetPlan.setRoutingTypeAllDemands(RoutingType.SOURCE_ROUTING);
135                this.currentNetPlan.addRoutesFromCandidatePathList(currentNetPlan.computeUnicastCandidatePathList(null , control_maxNumberOfPathsPerDemand.getInt(), -1, -1, -1, -1, -1, -1 , null));
136                
137                this.R = currentNetPlan.getNumberOfRoutes ();
138                this.control_routeIndexes_d = new int [D][];
139                for (Demand d : this.currentNetPlan.getDemands())
140                {
141                        control_routeIndexes_d [d.getIndex ()] = new int [d.getRoutes ().size ()]; 
142                        int counter_r = 0; for (Route r : d.getRoutes ()) control_routeIndexes_d [d.getIndex ()][counter_r ++] = r.getIndex ();
143                }
144
145                
146                for (Demand d : this.currentNetPlan.getDemands())
147                        updateDemandRoutingFromWeightsKnown (d);                
148
149                /* Initially all nodes receive a "wake up to transmit" event, aligned at time zero or y asynchr => randomly chosen */
150                for (Link e : currentNetPlan.getLinks())
151                {
152                        final double signalingTime = (signaling_isSynchronous.getBoolean())? signaling_averageInterMessageTime.getDouble() : Math.max(0 , signaling_averageInterMessageTime.getDouble() + signaling_maxFluctuationInterMessageTime.getDouble() * (rng.nextDouble() - 0.5));
153                        this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , SIGNALING_WAKEUPTOSENDMESSAGE , e));
154                }
155                for (Node n : currentNetPlan.getNodes())
156                {
157                        final double updateTime = (update_isSynchronous.getBoolean())? update_averageInterUpdateTime.getDouble() : Math.max(0 , update_averageInterUpdateTime.getDouble() + update_maxFluctuationInterUpdateTime.getDouble() * (rng.nextDouble() - 0.5));
158                        this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , UPDATE_WAKEUPTOUPDATE , n));
159                }
160
161                /* Intialize the traces */
162                this.stat_traceOf_xp = new TimeTrace ();
163                this.stat_traceOf_pie = new TimeTrace ();
164                this.stat_traceOf_ye = new TimeTrace ();
165                this.stat_traceOf_objFunction = new TimeTrace (); 
166                this.stat_traceOf_xp.add(0.0, this.currentNetPlan.getVectorRouteCarriedTraffic());
167                this.stat_traceOf_pie.add(0.0, this.routing_price_e.copy ());
168                this.stat_traceOf_ye.add(0.0, this.currentNetPlan.getVectorLinkCarriedTraffic());
169                this.stat_traceOf_objFunction.add(0.0, computeObjectiveFucntionFromNetPlan());
170
171        }
172
173        @Override
174        public void processEvent(NetPlan currentNetPlan, SimEvent event)
175        {
176                final double t = event.getEventTime();
177                switch (event.getEventType())
178                {
179                case SIGNALING_RECEIVEDMESSAGE: // A node receives a price information from a link
180                {
181                        final Triple<Node,Link,Double> signalInfo = (Triple<Node,Link,Double>) event.getEventObject();
182                        final Node nMe = signalInfo.getFirst();
183                        final Link e = signalInfo.getSecond();
184                        final double link_price_e = signalInfo.getThird();
185                        this.routing_mostUpdatedLinkPriceKnownByNode_ne.set(nMe.getIndex () , e.getIndex () , link_price_e);
186                        break;
187                }
188                
189                case SIGNALING_WAKEUPTOSENDMESSAGE: // A link updates its price (gradient), and signals it to all the nodes
190                {
191                        final Link eMe = (Link) event.getEventObject();
192
193                        /* Update the gradient iteration */
194                        final double previous_pi_e = this.routing_previousLinkWeight_e.get(eMe.getIndex ());
195                        final double old_pi_e = this.routing_price_e.get(eMe.getIndex ());
196                        final double gradient_e = eMe.getCarriedTraffic() - eMe.getCapacity() +  2*gradient_maxGradientAbsoluteNoise.getDouble()*(this.rng.nextDouble()-0.5);
197                        final double new_pi_e_notProjected = old_pi_e + this.gradient_gammaStep.getDouble() * gradient_e + this.gradient_heavyBallBetaParameter.getDouble() * (old_pi_e - previous_pi_e);
198                        double new_pi_e_projected = Math.max(0, new_pi_e_notProjected);
199                        if (gradient_maxGradientCoordinateChange.getDouble() > 0)
200                                new_pi_e_projected = GradientProjectionUtils.scaleDown_maxAbsoluteCoordinateChange (old_pi_e , new_pi_e_projected ,  gradient_maxGradientCoordinateChange.getDouble());
201
202                        this.routing_previousLinkWeight_e.set(eMe.getIndex (), old_pi_e);
203                        this.routing_price_e.set(eMe.getIndex () , new_pi_e_projected);
204                        eMe.setAttribute("pi_e" , "" + routing_price_e.get (eMe.getIndex ()));
205
206                        
207                        /* Send the events of the signaling information messages to all the nodes */
208                        if (rng.nextDouble() >= this.signaling_signalingLossProbability.getDouble()) // the signaling may be lost => lost to all nodes
209                                for (Node n : currentNetPlan.getNodes ())
210                                {
211                                        final double signalingReceptionTime = t + Math.max(0 , signaling_averageDelay.getDouble() + signaling_maxFluctuationInDelay.getDouble() * (rng.nextDouble() - 0.5));
212                                        this.scheduleEvent(new SimEvent (signalingReceptionTime , SimEvent.DestinationModule.EVENT_PROCESSOR , SIGNALING_RECEIVEDMESSAGE , Triple.of(n , eMe , routing_price_e.get(eMe.getIndex ()))));
213                                }
214                        
215                        /* Re-schedule when to wake up again */
216                        final double signalingTime = signaling_isSynchronous.getBoolean()? t + signaling_averageInterMessageTime.getDouble() : Math.max(t , t + signaling_averageInterMessageTime.getDouble() + signaling_maxFluctuationInterMessageTime.getDouble() * (rng.nextDouble() - 0.5));
217                        this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , SIGNALING_WAKEUPTOSENDMESSAGE , eMe));
218                        break;
219                        
220                }
221                
222                case UPDATE_WAKEUPTOUPDATE: // a node updates its source routing using the most updated information it has
223                {
224                        final Node nMe = (Node) event.getEventObject(); 
225                        for (Demand d : nMe.getOutgoingDemands())
226                                updateDemandRoutingFromWeightsKnown (d);                
227
228                        final double updateTime = update_isSynchronous.getBoolean()? t + update_averageInterUpdateTime.getDouble() : Math.max(t , t + update_averageInterUpdateTime.getDouble() + update_maxFluctuationInterUpdateTime.getDouble() * (rng.nextDouble() - 0.5));
229                        this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , UPDATE_WAKEUPTOUPDATE,  nMe));
230
231                        this.stat_traceOf_xp.add(t, this.currentNetPlan.getVectorRouteCarriedTraffic());
232                        this.stat_traceOf_pie.add(t, this.routing_price_e.copy ());
233                        this.stat_traceOf_ye.add(t, this.currentNetPlan.getVectorLinkCarriedTraffic());
234                        this.stat_traceOf_objFunction.add(t, computeObjectiveFucntionFromNetPlan());
235
236                        if (t > this.simulation_maxNumberOfUpdateIntervals.getDouble() * this.update_averageInterUpdateTime.getDouble()) { this.endSimulation (); }
237                        
238                        break;
239                }
240                        
241
242                default: throw new RuntimeException ("Unexpected received event");
243                }
244                
245                
246        }
247
248        public String finish (StringBuilder st , double simTime)
249        {
250                if (simulation_outFileNameRoot.getString().equals("")) return null;
251                stat_traceOf_xp.printToFile(new File (simulation_outFileNameRoot.getString() + "_xp.txt"));
252                stat_traceOf_pie.printToFile(new File (simulation_outFileNameRoot.getString() + "_pie.txt"));
253                stat_traceOf_ye.printToFile(new File (simulation_outFileNameRoot.getString() + "_ye.txt"));
254                stat_traceOf_objFunction.printToFile(new File (simulation_outFileNameRoot.getString() + "_objFunc.txt"));
255                Quadruple<DoubleMatrix1D,DoubleMatrix1D,DoubleMatrix1D,Double> pair = computeOptimumSolution (true);
256                DoubleMatrix1D x_p_opt = pair.getFirst();
257                DoubleMatrix1D pi_e = pair.getSecond();  
258                DoubleMatrix1D y_e = pair.getThird();  
259                double optCost = pair.getFourth();  
260                TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jomReg_objFunc.txt"), optCost);
261                TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jomReg_xp.txt"), x_p_opt);
262                TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jomReg_pie.txt"), pi_e);
263                TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jomReg_ye.txt"), y_e);
264                return null;
265        }
266        
267        private double computeObjectiveFucntionFromNetPlan ()
268        {
269                double objFunc = 0;
270                for (Route r : this.currentNetPlan.getRoutes())
271                {
272                        final double x_r = r.getCarriedTraffic();
273                        objFunc +=  x_r * r.getNumberOfHops() + this.gradient_regularizationEpsilon.getDouble() * Math.pow(x_r, 2);
274                }
275                return objFunc;
276        }
277        
278        private Quadruple<DoubleMatrix1D,DoubleMatrix1D,DoubleMatrix1D,Double> computeOptimumSolution (boolean isRegularized)
279        {
280                /* Modify the map so that it is the pojection where all elements sum h_d, and are non-negative */
281                final int P = this.currentNetPlan.getNumberOfRoutes();
282                final int E = this.currentNetPlan.getNumberOfLinks();
283                final DoubleMatrix1D h_d = this.currentNetPlan.getVectorDemandOfferedTraffic();
284                final DoubleMatrix1D u_e = this.currentNetPlan.getVectorLinkCapacity();
285                final DoubleMatrix1D h_p = this.currentNetPlan.getVectorRouteOfferedTrafficOfAssociatedDemand();
286                                
287                OptimizationProblem op = new OptimizationProblem();
288                op.addDecisionVariable("x_p", false , new int[] { 1 , P }, DoubleUtils.zeros(P) , h_p.toArray()); 
289                op.addDecisionVariable("y_e", false , new int[] { 1 , E }, DoubleUtils.zeros(E) , u_e.toArray()); 
290                op.setInputParameter("h_d", h_d , "row");
291                op.setInputParameter("u_e", u_e , "row");
292                op.setInputParameter("epsilon", this.gradient_regularizationEpsilon.getDouble());
293                
294                /* Set some input parameters */
295                if (!isRegularized)
296                        op.setObjectiveFunction("minimize", "sum (y_e)");
297                else
298                        op.setObjectiveFunction("minimize", "sum (y_e) + epsilon * x_p * x_p'");
299
300                /* VECTORIAL FORM OF THE CONSTRAINTS  */
301                op.setInputParameter("A_dp", currentNetPlan.getMatrixDemand2RouteAssignment());
302                op.setInputParameter("A_ep", currentNetPlan.getMatrixLink2RouteAssignment());
303                op.addConstraint("A_dp * x_p' == h_d'"); // for each demand, the 100% of the traffic is carried (summing the associated paths)
304                op.addConstraint("A_ep * x_p' == y_e'"); // set the traffic in each link equal to y_e
305                
306                /* Call the solver to solve the problem */
307                op.solve("ipopt");
308
309                /* If an optimal solution was not found, quit */
310                if (!op.solutionIsOptimal ()) throw new RuntimeException ("An optimal solution was not found");
311        
312                /* Retrieve the optimum solutions. Convert the bps into Erlangs */
313                final DoubleMatrix1D x_p = op.getPrimalSolution("x_p").view1D();
314                final DoubleMatrix1D y_e = op.getPrimalSolution("y_e").view1D();
315                final DoubleMatrix1D pi_e = op.getMultiplierOfUpperBoundConstraintToPrimalVariables("y_e").view1D();
316                
317                /* Check the solution */
318                for (Link e : this.currentNetPlan.getLinks())
319                {
320                        double yThisLink = 0; for (Route r : e.getTraversingRoutes()) yThisLink += x_p.get(r.getIndex ());
321                        if (yThisLink > e.getCapacity() + 1E-3) throw new RuntimeException ("Bad");
322                }
323                for (Demand d : this.currentNetPlan.getDemands())
324                {
325                        double trafDemand = 0; for (Route r : d.getRoutes()) trafDemand += x_p.get(r.getIndex ());
326                        if (Math.abs(trafDemand - d.getOfferedTraffic()) > 1E-3) throw new RuntimeException ("Bad");
327                }
328                
329                /* Compute optimum cost */
330                double objFunc = 0; for (Route r : this.currentNetPlan.getRoutes()) 
331                {
332                        final double x_r = x_p.get(r.getIndex ()); 
333                        objFunc +=  x_r * r.getNumberOfHops();
334                        if (isRegularized) objFunc += this.gradient_regularizationEpsilon.getDouble() * Math.pow(x_r, 2);
335                }
336                return Quadruple.of(x_p,pi_e,y_e,objFunc);
337
338        }
339        
340        
341        private void updateDemandRoutingFromWeightsKnown (Demand d)
342        {
343                final Node a_d = d.getIngressNode();
344                final double h_d = d.getOfferedTraffic();
345                final DoubleMatrix1D weightsKnown_e = this.routing_mostUpdatedLinkPriceKnownByNode_ne.viewRow(a_d.getIndex ()); 
346                DoubleMatrix1D a_k = DoubleFactory1D.dense.make (R);
347                for (Route r : d.getRoutes())
348                {
349                        double val = 0; 
350                        for (Link e : r.getSeqLinks()) val += weightsKnown_e.get(e.getIndex()) + 1; 
351                        a_k.set(r.getIndex (), val);
352                }
353
354                DoubleMatrix1D x_r = GradientProjectionUtils.regularizedProjection_sumEquality (a_k , control_routeIndexes_d [d.getIndex ()] , null , h_d , this.gradient_regularizationEpsilon.getDouble());
355                for (Route r : d.getRoutes ())
356                        r.setCarriedTraffic(x_r.get(r.getIndex ()) ,  x_r.get(r.getIndex ()));
357        }
358        
359}