001package com.net2plan.examples.ocnbook.offline;
002
003/*******************************************************************************
004 * Copyright (c) 2017 Pablo Pavon Marino and others.
005 * All rights reserved. This program and the accompanying materials
006 * are made available under the terms of the 2-clause BSD License 
007 * which accompanies this distribution, and is available at
008 * https://opensource.org/licenses/BSD-2-Clause
009 *
010 * Contributors:
011 *     Pablo Pavon Marino and others - initial API and implementation
012 *******************************************************************************/
013
014
015import cern.colt.matrix.tdouble.DoubleMatrix1D;
016import cern.colt.matrix.tdouble.DoubleMatrix2D;
017import cern.jet.math.tdouble.DoubleFunctions;
018import com.jom.OptimizationProblem;
019import com.net2plan.interfaces.networkDesign.IAlgorithm;
020import com.net2plan.interfaces.networkDesign.Net2PlanException;
021import com.net2plan.interfaces.networkDesign.NetPlan;
022import com.net2plan.utils.InputParameter;
023import com.net2plan.utils.Triple;
024
025import java.util.List;
026import java.util.Map;
027
028/**
029 * Solves several variants of node location problem formlations.
030 * @net2plan.description
031 * @net2plan.keywords Topology assignment (TA), JOM
032 * @net2plan.ocnbooksections Section 7.2
033 * @net2plan.inputParameters 
034 * @author Pablo Pavon-Marino
035 */
036public class Offline_tca_nodeLocation implements IAlgorithm
037{
038        private InputParameter solverName = new InputParameter ("solverName", "#select# glpk ipopt xpress cplex", "The solver name to be used by JOM. GLPK and IPOPT are free, XPRESS and CPLEX commercial. GLPK, XPRESS and CPLEX solve linear problems w/w.o integer contraints. IPOPT is can solve nonlinear problems (if convex, returns global optimum), but cannot handle integer constraints");
039        private InputParameter solverLibraryName = new InputParameter ("solverLibraryName", "", "The solver library full or relative path, to be used by JOM. Leave blank to use JOM default.");
040        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)");
041        private InputParameter linkCapacities = new InputParameter ("linkCapacities", (double) 100 , "The capacities to set in the links" , 0 , true , Double.MAX_VALUE , true);
042        private InputParameter linkPropagationSpeedInKmPerSecond = new InputParameter ("linkPropagationSpeedInKmPerSecond", (double) 200000 , "The propagation speed in km per second of the deployed links" , 0 , false , Double.MAX_VALUE , true);
043        private InputParameter coreNodeCost = new InputParameter ("coreNodeCost", (double) 1 , "Cost of one core node. Link cost is proportional to its distance, and normalized to the cost of the longest possible link is one" , 0 , true , Double.MAX_VALUE , true);
044        private InputParameter K_max = new InputParameter ("K_max", (int) 5 , "Maximum number of access nodes that can be connected to a core node" , (int) 1 , Integer.MAX_VALUE);
045        private InputParameter maxNumCoreNodesPerSite = new InputParameter ("maxNumCoreNodesPerSite", (int) 1 , "Maximum number of core nodes that can be placed in a site." , (int) 1 , Integer.MAX_VALUE);
046        private InputParameter maxNumCoreNodes = new InputParameter ("maxNumCoreNodes", (int) -1 , "Maximum number of core nodes in the network. If <= 0, there is no limit.");
047
048        
049        @Override
050        public String executeAlgorithm(NetPlan netPlan, Map<String, String> algorithmParameters, Map<String, String> net2planParameters)
051        {
052                /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
053                InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters);
054
055                /* Basic checks */
056                final int N = netPlan.getNumberOfNodes();
057                if (N == 0) throw new Net2PlanException("The input design must have nodes");
058
059                final DoubleMatrix2D linkDistanceMatrix_nn = netPlan.getMatrixNode2NodeEuclideanDistance();
060                final double maxDistance = linkDistanceMatrix_nn.getMaxLocation() [0];
061                final DoubleMatrix2D c_ij = linkDistanceMatrix_nn.copy ().assign (DoubleFunctions.div(maxDistance)); // normalize so the maximum possible link cost is one
062
063                /* Create the optimization problem object (JOM library) */
064                OptimizationProblem op = new OptimizationProblem();
065
066                /* Set some input parameters */
067                op.setInputParameter("c_ij", c_ij);
068                op.setInputParameter("K_max", K_max.getInt ());
069                op.setInputParameter("C", coreNodeCost.getDouble());
070                
071                /* Add the decision variables to the problem */
072                op.addDecisionVariable("z_j", true, new int[] { 1, N }, 0, maxNumCoreNodesPerSite.getInt()); /* 1 if there is a node in this site */
073                op.addDecisionVariable("e_ij", true, new int[] { N, N }, 0, 1); /* 1 if site i is connected to site j */
074
075                /* Sets the objective function */
076                op.setObjectiveFunction("minimize", "C * sum(z_j) + sum (e_ij .* c_ij)");
077
078                /* Constraints */
079                op.addConstraint("sum(e_ij , 2) == 1"); /* each site is connected to a core site */
080                op.addConstraint("sum(e_ij , 1) <= K_max * z_j"); /* a site is connected to other, if the second is a core site */
081                if (maxNumCoreNodes.getInt() > 0) op.addConstraint("sum(z_j) <= " + maxNumCoreNodes.getInt()); /* limit to the total number of core nodes in the network */
082
083                /* Call the solver to solve the problem */
084                op.solve(solverName.getString (), "solverLibraryName", solverLibraryName.getString () , "maxSolverTimeInSeconds" , maxSolverTimeInSeconds.getDouble ());
085
086                /* If no solution is found, quit */
087                if (op.feasibleSolutionDoesNotExist()) throw new Net2PlanException("The problem has no feasible solution");
088                if (!op.solutionIsFeasible()) throw new Net2PlanException("A feasible solution was not found");
089                
090                /* Retrieve the optimum solutions */
091                DoubleMatrix1D  z_j = op.getPrimalSolution("z_j").view1D();
092                DoubleMatrix2D e_ij = op.getPrimalSolution("e_ij").view2D();
093
094                System.out.println("z_j: " + z_j);
095
096                /* Remove all previous demands, links, protection segments, routes */
097                netPlan.removeAllLinks();
098
099                /* Save the new network links */
100                for (int n = 0; n < N ; n ++)
101                        if (z_j.get(n) == 1) netPlan.getNode (n).setAttribute("hasCoreNode" , "true"); else netPlan.getNode (n).setAttribute("hasCoreNode" , "false");
102                for (int i = 0; i < N ; i ++) for (int j = 0; j < N ; j ++)
103                        if (e_ij.get(i,j) == 1) 
104                        {
105                                if (z_j.get(j) == 0) throw new RuntimeException ("Bad");
106                                if (i != j) netPlan.addLink(netPlan.getNode(i), netPlan.getNode(j), linkCapacities.getDouble(),linkDistanceMatrix_nn.get(i,j), linkPropagationSpeedInKmPerSecond.getDouble() , null);
107                        }
108
109                return "Ok! Number of core nodes: " + z_j.zSum();
110        }
111
112        @Override
113        public String getDescription()
114        {
115                return "Given a set of access nodes, this algorithm computes the subset of access nodes which have a core node located next to it (in the same place), and the links access-to-core nodes, so that the network cost is minimized. This cost is given by a cost per core node (C) plus a cost per link, proportional to the link euclidean distance and normalized so that the maximum link cost is one. Access-core link capacities are fixed to the user-defined parameter linkCapacities. A core node cannot be connected to more than K_max access nodes, a user-defined parameter. This problem is modeled as an ILP and optimally solved using JOM.";
116        }
117
118        @Override
119        public List<Triple<String, String, String>> getParameters()
120        {
121                /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
122                return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
123        }
124        
125        
126}
127