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 cern.jet.math.tdouble.DoubleFunctions; 019import com.net2plan.examples.ocnbook.offline.Offline_cba_congControLinkBwSplitTwolQoS; 020import com.net2plan.interfaces.networkDesign.*; 021import com.net2plan.interfaces.simulation.IEventProcessor; 022import com.net2plan.interfaces.simulation.SimEvent; 023import com.net2plan.utils.Constants.RoutingType; 024import com.net2plan.utils.*; 025 026import java.io.File; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030import java.util.Random; 031 032/** 033 * This module implements a distributed primal-decomposition-based gradient algorithm, for a coordinated adjustment of the congestion control of two types of demands (with different utility functions), and the fraction of each link capacity to grant to the traffic of each type, to maximize the network utility enforcing a fair allocation of the resources. 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_sec11_3_congControlAndQoSLinkCap_primalDecomp.m">{@code fig_sec11_3_congControlAndQoSLinkCap_primalDecomp.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 Bandwidth assignment (BA), Capacity assignment (CA), Distributed algorithm, Primal decomposition 044 * @net2plan.ocnbooksections Section 11.3 045 * @net2plan.inputParameters 046 * @author Pablo Pavon-Marino 047 */ 048@SuppressWarnings("unchecked") 049public class Online_evProc_congControlAndQoSTwoClassesPrimalDecomp extends IEventProcessor 050{ 051 private double PRECISIONFACTOR; 052 private Random rng; 053 054 private int N,E,D1,D2,D; 055 private Map<String,String> algorithmParameters , net2PlanParameters; 056 057 private static final int MAC_UPDATE_WAKEUPTOUPDATE = 202; 058 private static final int CC_SIGNALING_WAKEUPTOSENDMESSAGE = 400; 059 private static final int CC_SIGNALING_RECEIVEDMESSAGE = 401; 060 private static final int CC_UPDATE_WAKEUPTOUPDATE = 402; 061 062 private InputParameter mac_update_isSynchronous = new InputParameter ("mac_update_isSynchronous", false , "true if all the distributed agents involved wake up synchronousely to update its state"); 063 private InputParameter mac_update_averageInterUpdateTime = new InputParameter ("mac_update_averageInterUpdateTime", 50.0 , "Average time between two updates of an agent" , 0 , false , Double.MAX_VALUE , true); 064 private InputParameter mac_update_maxFluctuationInterUpdateTime = new InputParameter ("mac_update_maxFluctuationInterUpdateTime", 10.0 , "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); 065 private InputParameter mac_gradient_gammaStep = new InputParameter ("mac_gradient_gammaStep", 5.0 , "Gamma step in the gradient algorithm" , 0 , false , Double.MAX_VALUE , true); 066 private InputParameter mac_gradient_maxGradientCoordinateChange = new InputParameter ("mac_gradient_maxGradientCoordinateChange", 1000.0 , "Maximum change in an iteration of a gradient coordinate" , 0 , false , Double.MAX_VALUE , true); 067 068 private InputParameter mac_simulation_maxNumberOfUpdateIntervals = new InputParameter ("mac_simulation_maxNumberOfUpdateIntervals", 600.0 , "Maximum number of update intervals in average per agent" , 0 , false , Double.MAX_VALUE , true); 069 private InputParameter simulation_randomSeed = new InputParameter ("simulation_randomSeed", (long) 1 , "Seed of the random number generator"); 070 private InputParameter simulation_outFileNameRoot = new InputParameter ("simulation_outFileNameRoot", "crossLayerCongControlTwoQoSPrimalDecomp" , "Root of the file name to be used in the output files. If blank, no output"); 071 072 private InputParameter cc_signaling_isSynchronous = new InputParameter ("cc_signaling_isSynchronous", false , "true if all the distributed agents involved wake up synchronously to send the signaling messages"); 073 private InputParameter cc_signaling_averageInterMessageTime = new InputParameter ("cc_signaling_averageInterMessageTime", 1.0 , "Average time between two signaling messages sent by an agent" , 0 , false , Double.MAX_VALUE , true); 074 private InputParameter cc_signaling_maxFluctuationInterMessageTime = new InputParameter ("cc_signaling_maxFluctuationInterMessageTime", 0.5 , "Max fluctuation in time between two signaling messages sent by an agent" , 0 , true , Double.MAX_VALUE , true); 075 private InputParameter cc_signaling_averageDelay = new InputParameter ("cc_signaling_averageDelay", 3.0 , "Average time between signaling message transmission by an agent and its reception by other or others" , 0 , true , Double.MAX_VALUE , true); 076 private InputParameter cc_signaling_maxFluctuationInDelay = new InputParameter ("cc_signaling_maxFluctuationInDelay", 0.5 , "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); 077 private InputParameter cc_signaling_signalingLossProbability = new InputParameter ("cc_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); 078 079 private InputParameter cc_update_isSynchronous = new InputParameter ("cc_update_isSynchronous", false , "true if all the distributed agents involved wake up synchronousely to update its state"); 080 private InputParameter cc_update_averageInterUpdateTime = new InputParameter ("cc_update_averageInterUpdateTime", 1.0 , "Average time between two updates of an agent" , 0 , false , Double.MAX_VALUE , true); 081 private InputParameter cc_update_maxFluctuationInterUpdateTime = new InputParameter ("cc_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); 082 083 private InputParameter cc_gradient_gammaStep = new InputParameter ("cc_gradient_gammaStep", 0.001 , "Gamma step in the gradient algorithm" , 0 , false , Double.MAX_VALUE , true); 084 private InputParameter cc_gradient_maxGradientAbsoluteNoise = new InputParameter ("cc_gradient_maxGradientAbsoluteNoise", 0.0 , "Max value of the added noise to the gradient coordinate in absolute values" , 0 , true , Double.MAX_VALUE , true); 085 086 private InputParameter cc_simulation_maxNumberOfUpdateIntervals = new InputParameter ("cc_simulation_maxNumberOfUpdateIntervals", 600.0 , "Maximum number of update intervals in average per agent" , 0 , false , Double.MAX_VALUE , true); 087 private InputParameter cc_control_minHd = new InputParameter ("cc_control_minHd", 0.1 , "Minimum traffic assigned to each demand" , 0 , true , Double.MAX_VALUE , true); 088 private InputParameter cc_control_maxHd = new InputParameter ("cc_control_maxHd", 1e6 , "Maximum traffic assigned to each demand" , 0 , true , Double.MAX_VALUE , true); 089 private InputParameter cc_control_initialiLinkPrices = new InputParameter ("cc_control_initialiLinkPrices", 1.0 , "Link prices in the algorithm initialization" , 0 , true , Double.MAX_VALUE , true); 090 091 private InputParameter cc_control_fairnessFactor_1 = new InputParameter ("cc_control_fairnessFactor_1", 1.0 , "Fairness factor in utility function of congestion control for demands of class 1" , 0 , true , Double.MAX_VALUE , true); 092 private InputParameter cc_control_fairnessFactor_2 = new InputParameter ("cc_control_fairnessFactor_2", 1.0 , "Fairness factor in utility function of congestion control for demands of class 2" , 0 , true , Double.MAX_VALUE , true); 093 private InputParameter cc_control_weightFairness_1 = new InputParameter ("cc_control_weightFairness_1", 1.0 , "Weight factor in utility function demands type 1" , 0 , true , Double.MAX_VALUE , true); 094 private InputParameter cc_control_weightFairness_2 = new InputParameter ("cc_control_weightFairness_2", 2.0 , "Weight factor in utility function demands type 2" , 0 , true , Double.MAX_VALUE , true); 095 private InputParameter mac_minCapacity_1 = new InputParameter ("mac_minCapacity_1", 0.1 , "Minimum capacity in each link, allocated to traffic of type 1" , 0 , true , Double.MAX_VALUE , true); 096 private InputParameter mac_minCapacity_2 = new InputParameter ("mac_minCapacity_2", 0.1 , "Minimum capacity in each link, allocated to traffic of type 2" , 0 , true , Double.MAX_VALUE , true); 097 098 private DoubleMatrix1D demandType; 099 private DoubleMatrix1D congControl_price1_e; 100 private DoubleMatrix1D congControl_price2_e; 101 private DoubleMatrix2D control_mostUpdatedLinkPriceKnownDemand_de; 102 private DoubleMatrix1D mac_u1; 103 private DoubleMatrix1D mac_u2; 104 105 private TimeTrace traceOf_pi1_e; 106 private TimeTrace traceOf_pi2_e; 107 private TimeTrace traceOf_u1_e; 108 private TimeTrace traceOf_u2_e; 109 private TimeTrace traceOf_y1_e; 110 private TimeTrace traceOf_y2_e; 111 private TimeTrace traceOf_h_d1; 112 private TimeTrace traceOf_h_d2; 113 private TimeTrace traceOf_objFunction; 114 115 private NetPlan currentNetPlan , copyInitialNetPlan; 116 117 118 @Override 119 public String getDescription() 120 { 121 return "This module implements a distributed primal-decomposition-based gradient algorithm, for a coordinated adjustment of the congestion control of two types of demands (with different utility functions), and the fraction of each link capacity to grant to the traffic of each type, to maximize the network utility enforcing a fair allocation of the resources."; 122 } 123 124 @Override 125 public List<Triple<String, String, String>> getParameters() 126 { 127 /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */ 128 return InputParameter.getInformationAllInputParameterFieldsOfObject(this); 129 } 130 131 @Override 132 public void initialize(NetPlan currentNp, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters) 133 { 134 /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */ 135 InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters); 136 137 this.currentNetPlan = currentNp; 138 this.algorithmParameters = algorithmParameters; 139 this.net2PlanParameters = net2planParameters; 140 if (currentNetPlan.getNumberOfLayers() != 1) throw new Net2PlanException ("This algorithm works in single layer networks"); 141 142 /* INITIALIZE VARIABLES COMMON FOR BOTH LAYERS */ 143 this.copyInitialNetPlan = currentNp.copy(); 144 if (currentNetPlan.getVectorLinkCapacity().getMaxLocation() [0]< mac_minCapacity_1.getDouble() + mac_minCapacity_2.getDouble()) throw new Net2PlanException ("Minimum link capacities for each class are too high for the available link capacities"); 145 146 this.PRECISIONFACTOR = Double.parseDouble(net2planParameters.get("precisionFactor")); 147 148 /* READ INPUT PARAMETERS BOTH LAYERS */ 149 this.rng = new Random (simulation_randomSeed.getLong()); 150 this.N = this.currentNetPlan.getNumberOfNodes(); 151 this.E = this.currentNetPlan.getNumberOfLinks(); 152 if (E == 0) throw new Net2PlanException ("The input design should have links"); 153 this.D1 = N*(N-1); 154 this.D2 = N*(N-1); 155 this.D = D1+D2; 156 157 /* Initialize the demands and routers per demand */ 158 this.currentNetPlan.removeAllDemands(); 159 this.currentNetPlan.setRoutingTypeAllDemands(RoutingType.SOURCE_ROUTING); 160 this.demandType = DoubleFactory1D.dense.make (D1+D2); 161 for (Node n1 : this.currentNetPlan.getNodes()) 162 for (Node n2 : this.currentNetPlan.getNodes()) 163 if (n1 != n2) 164 { 165 final Demand d1 = this.currentNetPlan.addDemand(n1, n2, 0.0, RoutingType.SOURCE_ROUTING , null); d1.setAttribute("type" , "1"); demandType.set(d1.getIndex (), 1); 166 final Demand d2 = this.currentNetPlan.addDemand(n1, n2, 0.0, RoutingType.SOURCE_ROUTING , null); d1.setAttribute("type" , "2"); demandType.set(d2.getIndex (), 2); 167 } 168 169 /* Remove all routes, and create one with the shortest path in km for each demand */ 170 currentNetPlan.removeAllUnicastRoutingInformation(); 171 currentNetPlan.setRoutingTypeAllDemands(RoutingType.SOURCE_ROUTING); 172 this.currentNetPlan.addRoutesFromCandidatePathList(currentNetPlan.computeUnicastCandidatePathList(currentNetPlan.getVectorLinkLengthInKm() , 1, -1, -1, -1, -1, -1, -1 , null)); 173 174 175 for (Route r : currentNp.getRoutes ()) r.setCarriedTraffic(cc_control_minHd.getDouble() , cc_control_minHd.getDouble()); 176 177 /* INITIALIZE control information */ 178 this.congControl_price1_e = DoubleFactory1D.dense.make (E , cc_control_initialiLinkPrices.getDouble()); 179 this.congControl_price2_e = DoubleFactory1D.dense.make (E , cc_control_initialiLinkPrices.getDouble()); 180 181 /* Initialize the information each demand knows of the prices of all the links */ 182 this.control_mostUpdatedLinkPriceKnownDemand_de = DoubleFactory2D.dense.make (D,E,cc_control_initialiLinkPrices.getDouble()); 183 184 this.mac_u1 = DoubleFactory1D.dense.make (E , mac_minCapacity_1.getDouble()); 185 this.mac_u2 = currentNetPlan.getVectorLinkCapacity().copy ().assign(DoubleFunctions.minus (mac_minCapacity_1.getDouble())); 186 187 /* Each demand adjusts its rate to the pi_e */ 188 /* Compute the traffic each demand injects, set it in net2plan, and tell routing layer there was an update in this */ 189 for (Demand d : currentNetPlan.getDemands()) 190 { 191 final double h_d = this.computeHdFromPrices(d); 192 d.setOfferedTraffic(h_d); 193 d.getRoutes().iterator().next ().setCarriedTraffic(h_d , h_d); 194 } 195 196 /* Initially all nodes receive a "wake up to transmit" event, aligned at time zero or y asynchr => randomly chosen */ 197 for (Link e : currentNp.getLinks()) 198 { 199 final double updateTime = (mac_update_isSynchronous.getBoolean())? mac_update_averageInterUpdateTime.getDouble() : Math.max(0 , mac_update_averageInterUpdateTime.getDouble() + mac_update_maxFluctuationInterUpdateTime.getDouble() * (rng.nextDouble() - 0.5)); 200 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , MAC_UPDATE_WAKEUPTOUPDATE , e)); 201 } 202 203 /* INITIALIZATION CONGESTION CONTROL LAYER */ 204 /* Initially all nodes receive a "wake up to transmit" event, aligned at time zero or y asynchr => randomly chosen */ 205 for (Link e : currentNp.getLinks()) 206 { 207 final double signalingTime = (cc_signaling_isSynchronous.getBoolean())? cc_signaling_averageInterMessageTime.getDouble() : Math.max(0 , cc_signaling_averageInterMessageTime.getDouble() + cc_signaling_maxFluctuationInterMessageTime.getDouble() * (rng.nextDouble() - 0.5)); 208 this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_SIGNALING_WAKEUPTOSENDMESSAGE , e)); 209 } 210 for (Demand d : currentNetPlan.getDemands()) 211 { 212 final double updateTime = (cc_update_isSynchronous.getBoolean())? cc_update_averageInterUpdateTime.getDouble() : Math.max(0 , cc_update_averageInterUpdateTime.getDouble() + cc_update_maxFluctuationInterUpdateTime.getDouble() * (rng.nextDouble() - 0.5)); 213 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_UPDATE_WAKEUPTOUPDATE , d)); 214 } 215 216 /* INITIALIZE STATISTIC VARIABLES FOR BOTH LAYERS */ 217 this.traceOf_pi1_e = new TimeTrace (); 218 this.traceOf_pi2_e = new TimeTrace (); 219 this.traceOf_u1_e = new TimeTrace (); 220 this.traceOf_u2_e = new TimeTrace (); 221 this.traceOf_y1_e = new TimeTrace (); 222 this.traceOf_y2_e = new TimeTrace (); 223 this.traceOf_h_d1 = new TimeTrace (); 224 this.traceOf_h_d2 = new TimeTrace (); 225 this.traceOf_objFunction = new TimeTrace (); 226 227 228 this.traceOf_pi1_e.add(0.0, this.congControl_price1_e.copy ()); 229 this.traceOf_pi2_e.add(0.0, this.congControl_price2_e.copy ()); 230 this.traceOf_u1_e.add(0.0, this.mac_u1.copy ()); 231 this.traceOf_u2_e.add(0.0, this.mac_u2.copy ()); 232 final Triple<Double,Pair<DoubleMatrix1D,DoubleMatrix1D>,Pair<DoubleMatrix1D,DoubleMatrix1D>> objFunctionInfo = computeObjectiveFunctionFromNetPlan(this.currentNetPlan); 233 this.traceOf_objFunction.add(0.0 , objFunctionInfo.getFirst()); 234 this.traceOf_h_d1.add(0.0, objFunctionInfo.getSecond().getFirst().copy ()); 235 this.traceOf_h_d2.add(0.0, objFunctionInfo.getSecond().getSecond().copy ()); 236 this.traceOf_y1_e.add(0.0, objFunctionInfo.getThird().getFirst().copy ()); 237 this.traceOf_y2_e.add(0.0, objFunctionInfo.getThird().getSecond().copy ()); 238 } 239 240 @Override 241 public void processEvent(NetPlan currentNetPlan, SimEvent event) 242 { 243 final double t = event.getEventTime(); 244 switch (event.getEventType()) 245 { 246 case MAC_UPDATE_WAKEUPTOUPDATE: 247 { 248 final Link eMe = (Link) event.getEventObject(); 249 final double current_u1 = mac_u1.get(eMe.getIndex ()); 250 final double current_u2 = mac_u2.get(eMe.getIndex ()); 251 final double gradient_1 = congControl_price1_e.get(eMe.getIndex ()); 252 final double gradient_2 = congControl_price2_e.get(eMe.getIndex ()); 253 final double nextBeforeProjection_u1 = current_u1 + this.mac_gradient_gammaStep.getDouble() * gradient_1; 254 final double nextBeforeProjection_u2 = current_u2 + this.mac_gradient_gammaStep.getDouble() * gradient_2; 255 DoubleMatrix1D initialSolution = DoubleFactory1D.dense.make (new double [] { current_u1 , current_u2 }); 256 DoubleMatrix1D inOut = DoubleFactory1D.dense.make (new double [] { nextBeforeProjection_u1 , nextBeforeProjection_u2 }); 257 DoubleMatrix1D uMin = DoubleFactory1D.dense.make (new double [] { mac_minCapacity_1.getDouble() , mac_minCapacity_2.getDouble() }); 258 GradientProjectionUtils.euclideanProjection_sumInequality (inOut , null , uMin , eMe.getCapacity()); 259 if (mac_gradient_maxGradientCoordinateChange.getDouble() > 0) 260 GradientProjectionUtils.scaleDown_maxAbsoluteCoordinateChange (initialSolution , inOut , null , mac_gradient_maxGradientCoordinateChange.getDouble()); 261 262 this.mac_u1.set(eMe.getIndex (), inOut.get(0)); 263 this.mac_u2.set(eMe.getIndex (), inOut.get(1)); 264 if (mac_u1.get(eMe.getIndex ()) + mac_u2.get(eMe.getIndex ()) > eMe.getCapacity() + PRECISIONFACTOR) throw new RuntimeException ("Bad"); 265 266 final double updateTime = mac_update_isSynchronous.getBoolean()? t + mac_update_averageInterUpdateTime.getDouble() : Math.max(t , t + mac_update_averageInterUpdateTime.getDouble() + mac_update_maxFluctuationInterUpdateTime.getDouble() * (rng.nextDouble() - 0.5)); 267 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , MAC_UPDATE_WAKEUPTOUPDATE, eMe)); 268 269 this.traceOf_u1_e.add(t, this.mac_u1.copy ()); 270 this.traceOf_u2_e.add(t, this.mac_u2.copy ()); 271 272 if (t > this.mac_simulation_maxNumberOfUpdateIntervals.getDouble() * this.mac_update_averageInterUpdateTime.getDouble()) { this.endSimulation (); } 273 274 break; 275 } 276 277 case CC_SIGNALING_RECEIVEDMESSAGE: // A node receives from an out neighbor the q_nt for any destination 278 { 279 final Pair<Demand,Triple<Link,Double,Double>> signalInfo = (Pair<Demand,Triple<Link,Double,Double>>) event.getEventObject(); 280 final Demand d = signalInfo.getFirst(); 281 final int type = (int) demandType.get(d.getIndex ()); 282 final Link e = signalInfo.getSecond().getFirst(); 283 final double pi1 = signalInfo.getSecond().getSecond(); 284 final double pi2 = signalInfo.getSecond().getThird(); 285 this.control_mostUpdatedLinkPriceKnownDemand_de.set(d.getIndex () , e.getIndex () , (type == 1)? pi1 : pi2); 286 break; 287 } 288 289 case CC_SIGNALING_WAKEUPTOSENDMESSAGE: // A node broadcasts signaling info to its 1 hop neighbors 290 { 291 final Link eMe = (Link) event.getEventObject(); 292 293 /* Update the new price with the gradient approach */ 294 Triple<Double,Pair<DoubleMatrix1D,DoubleMatrix1D>,Pair<DoubleMatrix1D,DoubleMatrix1D>> triple = computeObjectiveFunctionFromNetPlan (this.currentNetPlan); 295 final double u1 = this.mac_u1.get(eMe.getIndex ()); 296 final double u2 = this.mac_u2.get(eMe.getIndex ()); 297 final double y1 = triple.getThird().getFirst().get(eMe.getIndex ()); 298 final double y2 = triple.getThird().getSecond().get(eMe.getIndex ()); 299 final double old_pie_1 = this.congControl_price1_e.get(eMe.getIndex ()); 300 final double old_pie_2 = this.congControl_price2_e.get(eMe.getIndex ()); 301 final double new_pie_1 = Math.max(0, old_pie_1 - this.cc_gradient_gammaStep.getDouble() * (u1 - y1) + 2*cc_gradient_maxGradientAbsoluteNoise.getDouble()*(rng.nextDouble()-0.5)); 302 final double new_pie_2 = Math.max(0, old_pie_2 - this.cc_gradient_gammaStep.getDouble() * (u2 - y2) + 2*cc_gradient_maxGradientAbsoluteNoise.getDouble()*(rng.nextDouble()-0.5)); 303 this.congControl_price1_e.set(eMe.getIndex (), new_pie_1); 304 this.congControl_price2_e.set(eMe.getIndex (), new_pie_2); 305 306 this.traceOf_pi1_e.add(t, this.congControl_price1_e.copy ()); 307 this.traceOf_pi2_e.add(t, this.congControl_price2_e.copy ()); 308 309 /* Create the info I will signal */ 310 Triple<Link,Double,Double> infoToSignal = Triple.of(eMe , new_pie_1 , new_pie_2); 311 312 /* Send the events of the signaling information messages to all the nodes */ 313 for (Route route : eMe.getTraversingRoutes()) 314 { 315 if (rng.nextDouble() < this.cc_signaling_signalingLossProbability.getDouble()) continue; // the signaling may be lost => lost to all demands 316 final Demand d = route.getDemand (); 317 final double signalingReceptionTime = t + Math.max(0 , cc_signaling_averageDelay.getDouble() + cc_signaling_maxFluctuationInDelay.getDouble() * (rng.nextDouble() - 0.5)); 318 this.scheduleEvent(new SimEvent (signalingReceptionTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_SIGNALING_RECEIVEDMESSAGE , Pair.of(d , infoToSignal))); 319 } 320 321 /* Re-schedule when to wake up again */ 322 final double signalingTime = cc_signaling_isSynchronous.getBoolean()? t + cc_signaling_averageInterMessageTime.getDouble() : Math.max(t , t + cc_signaling_averageInterMessageTime.getDouble() + cc_signaling_maxFluctuationInterMessageTime.getDouble() * (rng.nextDouble() - 0.5)); 323 this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_SIGNALING_WAKEUPTOSENDMESSAGE , eMe)); 324 break; 325 } 326 327 case CC_UPDATE_WAKEUPTOUPDATE: 328 { 329 final Demand dMe = (Demand) event.getEventObject(); 330 final double new_hd = computeHdFromPrices (dMe); 331 332 dMe.setOfferedTraffic(new_hd); 333 dMe.getRoutes ().iterator().next().setCarriedTraffic(new_hd , new_hd); 334 335 final Triple<Double,Pair<DoubleMatrix1D,DoubleMatrix1D>,Pair<DoubleMatrix1D,DoubleMatrix1D>> objFunctionInfo = computeObjectiveFunctionFromNetPlan(this.currentNetPlan); 336 this.traceOf_objFunction.add(t , objFunctionInfo.getFirst()); 337 this.traceOf_h_d1.add(t, objFunctionInfo.getSecond().getFirst().copy ()); 338 this.traceOf_h_d2.add(t, objFunctionInfo.getSecond().getSecond().copy ()); 339 this.traceOf_y1_e.add(t, objFunctionInfo.getThird().getFirst().copy ()); 340 this.traceOf_y2_e.add(t, objFunctionInfo.getThird().getSecond().copy ()); 341 342 final double updateTime = cc_update_isSynchronous.getBoolean()? t + cc_update_averageInterUpdateTime.getDouble() : Math.max(t , t + cc_update_averageInterUpdateTime.getDouble() + cc_update_maxFluctuationInterUpdateTime.getDouble() * (rng.nextDouble() - 0.5)); 343 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_UPDATE_WAKEUPTOUPDATE, dMe)); 344 345 if (t > this.cc_simulation_maxNumberOfUpdateIntervals.getDouble() * this.cc_update_averageInterUpdateTime.getDouble()) { this.endSimulation (); } 346 347 break; 348 } 349 350 351 default: throw new RuntimeException ("Unexpected received event"); 352 } 353 354 355 } 356 357 public String finish (StringBuilder st , double simTime) 358 { 359 if (simulation_outFileNameRoot.getString().equals("")) return null; 360 traceOf_h_d1.printToFile(new File (simulation_outFileNameRoot.getString() + "_hd1.txt")); 361 traceOf_h_d2.printToFile(new File (simulation_outFileNameRoot.getString() + "_hd2.txt")); 362 traceOf_u1_e.printToFile(new File (simulation_outFileNameRoot.getString() + "_ue1.txt")); 363 traceOf_u2_e.printToFile(new File (simulation_outFileNameRoot.getString() + "_ue2.txt")); 364 traceOf_objFunction.printToFile(new File (simulation_outFileNameRoot.getString() + "_objFunc.txt")); 365 366 Map<String,String> param = new HashMap<String,String> (algorithmParameters); 367 param.put("solverName", "ipopt"); 368 param.put("solverLibraryName", ""); 369 param.put("maxSolverTimeInSeconds", "-1"); 370 new Offline_cba_congControLinkBwSplitTwolQoS().executeAlgorithm(copyInitialNetPlan , param , this.net2PlanParameters); 371 DoubleMatrix1D jom_hd1 = DoubleFactory1D.dense.make (D1); 372 DoubleMatrix1D jom_hd2 = DoubleFactory1D.dense.make (D2); 373 DoubleMatrix1D jom_ue1 = DoubleFactory1D.dense.make (E); 374 DoubleMatrix1D jom_ue2 = DoubleFactory1D.dense.make (E); 375 int counter_1 = 0; int counter_2 = 0; 376 for (Demand d : copyInitialNetPlan.getDemands ()) 377 if (d.getAttribute("type").equals ("1")) jom_hd1.set (counter_1 ++ , d.getOfferedTraffic()); else jom_hd2.set (counter_2 ++ , d.getOfferedTraffic()); 378 for (Link e : copyInitialNetPlan.getLinks ()) { jom_ue1.set (e.getIndex () , Double.parseDouble (e.getAttribute("u_1"))); jom_ue2.set (e.getIndex () , Double.parseDouble (e.getAttribute("u_2"))); } 379 final double jomObjcFunc = Double.parseDouble (copyInitialNetPlan.getAttribute("netUtility")); 380 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_hd1.txt"), jom_hd1); 381 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_hd2.txt"), jom_hd2); 382 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_ue1.txt"), jom_ue1); 383 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_ue2.txt"), jom_ue2); 384 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_objFunc.txt"), jomObjcFunc); 385 return null; 386 } 387 388 389 private Triple<Double,Pair<DoubleMatrix1D,DoubleMatrix1D>,Pair<DoubleMatrix1D,DoubleMatrix1D>> computeObjectiveFunctionFromNetPlan (NetPlan np) 390 { 391 DoubleMatrix1D y1 = DoubleFactory1D.dense.make (E); 392 DoubleMatrix1D y2 = DoubleFactory1D.dense.make (E); 393 DoubleMatrix1D h1 = DoubleFactory1D.dense.make (D1); 394 DoubleMatrix1D h2 = DoubleFactory1D.dense.make (D2); 395 double obj = 0; 396 int counter_d1 = 0; int counter_d2 = 0; 397 for (Demand d : np.getDemands()) 398 { 399 final double h_d = d.getCarriedTraffic(); 400 final int type = (int) this.demandType.get(d.getIndex()); 401 final List<Link> seqLinks = d.getRoutes ().iterator().next().getSeqLinks(); 402 for (Link e : seqLinks) 403 { 404 final int index_e = e.getIndex (); 405 if (type == 1) y1.set(index_e , y1.get(index_e) + h_d); else y2.set(index_e , y2.get(index_e) + h_d); 406 } 407 if (type == 1) 408 { 409 h1.set (counter_d1 , h_d); 410 obj += (this.cc_control_fairnessFactor_1.getDouble() == 1)? this.cc_control_weightFairness_1.getDouble() * Math.log(h_d) : this.cc_control_weightFairness_1.getDouble() * Math.pow(h_d, 1-this.cc_control_fairnessFactor_1.getDouble()) / (1-this.cc_control_fairnessFactor_1.getDouble()); 411 counter_d1 ++; 412 } else 413 { 414 h2.set (counter_d2 , h_d); 415 obj += (this.cc_control_fairnessFactor_2.getDouble() == 1)? this.cc_control_weightFairness_2.getDouble() * Math.log(h_d) : this.cc_control_weightFairness_2.getDouble() * Math.pow(h_d, 1-this.cc_control_fairnessFactor_2.getDouble()) / (1-this.cc_control_fairnessFactor_2.getDouble()); 416 counter_d2 ++; 417 } 418 } 419 if ((counter_d1 != D1) || (counter_d2 != D2)) throw new RuntimeException ("Bad"); 420 return Triple.of(obj, Pair.of(h1, h2),Pair.of(y1, y2)); 421 } 422 423 424 private double computeHdFromPrices (Demand d) 425 { 426 DoubleMatrix1D infoIKnow_price_e = this.control_mostUpdatedLinkPriceKnownDemand_de.viewRow(d.getIndex ()); 427 428 /* compute the demand price as weighted sum in the routes of route prices */ 429 double demandWeightedSumLinkPrices = 0; 430 double demandCarriedTraffic = 0; 431 for (Route r : d.getRoutes ()) 432 { 433 final double h_r = r.getCarriedTraffic(); 434 demandCarriedTraffic += h_r; 435 for (Link e : r.getSeqLinks()) 436 demandWeightedSumLinkPrices += h_r * infoIKnow_price_e.get(e.getIndex ()); 437 } 438 //if (Math.abs(demandCarriedTraffic - this.currentNetPlan.getDemandCarriedTraffic(dIdMe)) > 1E-3) throw new RuntimeException ("Not all the traffic is carried"); 439 demandWeightedSumLinkPrices /= demandCarriedTraffic; 440 441 /* compute the new h_d */ 442 final double alpha = (demandType.get(d.getIndex ()) == 1)? this.cc_control_fairnessFactor_1.getDouble() : this.cc_control_fairnessFactor_2.getDouble(); 443 final double weight = (demandType.get(d.getIndex ()) == 1)? this.cc_control_weightFairness_1.getDouble() : this.cc_control_weightFairness_2.getDouble(); 444 final double new_hd = Math.max(this.cc_control_minHd.getDouble() , Math.min(this.cc_control_maxHd.getDouble(), Math.pow(demandWeightedSumLinkPrices/weight, -1/alpha))); 445 446 return new_hd; 447 } 448 449}