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