Java tutorial
/* * CPAchecker is a tool for configurable software verification. * This file is part of CPAchecker. * * Copyright (C) 2007-2014 Dirk Beyer * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * CPAchecker web page: * http://cpachecker.sosy-lab.org */ package org.sosy_lab.cpachecker.cpa.arg; import static com.google.common.collect.FluentIterable.from; import static org.sosy_lab.cpachecker.util.AbstractStates.IS_TARGET_STATE; import java.io.IOException; import java.io.PrintStream; import java.io.Writer; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.logging.Level; import org.sosy_lab.common.Pair; import org.sosy_lab.common.configuration.Configuration; import org.sosy_lab.common.configuration.FileOption; import org.sosy_lab.common.configuration.InvalidConfigurationException; import org.sosy_lab.common.configuration.Option; import org.sosy_lab.common.configuration.Options; import org.sosy_lab.common.io.Files; import org.sosy_lab.common.io.Path; import org.sosy_lab.common.io.Paths; import org.sosy_lab.cpachecker.core.CPAcheckerResult.Result; import org.sosy_lab.cpachecker.core.CounterexampleInfo; import org.sosy_lab.cpachecker.core.counterexample.CFAPathWithAssignments; import org.sosy_lab.cpachecker.core.counterexample.ConcreteStatePath; import org.sosy_lab.cpachecker.core.counterexample.Model; import org.sosy_lab.cpachecker.core.interfaces.AbstractState; import org.sosy_lab.cpachecker.core.interfaces.ConfigurableProgramAnalysisWithConcreteCex; import org.sosy_lab.cpachecker.core.interfaces.IterationStatistics; import org.sosy_lab.cpachecker.core.reachedset.ReachedSet; import org.sosy_lab.cpachecker.cpa.arg.counterexamples.CEXExporter; import org.sosy_lab.cpachecker.util.CPAs; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableSet; import com.google.common.collect.SetMultimap; @Options(prefix = "cpa.arg") public class ARGStatistics implements IterationStatistics { @Option(secure = true, name = "dumpAfterIteration", description = "Dump all ARG related statistics files after each iteration of the CPA algorithm? (for debugging and demonstration)") private boolean dumpArgInEachCpaIteration = false; @Option(secure = true, name = "export", description = "export final ARG as .dot file") private boolean exportARG = true; @Option(secure = true, name = "file", description = "export final ARG as .dot file") @FileOption(FileOption.Type.OUTPUT_FILE) private Path argFile = Paths.get("ARG.dot"); @Option(secure = true, name = "simplifiedARG.file", description = "export final ARG as .dot file, showing only loop heads and function entries/exits") @FileOption(FileOption.Type.OUTPUT_FILE) private Path simplifiedArgFile = Paths.get("ARGSimplified.dot"); @Option(secure = true, name = "refinements.file", description = "export simplified ARG that shows all refinements to .dot file") @FileOption(FileOption.Type.OUTPUT_FILE) private Path refinementGraphFile = Paths.get("ARGRefinements.dot"); @Option(secure = true, name = "errorPath.export", description = "export error path to file, if one is found") private boolean exportErrorPath = true; private final ARGCPA cpa; private Writer refinementGraphUnderlyingWriter = null; private ARGToDotWriter refinementGraphWriter = null; private final CEXExporter cexExporter; public ARGStatistics(Configuration config, ARGCPA cpa) throws InvalidConfigurationException { this.cpa = cpa; config.inject(this); cexExporter = new CEXExporter(config, cpa.getLogger()); if (argFile == null && simplifiedArgFile == null && refinementGraphFile == null) { exportARG = false; } } ARGToDotWriter getRefinementGraphWriter() { if (!exportARG || refinementGraphFile == null) { return null; } if (refinementGraphWriter == null) { // Open output file for refinement graph, // we continuously write into this file during analysis. // We do this lazily so that the file is written only if there are refinements. try { refinementGraphUnderlyingWriter = Files.openOutputFile(refinementGraphFile); refinementGraphWriter = new ARGToDotWriter(refinementGraphUnderlyingWriter); } catch (IOException e) { if (refinementGraphUnderlyingWriter != null) { try { refinementGraphUnderlyingWriter.close(); } catch (IOException innerException) { e.addSuppressed(innerException); } } cpa.getLogger().logUserException(Level.WARNING, e, "Could not write refinement graph to file"); refinementGraphFile = null; // ensure we won't try again refinementGraphUnderlyingWriter = null; refinementGraphWriter = null; } } // either both are null or none assert (refinementGraphUnderlyingWriter == null) == (refinementGraphWriter == null); return refinementGraphWriter; } @Override public String getName() { return null; // return null because we do not print statistics } @Override public void printStatistics(PrintStream pOut, Result pResult, ReachedSet pReached) { if (!exportARG && !exportErrorPath) { // shortcut, avoid unnecessary creation of path etc. assert refinementGraphWriter == null; return; } final Set<Pair<ARGState, ARGState>> allTargetPathEdges = new HashSet<>(); int cexIndex = 0; for (Map.Entry<ARGState, CounterexampleInfo> cex : getAllCounterexamples(pReached).entrySet()) { cexExporter.exportCounterexample(cex.getKey(), cex.getValue(), cexIndex++, allTargetPathEdges, !cexExporter.shouldDumpErrorPathImmediately()); } if (exportARG) { final ARGState rootState = (ARGState) pReached.getFirstState(); exportARG(rootState, Predicates.in(allTargetPathEdges)); } } private void exportARG(final ARGState rootState, final Predicate<Pair<ARGState, ARGState>> isTargetPathEdge) { SetMultimap<ARGState, ARGState> relevantSuccessorRelation = ARGUtils.projectARG(rootState, ARGUtils.CHILDREN_OF_STATE, ARGUtils.RELEVANT_STATE); Function<ARGState, Collection<ARGState>> relevantSuccessorFunction = Functions .forMap(relevantSuccessorRelation.asMap(), ImmutableSet.<ARGState>of()); if (argFile != null) { try (Writer w = Files.openOutputFile(argFile)) { ARGToDotWriter.write(w, rootState, ARGUtils.CHILDREN_OF_STATE, Predicates.alwaysTrue(), isTargetPathEdge); } catch (IOException e) { cpa.getLogger().logUserException(Level.WARNING, e, "Could not write ARG to file"); } } if (simplifiedArgFile != null) { try (Writer w = Files.openOutputFile(simplifiedArgFile)) { ARGToDotWriter.write(w, rootState, relevantSuccessorFunction, Predicates.alwaysTrue(), Predicates.alwaysFalse()); } catch (IOException e) { cpa.getLogger().logUserException(Level.WARNING, e, "Could not write ARG to file"); } } assert (refinementGraphUnderlyingWriter == null) == (refinementGraphWriter == null); if (refinementGraphUnderlyingWriter != null) { try (Writer w = refinementGraphUnderlyingWriter) { // for auto-closing refinementGraphWriter.writeSubgraph(rootState, relevantSuccessorFunction, Predicates.alwaysTrue(), Predicates.alwaysFalse()); refinementGraphWriter.finish(); } catch (IOException e) { cpa.getLogger().logUserException(Level.WARNING, e, "Could not write refinement graph to file"); } } } private Map<ARGState, CounterexampleInfo> getAllCounterexamples(final ReachedSet pReached) { Map<ARGState, CounterexampleInfo> probableCounterexample = cpa.getCounterexamples(); // This map may contain too many counterexamples // (for target states that were in the mean time removed from the ReachedSet), // as well as too feww counterexamples // (for target states where we don't have a CounterexampleInfo // because we did no refinement). // So we create a map with all target states, // adding the CounterexampleInfo where we have it (null otherwise). Map<ARGState, CounterexampleInfo> counterexamples = new HashMap<>(); for (AbstractState targetState : from(pReached).filter(IS_TARGET_STATE)) { ARGState s = (ARGState) targetState; CounterexampleInfo cex = probableCounterexample.get(s); if (cex == null) { ARGPath path = ARGUtils.getOnePathTo(s); if (path.getInnerEdges().contains(null)) { // path is invalid, // this might be a partial path in BAM, from an intermediate TargetState to root of its ReachedSet. // TODO this check does not avoid dummy-paths in BAM, that might exist in main-reachedSet. } else { Model model = createModelForPath(path); cex = CounterexampleInfo.feasible(path, model); } } if (cex != null) { counterexamples.put(s, cex); } } return counterexamples; } private Model createModelForPath(ARGPath pPath) { FluentIterable<ConfigurableProgramAnalysisWithConcreteCex> cpas = CPAs.asIterable(cpa) .filter(ConfigurableProgramAnalysisWithConcreteCex.class); CFAPathWithAssignments result = null; // TODO Merge different paths for (ConfigurableProgramAnalysisWithConcreteCex wrappedCpa : cpas) { ConcreteStatePath path = wrappedCpa.createConcreteStatePath(pPath); CFAPathWithAssignments cexPath = CFAPathWithAssignments.of(path, cpa.getLogger(), cpa.getMachineModel()); if (result != null) { result = result.mergePaths(cexPath); } else { result = cexPath; } } if (result == null) { return Model.empty(); } else { return Model.empty().withAssignmentInformation(result); } } @Override public void printIterationStatistics(PrintStream pOut, ReachedSet pReached) { if (dumpArgInEachCpaIteration) { printStatistics(pOut, Result.UNKNOWN, pReached); } } }