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 *******************************************************************************/
011
012
013
014
015
016 
017
018
019
020
021package com.net2plan.examples.ocnbook.offline;
022
023import cern.colt.matrix.tdouble.DoubleFactory2D;
024import cern.colt.matrix.tdouble.DoubleMatrix1D;
025import cern.colt.matrix.tdouble.DoubleMatrix2D;
026import cern.jet.math.tdouble.DoubleFunctions;
027import com.jom.OptimizationProblem;
028import com.net2plan.interfaces.networkDesign.IAlgorithm;
029import com.net2plan.interfaces.networkDesign.Link;
030import com.net2plan.interfaces.networkDesign.Net2PlanException;
031import com.net2plan.interfaces.networkDesign.NetPlan;
032import com.net2plan.libraries.NetworkPerformanceMetrics;
033import com.net2plan.libraries.WirelessUtils;
034import com.net2plan.utils.InputParameter;
035import com.net2plan.utils.Triple;
036
037import java.util.List;
038import java.util.Map;
039
040/**
041 * Finds a fair allocation of the transmission power in a wireless network, solving a formulation.
042 * @net2plan.description
043 * @net2plan.keywords Capacity assignment (CA), Transmission power optimization, JOM, NUM, Wireless 
044 * @net2plan.ocnbooksections Section 5.5
045 * @net2plan.inputParameters 
046 * @author Pablo Pavon-Marino
047 */
048public class Offline_ca_wirelessTransmissionPower implements IAlgorithm
049{
050
051        private InputParameter solverName = new InputParameter ("solverName", "#select# ipopt", "The solver name to be used by JOM. ");
052        private InputParameter solverLibraryName = new InputParameter ("solverLibraryName", "" , "The solver library full or relative path, to be used by JOM. Leave blank to use JOM default.");
053        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)");
054        private InputParameter alphaFairnessFactor = new InputParameter ("alphaFairnessFactor", (double) 2 , "Fairness alpha factor" , 0 , true , Double.MAX_VALUE , true);
055        private InputParameter pathLossExponent = new InputParameter ("pathLossExponent", (double) 2 , "Exponent in the the path loss model, computing attenuation for different distances to the transmitter" , 0 , true , Double.MAX_VALUE , true);
056        private InputParameter worseRiseOverThermal_nu = new InputParameter ("worseRiseOverThermal_nu", (double) 10 , "Worse case ratio between interference power and thermal power. Used to set the thermal power in the receivers" , 0 , true , Double.MAX_VALUE , true);
057        private InputParameter interferenceAttenuationFactor_nu = new InputParameter ("interferenceAttenuationFactor_nu", (double) 1E6 , "The interference power received in natural units is multiplied by this to reduce its effect" , 0 , true , Double.MAX_VALUE , true);
058        private InputParameter maxTransmissionPower_logu = new InputParameter ("maxTransmissionPower_logu", (double) 3 , "The maximum link transmission power in logarithmic units (e.g. dBm)");
059        private InputParameter minTransmissionPower_logu = new InputParameter ("minTransmissionPower_logu", (double) 0 , "The minimum link transmission power in logarithmic units (e.g. dBm)");
060
061        @Override
062        public String executeAlgorithm(NetPlan netPlan, Map<String, String> algorithmParameters, Map<String, String> net2planParameters)
063        {
064                /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
065                InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters);
066                final int E = netPlan.getNumberOfLinks();
067                if (E == 0) throw new Net2PlanException ("The input topology has no links");
068                
069                /* Initialize the gains between links, normalizing them so that the maximum gain is one */
070                DoubleMatrix2D mac_g_nu_ee = WirelessUtils.computeInterferenceMatrixNaturalUnits (netPlan.getLinks () , interferenceAttenuationFactor_nu.getDouble() , pathLossExponent.getDouble());
071                //System.out.println("NOT normalized Gnu_ee: " + Gnu_ee);
072                final double maxGainValue = mac_g_nu_ee.getMaxLocation() [0];
073                mac_g_nu_ee.assign (DoubleFunctions.div(maxGainValue));
074                //System.out.println("normalized mac_g_nu_ee: " + mac_g_nu_ee);
075                
076                /* Initialize the thermal noise at the receivers, to have a worse case ROT (rise over thermal) */
077                double worseInterferenceReceivedAtMaxPower_nu = WirelessUtils.computeWorseReceiverInterferencePower_nu (maxTransmissionPower_logu.getDouble()  , mac_g_nu_ee);
078
079                /* Adjust the thermal noise in the receivers so that we have a given ROT */
080                final double mac_receptionThermalNoise_nu = worseInterferenceReceivedAtMaxPower_nu / worseRiseOverThermal_nu.getDouble();
081                
082                /* Make the formulation  */
083                DoubleMatrix2D G_ee = DoubleFactory2D.sparse.make (E,E);
084                DoubleMatrix2D G_eep = mac_g_nu_ee.copy ();
085                for (int e = 0; e < E ; e ++) { G_ee.set(e,e,mac_g_nu_ee.get(e,e)); G_eep.set (e,e,0); }
086                
087                OptimizationProblem op = new OptimizationProblem();
088                op.addDecisionVariable("p_e", false , new int[] { 1 , E }, minTransmissionPower_logu.getDouble() , maxTransmissionPower_logu.getDouble());
089                op.setInputParameter("b", 1-alphaFairnessFactor.getDouble());
090                op.setInputParameter("s2", mac_receptionThermalNoise_nu);
091                op.setInputParameter("G_ee", G_ee);
092                op.setInputParameter("G_eep", G_eep);
093                
094                /* For the objective function we use that e^(ln(x) = x */
095                if (alphaFairnessFactor.getDouble() == 1)
096                        op.setObjectiveFunction("maximize", "sum ( ln ( ln (  exp(p_e)*G_ee ./ (s2 + exp(p_e)*G_eep)  ) ) )");
097                else
098                        op.setObjectiveFunction("maximize", "(1/b) * sum (   ln (  exp(p_e)*G_ee ./ (s2 + exp(p_e)*G_eep)  )^b   )  ");
099                
100                /* Call the solver to solve the problem */
101                op.solve(solverName.getString (), "solverLibraryName", solverLibraryName.getString () ,  "maxSolverTimeInSeconds" , maxSolverTimeInSeconds.getDouble ());
102
103                /* If no solution is found, quit */
104                if (op.feasibleSolutionDoesNotExist()) throw new Net2PlanException("The problem has no feasible solution");
105                if (op.foundUnboundedSolution()) throw new Net2PlanException ("Found an unbounded solution");
106                if (!op.solutionIsFeasible()) throw new Net2PlanException("A feasible solution was not found");
107        
108                /* Retrieve the optimum solutions. Convert the bps into Erlangs */
109                final double optNetworkUtility = op.getOptimalCost(); // Warning: I saw in some tests, that IPOPT returned this value different to the optimum solution cost: I could not see if I did something wrong
110                DoubleMatrix1D p_e = op.getPrimalSolution("p_e").view1D ();
111
112                /* Update the netplan object with the resulting capacities */
113                for (Link e : netPlan.getLinks())
114                {
115                        final double sinr_e = WirelessUtils.computeSINRLink(e.getIndex () ,p_e , mac_g_nu_ee , mac_receptionThermalNoise_nu); 
116                        e.setCapacity(Math.log(sinr_e));
117                        e.setAttribute("p_e" , "" + p_e.get(e.getIndex ())); 
118                }
119
120                /* Check constraints */
121                if (p_e.getMinLocation() [0] < minTransmissionPower_logu.getDouble() - 1E-3) throw new RuntimeException ("Bad");
122                if (p_e.getMaxLocation() [0] > maxTransmissionPower_logu.getDouble() + 1E-3) throw new RuntimeException ("Bad");
123                final boolean allMaxPower = (p_e.getMinLocation() [0] >= maxTransmissionPower_logu.getDouble() - 1E-3);
124
125                System.out.println("Optimum solution: u_e: " + netPlan.getVectorLinkCapacity());
126                System.out.println("Optimum solution: p_e: " + p_e);
127                System.out.println("ALL AT THE MAX POWER: " + allMaxPower);     
128
129                final double optimumNetUtilityFromCapacities = NetworkPerformanceMetrics.alphaUtility(netPlan.getVectorLinkCapacity() , alphaFairnessFactor.getDouble()); 
130                return "Ok! Solution guaranteed to be optimal: " + op.solutionIsOptimal() + ", Optimal net utility: " + optimumNetUtilityFromCapacities + ", from JOM output: " + optNetworkUtility;
131        }
132
133        @Override
134        public String getDescription()
135        {
136                return "This algorithm computes the optimum transmission power of each link in a wireless network subject to interferences. The link capacity is approximated as proportional to the logarithm of the signal-to-noise (including interferences) ratio. The target when optimizing the transmission power is enforcing a fair allocation of the resulting link capacities. Initially, the input network interference matrix is normalized so that the worst case rise-over-thermal (ROT) of any link matches a given value.";
137        }
138
139        @Override
140        public List<Triple<String, String, String>> getParameters()
141        {
142                /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
143                return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
144        }
145
146}