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.net2plan.examples.ocnbook.offline.Offline_ca_wirelessPersistenceProbability; 019import com.net2plan.interfaces.networkDesign.Link; 020import com.net2plan.interfaces.networkDesign.Net2PlanException; 021import com.net2plan.interfaces.networkDesign.NetPlan; 022import com.net2plan.interfaces.networkDesign.Node; 023import com.net2plan.interfaces.simulation.IEventProcessor; 024import com.net2plan.interfaces.simulation.SimEvent; 025import com.net2plan.libraries.NetworkPerformanceMetrics; 026import com.net2plan.libraries.WirelessUtils; 027import com.net2plan.utils.GradientProjectionUtils; 028import com.net2plan.utils.InputParameter; 029import com.net2plan.utils.TimeTrace; 030import com.net2plan.utils.Triple; 031 032import java.io.File; 033import java.io.FileOutputStream; 034import java.io.PrintStream; 035import java.util.*; 036import java.util.Map.Entry; 037 038/** 039 * This module implements a distributed primal-gradient based algorithm for adjusting the link persistence probabilities in a wireless network with a ALOHA-type random-access based MAC, to maximize the network utility enforcing a fair allocation of the resources. 040 * 041 * Ths event processor is adapted to permit observing the algorithm performances under user-defined conditions, 042 * including asynchronous distributed executions, where signaling can be affected by losses and/or delays, and/or measurement errors. 043 * The time evolution of different metrics can be stored in output files, for later processing. 044 * As an example, see the <a href="../../../../../../graphGeneratorFiles/fig_sec9_5_persitenceProbabilityAdjustmentPrimal.m">{@code fig_sec9_5_persitenceProbabilityAdjustmentPrimal.m}</a> MATLAB file used for generating the graph/s of the case study in the 045 * <a href="http://eu.wiley.com/WileyCDA/WileyTitle/productCd-1119013356.html">book</a> using this algorithm. 046 * 047 * To simulate a network with this module, use the {@code Online_evGen_doNothing} generator. 048 * 049 * @net2plan.keywords Random-access MAC, Wireless, Distributed algorithm, Primal gradient algorithm, Capacity assignment (CA) 050 * @net2plan.ocnbooksections Section 9.5 051 * @net2plan.inputParameters 052 * @author Pablo Pavon-Marino 053 */ 054@SuppressWarnings("unchecked") 055public class Online_evProc_persistenceProbAdjustmentPrimal extends IEventProcessor 056{ 057 private static PrintStream getNulFile () { try { return new PrintStream (new FileOutputStream ("NUL") , false); } catch (Exception e) {e.printStackTrace(); throw new RuntimeException ("Not NUL file"); } } 058 private PrintStream log = getNulFile (); //System.err;//new PrintStream (new FileOutputStream ("NUL") , true); 059 060 private Random rng; 061 062 private static final int SIGNALING_WAKEUPTOSENDMESSAGE = 300; 063 private static final int SIGNALING_RECEIVEDMESSAGE = 301; 064 private static final int UPDATE_WAKEUPTOUPDATE = 302; 065 066 private InputParameter signaling_isSynchronous = new InputParameter ("signaling_isSynchronous", false , "true if all the distributed agents involved wake up synchronously to send the signaling messages"); 067 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); 068 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); 069 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); 070 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); 071 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); 072 private InputParameter update_isSynchronous = new InputParameter ("update_isSynchronous", false , "true if all the distributed agents involved wake up synchronousely to update its state"); 073 private InputParameter update_averageInterUpdateTime = new InputParameter ("update_averageInterUpdateTime", 1.0 , "Average time between two updates of an agent" , 0 , false , Double.MAX_VALUE , true); 074 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); 075 076 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); 077 private InputParameter gradient_gammaStep = new InputParameter ("gradient_gammaStep", 0.00001 , "Gamma step in the gradient algorithm" , 0 , false , Double.MAX_VALUE , true); 078 private InputParameter gradient_maxGradientCoordinateChange = new InputParameter ("gradient_maxGradientCoordinateChange", 0.1 , "Maximum change in an iteration of a gradient coordinate" , 0 , false , Double.MAX_VALUE , true); 079 private InputParameter simulation_randomSeed = new InputParameter ("simulation_randomSeed", (long) 1 , "Seed of the random number generator"); 080 private InputParameter simulation_outFileNameRoot = new InputParameter ("simulation_outFileNameRoot", "persistenceProbAdjustmentPrimal" , "Root of the file name to be used in the output files. If blank, no output"); 081 private InputParameter simulation_maxNumberOfUpdateIntervals = new InputParameter ("simulation_maxNumberOfUpdateIntervals", 100.0 , "Maximum number of update intervals in average per agent" , 0 , false , Double.MAX_VALUE , true); 082 083 private InputParameter control_maxUeRelativeNoise = new InputParameter ("control_maxUeRelativeNoise", 0 , "Maximum relative fluctuation in link capacity estimation, that reflects into gradient noise" , 0 , true , Double.MAX_VALUE , true); 084 private InputParameter control_simultaneousTxAndRxPossible = new InputParameter ("control_simultaneousTxAndRxPossible", false , "If false, a node cannot transmit and receive simultaneously. If true, it can. This affects the interference map calculation"); 085 private InputParameter control_linkNominalCapacity = new InputParameter ("control_linkNominalCapacity", 1.0 , "Nominal rate of the links. If non positive, nominal rates are rates of the initial design"); 086 private InputParameter control_minLinkPersistenceProb = new InputParameter ("control_minLinkPersistenceProb", 0.03 , "Minimum persistence probability of a link" , 0 , true , 1 , true); 087 private InputParameter control_maxNodePersistenceProb = new InputParameter ("control_maxNodePersistenceProb", 0.99 , "Maximum persistence probability of a node (summing the persistence probabilities of its outoingl links)" , 0 , true , 1 , true); 088 private InputParameter control_fairnessFactor = new InputParameter ("control_fairnessFactor", 2.0 , "Fairness factor in utility function of link capacities (>= 1 to be a convex program)" , 0 , true , Double.MAX_VALUE , true); 089 090 private NetPlan currentNetPlan , copyInitialNetPlan; 091 private int E , N; 092 093 private DoubleMatrix1D control_linkNominalCapacities; 094 private DoubleMatrix1D control_p_e; 095 private DoubleMatrix1D control_q_n; 096 private DoubleMatrix2D control_mostUpdatedQn2ValueNodeKnowByNode1_n1n2; // each node is assigned a map with known p_n values of one hop neighbors and two hop neighbors 097 private DoubleMatrix2D control_mostUpdatedUeValueNodeKnowByNode_ne; // each node is assigned a map with known s_e values of one hop neighbors and two hop neighbors 098 099 private Map<Link,Set<Node>> control_nodesInterfTo_e; 100 private Map<Node,Set<Link>> control_linksInterfFrom_n; 101 private Map<Node,int []> control_outLinksIndexes; 102 103 private TimeTrace stat_traceOf_p_e; 104 private TimeTrace stat_traceOf_u_e; 105 private TimeTrace stat_traceOf_objFunction; 106 107 108 @Override 109 public String getDescription() 110 { 111 return "This module implements a distributed primal-gradient based algorithm for adjusting the link persistence probabilities in a wireless network with a ALOHA-type random-access based MAC, to maximize the network utility enforcing a fair allocation of the resources."; 112 } 113 114 @Override 115 public List<Triple<String, String, String>> getParameters() 116 { 117 /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */ 118 return InputParameter.getInformationAllInputParameterFieldsOfObject(this); 119 } 120 121 @Override 122 public void initialize(NetPlan currentNetPlan, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters) 123 { 124 /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */ 125 InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters); 126 127 this.currentNetPlan = currentNetPlan; 128 this.copyInitialNetPlan = currentNetPlan.copy (); 129 if (currentNetPlan.getNumberOfLayers() != 1) throw new Net2PlanException ("This algorithm works in single layer networks"); 130 this.N = currentNetPlan.getNumberOfNodes (); 131 this.E = currentNetPlan.getNumberOfLinks (); 132 133 if (control_linkNominalCapacity.getDouble() > 0) currentNetPlan.setVectorLinkCapacity(DoubleFactory1D.dense.make (E , control_linkNominalCapacity.getDouble())); 134 control_linkNominalCapacities = currentNetPlan.getVectorLinkCapacity(); 135 136 this.rng = new Random (simulation_randomSeed.getLong()); 137 138 /* Check all nodes have output links */ 139 for (Node n : currentNetPlan.getNodes()) if (n.getOutgoingLinks().isEmpty()) throw new Net2PlanException ("All nodes should have output links"); 140 for (Node n : currentNetPlan.getNodes()) if (control_minLinkPersistenceProb.getDouble() * n.getOutgoingLinks().size () > control_maxNodePersistenceProb.getDouble()) throw new Net2PlanException("Minimum persistence per link is too high or maximum persistence per node too small: the problem has no feasible solutions"); 141 142 Triple<DoubleMatrix2D, Map<Link,Set<Node>> , Map<Node,Set<Link>>> interfMap = WirelessUtils.computeInterferenceMap(currentNetPlan.getNodes () , currentNetPlan.getLinks () , control_simultaneousTxAndRxPossible.getBoolean()); 143 this.control_nodesInterfTo_e = interfMap.getSecond (); 144 this.control_linksInterfFrom_n = interfMap.getThird(); 145 146 this.control_outLinksIndexes = new HashMap<Node,int []> (); 147 for (Node n : currentNetPlan.getNodes ()) 148 { 149 int [] indexes = new int [n.getOutgoingLinks().size ()]; 150 int counter = 0; for (Link e : n.getOutgoingLinks()) indexes [counter ++] = e.getIndex (); 151 control_outLinksIndexes.put (n , indexes); 152 } 153 154 155 /* Initialize the persistence probabilities: p_e to the minimum */ 156 this.control_q_n = DoubleFactory1D.dense.make (N); 157 this.control_p_e = DoubleFactory1D.dense.make (E , control_minLinkPersistenceProb.getDouble()); 158 for (Node n : currentNetPlan.getNodes ()) 159 this.control_q_n.set(n.getIndex () , control_minLinkPersistenceProb.getDouble() * n.getOutgoingLinks().size ()); 160 control_mostUpdatedUeValueNodeKnowByNode_ne = DoubleFactory2D.dense.make (N,E); 161 control_mostUpdatedQn2ValueNodeKnowByNode1_n1n2 = DoubleFactory2D.dense.make (N,N); 162 163 /* Initialize the most updated signaled values known of q_n: one and two hop neighbors */ 164 for (Node n1 : currentNetPlan.getNodes()) 165 { 166 for (Node nNeighborOneHop : n1.getOutNeighbors()) 167 { 168 control_mostUpdatedQn2ValueNodeKnowByNode1_n1n2.set (n1.getIndex () , nNeighborOneHop.getIndex () , control_q_n.get (nNeighborOneHop.getIndex ())); 169 for (Node nNeighborTwoHops : nNeighborOneHop.getOutNeighbors()) 170 if (nNeighborTwoHops != n1) 171 control_mostUpdatedQn2ValueNodeKnowByNode1_n1n2.set (n1.getIndex () , nNeighborTwoHops.getIndex () , control_q_n.get (nNeighborTwoHops.getIndex ())); 172 } 173 } 174 175 /* Set link capacities to its actual values */ 176 for (Link e : this.currentNetPlan.getLinks ()) 177 { 178 /* compute link capacity */ 179 double u_e = this.control_linkNominalCapacities.get(e.getIndex ()) * this.control_p_e.get(e.getIndex ()); 180 for (Node n : this.control_nodesInterfTo_e.get(e)) 181 u_e *= Math.max(0 , 1 - this.control_q_n.get(n.getIndex ())); 182 e.setAttribute("p_e" , "" + control_p_e.get(e.getIndex ())); 183 e.setCapacity(u_e); 184 } 185 186 /* Set the most updated values known in each node, from the true u_e values */ 187 DoubleMatrix1D noisyUeEstimation_e = DoubleFactory1D.dense.make (E); 188 for (Link e : currentNetPlan.getLinks()) 189 noisyUeEstimation_e.set(e.getIndex (), e.getCapacity() * ( 1 + control_maxUeRelativeNoise.getDouble()*2*(rng.nextDouble()-0.5))); 190 for (Node n : currentNetPlan.getNodes()) 191 { 192 for (Link e : this.control_linksInterfFrom_n.get(n)) control_mostUpdatedUeValueNodeKnowByNode_ne.set (n.getIndex () , e.getIndex () , noisyUeEstimation_e.get(e.getIndex ())); 193 for (Link e : n.getOutgoingLinks()) control_mostUpdatedUeValueNodeKnowByNode_ne.set (n.getIndex () , e.getIndex () , noisyUeEstimation_e.get(e.getIndex ())); 194 for (Link e : n.getIncomingLinks()) control_mostUpdatedUeValueNodeKnowByNode_ne.set (n.getIndex () , e.getIndex () , noisyUeEstimation_e.get(e.getIndex ())); 195 } 196 197 /* Initially all nodes receive a "wake up to transmit" event, aligned at time zero or y asynchr => randomly chosen */ 198 for (Node n : currentNetPlan.getNodes()) 199 { 200 final double signalingTime = (signaling_isSynchronous.getBoolean())? signaling_averageInterMessageTime.getDouble() : Math.max(0 , signaling_averageInterMessageTime.getDouble() + signaling_maxFluctuationInterMessageTime.getDouble() * (rng.nextDouble() - 0.5)); 201 this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , SIGNALING_WAKEUPTOSENDMESSAGE , n)); 202 final double updateTime = (update_isSynchronous.getBoolean())? update_averageInterUpdateTime.getDouble() : Math.max(0 , update_averageInterUpdateTime.getDouble() + update_maxFluctuationInterUpdateTime.getDouble() * (rng.nextDouble() - 0.5)); 203 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , UPDATE_WAKEUPTOUPDATE , n)); 204 } 205 206 /* Intialize the traces */ 207 this.stat_traceOf_p_e = new TimeTrace (); 208 this.stat_traceOf_u_e = new TimeTrace (); 209 this.stat_traceOf_objFunction = new TimeTrace (); 210 this.stat_traceOf_p_e.add(0.0, control_p_e.copy()); 211 this.stat_traceOf_u_e.add(0.0, currentNetPlan.getVectorLinkCapacity()); 212 this.stat_traceOf_objFunction.add(0.0 , NetworkPerformanceMetrics.alphaUtility(currentNetPlan.getVectorLinkCapacity() , control_fairnessFactor.getDouble())); 213 } 214 215 @Override 216 public void processEvent(NetPlan currentNetPlan, SimEvent event) 217 { 218 final double t = event.getEventTime(); 219 switch (event.getEventType()) 220 { 221 case SIGNALING_RECEIVEDMESSAGE: // A node broadcasts signaling info to its 1 hop neighbors 222 { 223 final Triple<Node,Map<Node,Double>,Map<Link,Double>> signalInfo = (Triple<Node,Map<Node,Double>,Map<Link,Double>>) event.getEventObject(); 224 final Node nMe = signalInfo.getFirst(); 225 final Map<Node,Double> receivedInfo_qn = signalInfo.getSecond(); 226 final Map<Link,Double> receivedInfo_ue = signalInfo.getThird(); 227 /* Take the p_n values signaled except my own p_n (I prefer my own estimation of q_n, than something estimated by others) */ 228 for (Entry<Node,Double> nodeInfo : receivedInfo_qn.entrySet()) 229 if (nodeInfo.getKey() != nMe) control_mostUpdatedQn2ValueNodeKnowByNode1_n1n2.set (nMe.getIndex () , nodeInfo.getKey().getIndex () , nodeInfo.getValue()); 230 /* Take the u_e values signaled */ 231 for (Entry<Link,Double> linkInfo : receivedInfo_ue.entrySet()) 232 control_mostUpdatedUeValueNodeKnowByNode_ne.set (nMe.getIndex () , linkInfo.getKey().getIndex () , linkInfo.getValue()); 233 break; 234 } 235 236 case SIGNALING_WAKEUPTOSENDMESSAGE: // A node broadcasts signaling info to its 1 hop neighbors 237 { 238 final Node nMe = (Node) event.getEventObject(); 239 final DoubleMatrix1D infoIKnow_qn = control_mostUpdatedQn2ValueNodeKnowByNode1_n1n2.viewRow (nMe.getIndex ()); 240 infoIKnow_qn.set (nMe.getIndex () , control_q_n.get (nMe.getIndex ())); 241 242 /* Create the info I will signal */ 243 Map<Node,Double> infoToSignal_qn = new HashMap<Node,Double> (); 244 infoToSignal_qn.put(nMe, this.control_q_n.get (nMe.getIndex ())); 245 for (Node inNeighbor : nMe.getInNeighbors()) 246 infoToSignal_qn.put(inNeighbor, infoIKnow_qn.get(inNeighbor.getIndex ())); 247 Map<Link,Double> infoToSignal_ue = new HashMap<Link,Double> (); 248 for (Link inLink : nMe.getIncomingLinks()) 249 infoToSignal_ue.put(inLink, inLink.getCapacity() * ( 1 + 2*this.control_maxUeRelativeNoise.getDouble()*(rng.nextDouble() - 0.5) ) ); 250 251 /* Send the events of the signaling information messages to the neighbors */ 252 if (rng.nextDouble() >= this.signaling_signalingLossProbability.getDouble()) // the signaling may be lost => lost to all nodes 253 for (Node outNeighbor : nMe.getOutNeighbors()) 254 { 255 final double signalingReceptionTime = t + Math.max(0 , signaling_averageDelay.getDouble() + signaling_maxFluctuationInDelay.getDouble() * (rng.nextDouble() - 0.5)); 256 this.scheduleEvent(new SimEvent (signalingReceptionTime , SimEvent.DestinationModule.EVENT_PROCESSOR , SIGNALING_RECEIVEDMESSAGE , Triple.of(outNeighbor, infoToSignal_qn , infoToSignal_ue))); 257 } 258 259 /* Re-schedule when to wake up again */ 260 final double signalingTime = signaling_isSynchronous.getBoolean()? t + signaling_averageInterMessageTime.getDouble() : Math.max(t , t + signaling_averageInterMessageTime.getDouble() + signaling_maxFluctuationInterMessageTime.getDouble() * (rng.nextDouble() - 0.5)); 261 this.scheduleEvent(new SimEvent (signalingTime , SimEvent.DestinationModule.EVENT_PROCESSOR , SIGNALING_WAKEUPTOSENDMESSAGE , nMe)); 262 break; 263 } 264 265 case UPDATE_WAKEUPTOUPDATE: // a node updates its p_n, p_e values, using most updated info available 266 { 267 final Node nMe = (Node) event.getEventObject(); 268 269 final DoubleMatrix1D infoIKnow_qn = control_mostUpdatedQn2ValueNodeKnowByNode1_n1n2.viewRow (nMe.getIndex ()); 270 infoIKnow_qn.set (nMe.getIndex () , control_q_n.get (nMe.getIndex ())); 271 DoubleMatrix1D infoIKnow_ue = control_mostUpdatedUeValueNodeKnowByNode_ne.viewRow (nMe.getIndex ()); 272 DoubleMatrix1D newMacValues_e = DoubleFactory1D.dense.make (E); 273 for (int eIndex : control_outLinksIndexes.get (nMe)) 274 { 275 final Link e = currentNetPlan.getLink (eIndex); 276 final double current_pe = this.control_p_e.get(eIndex); 277 final double gradientThisLink = computeGradient (e , this.control_fairnessFactor.getDouble() , current_pe , infoIKnow_qn , infoIKnow_ue) + 2*gradient_maxGradientAbsoluteNoise.getDouble()*(rng.nextDouble()-0.5); 278 newMacValues_e.set(eIndex, current_pe + gradient_gammaStep.getDouble() * gradientThisLink); 279 } 280 GradientProjectionUtils.euclideanProjection_sumInequality(newMacValues_e , control_outLinksIndexes.get (nMe) , control_minLinkPersistenceProb.getDouble() , control_maxNodePersistenceProb.getDouble()); 281 282 if (gradient_maxGradientCoordinateChange.getDouble() > 0) 283 GradientProjectionUtils.scaleDown_maxAbsoluteCoordinateChange (control_p_e , newMacValues_e , control_outLinksIndexes.get (nMe) , gradient_maxGradientCoordinateChange.getDouble()); 284 for (int eIndex : control_outLinksIndexes.get (nMe)) this.control_p_e.set (eIndex , newMacValues_e.get (eIndex)); 285 286 /* update p_n value applied by me */ 287 double thisNode_pn = 0; for (Link e : nMe.getOutgoingLinks()) thisNode_pn += this.control_p_e.get(e.getIndex ()); 288 if ((thisNode_pn <= 0) || (thisNode_pn > 1 + 1E-3)) throw new RuntimeException ("Bad"); 289 this.control_q_n.set(nMe.getIndex (), thisNode_pn); 290 291 /* Send event next recomputing time */ 292 final double updateTime = update_isSynchronous.getBoolean()? t + update_averageInterUpdateTime.getDouble() : Math.max(t , t + update_averageInterUpdateTime.getDouble() + update_maxFluctuationInterUpdateTime.getDouble() * (rng.nextDouble() - 0.5)); 293 this.scheduleEvent(new SimEvent (updateTime , SimEvent.DestinationModule.EVENT_PROCESSOR , UPDATE_WAKEUPTOUPDATE, nMe)); 294 295 /* Set link capacities to its actual values, update n2p object */ 296 for (Link e : currentNetPlan.getLinks ()) 297 { 298 /* compute link capacity */ 299 double u_e = this.control_linkNominalCapacities.get(e.getIndex ()) * this.control_p_e.get(e.getIndex ()); 300 for (Node n : this.control_nodesInterfTo_e.get(e)) 301 u_e *= Math.max(0 , 1 - this.control_q_n.get(n.getIndex ())); 302 e.setAttribute("p_e" , "" + control_p_e.get(e.getIndex ())); 303 e.setCapacity(u_e); 304 } 305 for (Node n : currentNetPlan.getNodes ()) { n.setAttribute("q_n" , "" + control_q_n.get(n.getIndex ())); } 306 307 checkCapacitiesNetPlan (); 308 309 this.stat_traceOf_p_e.add(t, control_p_e.copy ()); 310 this.stat_traceOf_u_e.add(t, this.currentNetPlan.getVectorLinkCapacity()); 311 this.stat_traceOf_objFunction.add(t , NetworkPerformanceMetrics.alphaUtility(currentNetPlan.getVectorLinkCapacity() , control_fairnessFactor.getDouble())); 312 313 if (t > this.simulation_maxNumberOfUpdateIntervals.getDouble() * this.update_averageInterUpdateTime.getDouble()) { this.endSimulation (); } 314 315 break; 316 } 317 318 319 default: throw new RuntimeException ("Unexpected received event"); 320 } 321 322 323 } 324 325 public String finish (StringBuilder st , double simTime) 326 { 327 if (simulation_outFileNameRoot.getString().equals("")) return null; 328 stat_traceOf_u_e.printToFile(new File (simulation_outFileNameRoot.getString() + "_ue.txt")); 329 stat_traceOf_objFunction.printToFile(new File (simulation_outFileNameRoot.getString() + "_objFunc.txt")); 330 stat_traceOf_p_e.printToFile(new File (simulation_outFileNameRoot.getString() + "_pe.txt")); 331 /* compute optimum solution */ 332 Map<String,String> param = new HashMap<String,String> (); 333 param.put("alphaFairnessFactor", "" + this.control_fairnessFactor.getDouble()); 334 param.put("minLinkPersistenceProb", "" + this.control_minLinkPersistenceProb.getDouble()); 335 param.put("maxNodePersistenceProb", "" + this.control_maxNodePersistenceProb.getDouble()); 336 param.put("linkNominalCapacity", "" + this.control_linkNominalCapacity.getDouble()); 337 param.put("simultaneousTxAndRxPossible", "" + this.control_simultaneousTxAndRxPossible.getBoolean()); 338 param.put("solverName", "ipopt"); 339 param.put("solverLibraryName", ""); 340 param.put("maxSolverTimeInSeconds", "-1"); 341// private InputParameter solverName = new InputParameter ("solverName", "#select# ipopt", "The solver name to be used by JOM. "); 342// private InputParameter solverLibraryName = new InputParameter ("solverLibraryName", Configuration.getOption("glpkSolverLibraryName") , "The solver library full or relative path, to be used by JOM. Leave blank to use JOM default."); 343// private InputParameter maxSolverTimeInSeconds = new InputParameter ("maxSolverTimeInSeconds", (double) -1 , "Maximum time granted to the solver to solve the problem. If this time expires, the solver returns the best solution found so far (if a feasible solution is found)"); 344 new Offline_ca_wirelessPersistenceProbability ().executeAlgorithm(copyInitialNetPlan , param , null); 345 final double optimumNetUtilityJOM = NetworkPerformanceMetrics.alphaUtility(copyInitialNetPlan.getVectorLinkCapacity() , control_fairnessFactor.getDouble()); 346 DoubleMatrix1D optimum_ue = copyInitialNetPlan.getVectorLinkCapacity(); 347 DoubleMatrix1D optimum_pe = DoubleFactory1D.dense.make (E); 348 for (Link e : copyInitialNetPlan.getLinks ()) optimum_pe.set (e.getIndex () , Double.parseDouble (e.getAttribute("p_e"))); 349 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_ue.txt"), optimum_ue); 350 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_pe.txt"), optimum_pe); 351 TimeTrace.printToFile(new File (simulation_outFileNameRoot.getString() + "_jom_objFunc.txt"), optimumNetUtilityJOM); 352 return null; 353 } 354 355 private double computeGradient (Link thisLink , double fairnessFactor , double thisLink_pe , DoubleMatrix1D infoIKnow_p_n , DoubleMatrix1D infoIKnow_ue) 356 { 357 final Node a_e = thisLink.getOriginNode(); 358 if (thisLink_pe == 0) throw new RuntimeException ("Link " + thisLink + " has zero p_e"); 359 double gradient = Math.pow(infoIKnow_ue.get(thisLink.getIndex ()) , 1 - fairnessFactor) / thisLink_pe; 360 for (Link e : this.control_linksInterfFrom_n.get(a_e)) 361 { 362 if (e.getOriginNode() == thisLink.getOriginNode()) throw new RuntimeException ("Bad"); 363 gradient -= Math.pow(infoIKnow_ue.get(e.getIndex ()),1-fairnessFactor) / (1 - infoIKnow_p_n.get(e.getOriginNode().getIndex ())); 364 } 365 if (Double.isNaN(gradient)) throw new RuntimeException ("Link " + thisLink + " gradient is Nan"); 366 if (Double.isInfinite(gradient)) throw new RuntimeException ("Link " + thisLink + " gradient is inifinte"); 367 return gradient; 368 } 369 370 private void checkCapacitiesNetPlan () 371 { 372 double [] p_e = new double [E]; 373 for (Link e : currentNetPlan.getLinks ()) { p_e [e.getIndex ()] = Double.parseDouble (e.getAttribute("p_e")); if ((p_e [e.getIndex ()] < control_minLinkPersistenceProb.getDouble() - 1E-3) ||(p_e [e.getIndex ()] > 1E-3 + control_maxNodePersistenceProb.getDouble())) throw new RuntimeException ("Bad"); } 374 double [] q_n = new double [N]; 375 for (Node n : currentNetPlan.getNodes ()) 376 { 377 for (Link e : n.getOutgoingLinks()) q_n [n.getIndex ()] += p_e [e.getIndex ()]; 378 if (Math.abs (q_n [n.getIndex ()] - Double.parseDouble (n.getAttribute("q_n"))) > 1E-3) throw new RuntimeException ("Bad"); 379 if (q_n [n.getIndex ()] > control_maxNodePersistenceProb.getDouble() + 1E-3) throw new RuntimeException ("Bad"); 380 } 381 for (Link e : currentNetPlan.getLinks ()) 382 { 383 final double u_e = e.getCapacity(); 384 double supposedCapacity = control_linkNominalCapacities.get(e.getIndex ()) * control_p_e.get (e.getIndex ()); 385 for (Node n : control_nodesInterfTo_e.get(e)) supposedCapacity *= 1 - q_n [n.getIndex ()]; 386 if (Math.abs (u_e - supposedCapacity) > 1e-3) throw new RuntimeException ("Bad"); 387 } 388 } 389 390}