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.offline; 012 013 014import cern.colt.matrix.tdouble.DoubleMatrix1D; 015import com.net2plan.interfaces.networkDesign.IAlgorithm; 016import com.net2plan.interfaces.networkDesign.Link; 017import com.net2plan.interfaces.networkDesign.Net2PlanException; 018import com.net2plan.interfaces.networkDesign.NetPlan; 019import com.net2plan.utils.*; 020import com.net2plan.utils.Constants.RoutingType; 021 022import java.io.File; 023import java.util.*; 024 025/** 026 * Searches for the OSPF link weights that minimize a measure of congestion, using a greedy heuristic 027 * @net2plan.description 028 * @net2plan.keywords IP/OSPF, Flow assignment (FA), Greedy heuristic 029 * @net2plan.ocnbooksections Section 12.6 030 * @net2plan.inputParameters 031 * @author Pablo Pavon-Marino 032 */ 033public class Offline_fa_ospfWeightOptimization_greedy implements IAlgorithm 034{ 035 private TimeTrace stat_objFunction; 036 private OSPFHeuristicUtils ospfEngine; 037 038 private InputParameter greedy_initializationType = new InputParameter ("greedy_initializationType", "#select# random" , "The type of initialization of the OSPF link weights"); 039 private InputParameter greedy_differenceInWeightToBeNeighbors = new InputParameter ("greedy_differenceInWeightToBeNeighbors", (int) 1 , "Two solutions where all the links have the same weight, but one link where the weight differs in the quantity given by this parameter, are considered neighbors"); 040 private InputParameter ospf_maxLinkWeight = new InputParameter ("ospf_maxLinkWeight", (int) 16 , "OSPF link weights are constrained to be integers between 1 and this parameter" , 1 , Integer.MAX_VALUE); 041 private InputParameter algorithm_randomSeed = new InputParameter ("algorithm_randomSeed", (long) 1 , "Seed of the random number generator"); 042 private InputParameter algorithm_outputFileNameRoot = new InputParameter ("algorithm_outputFileNameRoot", "ospfWeghtOptimization_greedy" , "Root of the file name to be used in the output files. If blank, no output"); 043 private InputParameter algorithm_numSamples = new InputParameter ("algorithm_numSamples", (int) 100 , "Number of repetitions, returns the last, but prints in file all of them" , 1 , Integer.MAX_VALUE); 044 private InputParameter ospf_weightOfMaxUtilizationInObjectiveFunction = new InputParameter ("ospf_weightOfMaxUtilizationInObjectiveFunction", (double) 0.9 , "Objective function is this factor multiplied by maximum link utilization, plus 1 minus this factor by average link utilization" , 0 , true , 1 , true); 045 046 @Override 047 public String executeAlgorithm(NetPlan netPlan, Map<String, String> algorithmParameters, Map<String, String> net2planParameters) 048 { 049 /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */ 050 InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters); 051 052 /* Basic checks */ 053 final int N = netPlan.getNumberOfNodes(); 054 final int E = netPlan.getNumberOfLinks(); 055 if (N == 0) throw new Net2PlanException("The input design must have nodes"); 056 netPlan.removeAllUnicastRoutingInformation(); 057 netPlan.setRoutingTypeAllDemands (RoutingType.HOP_BY_HOP_ROUTING); 058 059 060 Random rng = new Random (algorithm_randomSeed.getLong()); 061 this.ospfEngine = new OSPFHeuristicUtils(netPlan, ospf_maxLinkWeight.getInt (), ospf_weightOfMaxUtilizationInObjectiveFunction.getDouble(), rng); 062 063 this.stat_objFunction = new TimeTrace (); 064 065 for (int it = 0 ; it < algorithm_numSamples.getInt () ; it ++) 066 { 067 Pair<DoubleMatrix1D,Double> p = ospfEngine.getInitialSolution (greedy_initializationType.getString()); 068 DoubleMatrix1D currentSol = p.getFirst(); 069 double currentObjFunction = p.getSecond(); 070 071 /* Create a randomly shuffled sequence of link ids */ 072 List<Link> shuffledLinks = new ArrayList<Link> (netPlan.getLinks()); 073 Collections.shuffle(shuffledLinks); 074 075 for (Link e : shuffledLinks) 076 { 077 Pair<double [],int []> pair = ospfEngine.computeSolutionsVaryingLinkWeight (e , currentSol , null , greedy_differenceInWeightToBeNeighbors.getInt ()); 078 final int indexOfBestWeight = DoubleUtils.maxIndexes (pair.getFirst() , Constants.SearchType.FIRST) [0]; 079 final int bestWeight = pair.getSecond() [indexOfBestWeight]; 080 currentObjFunction = pair.getFirst() [indexOfBestWeight]; 081 currentSol.set(e.getIndex(), (double) bestWeight); 082 } 083 stat_objFunction.add(it , currentObjFunction); 084 } 085 086 stat_objFunction.printToFile(new File (algorithm_outputFileNameRoot.getString () + "_D" + greedy_differenceInWeightToBeNeighbors.getInt () + "_cong.txt")); 087 088 double minObjectiveFunction = Double.MAX_VALUE; 089 for (Pair<Double,Object> element : stat_objFunction.getList()) minObjectiveFunction = Math.min(minObjectiveFunction, (Double) element.getSecond()); 090 return "Ok! Min congestion factor: " + minObjectiveFunction; 091 } 092 093 @Override 094 public String getDescription() 095 { 096 return "Given a set of nodes, links and offered traffic, this algorithm assumes that the nodes are IP routers running the OSPF protocol (applying ECMP rules) for routing it. The algorithm searches for the set of link weights that optimize the routing. In particular, the target is minimizing a congestion metric computed as a function of both the worst-case link utilization and the average link utilization. The algorithm is based on applying a greedy heuristic approach."; 097 } 098 099 @Override 100 public List<Triple<String, String, String>> getParameters() 101 { 102 /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */ 103 return InputParameter.getInformationAllInputParameterFieldsOfObject(this); 104 } 105}