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_wirelessCongControlTransmissionPowerAssignment; 020import com.net2plan.interfaces.networkDesign.*; 021import com.net2plan.interfaces.simulation.IEventProcessor; 022import com.net2plan.interfaces.simulation.SimEvent; 023import com.net2plan.libraries.NetworkPerformanceMetrics; 024import com.net2plan.libraries.WirelessUtils; 025import com.net2plan.utils.Constants.RoutingType; 026import com.net2plan.utils.*; 027 028import java.io.File; 029import java.util.HashMap; 030import java.util.List; 031import java.util.Map; 032import java.util.Random; 033 034/** 035 * This module implements a distributed dual-decomposition-based gradient algorithm, for a coordinated adjustment of the traffic to inject by each demand (congestion control), and the transmission power in each link of the underlying wireless network, to maximize the network utility enforcing a fair allocation of the resources. 036 * 037 * Ths event processor is adapted to permit observing the algorithm performances under user-defined conditions, 038 * including asynchronous distributed executions, where signaling can be affected by losses and/or delays, and/or measurement errors. 039 * The time evolution of different metrics can be stored in output files, for later processing. 040 * As an example, see the <a href="../../../../../../graphGeneratorFiles/fig_sec11_4_congControlAndBackpressureRouting_dualDecomp.m">{@code fig_sec11_4_congControlAndBackpressureRouting_dualDecomp.m}</a> MATLAB file used for generating the graph/s of the case study in the 041 * <a href="http://eu.wiley.com/WileyCDA/WileyTitle/productCd-1119013356.html">book</a> using this algorithm. 042 * 043 * To simulate a network with this module, use the {@code Online_evGen_doNothing} generator. 044 * 045 * @net2plan.keywords Bandwidth assignment (BA), Transmission power optimization, Wireless, Capacity assignment (CA), Distributed algorithm, Dual decomposition 046 * @net2plan.ocnbooksections Section 11.4 047 * @net2plan.inputParameters 048 * @author Pablo Pavon-Marino 049 */ 050@SuppressWarnings("unchecked") 051public class Online_evProc_congControlAndTransmissionPowerAssignmentDualDecomp extends IEventProcessor 052{ 053 private Random rng; 054 055 static final int MAC_SIGNALING_WAKEUPTOSENDMESSAGE = 200; 056 static final int MAC_SIGNALING_RECEIVEDMESSAGE = 201; 057 static final int MAC_UPDATE_WAKEUPTOUPDATE = 202; 058 059 static final int CC_SIGNALING_WAKEUPTOSENDMESSAGE = 400; 060 static final int CC_SIGNALING_RECEIVEDMESSAGE = 401; 061 static final int CC_UPDATE_WAKEUPTOUPDATE = 402; 062 063 064 private InputParameter mac_signaling_isSynchronous = new InputParameter ("mac_signaling_isSynchronous", false , "true if all the distributed agents involved wake up synchronously to send the signaling messages"); 065 private InputParameter mac_signaling_averageInterMessageTime = new InputParameter ("mac_signaling_averageInterMessageTime", 1.0 , "Average time between two signaling messages sent by an agent" , 0 , false , Double.MAX_VALUE , true); 066 private InputParameter mac_signaling_maxFluctuationInterMessageTime = new InputParameter ("mac_signaling_maxFluctuationInterMessageTime", 0.5 , "Max fluctuation in time between two signaling messages sent by an agent" , 0 , true , Double.MAX_VALUE , true); 067 private InputParameter mac_signaling_averageDelay = new InputParameter ("mac_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); 068 private InputParameter mac_signaling_maxFluctuationInDelay = new InputParameter ("mac_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); 069 private InputParameter mac_signaling_signalingLossProbability = new InputParameter ("mac_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); 070 071 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"); 072 private InputParameter mac_update_averageInterUpdateTime = new InputParameter ("mac_update_averageInterUpdateTime", 1.0 , "Average time between two updates of an agent" , 0 , false , Double.MAX_VALUE , true); 073 private InputParameter mac_update_maxFluctuationInterUpdateTime = new InputParameter ("mac_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); 074 075 private InputParameter mac_gradient_maxGradientAbsoluteNoise = new InputParameter ("mac_gradient_maxGradientAbsoluteNoise", 0.01 , "Max value of the added noise to the gradient coordinate in absolute values" , 0 , true , Double.MAX_VALUE , true); 076 private InputParameter mac_gradient_gammaStep = new InputParameter ("mac_gradient_gammaStep", 1.0 , "Gamma step in the gradient algorithm" , 0 , false , Double.MAX_VALUE , true); 077 private InputParameter mac_gradient_heavyBallBetaParameter = new InputParameter ("mac_gradient_heavyBallBetaParameter", 0.0 , "Beta parameter of heavy ball, between 0 and 1. Value 0 means no heavy ball" , 0 , true , 1.0 , true); 078 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); 079 080 private InputParameter mac_pathLossExponent = new InputParameter ("mac_pathLossExponent", 3.0 , "Exponent in the model for propagation losses" , 0 , true , Double.MAX_VALUE , true); 081 private InputParameter mac_worseRiseOverThermal_nu = new InputParameter ("mac_worseRiseOverThermal_nu", 10.0 , "Worse case ratio between interference power and thermal power at any receiver. Used to set the common thermal power in the receivers" , 0 , true , Double.MAX_VALUE , true); 082 private InputParameter mac_interferenceAttenuationFactor_nu = new InputParameter ("mac_interferenceAttenuationFactor_nu", 1.0e6 , "The interference power received in natural units is divided by this to reduce its effect" , 1 , true , Double.MAX_VALUE , true); 083 private InputParameter mac_maxTransmissionPower_logu = new InputParameter ("mac_maxTransmissionPower_logu", 3.0 , "The maximum link transmission power in logarithmic units (e.g. dBm)"); 084 private InputParameter mac_minTransmissionPower_logu = new InputParameter ("mac_minTransmissionPower_logu", 0.0 , "The minimum link transmission power in logarithmic units (e.g. dBm)"); 085 private InputParameter mac_simulation_maxNumberOfUpdateIntervals = new InputParameter ("mac_simulation_maxNumberOfUpdateIntervals", 2000.0 , "Maximum number of update intervals in average per agent" , 0 , false , Double.MAX_VALUE , true); 086 087 private InputParameter simulation_randomSeed = new InputParameter ("simulation_randomSeed", (long) 1 , "Seed of the random number generator"); 088 private InputParameter simulation_outFileNameRoot = new InputParameter ("simulation_outFileNameRoot", "crossLayerCongControlPowerTransmissionAsignmentDualDecomp" , "Root of the file name to be used in the output files. If blank, no output"); 089 090 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"); 091 private InputParameter cc_signaling_averageInterMessageTime = new InputParameter ("cc_signaling_averageInterMessageTime", 10.0 , "Average time between two signaling messages sent by an agent" , 0 , false , Double.MAX_VALUE , true); 092 private InputParameter cc_signaling_maxFluctuationInterMessageTime = new InputParameter ("cc_signaling_maxFluctuationInterMessageTime", 5.0 , "Max fluctuation in time between two signaling messages sent by an agent" , 0 , true , Double.MAX_VALUE , true); 093 private InputParameter cc_signaling_averageDelay = new InputParameter ("cc_signaling_averageDelay", 30.0 , "Average time between signaling message transmission by an agent and its reception by other or others" , 0 , true , Double.MAX_VALUE , true); 094 private InputParameter cc_signaling_maxFluctuationInDelay = new InputParameter ("cc_signaling_maxFluctuationInDelay", 15.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); 095 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); 096 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"); 097 private InputParameter cc_update_averageInterUpdateTime = new InputParameter ("cc_update_averageInterUpdateTime", 10.0 , "Average time between two updates of an agent" , 0 , false , Double.MAX_VALUE , true); 098 private InputParameter cc_update_maxFluctuationInterUpdateTime = new InputParameter ("cc_update_maxFluctuationInterUpdateTime", 5.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); 099 100 private InputParameter cc_gradient_gammaStep = new InputParameter ("cc_gradient_gammaStep", 0.001 , "Gamma step in the gradient algorithm" , 0 , false , Double.MAX_VALUE , true); 101 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); 102 103 private InputParameter cc_minHd = new InputParameter ("cc_minHd", 0.1 , "Minimum traffic assigned to each demand" , 0 , true , Double.MAX_VALUE , true); 104 private InputParameter cc_maxHd = new InputParameter ("cc_maxHd", 1.0E6 , "Maximum traffic assigned to each demand" , 0 , true , Double.MAX_VALUE , true); 105 private InputParameter cc_fairnessFactor = new InputParameter ("cc_fairnessFactor", 1.0 , "Fairness factor in utility function of congestion control" , 0 , true , Double.MAX_VALUE , true); 106 private InputParameter cc_initialLinkPrices = new InputParameter ("cc_initialLinkPrices", 1 , "Initial value of the link weights" , 0 , true , Double.MAX_VALUE , true); 107 private InputParameter cc_simulation_maxNumberOfUpdateIntervals = new InputParameter ("cc_simulation_maxNumberOfUpdateIntervals", 2000.0 , "Maximum number of update intervals in average per agent" , 0 , false , Double.MAX_VALUE , true); 108 109 private Map<String, String> algorithmParameters; 110 private Map<String, String> net2planParameters; 111 112 private DoubleMatrix1D cc_price_e; 113 private DoubleMatrix2D cc_mostUpdatedLinkPriceKnownByDemand_de; 114 115 private DoubleMatrix2D mac_g_nu_ee; 116 private DoubleMatrix1D mac_transmissionPower_logu_e; 117 private DoubleMatrix1D mac_previousTransmissionPower_logu_e; 118 private double mac_receptionThermalNoise_nu; 119 private DoubleMatrix2D mac_mostUpdatedMe2ValueKnownByLink1_e1e2; 120 121 private TimeTrace traceOf_pi_e; 122 private TimeTrace traceOf_u_e; 123 private TimeTrace traceOf_y_e; 124 private TimeTrace traceOf_p_e; 125 private TimeTrace traceOf_h_d; 126 private TimeTrace traceOf_objFunction; 127 128 private NetPlan currentNetPlan; 129 private NetPlan copyInitialNetPlan; 130 private int E,N,D; 131 132 @Override 133 public String getDescription() 134 { 135 return "This module implements a distributed dual-decomposition-based gradient algorithm, for a coordinated adjustment of the traffic to inject by each demand (congestion control), and the transmission power in each link of the underlying wireless network, to maximize the network utility enforcing a fair allocation of the resources."; 136 } 137 138 @Override 139 public List<Triple<String, String, String>> getParameters() 140 { 141 /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */ 142 return InputParameter.getInformationAllInputParameterFieldsOfObject(this); 143 } 144 145 @Override 146 public void initialize(NetPlan currentNp, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters) 147 { 148 /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */ 149 InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters); 150 151 this.currentNetPlan = currentNp; 152 this.copyInitialNetPlan = currentNp.copy(); 153 this.algorithmParameters = algorithmParameters; 154 this.net2planParameters = net2planParameters; 155 this.N = this.currentNetPlan.getNumberOfNodes(); 156 this.E = this.currentNetPlan.getNumberOfLinks(); 157 if (currentNp.getNumberOfLayers() != 1) throw new Net2PlanException ("This algorithm works in single layer networks"); 158 if (E == 0) throw new Net2PlanException ("The input design should have links"); 159 160 this.rng = new Random (simulation_randomSeed.getLong ()); 161 162 /* INITIALIZE INFORMATION COMMON TO MAC AND CONGESTION CONTROL */ 163 this.cc_price_e = DoubleFactory1D.dense.make (E , cc_initialLinkPrices.getDouble()); 164 165 /* Remove all routes, and create one with the shortest path in km for each demand */ 166 this.currentNetPlan.removeAllDemands(); 167 currentNetPlan.setRoutingTypeAllDemands(RoutingType.SOURCE_ROUTING); 168 for (Node n1 : this.currentNetPlan.getNodes()) 169 for (Node n2 : this.currentNetPlan.getNodes()) 170 if (n1 != n2) 171 this.currentNetPlan.addDemand(n1, n2, cc_minHd.getDouble(), RoutingType.SOURCE_ROUTING , null); 172 this.currentNetPlan.addRoutesFromCandidatePathList(currentNetPlan.computeUnicastCandidatePathList(currentNetPlan.getVectorLinkLengthInKm() , 1, -1, -1, -1, -1, -1, -1 , null)); 173 174 175 for (Route r : currentNetPlan.getRoutes ()) r.setCarriedTraffic(r.getDemand().getOfferedTraffic() , r.getDemand().getOfferedTraffic()); 176 this.D = this.currentNetPlan.getNumberOfDemands(); 177 178 /* Initialize the gains between links, normalizing them so that the maximum gain is one */ 179 this.mac_g_nu_ee = WirelessUtils.computeInterferenceMatrixNaturalUnits (currentNetPlan.getLinks () , mac_interferenceAttenuationFactor_nu.getDouble() , mac_pathLossExponent.getDouble()); 180 final double maxGainValue = mac_g_nu_ee.getMaxLocation() [0]; 181 mac_g_nu_ee.assign (DoubleFunctions.div(maxGainValue)); 182 183 /* Initialize the thermal noise at the receivers, to have a worse case ROT (rise over thermal) */ 184 double worseInterferenceReceivedAtMaxPower_nu = WirelessUtils.computeWorseReceiverInterferencePower_nu (mac_maxTransmissionPower_logu.getDouble() , mac_g_nu_ee); 185 186 /* Adjust the thermal noise in the receivers so that we have a given ROT */ 187 this.mac_receptionThermalNoise_nu = worseInterferenceReceivedAtMaxPower_nu / mac_worseRiseOverThermal_nu.getDouble(); 188 189 /* Initialize the transmission power variables */ 190 this.mac_transmissionPower_logu_e = DoubleFactory1D.dense.make (E , mac_minTransmissionPower_logu.getDouble()); 191 this.mac_previousTransmissionPower_logu_e = DoubleFactory1D.dense.make (E , mac_minTransmissionPower_logu.getDouble()); 192 193 /* Update the netplan object with the resulting capacities */ 194 for (Link e : currentNp.getLinks()) 195 e.setCapacity(Math.log(computeSINR_e (e))); 196 197 this.mac_mostUpdatedMe2ValueKnownByLink1_e1e2 = DoubleFactory2D.dense.make (E,E); 198 for (Link e1 : currentNp.getLinks()) 199 { 200 for (Link otherLink : currentNp.getLinks()) 201 if (e1 != otherLink) 202 mac_mostUpdatedMe2ValueKnownByLink1_e1e2.set(e1.getIndex () , otherLink.getIndex(), computeMeFactor_e (otherLink)); 203 } 204 205 /* Initially all nodes receive a "wake up to transmit" event, aligned at time zero or y asynchr => randomly chosen */ 206 for (Link e : currentNp.getLinks()) 207 { 208 final double signalingTime = (mac_signaling_isSynchronous.getBoolean())? mac_signaling_averageInterMessageTime.getDouble() : Math.max(0 , mac_signaling_averageInterMessageTime.getDouble() + mac_signaling_maxFluctuationInterMessageTime.getDouble() * (rng.nextDouble() - 0.5)); 209 this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , MAC_SIGNALING_WAKEUPTOSENDMESSAGE , e)); 210 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)); 211 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , MAC_UPDATE_WAKEUPTOUPDATE , e)); 212 } 213 214 /* INITIALIZATION CONGESTION CONTROL LAYER */ 215 216 /* Initialize the information each demand knows of the prices of all the links */ 217 this.cc_mostUpdatedLinkPriceKnownByDemand_de = DoubleFactory2D.dense.make (D,E,cc_initialLinkPrices.getDouble()); 218 219 /* Compute the traffic each demand injects, set it in net2plan, and tell routing layer there was an update in this */ 220 for (Demand d : currentNetPlan.getDemands()) 221 { 222 final double h_d = this.computeHdFromPrices(d); 223 d.setOfferedTraffic(h_d); 224 d.getRoutes ().iterator().next().setCarriedTraffic(h_d , h_d); 225 } 226 227 /* Initially all nodes receive a "wake up to transmit" event, aligned at time zero or y asynchr => randomly chosen */ 228 for (Link e : currentNetPlan.getLinks()) 229 { 230 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)); 231 this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_SIGNALING_WAKEUPTOSENDMESSAGE , e)); 232 } 233 for (Demand d : currentNetPlan.getDemands()) 234 { 235 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)); 236 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_UPDATE_WAKEUPTOUPDATE , d)); 237 } 238 239 /* INITIALIZE STATISTIC VARIABLES FOR BOTH LAYERS */ 240 this.traceOf_u_e = new TimeTrace (); 241 this.traceOf_y_e = new TimeTrace (); 242 this.traceOf_p_e = new TimeTrace (); 243 this.traceOf_pi_e = new TimeTrace (); 244 this.traceOf_h_d = new TimeTrace (); 245 this.traceOf_objFunction = new TimeTrace (); 246 247 this.traceOf_u_e.add(0.0, this.currentNetPlan.getVectorLinkCapacity()); 248 this.traceOf_y_e.add(0.0, this.currentNetPlan.getVectorLinkCarriedTraffic()); 249 this.traceOf_p_e.add(0.0, this.mac_transmissionPower_logu_e.copy ()); 250 this.traceOf_pi_e.add(0.0, this.cc_price_e.copy ()); 251 this.traceOf_h_d.add(0.0, this.currentNetPlan.getVectorDemandCarriedTraffic()); 252 this.traceOf_objFunction.add(0.0 , NetworkPerformanceMetrics.alphaUtility(this.currentNetPlan.getVectorDemandOfferedTraffic() , cc_fairnessFactor.getDouble())); 253 254 } 255 256 @Override 257 public void processEvent(NetPlan currentNetPlan, SimEvent event) 258 { 259 final double t = event.getEventTime(); 260 switch (event.getEventType()) 261 { 262 case MAC_SIGNALING_RECEIVEDMESSAGE: // A node broadcasts signaling info to its 1 hop neighbors 263 { 264 final Pair<Link,Pair<Link,Double>> signalInfo = (Pair<Link,Pair<Link,Double>>) event.getEventObject(); 265 final Link eMe = signalInfo.getFirst(); 266 final Link otherLink = signalInfo.getSecond().getFirst(); 267 final double otherLink_me = signalInfo.getSecond().getSecond(); 268 mac_mostUpdatedMe2ValueKnownByLink1_e1e2.set (eMe.getIndex () , otherLink.getIndex () , otherLink_me); 269 break; 270 } 271 272 case MAC_SIGNALING_WAKEUPTOSENDMESSAGE: // A node broadcasts signaling info to its 1 hop neighbors 273 { 274 final Link eMe = (Link) event.getEventObject(); 275 276 Pair<Link,Double> infoToSignal = Pair.of(eMe , this.computeMeFactor_e(eMe)); 277 if (rng.nextDouble() >= this.mac_signaling_signalingLossProbability.getDouble()) // the signaling may be lost => lost to all nodes 278 for (Link otherLink : currentNetPlan.getLinks ()) 279 if (otherLink != eMe) 280 { 281 final double signalingReceptionTime = t + Math.max(0 , mac_signaling_averageDelay.getDouble() + mac_signaling_maxFluctuationInDelay.getDouble() * (rng.nextDouble() - 0.5)); 282 this.scheduleEvent(new SimEvent (signalingReceptionTime , SimEvent.DestinationModule.EVENT_PROCESSOR , MAC_SIGNALING_RECEIVEDMESSAGE , Pair.of(otherLink , infoToSignal))); 283 } 284 285 /* Re-schedule when to wake up again */ 286 final double signalingTime = mac_signaling_isSynchronous.getBoolean()? t + mac_signaling_averageInterMessageTime.getDouble() : Math.max(t , t + mac_signaling_averageInterMessageTime.getDouble() + mac_signaling_maxFluctuationInterMessageTime.getDouble() * (rng.nextDouble() - 0.5)); 287 this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , MAC_SIGNALING_WAKEUPTOSENDMESSAGE , eMe)); 288 break; 289 } 290 291 case MAC_UPDATE_WAKEUPTOUPDATE: 292 { 293 final Link eMe = (Link) event.getEventObject(); 294 295 final double currentTransmissionPower_logu = this.mac_transmissionPower_logu_e.get(eMe.getIndex ()); 296 double gradientThisLink = computeGradient (eMe) + 2*mac_gradient_maxGradientAbsoluteNoise.getDouble()*(rng.nextDouble()-0.5); 297 double nextTransmissionPower_logu = currentTransmissionPower_logu + this.mac_gradient_gammaStep.getDouble() * gradientThisLink; 298 299 /* heavy ball */ 300 nextTransmissionPower_logu += this.mac_gradient_heavyBallBetaParameter.getDouble() * (currentTransmissionPower_logu - mac_previousTransmissionPower_logu_e.get(eMe.getIndex ())); 301 /* projection */ 302 nextTransmissionPower_logu = GradientProjectionUtils.euclideanProjection_boxLike(nextTransmissionPower_logu, this.mac_minTransmissionPower_logu.getDouble(), this.mac_maxTransmissionPower_logu.getDouble()); 303 304 if (mac_gradient_maxGradientCoordinateChange.getDouble() > 0) 305 nextTransmissionPower_logu = GradientProjectionUtils.scaleDown_maxAbsoluteCoordinateChange (currentTransmissionPower_logu , nextTransmissionPower_logu , mac_gradient_maxGradientCoordinateChange.getDouble()); 306 307 this.mac_previousTransmissionPower_logu_e.set(eMe.getIndex (), this.mac_transmissionPower_logu_e.get(eMe.getIndex ())); 308 this.mac_transmissionPower_logu_e.set(eMe.getIndex (), nextTransmissionPower_logu); 309 310 /* Send event next recomputing time */ 311 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)); 312 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , MAC_UPDATE_WAKEUPTOUPDATE, eMe)); 313 314 /* Update in currentNetPlan the capacity values */ 315 for (Link e : this.currentNetPlan.getLinks()) 316 e.setCapacity(Math.log(computeSINR_e (e))); 317 318 this.traceOf_u_e.add(t, this.currentNetPlan.getVectorLinkCapacity()); 319 this.traceOf_y_e.add(t, this.currentNetPlan.getVectorLinkCarriedTraffic()); 320 this.traceOf_p_e.add(t, this.mac_transmissionPower_logu_e.copy ()); 321 this.traceOf_pi_e.add(t, this.cc_price_e.copy ()); 322 this.traceOf_h_d.add(t, this.currentNetPlan.getVectorDemandCarriedTraffic()); 323 this.traceOf_objFunction.add(t , NetworkPerformanceMetrics.alphaUtility(this.currentNetPlan.getVectorDemandOfferedTraffic() , cc_fairnessFactor.getDouble())); 324 325 if (t > this.mac_simulation_maxNumberOfUpdateIntervals.getDouble() * this.mac_update_averageInterUpdateTime.getDouble()) { this.endSimulation (); } 326 break; 327 } 328 329 case CC_SIGNALING_RECEIVEDMESSAGE: // A node receives from an out neighbor the q_nt for any destination 330 { 331 final Pair<Demand,Pair<Link,Double>> signalInfo = (Pair<Demand,Pair<Link,Double>>) event.getEventObject(); 332 final Demand d = signalInfo.getFirst(); 333 final Pair<Link,Double> receivedInfo_price_e = signalInfo.getSecond(); 334 this.cc_mostUpdatedLinkPriceKnownByDemand_de.set(d.getIndex() , receivedInfo_price_e.getFirst().getIndex () ,receivedInfo_price_e.getSecond()); 335 break; 336 } 337 338 case CC_SIGNALING_WAKEUPTOSENDMESSAGE: // A node broadcasts signaling info to its 1 hop neighbors 339 { 340 final Link eMe = (Link) event.getEventObject(); 341 342 /* Update the new price with the gradient approach */ 343 final double u_e = eMe.getCapacity(); 344 final double y_e = eMe.getCarriedTraffic(); 345 final double old_pie = this.cc_price_e.get(eMe.getIndex()); 346 final double new_pie = Math.max(0, old_pie - this.cc_gradient_gammaStep.getDouble() * (u_e - y_e) + 2*cc_gradient_maxGradientAbsoluteNoise.getDouble()*(rng.nextDouble()-0.5)); 347 this.cc_price_e.set(eMe.getIndex(), new_pie); 348 349 /* Create the info I will signal */ 350 Pair<Link,Double> infoToSignal = Pair.of(eMe , new_pie); 351 352 /* Send the events of the signaling information messages to all the nodes */ 353 for (Route route : eMe.getTraversingRoutes()) 354 { 355 if (rng.nextDouble() < this.cc_signaling_signalingLossProbability.getDouble()) continue; // the signaling may be lost => lost to all demands 356 final Demand d = route.getDemand(); 357 final double signalingReceptionTime = t + Math.max(0 , cc_signaling_averageDelay.getDouble() + cc_signaling_maxFluctuationInDelay.getDouble() * (rng.nextDouble() - 0.5)); 358 this.scheduleEvent(new SimEvent (signalingReceptionTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_SIGNALING_RECEIVEDMESSAGE , Pair.of(d , infoToSignal))); 359 } 360 361 /* Re-schedule when to wake up again */ 362 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)); 363 this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_SIGNALING_WAKEUPTOSENDMESSAGE , eMe)); 364 break; 365 } 366 367 case CC_UPDATE_WAKEUPTOUPDATE: // a node updates its p_n, p_e values, using most updated info available 368 { 369 final Demand dMe = (Demand) event.getEventObject(); 370 371 /* compute the new h_d and apply it */ 372 final double new_hd = computeHdFromPrices (dMe); 373 dMe.setOfferedTraffic(new_hd); 374 dMe.getRoutes ().iterator().next().setCarriedTraffic(new_hd , new_hd); 375 376 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)); 377 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , CC_UPDATE_WAKEUPTOUPDATE, dMe)); 378 379 this.traceOf_objFunction.add(t, NetworkPerformanceMetrics.alphaUtility(this.currentNetPlan.getVectorDemandOfferedTraffic() , cc_fairnessFactor.getDouble())); 380 381 if (t > this.cc_simulation_maxNumberOfUpdateIntervals.getDouble() * this.cc_update_averageInterUpdateTime.getDouble()) { this.endSimulation (); } 382 break; 383 } 384 385 386 default: throw new RuntimeException ("Unexpected received event"); 387 } 388 389 390 } 391 392 public String finish (StringBuilder st , double simTime) 393 { 394 if (simulation_outFileNameRoot.getString().equals("")) return null; 395 this.traceOf_objFunction.printToFile(new File (simulation_outFileNameRoot.getString() + "_objFunc.txt")); 396 this.traceOf_u_e.printToFile(new File (simulation_outFileNameRoot.getString() + "_ue.txt")); 397 this.traceOf_y_e.printToFile(new File (simulation_outFileNameRoot.getString() + "_ye.txt")); 398 this.traceOf_p_e.printToFile(new File (simulation_outFileNameRoot.getString() + "_pe.txt")); 399 this.traceOf_pi_e.printToFile(new File (simulation_outFileNameRoot.getString() + "_pie.txt")); 400 this.traceOf_h_d.printToFile(new File (simulation_outFileNameRoot.getString() + "_hd.txt")); 401 402 Map<String,String> param = new HashMap<String,String> (algorithmParameters); 403 param.put("solverName", "ipopt"); 404 param.put("solverLibraryName", ""); 405 param.put("maxSolverTimeInSeconds", "-1"); 406 new Offline_cba_wirelessCongControlTransmissionPowerAssignment ().executeAlgorithm(copyInitialNetPlan , param , this.net2planParameters); 407 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_objFunc.txt") , NetworkPerformanceMetrics.alphaUtility(copyInitialNetPlan.getVectorDemandOfferedTraffic() , cc_fairnessFactor.getDouble())); 408 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_ue.txt") , copyInitialNetPlan.getVectorLinkCapacity()); 409 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_ye.txt") , copyInitialNetPlan.getVectorLinkCarriedTraffic()); 410 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_hd.txt") , copyInitialNetPlan.getVectorDemandCarriedTraffic()); 411 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_pe.txt") , copyInitialNetPlan.getVectorAttributeValues(copyInitialNetPlan.getLinks () , "p_e")); 412 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_pie.txt") , copyInitialNetPlan.getVectorAttributeValues(copyInitialNetPlan.getLinks () , "pi_e")); 413 return null; 414 } 415 416 417 private double computeGradient (Link thisLink) 418 { 419 final DoubleMatrix1D infoIKnow_me = mac_mostUpdatedMe2ValueKnownByLink1_e1e2.viewRow (thisLink.getIndex ()); 420 421 double gradient = cc_price_e.get(thisLink.getIndex ()); 422 double accumFactor = 0; 423 for (Link epp : this.currentNetPlan.getLinks()) 424 if (epp != thisLink) 425 accumFactor += this.mac_g_nu_ee.get(thisLink.getIndex (),epp.getIndex ()) * infoIKnow_me.get(epp.getIndex ()); 426 accumFactor *= Math.exp(this.mac_transmissionPower_logu_e.get(thisLink.getIndex ())); 427 gradient -= accumFactor; 428 return gradient; 429 } 430 431 private double computeMeFactor_e (Link e) 432 { 433 final double snr_e = Math.exp(e.getCapacity()); 434 final double pi_e = this.cc_price_e.get(e.getIndex ()); 435 final double g_ee = this.mac_g_nu_ee.get(e.getIndex (),e.getIndex ()); 436 return pi_e * snr_e / (Math.exp(this.mac_transmissionPower_logu_e.get(e.getIndex ())) * g_ee); 437 } 438 439 private double computeSINR_e (Link e) 440 { 441 final double receivedPower_nu = Math.exp(this.mac_transmissionPower_logu_e.get(e.getIndex())) * this.mac_g_nu_ee.get(e.getIndex (),e.getIndex ()); 442 double interferencePower_nu = this.mac_receptionThermalNoise_nu; 443 for (Link eInt : this.currentNetPlan.getLinks ()) 444 if (eInt != e) interferencePower_nu += Math.exp(this.mac_transmissionPower_logu_e.get(eInt.getIndex())) * this.mac_g_nu_ee.get(eInt.getIndex (),e.getIndex ()); 445 return receivedPower_nu / interferencePower_nu; 446 } 447 448 private double computeHdFromPrices (Demand d) 449 { 450 DoubleMatrix1D infoIKnow_price_e = this.cc_mostUpdatedLinkPriceKnownByDemand_de.viewRow(d.getIndex()); 451 452 /* compute the demand price as weighted sum in the routes of route prices */ 453 double demandWeightedSumLinkPrices = 0; 454 double demandCarriedTraffic = 0; 455 for (Route r : d.getRoutes ()) 456 { 457 final double h_r = r.getCarriedTraffic(); 458 demandCarriedTraffic += h_r; 459 for (Link e : r.getSeqLinks()) 460 demandWeightedSumLinkPrices += h_r * infoIKnow_price_e.get(e.getIndex()); 461 } 462 //if (Math.abs(demandCarriedTraffic - this.currentNetPlan.getDemandCarriedTraffic(dIdMe)) > 1E-3) throw new RuntimeException ("Not all the traffic is carried"); 463 demandWeightedSumLinkPrices /= demandCarriedTraffic; 464 465 /* compute the new h_d */ 466 final double new_hd = Math.max(this.cc_minHd.getDouble() , Math.min(this.cc_maxHd.getDouble(), Math.pow(demandWeightedSumLinkPrices, -1/this.cc_fairnessFactor.getDouble()))); 467 468 return new_hd; 469 } 470 471}