// SPDX-FileCopyrightText: 2020 Roberto Posenato // // SPDX-License-Identifier: LGPL-3.0-or-later package it.univr.di.cstnu.util; import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.ObjectList; import it.unimi.dsi.fastutil.objects.ObjectObjectImmutablePair; import it.univr.di.cstnu.algorithms.STNU; import it.univr.di.cstnu.graph.*; import org.apache.commons.math3.stat.descriptive.SummaryStatistics; import org.kohsuke.args4j.Option; import org.xml.sax.SAXException; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; /** * Simple class to determine the average execution time (and standard dev) of the STN(U) dispatchability algorithms on a given set of STNUs. *

* The main idea is the following: *

* The algorithms of the MDE family (MDE, MDE*, …) are benchmarked by a dedicated class. * * @author posenato * @version $Rev: 732 $ */ public class DispatchabilityBenchmarkRunner extends AbstractBenchmarkRunner { /** * Each instance of this class represents a set of global statistics. Each global statistics element represents a map * {@code (GlobalStatisticsKey, SummaryStatistics)}. Each SummaryStatistics element allows the determination of different statistics about all added items to the element. */ //formatter:off static private class GlobalStatistics { final Object2ObjectMap FD_STNUExecTimeInSec = new Object2ObjectAVLTreeMap<>(); final Object2ObjectMap FD_STNUNetworkEdges = new Object2ObjectAVLTreeMap<>(); final Object2ObjectMap maxMinEdges = new Object2ObjectAVLTreeMap<>(); final Object2ObjectMap minDispOfFD_STNUExecTimeInSec = new Object2ObjectAVLTreeMap<>(); final Object2ObjectMap minDispOfFD_STNUNetworkEdges = new Object2ObjectAVLTreeMap<>(); final Object2ObjectMap minDispOfMorris2014ExecTimeInSec = new Object2ObjectAVLTreeMap<>(); final Object2ObjectMap minDispOfMorris2014NetworkEdges = new Object2ObjectAVLTreeMap<>(); final Object2ObjectMap morris2014ExecTimeInSec = new Object2ObjectAVLTreeMap<>(); final Object2ObjectMap morris2014NetworkEdges = new Object2ObjectAVLTreeMap<>(); final Object2ObjectMap networkEdges = new Object2ObjectAVLTreeMap<>(); } //formatter:on /** * class logger */ static final Logger LOG = Logger.getLogger(DispatchabilityBenchmarkRunner.class.getName()); /** * Global header */ //@formatter:off static final String GLOBAL_HEADER = "%n%nGlobal statistics%n" // + "#networks" + CSVSep // + "#nodes" + CSVSep // + "#contingents" + CSVSep// + "#avgEdges" + CSVSep // + "stdDevEdges" + CSVSep // + "avgExeTimeMorris2014[s]" + CSVSep// + "stdDevExeTimeMorris2014[s]" + CSVSep// + "avgEdgesMorris2014" + CSVSep // + "stdDevEdgesMorris2014" + CSVSep// + "avnExeTimeMinDispESTNU_Morris[s]" + CSVSep// + "stdDevExeTimeMinDispESTNU_Morris[s]" + CSVSep// + "avgEdgesMinDispESTNU_Morris" + CSVSep // + "stdDevEdgesMinDispESTNU_Morris" + CSVSep// + "avgExeTimeFD_STNU[s]" + CSVSep // + "stdDevFD_STNU[s]" + CSVSep // + "avgEdgesFD_STNU" + CSVSep// + "stdDevEdgesFD_STNU" + CSVSep// + "avgExeTimeMinDispESTNU_FD_STNU[s]" + CSVSep// + "stdDevMinDispESTNU_FD_STNU[s]" + CSVSep // + "avgEdgesMinDispESTNU_FD_STNU" + CSVSep // + "stdDevEdgesMinDispESTNU_FD_STNU" + CSVSep// + "avgMaxMinEdges" + CSVSep // + "%n";// /** * */ static final String GLOBAL_HEADER_ROW = "%d" + CSVSep // + "%d" + CSVSep // + "%d" + CSVSep // + "%E" + CSVSep // avgEdges + "%E" + CSVSep // avgEdges std.dev. + "%E" + CSVSep // Morris2014 avgExe + "%E" + CSVSep // Morris2014 ExeTime std.dev. + "%E" + CSVSep // Morris2014 avgEdges + "%E" + CSVSep // Morris2014 Edges std.dev. + "%E" + CSVSep // minDispESTNU(Morris) avgExeTime + "%E" + CSVSep // minDispESTNU(Morris) ExeTime std.dev. + "%E" + CSVSep // minDispESTNU(Morris) avgEdges + "%E" + CSVSep // minDispESTNU(Morris) Edges std.dev. + "%E" + CSVSep // FD_STNU avgExeTime + "%E" + CSVSep // FD_STNU ExeTime std.dev. + "%E" + CSVSep // FD_STNU avgEdges + "%E" + CSVSep // FD_STNU Edges std.dev. + "%E" + CSVSep // minDispESTNU(FD_STNU) avgExeTime + "%E" + CSVSep // minDispESTNU(FD_STNU) ExeTime std.dev. + "%E" + CSVSep // minDispESTNU(FD_STNU) avgEdges + "%E" + CSVSep // minDispESTNU(FD_STNU) Edges std.dev. + "%E" + CSVSep // avgMaxMinEdges + "%n"; /** * Output file header */ static final String OUTPUT_HEADER = "fileName" + CSVSep // + "#nodes" + CSVSep// + "#contingents" + CSVSep // + "#edges" + CSVSep // + "Morris2014 avgExeTime[s]" + CSVSep // + "std.dev.[s]" + CSVSep // + "Morris2014 #edges" + CSVSep// + "DC Morris2014" + CSVSep // + "minDispESTNU(Morris) avgExeTime[s]" + CSVSep // + "std.dev." + CSVSep // + "minDispESTNU(Morris) #edges" + CSVSep // + "maxMinEdgesMorris" + CSVSep // + "FD_STNU avgExeTime[s]" + CSVSep // + "std.dev.[s]" + CSVSep // + "FD_STNU #edges" + CSVSep// + "DC FD_STNU" + CSVSep // + "minDispESTNU(FD_STNU) avgExeTime[s]" + CSVSep// + "std.dev." + CSVSep // + "minDispESTNU(FD_STNU) #edges" + CSVSep// + "maxMinEdgesFD"; /** * OUTPUT_ROW is split in OUTPUT_ROW_GRAPH + [OUTPUT_ROW_ALG_STATS]{4} */ static final String OUTPUT_ROW_GRAPH = "%s" + CSVSep // + "%d" + CSVSep // + "%d" + CSVSep // + "%d" + CSVSep;// /** * OUTPUT_ROW is split in OUTPUT_ROW_GRAPH + [OUTPUT_ROW_ALG_STATS]{4} */ static final String OUTPUT_ROW_ALG_STATS = "%E" + CSVSep // alg avgExe + "%E" + CSVSep // alg avgExe dev std + "%d" + CSVSep // alg #edges + "%s" + CSVSep; // alg status /** * Row fragment used for an algorithm that was not selected. */ static final String NOT_EXECUTED_STATS = String.format(OUTPUT_ROW_ALG_STATS, Double.valueOf(Double.NaN), Double.valueOf(Double.NaN), Integer.valueOf(0), "NOT EXECUTED"); //@formatter:on /** * Version */ // static final String VERSIONandDATE = "1.0, December, 01 2023"; // static final String VERSIONandDATE = "2.0, February 07, 2025";// added the possibility to test 'minDispatchableESTNU4Diamonds' // static final String VERSIONandDATE = "3.0, December 07, 2025";// added MDE check static final String VERSIONandDATE = "4.0, July 17, 2026";// removed MDE (the MDE family will be benchmarked by a dedicated class); rationalized testers /** * Allows checking the execution time of algorithms on a set of instances. * * @param args an array of {@link String} objects. */ public static void main(String[] args) { LOG.finest("Checker " + VERSIONandDATE + "\nStart..."); System.out.println("Checker " + VERSIONandDATE + "\n" + getNow() + ": Start of execution."); final DispatchabilityBenchmarkRunner tester = new DispatchabilityBenchmarkRunner(); if (tester.manageParameters(args)) { return; } LOG.finest("Parameters ok!"); if (tester.versionReq) { return; } LOG.finest("minDispatchable4Diamonds: " + tester.minDispatchable4Diamonds); /* * To collect statistics w.r.t. the dimension of networks */ final GlobalStatistics globalStatistics = new GlobalStatistics(); final RunMeter runMeter = new RunMeter(System.currentTimeMillis(), tester.instances.size(), 0); runMeter.printProgress(0); tester.output.println("*".repeat(79)); tester.output.println("* Trial date: " + getNow()); tester.output.println("*".repeat(79)); if (tester.minDispatchable4Diamonds) { tester.output.println("\nThe following statistics labeled by `MinDispESTNU[.*]` are determined using the STNU.applyBetterMinDispESTNU(true) method, i.e., applyBetterMinDispESTNU optimized for STNUs having diamonds.\n"); tester.output.println("-".repeat(79)); } tester.output.println(OUTPUT_HEADER); tester.output.flush(); int nTaskSuccessfullyFinished = 0; for (final File file : tester.instances) { if (tester.worker(file, runMeter, globalStatistics)) { nTaskSuccessfullyFinished++; } } final String msg = "Number of instances processed successfully over total: " + nTaskSuccessfullyFinished + "/" + tester.instances.size() + "."; LOG.info(msg); System.out.println("\n" + getNow() + ": " + msg); tester.output.printf(GLOBAL_HEADER); // Use one of the elements in globalStatistics to extract all the possible globalStatisticsKeys for (final Object2ObjectMap.Entry entryNetworkEdges : globalStatistics.networkEdges.object2ObjectEntrySet()) { // @formatter:off final GlobalStatisticsKey globalStatisticsKey = entryNetworkEdges.getKey(); tester.output.printf(GLOBAL_HEADER_ROW, Long.valueOf(entryNetworkEdges.getValue().getN()), Integer.valueOf(globalStatisticsKey.nodes()), Integer.valueOf(globalStatisticsKey.contingents()), Double.valueOf(entryNetworkEdges.getValue().getMean()), Double.valueOf(entryNetworkEdges.getValue().getStandardDeviation()), Double.valueOf(globalStatistics.morris2014ExecTimeInSec.get(globalStatisticsKey).getMean()), Double.valueOf(globalStatistics.morris2014ExecTimeInSec.get(globalStatisticsKey).getStandardDeviation()), Double.valueOf(globalStatistics.morris2014NetworkEdges.get(globalStatisticsKey).getMean()), Double.valueOf(globalStatistics.morris2014NetworkEdges.get(globalStatisticsKey).getStandardDeviation()), Double.valueOf(globalStatistics.minDispOfMorris2014ExecTimeInSec.get(globalStatisticsKey).getMean()), Double.valueOf(globalStatistics.minDispOfMorris2014ExecTimeInSec.get(globalStatisticsKey).getStandardDeviation()), Double.valueOf(globalStatistics.minDispOfMorris2014NetworkEdges.get(globalStatisticsKey).getMean()), Double.valueOf(globalStatistics.minDispOfMorris2014NetworkEdges.get(globalStatisticsKey).getStandardDeviation()), Double.valueOf(globalStatistics.FD_STNUExecTimeInSec.get(globalStatisticsKey).getMean()), Double.valueOf(globalStatistics.FD_STNUExecTimeInSec.get(globalStatisticsKey).getStandardDeviation()), Double.valueOf(globalStatistics.FD_STNUNetworkEdges.get(globalStatisticsKey).getMean()), Double.valueOf(globalStatistics.FD_STNUNetworkEdges.get(globalStatisticsKey).getStandardDeviation()), Double.valueOf(globalStatistics.minDispOfFD_STNUExecTimeInSec.get(globalStatisticsKey).getMean()), Double.valueOf(globalStatistics.minDispOfFD_STNUExecTimeInSec.get(globalStatisticsKey).getStandardDeviation()), Double.valueOf(globalStatistics.minDispOfFD_STNUNetworkEdges.get(globalStatisticsKey).getMean()), Double.valueOf(globalStatistics.minDispOfFD_STNUNetworkEdges.get(globalStatisticsKey).getStandardDeviation()), Double.valueOf(globalStatistics.maxMinEdges.get(globalStatisticsKey).getMean()) ); // @formatter:on } tester.output.printf("%n%n%n"); tester.output.close(); } /** * Check a STNU instance using the Morris algorithm */ @Option(name = "--fd", usage = "Check a STNU instance using FD_STNU.") private boolean fd_stnu; /** * Determine the minimal dispatchable form */ @Option(name = "--minDisp4Diamonds", usage = "Determine the minimal dispatchable ESTNU of a DC dispatchable instance. The input must a dispatchable instance. This version of algorithm is suitable when the network contains many diamond structures.") private boolean minDispatchable4Diamonds; /** * Determine min dispatchable. */ @Option(name = "--minFD", usage = "Execute the min dispatchable ESTNU after FD_STNU check.") private boolean minDispatchableFD; /** * Determine min dispatchable. */ @Option(name = "--minMorris", usage = "Execute the min dispatchable ESTNU after Morris2014.") private boolean minDispatchableMorris; /** * Check a STNU instance using the Morris algorithm */ @Option(name = "--morris", usage = "Check a STNU instance using Morris2014Dispatchable.") private boolean morris2014; /** * Parameter for reusing previously checked STNU instances in the minimization phase. */ @Option(name = "--reuseFDCheckedSTNU", depends = "--minFD", usage = "Suffix of the file representing the already dispatchable instance (made by FD_STNU) to use in the minimization phase. Such a parameter can be used when --minFD [--minDisp4Diamonds] is specified. Example: if the instance is named 'stnu000.stnu' and the dispatchable instance 'stnu000.FD_STNU-checked.stnu'; This parameter must be '.FD_STNU-checked.stnu' to use the saved instance 'stnu000.FD_STNU-checked.-minimized.stnu'") private String reuseFDCheckedSTNU; /** * Parameter for reusing previously checked STNU instances in the minimization phase. */ @Option(name = "--reuseMorrisCheckedSTNU", depends = "--minMorris", usage = "Suffix of the file representing the already dispatchable instance (made by Morris) to use in the minimization phase. Such a parameter can be used when --minMorris [--minDisp4Diamonds] is specified. Example: if the instance is named 'stnu000.stnu' and the dispatchable instance 'stnu000.Morris2014Dispatchable-checked.stnu'; This parameter must be '.Morris2014Dispatchable-checked.stnu' to use the saved instance 'stnu000.Morris2014Dispatchable-checked.-minimized.stnu'") private String reuseMorrisCheckedSTNU; @Override String getVersionAndDate() { return VERSIONandDATE; } /** * Checks that the minimization options are consistent with the DC-check options. * * @return null if consistent; the error message otherwise. */ @Override @Nullable String validateAlgorithmOptions() { if (minDispatchableMorris && !morris2014 && reuseMorrisCheckedSTNU == null) { return "--minMorris requires --morris or --reuseMorrisCheckedSTNU because the minimization works on a network already made dispatchable."; } if (minDispatchableFD && !fd_stnu && reuseFDCheckedSTNU == null) { return "--minFD requires --fd or --reuseFDCheckedSTNU because the minimization works on a network already made dispatchable."; } return null; } /** * Builds the {@link #OUTPUT_ROW_ALG_STATS} fragment corresponding to {@code outcome} and updates the global statistics. *

* On success, the average and the standard deviation of the execution times are stored in the check status of the tested instance, the average is * added to {@code gExecTimeInSec}, and the number of edges of the resulting network is added to {@code gNetworkEdges}. On timeout, {@link #timeOut} * is added to {@code gExecTimeInSec} and nothing is added to {@code gNetworkEdges}; on any other failure, no global statistic is updated. * * @param outcome outcome of the repetitions. * @param successStatusString string to print in the last field of the fragment when the executions were successful. * @param gExecTimeInSec global statistics of the execution times. * @param gNetworkEdges global statistics of the number of edges of the resulting networks. * * @return the fragment to append to the row of the statistics file. */ private String algStatsFragment(@Nonnull RepetitionOutcome outcome, @Nonnull String successStatusString, @Nonnull SummaryStatistics gExecTimeInSec, @Nonnull SummaryStatistics gNetworkEdges) { //Claude optimized final STNU.STNUCheckStatus status = outcome.stnu.getCheckStatus(); final int nEdges = outcome.stnu.getGraph().getEdgeCount(); if (status.timeout || outcome.interrupted) { if (status.timeout) { gExecTimeInSec.addValue(timeOut); } return String.format(OUTPUT_ROW_ALG_STATS, Double.valueOf(nanoSeconds2Seconds(status.executionTimeNS)), Double.valueOf(Double.NaN), // in the case of a failure, at most one time is available Integer.valueOf(nEdges), (status.timeout) ? "Timeout of " + timeOut + " seconds." : outcome.error); } status.executionTimeNS = (long) outcome.executionTimeNS.getMean(); status.stdDevExecutionTimeNS = (long) outcome.executionTimeNS.getStandardDeviation(); final double localAvgInSec = nanoSeconds2Seconds(status.executionTimeNS); final double localStdDevInSec = nanoSeconds2Seconds(status.stdDevExecutionTimeNS); gExecTimeInSec.addValue(localAvgInSec); gNetworkEdges.addValue(nEdges); return String.format(OUTPUT_ROW_ALG_STATS, Double.valueOf(localAvgInSec), Double.valueOf((nDCRepetition > 1) ? localStdDevInSec : Double.NaN), Integer.valueOf(nEdges), successStatusString); } /** * Checks the STNU {@link #nDCRepetition} times using {@code stnuCheckAlgorithm}, each time on a fresh copy of the current graph of {@code stnu}. * Then, it adds statistics to gExecTimeInSec and gNetworkEdges. It returns the string representing the ({@link #OUTPUT_ROW_ALG_STATS}) part to add * to the row in the statistics file. *

* At the end, {@code stnu} contains the graph produced by the last repetition of the check. */ private String dcCheckTester(@Nonnull STNU stnu, @Nonnull STNU.CheckAlgorithm stnuCheckAlgorithm, @Nonnull SummaryStatistics gExecTimeInSec, @Nonnull SummaryStatistics gNetworkEdges) { //Claude optimized final TemporalConstraintGraph graphToCheck = stnu.getGraph(); final String fileName = Objects.requireNonNull(graphToCheck.getInputFile()).getName(); final RepetitionOutcome outcome = repeatMeasure(fileName, "DC check (" + stnuCheckAlgorithm + ")", () -> { // It is necessary to reset the graph! stnu.setG(graphToCheck.newInstance(graphToCheck)); return stnu; }, (s) -> { s.dynamicControllabilityCheck(stnuCheckAlgorithm); return true; }); final STNU.STNUCheckStatus status = outcome.stnu.getCheckStatus(); final String fragment = algStatsFragment(outcome, (status.consistency) ? "TRUE" : "FALSE", gExecTimeInSec, gNetworkEdges); if (!status.timeout && !outcome.interrupted) { LOG.info(fileName + " has been checked (algorithm ends in a stable state): " + status.finished + "\n" + fileName + " is DC: " + status.consistency + "\n" + fileName + " average checking time [s]: " + nanoSeconds2Seconds(status.executionTimeNS) + "\n" + fileName + " std. deviation [s]: " + nanoSeconds2Seconds(status.stdDevExecutionTimeNS)); if (status.consistency && this.save) { // save the result final String outFileName = fileName.substring(0, fileName.length() - 4) + stnuCheckAlgorithm + "-checked.stnu"; outcome.stnu.setfOutput(new File(outFileName)); outcome.stnu.saveGraphToFile(); } } return fragment; } /** * Determines the minDispatchESTNU of stnu {@link #nDCRepetition} times, each time on a fresh copy of {@code inputSTNU}, without modifying it. * Then, it adds statistics to gExecTimeInSec, gNetworkEdges, and (if not null) gMaxMinEdges, fills {@code minimizedGraph} with the minimized * network, and returns the string representing the ({@link #OUTPUT_ROW_ALG_STATS}) part to add to the row in the statistics file. * * @param inputSTNU input DC checked and dispatchable STNU * @param gExecTimeInSec global statistics of the execution times * @param gNetworkEdges global statistics of the number of edges of the minimized networks * @param gMaxMinEdges global statistics of the maxMinConstraint values; null if it must not be updated * @param minimizedGraph graph that will contain the minimized dispatchable STNU * @param isFD true if the inputSTNU was checked by the FD_STNU algorithm * @param inputMinDispatchable4Diamonds true if the minDispatch algorithm suited for managing diamonds in the instance must be used. */ @SuppressWarnings("deprecation") // deprecation: inputSTNU.getG() and outcome.stnu.getGChecked() below are genuinely dense: the // only use is DenseTCGraph#getFileName() (no generic counterpart) and DenseTCGraph#takeFrom(DenseTCGraph) // (dense-only, and minimizedGraph is itself declared DenseTCGraph by this method's contract). private String minDispatcherTester(@Nonnull STNU inputSTNU, @Nonnull SummaryStatistics gExecTimeInSec, @Nonnull SummaryStatistics gNetworkEdges, @Nullable SummaryStatistics gMaxMinEdges, @Nonnull DenseTCGraph minimizedGraph, boolean isFD, boolean inputMinDispatchable4Diamonds) { //Claude optimized String fileName = inputSTNU.getG().getFileName().getName(); if (this.reuseFDCheckedSTNU != null || this.reuseMorrisCheckedSTNU != null) { final DenseTCGraph graphToCheck; final TCGraphMLReader graphMLReader = new TCGraphMLReader<>(); String checkedFileName = fileName.substring(0, fileName.length() - 5); if (!isFD && this.reuseMorrisCheckedSTNU != null) { checkedFileName += this.reuseMorrisCheckedSTNU; } if (isFD && this.reuseFDCheckedSTNU != null) { checkedFileName += this.reuseFDCheckedSTNU; } final File file = new File(checkedFileName); fileName = checkedFileName; try { graphToCheck = graphMLReader.readGraph(file, currentEdgeImplClass); } catch (IOException | ParserConfigurationException | SAXException e2) { final String msg = "File " + file.getName() + " cannot be found or parsed. Details: " + e2.getMessage() + ".\nIgnored."; LOG.warning(msg); System.err.println(msg); return String.format(OUTPUT_ROW_ALG_STATS, Double.valueOf(Double.NaN), Double.valueOf(Double.NaN), Integer.valueOf(0), "STNU cannot be found or parsed. Ignored"); } inputSTNU = new STNU(graphToCheck); //We have to ensure that the network has already been checked. try { inputSTNU.initAndCheck(); } catch (Exception e) { final String msg = getNow() + ": " + file.getName() + " is not a not well-defined instance. Details:" + e.getMessage() + "\nIgnored."; System.err.println(msg); LOG.severe(msg); return String.format(OUTPUT_ROW_ALG_STATS, Double.valueOf(Double.NaN), Double.valueOf(Double.NaN), Integer.valueOf(0), "STNU is not well-defined. Ignored."); } final STNU.STNUCheckStatus status = inputSTNU.getCheckStatus(); status.consistency = true; status.setCheckAlgorithm((isFD) ? STNU.CheckAlgorithm.FD_STNU : STNU.CheckAlgorithm.Morris2014Dispatchable); } final STNU baseSTNU = inputSTNU; // It is necessary to reset the network at each repetition: the minimization runs on a fresh copy of the input STNU. // A repetition returning false (not minimized) is considered failed and does not contribute to the time statistics. final RepetitionOutcome outcome = repeatMeasure(fileName, "minDispatch", () -> new STNU(baseSTNU), (s) -> s.applyBetterMinDispESTNU(inputMinDispatchable4Diamonds)); final STNU.STNUCheckStatus status = outcome.stnu.getCheckStatus(); final String fragment = algStatsFragment(outcome, String.valueOf(status.getMaxMinConstraint()), gExecTimeInSec, gNetworkEdges); if (!status.timeout && !outcome.interrupted) { LOG.info("%s has been minimized.".formatted(fileName)); LOG.info("%s average execution time [s]: %s".formatted(fileName, nanoSeconds2Seconds(status.executionTimeNS))); LOG.info("%s std. deviation [s]: %s".formatted(fileName, nanoSeconds2Seconds(status.stdDevExecutionTimeNS))); minimizedGraph.takeFrom(outcome.stnu.getGChecked()); if (gMaxMinEdges != null) { gMaxMinEdges.addValue(status.getMaxMinConstraint()); } if (this.save) { // save the result final String outFileName = fileName.substring(0, fileName.length() - 5) + ((this.minDispatchable4Diamonds) ? "-minimized4Diamonds.stnu" : "-minimized.stnu"); outcome.stnu.setfOutput(new File(outFileName)); outcome.stnu.saveGraphToFile(); } } return fragment; } /** * Loads the file and executes all the actions (specified as instance parameters) on the network represented by the file. * * @param file input file * @param runState current state * @param globalStatistics global statistics * * @return true if the required task ends successfully, false otherwise. */ private boolean worker(@Nonnull File file, @Nonnull RunMeter runState, @Nonnull GlobalStatistics globalStatistics) { //Claude optimized if (LOG.isLoggable(Level.FINER)) { LOG.finer("Loading " + file.getName() + "..."); } final TCGraphMLReader graphMLReader = new TCGraphMLReader<>(); final DenseTCGraph graphToCheck; try { graphToCheck = graphMLReader.readGraph(file, currentEdgeImplClass); } catch (IOException | ParserConfigurationException | SAXException e2) { final String msg = "File " + file.getName() + " cannot be parsed. Details: " + e2.getMessage() + ".\nIgnored."; LOG.warning(msg); System.out.println(msg); return false; } LOG.finer("...done!"); // NODES and EDGES in the original graph. DO NOT MOVE such a variable. final int nNodes = graphToCheck.getVertexCount(); final int nEdges = graphToCheck.getEdgeCount(); final STNU stnu; stnu = makeSTNUInstance(graphToCheck); try { stnu.initAndCheck(); } catch (Exception e) { final String msg = getNow() + ": " + file.getName() + " is not a not well-defined instance. Details:" + e.getMessage() + "\nIgnored."; System.out.println(msg); LOG.severe(msg); return false; } final STNU stnuCopy = new STNU(stnu);// for FD! // Only now, the contingent node number is significant final int nContingents = graphToCheck.getContingentNodeCount(); final GlobalStatisticsKey globalStatisticsKey = new GlobalStatisticsKey(nNodes, nContingents); // The statistics of the key are created also for the not-selected algorithms: // the global-statistics printing in main() assumes that every map has an entry for every key (empty statistics print NaN). getOrCreateStats(globalStatistics.networkEdges, globalStatisticsKey).addValue(nEdges); final SummaryStatistics gMorris2014ExecTimeInSec = getOrCreateStats(globalStatistics.morris2014ExecTimeInSec, globalStatisticsKey); final SummaryStatistics gMorris2014NetworkEdges = getOrCreateStats(globalStatistics.morris2014NetworkEdges, globalStatisticsKey); final SummaryStatistics gMinDispOfMorris2014ExecTimeInSec = getOrCreateStats(globalStatistics.minDispOfMorris2014ExecTimeInSec, globalStatisticsKey); final SummaryStatistics gMinDispOfMorris2014NetworkEdges = getOrCreateStats(globalStatistics.minDispOfMorris2014NetworkEdges, globalStatisticsKey); final SummaryStatistics gFD_STNUExecTimeInSec = getOrCreateStats(globalStatistics.FD_STNUExecTimeInSec, globalStatisticsKey); final SummaryStatistics gFD_STNUNetworkEdges = getOrCreateStats(globalStatistics.FD_STNUNetworkEdges, globalStatisticsKey); final SummaryStatistics gMinDispOfFD_STNUExecTimeInSec = getOrCreateStats(globalStatistics.minDispOfFD_STNUExecTimeInSec, globalStatisticsKey); final SummaryStatistics gMinDispOfFD_STNUNetworkEdges = getOrCreateStats(globalStatistics.minDispOfFD_STNUNetworkEdges, globalStatisticsKey); final SummaryStatistics gMaxMinEdges = getOrCreateStats(globalStatistics.maxMinEdges, globalStatisticsKey); final StringBuilder rowToWrite = new StringBuilder(String.format(OUTPUT_ROW_GRAPH, file.getName(), Integer.valueOf(nNodes), Integer.valueOf(nContingents), Integer.valueOf(nEdges))); if (this.morris2014) { LOG.info(getNow() + ": Morris2014Dispatchable: start."); rowToWrite.append(dcCheckTester(stnu, STNU.CheckAlgorithm.Morris2014Dispatchable, gMorris2014ExecTimeInSec, gMorris2014NetworkEdges)); } else { rowToWrite.append(NOT_EXECUTED_STATS); } final DenseTCGraph morrisMinimized = new DenseTCGraph<>("morrisMinimized", currentEdgeImplClass); if (this.minDispatchableMorris) { LOG.info(getNow() + ": MinDispatchable of Morris2014Dispatchable: start."); rowToWrite.append(minDispatcherTester(stnu, gMinDispOfMorris2014ExecTimeInSec, gMinDispOfMorris2014NetworkEdges, null, morrisMinimized, false, this.minDispatchable4Diamonds)); } else { rowToWrite.append(NOT_EXECUTED_STATS); } // use the second stnu to check with FD if (this.fd_stnu) { LOG.info(getNow() + ": FD_STNU: start."); rowToWrite.append(dcCheckTester(stnuCopy, STNU.CheckAlgorithm.FD_STNU, gFD_STNUExecTimeInSec, gFD_STNUNetworkEdges)); } else { rowToWrite.append(NOT_EXECUTED_STATS); } final DenseTCGraph ftMinimized = new DenseTCGraph<>("fdMinimized", currentEdgeImplClass); if (this.minDispatchableFD) { LOG.info(getNow() + ": MinDispatchable of FD_STNU: start."); rowToWrite.append(minDispatcherTester(stnuCopy, gMinDispOfFD_STNUExecTimeInSec, gMinDispOfFD_STNUNetworkEdges, gMaxMinEdges, ftMinimized, true, this.minDispatchable4Diamonds)); } else { rowToWrite.append(NOT_EXECUTED_STATS); } if (this.minDispatchableMorris && this.minDispatchableFD) { final ObjectList> differentEdges = morrisMinimized.differentEdgesOf(ftMinimized); if (differentEdges.size() > 0) { System.err.println("Different edges are: " + differentEdges.size() + ":\n" + differentEdges); } } output.println(rowToWrite); output.flush(); runState.printProgress(); return true; } }