001/*******************************************************************************
002 * Copyright (c) 2016 Pablo Pavon Mariño.
003 * All rights reserved. This program and the accompanying materials
004 * are made available under the terms of the GNU Lesser Public License v2.1
005 * which accompanies this distribution, and is available at
006 * http://www.gnu.org/licenses/lgpl.html
007 ******************************************************************************/
008
009
010
011
012package com.net2plan.examples.ocnbook.reports;
013
014import java.io.Closeable;
015import java.io.File;
016import java.text.DecimalFormat;
017import java.util.ArrayList;
018import java.util.HashSet;
019import java.util.List;
020import java.util.Map;
021import java.util.Set;
022
023import cern.colt.function.tdouble.DoubleDoubleFunction;
024import cern.colt.function.tdouble.DoubleFunction;
025import cern.colt.list.tdouble.DoubleArrayList;
026import cern.colt.list.tint.IntArrayList;
027import cern.colt.matrix.tdouble.DoubleFactory1D;
028import cern.colt.matrix.tdouble.DoubleMatrix1D;
029import cern.colt.matrix.tdouble.DoubleMatrix2D;
030
031import com.net2plan.interfaces.networkDesign.Demand;
032import com.net2plan.interfaces.networkDesign.IReport;
033import com.net2plan.interfaces.networkDesign.Link;
034import com.net2plan.interfaces.networkDesign.MulticastDemand;
035import com.net2plan.interfaces.networkDesign.Net2PlanException;
036import com.net2plan.interfaces.networkDesign.NetPlan;
037import com.net2plan.interfaces.networkDesign.NetworkLayer;
038import com.net2plan.interfaces.networkDesign.Node;
039import com.net2plan.interfaces.networkDesign.SharedRiskGroup;
040import com.net2plan.interfaces.simulation.IEventProcessor;
041import com.net2plan.interfaces.simulation.SimEvent;
042import com.net2plan.libraries.SRGUtils;
043import com.net2plan.utils.ClassLoaderUtils;
044import com.net2plan.utils.InputParameter;
045import com.net2plan.utils.StringUtils;
046import com.net2plan.utils.Triple;
047
048/**
049 * This report receives as an input a network design, the network recovery scheme algorithm, and the network risks (SRGs), and estimates the availability of the 
050 * network (including individual availabilities for each demand), using an enumerative process that also provides an estimation of the estimation error. 
051 * 
052 * @net2plan.keywords Network recovery: protection , Network recovery: restoration
053 * @net2plan.ocnbooksections Section 3.7.3
054 * @net2plan.inputParameters 
055 * @author Pablo Pavon-Marino
056 */
057public class Report_availability implements IReport
058{
059        private InputParameter provisioningAlgorithm = new InputParameter ("provisioningAlgorithm" , "#eventProcessor#" , "Algorithm to process failure events");
060        private InputParameter analyzeDoubleFailures = new InputParameter ("analyzeDoubleFailures" , true , "Indicates whether double failures are studied");
061        private InputParameter defaultMTTFInHours = new InputParameter ("defaultMTTFInHours" , (double) 8748 , "Default value for Mean Time To Fail (hours)" , 0 , false , Double.MAX_VALUE , true);
062        private InputParameter defaultMTTRInHours = new InputParameter ("defaultMTTRInHours" , (double) 12 , "Default value for Mean Time To Repair (hours)" , 0 , false , Double.MAX_VALUE , true);
063        private InputParameter failureModel = new InputParameter ("failureModel" , "#select# perBidirectionalLinkBundle SRGfromNetPlan perNode perLink perDirectionalLinkBundle" , "Failure model selection: SRGfromNetPlan, perNode, perLink, perDirectionalLinkBundle, perBidirectionalLinkBundle");
064        private InputParameter considerTrafficInOversubscribedLinksAsLost = new InputParameter ("considerTrafficInOversubscribedLinksAsLost" , true , "If true, all the demands whose traffic (even only a fraction of it) traverses an oversubscribed link, are considered that all its treaffic is blocked, as they are supposed to fail to satisfy QoS agreements");
065        private InputParameter maximumE2ELatencyMs = new InputParameter ("maximumE2ELatencyMs", (double) -1 , "Maximum end-to-end latency of the traffic of any demand (a non-positive value means no limit). All the traffic of demands where a fraction of its traffic can exceed this value, are considered as lost, as they are supposed to fail to satisfy QoS agreements");
066        
067        private ArrayList<DoubleMatrix1D> availabilityClassicNoFailure_ld, availabilityWeightedNoFailure_ld, availabilityClassicNoFailure_lmd, availabilityWeightedNoFailure_lmd;
068        private ArrayList<DoubleMatrix1D> availabilityClassicTotal_ld, availabilityWeightedTotal_ld, availabilityClassicTotal_lmd, availabilityWeightedTotal_lmd;
069        private double pi_excess;
070
071        private IEventProcessor algorithm;
072        
073        @Override
074        public String executeReport(NetPlan netPlan, Map<String, String> reportParameters, Map<String, String> net2planParameters)
075        {
076                /* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
077                InputParameter.initializeAllInputParameterFieldsOfObject(this, reportParameters);
078
079                String algorithmFile = reportParameters.get("provisioningAlgorithm_file");
080                String algorithmName = reportParameters.get("provisioningAlgorithm_classname");
081                String algorithmParam = reportParameters.get("provisioningAlgorithm_parameters");
082                if (algorithmFile.isEmpty() || algorithmName.isEmpty()) throw new Net2PlanException("A provisioning algorithm must be defined");
083                final double PRECISION_FACTOR_hd = Double.parseDouble(net2planParameters.get("precisionFactor"));
084                final double PRECISION_FACTOR_blocking = PRECISION_FACTOR_hd * PRECISION_FACTOR_hd;
085                
086                
087                Map<String, String> algorithmParameters = StringUtils.stringToMap(algorithmParam);
088                switch (failureModel.getString ())
089                {
090                        case "SRGfromNetPlan":
091                                break;
092
093                        case "perNode":
094                                SRGUtils.configureSRGs(netPlan, defaultMTTFInHours.getDouble(), defaultMTTRInHours.getDouble(), SRGUtils.SharedRiskModel.PER_NODE, true);
095                                break;
096
097                        case "perLink":
098                                SRGUtils.configureSRGs(netPlan, defaultMTTFInHours.getDouble(), defaultMTTRInHours.getDouble(), SRGUtils.SharedRiskModel.PER_LINK, true);
099                                break;
100
101                        case "perDirectionalLinkBundle":
102                                SRGUtils.configureSRGs(netPlan, defaultMTTFInHours.getDouble(), defaultMTTRInHours.getDouble(), SRGUtils.SharedRiskModel.PER_DIRECTIONAL_LINK_BUNDLE, true);
103                                break;
104
105                        case "perBidirectionalLinkBundle":
106                                SRGUtils.configureSRGs(netPlan, defaultMTTFInHours.getDouble(), defaultMTTRInHours.getDouble(), SRGUtils.SharedRiskModel.PER_BIDIRECTIONAL_LINK_BUNDLE, true);
107                                break;
108
109                        default:
110                                throw new Net2PlanException("Failure model not valid. Please, check algorithm parameters description");
111                }
112
113                netPlan.setAllNodesFailureState(true);
114                for (NetworkLayer layer : netPlan.getNetworkLayers ())
115                        netPlan.setAllLinksFailureState(true , layer);
116                DoubleMatrix1D A_f = netPlan.getVectorSRGAvailability();
117                List<SharedRiskGroup> srgs = netPlan.getSRGs();
118                DoubleMatrix2D F_s = SRGUtils.getMatrixFailureState2SRG(srgs, true, analyzeDoubleFailures.getBoolean());
119                
120                /* Compute state probabilities (pi_s) */
121                DoubleMatrix1D pi_s = SRGUtils.computeStateProbabilities(F_s , A_f);
122                final double sum_pi_s = pi_s.zSum();
123                
124                final double pi_s0 = pi_s.get(0); System.out.println ("Probability no failure state: " + pi_s0);
125                
126                pi_excess = 1 - sum_pi_s;
127
128                /* Initialize statistics variables */
129                availabilityClassicNoFailure_ld = new ArrayList<DoubleMatrix1D> ();
130                availabilityWeightedNoFailure_ld = new ArrayList<DoubleMatrix1D> ();
131                availabilityClassicNoFailure_lmd = new ArrayList<DoubleMatrix1D> ();
132                availabilityWeightedNoFailure_lmd = new ArrayList<DoubleMatrix1D> ();
133                availabilityClassicTotal_ld = new ArrayList<DoubleMatrix1D> (); 
134                availabilityWeightedTotal_ld = new ArrayList<DoubleMatrix1D> ();
135                availabilityClassicTotal_lmd = new ArrayList<DoubleMatrix1D> ();
136                availabilityWeightedTotal_lmd = new ArrayList<DoubleMatrix1D> ();
137                for(int indexLayer = 0 ; indexLayer < netPlan.getNumberOfLayers() ; indexLayer ++)
138                {
139                        final NetworkLayer layer = netPlan.getNetworkLayer (indexLayer);
140                        final int D = netPlan.getNumberOfDemands(layer);
141                        final int MD = netPlan.getNumberOfMulticastDemands(layer);
142                        availabilityClassicTotal_ld.add (DoubleFactory1D.dense.make (D,0.0));
143                        availabilityWeightedTotal_ld.add (DoubleFactory1D.dense.make (D,0.0));
144                        availabilityClassicTotal_lmd.add (DoubleFactory1D.dense.make (MD,0.0));
145                        availabilityWeightedTotal_lmd.add (DoubleFactory1D.dense.make (MD,0.0));
146                }
147
148//              List<Link> upAndOversubscribedLinksSetToDown = new LinkedList<Link> ();
149//              if (considerTrafficInOversubscribedLinksAsLost.getBoolean())
150//              {
151//                      for (NetworkLayer layer : netPlan.getNetworkLayers ())
152//                      {
153////                            System.out.println ("Layer " + layer + ", initial link capacity traffic: " + netPlan.getVectorLinkCapacity(layer));
154////                            System.out.println ("Layer " + layer + ", initial demand carried traffic: " + netPlan.getVectorDemandCarriedTraffic(layer));
155//                              for (Link e : netPlan.getLinks (layer)) if (e.isUp() && e.isOversubscribed()) { upAndOversubscribedLinksSetToDown.add (e); }
156////                            System.out.println ("Layer: " + layer + ", upAndOversubscribedLinksSetToDown: " + upAndOversubscribedLinksSetToDown);
157//                      }
158//                      netPlan.setLinksAndNodesFailureState(null , upAndOversubscribedLinksSetToDown , null , null);
159//              }
160//
161//              System.out.println ("Links set to down all layers: " + netPlan.getLinksDownAllLayers());
162
163                /* Statistics for the no-failure state */
164                for(int indexLayer = 0 ; indexLayer < netPlan.getNumberOfLayers() ; indexLayer ++)
165                {
166                        final NetworkLayer layer = netPlan.getNetworkLayer (indexLayer);
167
168                        final DoubleMatrix1D h_d = netPlan.getVectorDemandOfferedTraffic(layer);
169                        final DoubleMatrix1D blocked_d = netPlan.getVectorDemandBlockedTraffic(layer);
170                        if (considerTrafficInOversubscribedLinksAsLost.getBoolean()) for (Demand d : netPlan.getDemands (layer)) if (d.isTraversingOversubscribedLinks()) blocked_d.set (d.getIndex () , d.getOfferedTraffic());
171                        if (maximumE2ELatencyMs.getDouble () > 0) for (Demand d : netPlan.getDemands (layer)) if (d.getWorseCasePropagationTimeInMs() > maximumE2ELatencyMs.getDouble ()) blocked_d.set (d.getIndex () , d.getOfferedTraffic());
172                        
173                        final DoubleMatrix1D h_md = netPlan.getVectorMulticastDemandOfferedTraffic(layer);
174                        final DoubleMatrix1D blocked_md = netPlan.getVectorMulticastDemandBlockedTraffic(layer);
175                        if (considerTrafficInOversubscribedLinksAsLost.getBoolean()) for (MulticastDemand d : netPlan.getMulticastDemands (layer)) if (d.isTraversingOversubscribedLinks()) blocked_md.set (d.getIndex () , d.getOfferedTraffic());
176                        if (maximumE2ELatencyMs.getDouble () > 0) for (MulticastDemand d : netPlan.getMulticastDemands(layer)) if (d.getWorseCasePropagationTimeInMs() > maximumE2ELatencyMs.getDouble ()) blocked_md.set (d.getIndex () , d.getOfferedTraffic());
177
178                        //                      System.out.println ("****** No failure Layer  " + layer + ", blocked_d: " + blocked_d);
179                        final DoubleMatrix1D availabilityClassic_d = blocked_d.copy ().assign (new DoubleFunction () { public double apply (double x) { return x > PRECISION_FACTOR_blocking? 0 : 1;  }  } );
180                        final DoubleMatrix1D availabilityWeighted_d = blocked_d.copy ().assign (h_d , new DoubleDoubleFunction () { public double apply (double x , double y) { return y < PRECISION_FACTOR_hd? 1 : 1 - x/y; }  } );
181                        final DoubleMatrix1D availabilityClassic_md = blocked_md.copy ().assign (new DoubleFunction () { public double apply (double x) { return x > PRECISION_FACTOR_blocking ? 0 : 1;  }  } );
182                        final DoubleMatrix1D availabilityWeighted_md = blocked_md.copy ().assign (h_md , new DoubleDoubleFunction () { public double apply (double x , double y) { return y < PRECISION_FACTOR_hd ? 1 : 1 - x/y; }  } );
183
184                        availabilityClassicTotal_ld.get(layer.getIndex ()).assign (availabilityClassic_d , new DoubleDoubleFunction () { public double apply (double x , double y) { return x + pi_s0 * y; } } );
185                        availabilityWeightedTotal_ld.get(layer.getIndex ()).assign (availabilityWeighted_d , new DoubleDoubleFunction () { public double apply (double x , double y) { return x + pi_s0 * y; } } );
186                        availabilityClassicTotal_lmd.get(layer.getIndex ()).assign (availabilityClassic_md , new DoubleDoubleFunction () { public double apply (double x , double y) { return x + pi_s0 * y; } } );
187                        availabilityWeightedTotal_lmd.get(layer.getIndex ()).assign (availabilityWeighted_md , new DoubleDoubleFunction () { public double apply (double x , double y) { return x + pi_s0 * y; } } );
188
189                        availabilityClassicNoFailure_ld.add(availabilityClassic_d);
190                        availabilityWeightedNoFailure_ld.add(availabilityWeighted_d);
191                        availabilityClassicNoFailure_lmd.add(availabilityClassic_md);
192                        availabilityWeightedNoFailure_lmd.add(availabilityWeighted_md);
193                }
194//              System.out.println ("Before any failure state: availabilityClassicTotal_ld: " + availabilityClassicTotal_ld);
195//              System.out.println ("Before any failure state: availabilityClassicNoFailure_ld: " + availabilityClassicNoFailure_ld);
196
197                
198                /* the up and oversubscribed links that were set as down, are set to up again */
199//              if (considerTrafficInOversubscribedLinksAsLost.getBoolean())
200//                      netPlan.setLinksAndNodesFailureState(upAndOversubscribedLinksSetToDown , null , null , null);
201
202                if (!netPlan.getLinksDownAllLayers().isEmpty() || !netPlan.getNodesDown().isEmpty()) throw new RuntimeException ("Bad");
203
204                NetPlan auxNetPlan = netPlan.copy ();
205                this.algorithm = ClassLoaderUtils.getInstance(new File(algorithmFile), algorithmName, IEventProcessor.class);
206                this.algorithm.initialize(auxNetPlan , algorithmParameters , reportParameters , net2planParameters);
207                Set<Link> initialLinksDownAllLayers = auxNetPlan.getLinksDownAllLayers();
208                Set<Node> initialNodesDown = auxNetPlan.getNodesDown();
209                Set<Link> linksAllLayers = new HashSet<Link> (); for (NetworkLayer layer : auxNetPlan.getNetworkLayers()) linksAllLayers.addAll (auxNetPlan.getLinks (layer));
210
211                for (int failureState = 1 ; failureState < F_s.rows () ; failureState ++) // first failure state (no failure) was already considered
212                {
213                        if (!auxNetPlan.getLinksDownAllLayers().equals (initialLinksDownAllLayers) || !auxNetPlan.getNodesDown().equals(initialNodesDown)) throw new RuntimeException ("Bad");
214
215                        IntArrayList srgs_thisState = new IntArrayList (); F_s.viewRow (failureState).getNonZeros (srgs_thisState , new DoubleArrayList ());
216                        final double pi_s_thisState = pi_s.get (failureState);
217
218                        Set<Link> linksToSetAsDown = new HashSet<Link> ();
219                        Set<Node> nodesToSetAsDown = new HashSet<Node> ();
220                        for (SharedRiskGroup srg : auxNetPlan.getSRGs())
221                        {
222                                if (F_s.get(failureState , srg.getIndex ()) != 1) continue;
223                                nodesToSetAsDown.addAll (srg.getNodes ());
224                                linksToSetAsDown.addAll (srg.getLinks ());
225                        }
226
227                        /* Make the algorithm process the event of nodes and links down */
228                        SimEvent.NodesAndLinksChangeFailureState failureInfo = new SimEvent.NodesAndLinksChangeFailureState(null , nodesToSetAsDown , null , linksToSetAsDown);
229                        try
230                        {
231                                /* Apply the reaction algorithm */
232                                algorithm.processEvent(auxNetPlan, new SimEvent(0, SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , failureInfo));
233                        }
234                        catch (Throwable e)
235                        {
236                                try { ((Closeable) algorithm.getClass().getClassLoader()).close(); }
237                                catch (Throwable e1) { }                                        
238
239                                throw (e);
240                        }
241                        
242                        try { ((Closeable) algorithm.getClass().getClassLoader()).close(); }
243                        catch (Throwable e1) { }                                        
244
245                        for(NetworkLayer layer : auxNetPlan.getNetworkLayers ())
246                        {
247                                final DoubleMatrix1D h_d = auxNetPlan.getVectorDemandOfferedTraffic(layer);
248                                final DoubleMatrix1D blocked_d = auxNetPlan.getVectorDemandBlockedTraffic(layer);
249                                if (considerTrafficInOversubscribedLinksAsLost.getBoolean()) for (Demand d : auxNetPlan.getDemands (layer)) if (d.isTraversingOversubscribedLinks()) blocked_d.set (d.getIndex () , d.getOfferedTraffic());
250                                if (maximumE2ELatencyMs.getDouble () > 0) for (Demand d : auxNetPlan.getDemands (layer)) if (d.getWorseCasePropagationTimeInMs() > maximumE2ELatencyMs.getDouble ()) blocked_d.set (d.getIndex () , d.getOfferedTraffic());
251                                final DoubleMatrix1D h_md = auxNetPlan.getVectorMulticastDemandOfferedTraffic(layer);
252                                final DoubleMatrix1D blocked_md = auxNetPlan.getVectorMulticastDemandBlockedTraffic(layer);
253                                if (considerTrafficInOversubscribedLinksAsLost.getBoolean()) for (MulticastDemand d : auxNetPlan.getMulticastDemands (layer)) if (d.isTraversingOversubscribedLinks()) blocked_md.set (d.getIndex () , d.getOfferedTraffic());
254                                if (maximumE2ELatencyMs.getDouble () > 0) for (MulticastDemand d : auxNetPlan.getMulticastDemands(layer)) if (d.getWorseCasePropagationTimeInMs() > maximumE2ELatencyMs.getDouble ()) blocked_md.set (d.getIndex () , d.getOfferedTraffic());
255                                final DoubleMatrix1D availabilityClassic_d = blocked_d.copy ().assign (new DoubleFunction () { public double apply (double x) { return x > PRECISION_FACTOR_blocking? 0 : 1;  }  } );
256                                final DoubleMatrix1D availabilityWeighted_d = blocked_d.copy ().assign (h_d , new DoubleDoubleFunction () { public double apply (double x , double y) { return y < PRECISION_FACTOR_hd? 1 : 1 - x/y; }  } );
257                                final DoubleMatrix1D availabilityClassic_md = blocked_md.copy ().assign (new DoubleFunction () { public double apply (double x) { return x > PRECISION_FACTOR_blocking? 0 : 1;  }  } );
258                                final DoubleMatrix1D availabilityWeighted_md = blocked_md.copy ().assign (h_md , new DoubleDoubleFunction () { public double apply (double x , double y) { return y < PRECISION_FACTOR_hd? 1 : 1 - x/y; }  } );
259
260//                              System.out.println ("****** Failure: " + failureState + ", Layer  " + layer + ", blocked_d: " + blocked_d);
261                                
262                                availabilityClassicTotal_ld.get(layer.getIndex ()).assign (availabilityClassic_d , new DoubleDoubleFunction () { public double apply (double x , double y) { return x + pi_s_thisState * y; } } );
263                                availabilityWeightedTotal_ld.get(layer.getIndex ()).assign (availabilityWeighted_d , new DoubleDoubleFunction () { public double apply (double x , double y) { return x + pi_s_thisState * y; } } );
264                                availabilityClassicTotal_lmd.get(layer.getIndex ()).assign (availabilityClassic_md , new DoubleDoubleFunction () { public double apply (double x , double y) { return x + pi_s_thisState * y; } } );
265                                availabilityWeightedTotal_lmd.get(layer.getIndex ()).assign (availabilityWeighted_md , new DoubleDoubleFunction () { public double apply (double x , double y) { return x + pi_s_thisState * y; } } );
266                                
267//                              System.out.println ("Failure " + failureState + ", availabilityClassicTotal_ld: " + availabilityClassicTotal_ld);
268                        }
269                        
270//                      System.out.println ("4. failure state: " + failureState + ", auxNetPlan.getLinksDownAllLayers(): " + auxNetPlan.getLinksDownAllLayers() + ", auxNetPlan.getNodesDown(): " + auxNetPlan.getNodesDown() + ", linksToSetDown: " + linksToSetAsDown);
271                        
272                        failureInfo = new SimEvent.NodesAndLinksChangeFailureState(auxNetPlan.getNodes() , null , linksAllLayers , null);
273                        algorithm.processEvent(auxNetPlan, new SimEvent(0, SimEvent.DestinationModule.EVENT_PROCESSOR , -1 , failureInfo));
274
275//                      System.out.println ("5. failure state: " + failureState + ", auxNetPlan.getLinksDownAllLayers(): " + auxNetPlan.getLinksDownAllLayers() + ", auxNetPlan.getNodesDown(): " + auxNetPlan.getNodesDown() + ", linksToSetDown: " + linksToSetAsDown);
276                }
277
278                return printReport(netPlan , reportParameters);
279        }
280
281        @Override
282        public String getDescription()
283        {
284                return "This report receives as an input a network design, the network recovery scheme algorithm, and the network risks (SRGs), and estimates the availability of the network (including individual availabilities for each demand), using an enumerative process that also provides an estimation of the estimation error. ";
285        }
286
287        @Override
288        public List<Triple<String, String, String>> getParameters()
289        {
290                /* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
291                return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
292        }
293
294        @Override
295        public String getTitle()
296        {
297                return "Availability report";
298        }
299
300        
301        private String printReport(NetPlan np , Map<String,String> reportParameters)
302        {
303                StringBuilder out = new StringBuilder();
304                DecimalFormat df_6 = new DecimalFormat("#.######");
305                out.append("<html><body>");
306                out.append("<head><title>Availability report</title></head>");
307                out.append("<h1>Introduction</h1>");
308                out.append("<p>This report computes several availability measures for the different unicast and multicast demands in the different layers of the network." +
309                                "The network is supposed to be subject to the failures defined by the SRGs, and the possible network states considered are: </p>");
310                out.append ("<ul>");
311                out.append ("<li>No failure occurs in the network</li>");
312                out.append ("<li>Single SRG failure: A single SRG fails, while the rest of failures associated to the other SRGs do not occur</li>");
313                out.append ("<li>Double SRG failure (optional): Two SRGs simultaneously fail, while the rest of failures associated to the other SRGs do not occur</li>");
314                out.append ("</ul>");
315                out.append("<p>A numerical method is used that (i) enumerates the possible failure states considered and the probability of occurrence, (ii) computes the network reaction" +
316                                "to that failure state using a used-defined algorithm, (iii) builds up the availability results for each demand from that.</p>");
317                out.append("<p>Then, the method is able to produce an estimation of the availability of each unicast and multicast demand (and from them network-wide availability measures) under the given failures, and" +
318                                " assuming that the network reacts according to an arbitrary protection/restoration provided algorithm.</p>");
319                out.append("<p>Two types of availability metrics are provided:</p>");
320                out.append ("<ul>");
321                out.append ("<li>Availability of a demand/network: Fraction of time in which the demand/network is carrying the 100% of the offered traffic</li>");
322                out.append ("<li>Traffic survivability of a demand/network: Fraction of the offered traffic that the network carries</li>");
323                out.append ("</ul>");
324                out.append("<p>Traffic survivability is always equals or higher than analogous availability value. For instance, if during some failure states that mean a 1% of the time, a demad is " +
325                                "carrying just a 50% of the traffic, the network availability is 99% (99% of the time everythign works perfectly well), but traffic survivability is " +
326                                "0.99*1 + 0.01*0.5 = 99.5%</p>");
327                out.append("<p>In each metric, we provide a pessimistic and optimistic estimation. The pessimistic estimation, considers that in the triple, quadruple etc. " +
328                                "failure states, all the traffic is lost. In the optimistic case, we assume that in such cases, all the traffic is carried. </p>");
329                
330                out.append("<p>For more information of this method:</p>");
331                out.append("<p>P. Pavón Mariño, \"Optimization of computer networks. Modeling and algorithms. A hands-on approach\", Wiley 2016</p>");
332                out.append("<h1>Global information</h1>");
333                out.append("<h2>Input Parameters</h2>");
334                out.append("<table border='1'>");
335                out.append("<tr><th><b>Name</b></th><th><b>Value</b></th><th><b>Description</b></th>");
336                for (Triple<String, String, String> paramDef : getParameters())
337                {
338                        String name = paramDef.getFirst();
339                        String description = paramDef.getThird();
340                        String value = reportParameters.get(name);
341                        out.append("<tr><td>").append(name).append("</td><td>").append(value).append("</td><td>").append(description).append("</td></tr>");
342                }
343                out.append("<tr><td>--Estimated error in availability calculations: </td><td>" + pi_excess + "</td><td>Probabilities of triple failure, quadruple etc. of non enumerated network states</td></tr>");
344                out.append("</table>");
345
346                out.append("<h1>PER LAYER INFORMATION SUMMARY</h1>");
347                for (NetworkLayer layer : np.getNetworkLayers ())
348                {
349                        double val;
350
351                        out.append("<h2>Layer " + layer.getName () + ", index = " + layer.getIndex () + ", id = " + layer.getId () + "</h2>");
352                        final DoubleMatrix1D h_d = np.getVectorDemandOfferedTraffic(layer);
353                        final DoubleMatrix1D h_md = np.getVectorMulticastDemandOfferedTraffic(layer);
354                        final DoubleMatrix1D avNoFailure_d = this.availabilityClassicNoFailure_ld.get(layer.getIndex ());
355                        final DoubleMatrix1D survNoFailure_d = this.availabilityWeightedNoFailure_ld.get(layer.getIndex ());
356                        final DoubleMatrix1D avNoFailure_md = this.availabilityClassicNoFailure_lmd.get(layer.getIndex ());
357                        final DoubleMatrix1D survNoFailure_md = this.availabilityWeightedNoFailure_lmd.get(layer.getIndex ());
358                        final DoubleMatrix1D avTotal_d = this.availabilityClassicTotal_ld.get(layer.getIndex ());
359                        final DoubleMatrix1D survTotal_d = this.availabilityWeightedTotal_ld.get(layer.getIndex ());
360                        final DoubleMatrix1D avTotal_md = this.availabilityClassicTotal_lmd.get(layer.getIndex ());
361                        final DoubleMatrix1D survTotal_md = this.availabilityWeightedTotal_lmd.get(layer.getIndex ());
362
363                        out.append ("<ul>");
364                        final double H = h_d.zSum();
365                        val = h_d.size () == 0? 0 : H; out.append ("<li>UNICAST TRAFFIC: (Deterministic) Total offered traffic: " + df_6.format (val) + "</li>");
366                        if (np.getNumberOfDemands (layer) != 0)
367                        {
368                                val = survNoFailure_d.size () == 0? 0 : 1 - (survNoFailure_d.zDotProduct(h_d) / H); out.append ("<li>UNICAST TRAFFIC: (Deterministic) Blocked traffic when no failure occurs: " + df_6.format (val) + "</li>");
369                                val = avTotal_d.size () == 0? 0 : avTotal_d.zDotProduct(h_d) / H; out.append ("<li>UNICAST TRAFFIC: (Estimated) Network availability: " + df_6.format(val) + " - " + df_6.format(val + pi_excess)  + "</li>");
370                                val = survTotal_d.size () == 0? 0 : survTotal_d.zDotProduct(h_d) / H; out.append ("<li>UNICAST TRAFFIC: (Estimated) Network traffic survivability: " + df_6.format(val) + " - " + df_6.format(val + pi_excess) + "</li>");
371                                val = avTotal_d.size () == 0? 0 : avTotal_d.getMinLocation() [0]; out.append ("<li>UNICAST TRAFFIC: (Estimated) Worse availability among demands: " + df_6.format(val) + " - " + df_6.format(val + pi_excess)  + "</li>");
372                                val = survTotal_d.size () == 0? 0 : survTotal_d.getMinLocation() [0]; out.append ("<li>UNICAST TRAFFIC: (Estimated) Worse traffic survivability among demands: " + df_6.format(val) + " - " + df_6.format(val + pi_excess)  + "</li>");
373                        }                       
374                        final double MH = h_md.zSum();
375                        val = h_md.size () == 0? 0 : MH; out.append ("<li>MULTICAST TRAFFIC: (Deterministic) Total offered traffic: " + df_6.format (val) + "</li>");
376                        if (np.getNumberOfMulticastDemands(layer) != 0)
377                        {
378                                val = survNoFailure_md.size () == 0? 0 : 1-(survNoFailure_md.zDotProduct(h_md) / MH); out.append ("<li>MULTICAST TRAFFIC: (Deterministic) Blocked traffic when no failure occurs: " + df_6.format (val) + "</li>");
379                                val = avTotal_md.size () == 0? 0 : avTotal_md.zDotProduct(h_md) / MH; out.append ("<li>MULTICAST TRAFFIC: (Estimated) Network availability: " + df_6.format(val) + " - " + df_6.format(val + pi_excess)  + "</li>");
380                                val = survTotal_md.size () == 0? 0 : survTotal_md.zDotProduct(h_md) /MH; out.append ("<li>MULTICAST TRAFFIC: (Estimated) Network traffic survivability: " + df_6.format(val) + " - " + df_6.format(val + pi_excess) + "</li>");
381                                val = avTotal_md.size () == 0? 0 : avTotal_md.getMinLocation() [0]; out.append ("<li>MULTICAST TRAFFIC: (Estimated) Worse availability among demands: " + df_6.format(val) + " - " + df_6.format(val + pi_excess)  + "</li>");
382                                val = survTotal_md.size () == 0? 0 : survTotal_md.getMinLocation() [0]; out.append ("<li>MULTICAST TRAFFIC: (Estimated) Worse traffic survivability among demands: " + df_6.format(val) + " - " + df_6.format(val + pi_excess)  + "</li>");
383                        }
384                }
385
386                
387                out.append("<h1>PER LAYER INFORMATION DETAILED INFORMATION</h1>");
388                for (NetworkLayer layer : np.getNetworkLayers ())
389                {
390                        out.append("<h2>Layer " + layer.getName () + ", index = " + layer.getIndex () + ", id = " + layer.getId () + "</h2>");
391                        final DoubleMatrix1D avTotal_d = this.availabilityClassicTotal_ld.get(layer.getIndex ());
392                        final DoubleMatrix1D survTotal_d = this.availabilityWeightedTotal_ld.get(layer.getIndex ());
393                        final DoubleMatrix1D avTotal_md = this.availabilityClassicTotal_lmd.get(layer.getIndex ());
394                        final DoubleMatrix1D survTotal_md = this.availabilityWeightedTotal_lmd.get(layer.getIndex ());
395
396                        if (np.getNumberOfDemands(layer) != 0)
397                        {
398                                out.append("<table border='1'>");
399                                out.append("<tr><th><b>Demand</b></th><th><b>Origin node</b></th><th><b>Destination node</b></th><th><b>Availability</b></th><th><b>Traffic survivability</b></th></tr>");
400                                for (Demand d : np.getDemands (layer))
401                                        out.append("<tr><td> " + d.getIndex () + " id (" + d.getId () + ")" + "</td><td>" + d.getIngressNode ().getIndex () + " (" + d.getIngressNode ().getName () + ") </td><td> " + d.getEgressNode().getIndex () + " (" + d.getEgressNode().getName () + ")</td><td>" + avTotal_d.get(d.getIndex()) +" ... " + (avTotal_d.get(d.getIndex()) + pi_excess) + "</td><td>" +  survTotal_d.get(d.getIndex()) + " ... " + (survTotal_d.get(d.getIndex()) + pi_excess) + "</td></tr>");
402                                out.append("</table>");
403        
404                                out.append("<p></p><p></p>");
405                        }
406                        if (np.getNumberOfMulticastDemands(layer) != 0)
407                        {
408                                out.append("<table border='1'>");
409                                out.append("<tr><th><b>Multicast demand</b></th><th><b>Origin node</b></th><th><b>Destination nodes</b></th><th><b>Availability</b></th><th><b>Traffic survivability</b></th></tr>");
410                                for (MulticastDemand d : np.getMulticastDemands (layer))
411                                {
412                                        String egressNodesInfo = ""; for (Node n : d.getEgressNodes()) egressNodesInfo += n.getIndex () + "(" + n.getName () + ") ";
413                                        out.append("<tr><td> " + d.getIndex () + " id (" + d.getId () + ")" + "</td><td>" + d.getIngressNode ().getIndex () + " (" + d.getIngressNode ().getName () + ") </td><td> " + egressNodesInfo + "</td><td>" + avTotal_md.get(d.getIndex())  + " ... " + (avTotal_md.get(d.getIndex()) + pi_excess) + "</td><td>" +  survTotal_md.get(d.getIndex())  + " ... " + (survTotal_md.get(d.getIndex()) + pi_excess) + "</td></tr>");
414                                }
415                                out.append("</table>");
416                        }                       
417                }
418                
419                return out.toString();
420        }
421
422        
423        
424}