/// <summary> /// Initializes a new instance. /// </summary> /// <param name="runtimeModelCreator">A factory function that creates the model instance that should be executed.</param> /// <param name="formulas">The formulas that should be evaluated for each state.</param> /// <param name="configuration">The analysis configuration that should be used.</param> /// <param name="stateHeaderBytes"> /// The number of bytes that should be reserved at the beginning of each state vector for the model checker tool. /// </param> internal ActivationMinimalExecutedModel(CoupledExecutableModelCreator <TExecutableModel> runtimeModelCreator, int stateHeaderBytes, Func <bool>[] formulas, AnalysisConfiguration configuration) : base(runtimeModelCreator, stateHeaderBytes, configuration) { formulas = formulas ?? RuntimeModel.Formulas.Select(formula => FormulaCompilationVisitor <TExecutableModel> .Compile(RuntimeModel, formula)).ToArray(); _transitions = new ActivationMinimalTransitionSetBuilder <TExecutableModel>(TemporaryStateStorage, configuration.SuccessorCapacity, formulas); _stateConstraints = RuntimeModel.StateConstraints; bool useForwardOptimization; switch (configuration.MomentOfIndependentFaultActivation) { case MomentOfIndependentFaultActivation.AtStepBeginning: case MomentOfIndependentFaultActivation.OnFirstMethodWithoutUndo: useForwardOptimization = false; break; case MomentOfIndependentFaultActivation.OnFirstMethodWithUndo: useForwardOptimization = true; break; default: throw new ArgumentOutOfRangeException(); } ChoiceResolver = new NondeterministicChoiceResolver(useForwardOptimization); FaultSet.CheckFaultCount(RuntimeModel.Faults.Length); RuntimeModel.SetChoiceResolver(ChoiceResolver); _allowFaultsOnInitialTransitions = configuration.AllowFaultsOnInitialTransitions; }
/// <summary> /// Initializes a new instance. /// </summary> /// <param name="runtimeModelCreator">A factory function that creates the model instance that should be executed.</param> /// <param name="formulas">The formulas that should be evaluated for each state.</param> /// <param name="configuration">The analysis configuration that should be used.</param> /// <param name="stateHeaderBytes"> /// The number of bytes that should be reserved at the beginning of each state vector for the model checker tool. /// </param> internal ActivationMinimalExecutedModel(CoupledExecutableModelCreator <TExecutableModel> runtimeModelCreator, int stateHeaderBytes, Func <bool>[] formulas, AnalysisConfiguration configuration) : base(runtimeModelCreator, stateHeaderBytes, configuration) { formulas = formulas ?? RuntimeModel.Formulas.Select(formula => FormulaCompilationVisitor <TExecutableModel> .Compile(RuntimeModel, formula)).ToArray(); _transitions = new ActivationMinimalTransitionSetBuilder <TExecutableModel>(TemporaryStateStorage, configuration.SuccessorCapacity, formulas); _stateConstraints = RuntimeModel.StateConstraints; var useForwardOptimization = configuration.EnableStaticPruningOptimization; ChoiceResolver = new NondeterministicChoiceResolver(useForwardOptimization); FaultSet.CheckFaultCount(RuntimeModel.Faults.Length); RuntimeModel.SetChoiceResolver(ChoiceResolver); _allowFaultsOnInitialTransitions = configuration.AllowFaultsOnInitialTransitions; }
/// <summary> /// Computes the minimal critical sets for the <paramref name="hazard" />. /// </summary> /// <param name="model">The model the safety analysis should be conducted for.</param> /// <param name="hazard">The hazard the minimal critical sets should be computed for.</param> /// <param name="maxCardinality"> /// The maximum cardinality of the fault sets that should be checked. By default, all minimal /// critical fault sets are determined. /// </param> public Result ComputeMinimalCriticalSets(ModelBase model, Formula hazard, int maxCardinality = Int32.MaxValue) { Requires.NotNull(model, nameof(model)); Requires.NotNull(hazard, nameof(hazard)); _modelChecker.Configuration = Configuration; ConsoleHelpers.WriteLine("Running Deductive Cause Consequence Analysis."); var stopwatch = new Stopwatch(); stopwatch.Start(); var allFaults = model.Faults; FaultSet.CheckFaultCount(allFaults.Length); var forcedFaults = allFaults.Where(fault => fault.Activation == Activation.Forced).ToArray(); var suppressedFaults = allFaults.Where(fault => fault.Activation == Activation.Suppressed).ToArray(); var nondeterministicFaults = allFaults.Where(fault => fault.Activation == Activation.Nondeterministic).ToArray(); var suppressedSet = new FaultSet(suppressedFaults); var forcedSet = new FaultSet(forcedFaults); var isComplete = true; var safeSets = new HashSet <FaultSet>(); var criticalSets = new HashSet <FaultSet>(); var checkedSets = new HashSet <FaultSet>(); var counterExamples = new Dictionary <FaultSet, CounterExample>(); var exceptions = new Dictionary <FaultSet, Exception>(); // Store the serialized model to improve performance var serializer = new RuntimeModelSerializer(); serializer.Serialize(model, !hazard); // We check fault sets by increasing cardinality; this is, we check the empty set first, then // all singleton sets, then all sets with two elements, etc. We don't check sets that we // know are going to be critical sets due to monotonicity for (var cardinality = 0; cardinality <= allFaults.Length; ++cardinality) { // Generate the sets for the current level that we'll have to check var sets = GeneratePowerSetLevel(safeSets, criticalSets, cardinality, allFaults); // Clear the safe sets, we don't need the previous level to generate the next one safeSets.Clear(); // If there are no sets to check, we're done; this happens when there are so many critical sets // that this level does not contain any set that is not a super set of any of those critical sets if (sets.Count == 0) { break; } // Remove all sets that conflict with the forced or suppressed faults; these sets are considered to be safe. // If no sets remain, skip to the next level sets = RemoveInvalidSets(sets, suppressedSet, forcedSet, safeSets); if (sets.Count == 0) { continue; } // Abort if we've exceeded the maximum fault set cardinality; doing the check here allows us // to report the analysis as complete if the maximum cardinality is never reached if (cardinality > maxCardinality) { isComplete = false; break; } if (cardinality == 0) { ConsoleHelpers.WriteLine("Checking the empty fault set..."); } else { ConsoleHelpers.WriteLine($"Checking {sets.Count} sets of cardinality {cardinality}..."); } // We have to check each set; if one of them is a critical set, it has no effect on the other // sets we have to check foreach (var set in sets) { // Enable or disable the faults that the set represents set.SetActivation(nondeterministicFaults); // If there was a counter example, the set is a critical set try { var result = _modelChecker.CheckInvariant(CreateRuntimeModel(serializer, allFaults)); if (!result.FormulaHolds) { ConsoleHelpers.WriteLine($" critical: {{ {set.ToString(allFaults)} }}", ConsoleColor.DarkRed); criticalSets.Add(set); } else { safeSets.Add(set); } checkedSets.Add(set); if (result.CounterExample != null) { counterExamples.Add(set, result.CounterExample); } } catch (AnalysisException e) { ConsoleHelpers.WriteLine($" critical: {{ {set.ToString(allFaults)} }} [exception thrown]", ConsoleColor.DarkRed); checkedSets.Add(set); criticalSets.Add(set); exceptions.Add(set, e.InnerException); if (e.CounterExample != null) { counterExamples.Add(set, e.CounterExample); } } } } // Reset the nondeterministic faults so as to not influence subsequent analyses foreach (var fault in nondeterministicFaults) { fault.Activation = Activation.Nondeterministic; } return(new Result( model, isComplete, criticalSets, checkedSets, allFaults, suppressedFaults, forcedFaults, counterExamples, exceptions, stopwatch.Elapsed)); }
/// <summary> /// Computes the minimal critical sets for the <paramref name="hazard" />. /// </summary> /// <param name="createModel">The creator for the model that should be checked.</param> /// <param name="hazard">The hazard the minimal critical sets should be computed for.</param> /// <param name="maxCardinality"> /// The maximum cardinality of the fault sets that should be checked. By default, all minimal /// critical fault sets are determined. /// </param> public SafetyAnalysisResults <TExecutableModel> ComputeMinimalCriticalSets(CoupledExecutableModelCreator <TExecutableModel> createModel, Formula hazard, int maxCardinality = Int32.MaxValue) { Requires.NotNull(createModel, nameof(createModel)); Requires.NotNull(hazard, nameof(hazard)); ConsoleHelpers.WriteLine("Running Deductive Cause Consequence Analysis."); var heuristicWatch = new Stopwatch(); var stopwatch = new Stopwatch(); stopwatch.Start(); var allFaults = createModel.FaultsInBaseModel; FaultSet.CheckFaultCount(allFaults.Length); var forcedFaults = allFaults.Where(fault => fault.Activation == Activation.Forced).ToArray(); var suppressedFaults = allFaults.Where(fault => fault.Activation == Activation.Suppressed).ToArray(); var nondeterministicFaults = allFaults.Where(fault => fault.Activation == Activation.Nondeterministic).ToArray(); var nonSuppressedFaults = allFaults.Where(fault => fault.Activation != Activation.Suppressed).ToArray(); ConsoleHelpers.WriteLine(); ConsoleHelpers.WriteLine($"Of the {allFaults.Length} faults contained in the model,"); ConsoleHelpers.WriteLine($" {suppressedFaults.Length} faults are suppressed,"); ConsoleHelpers.WriteLine($" {forcedFaults.Length} faults are forced, and"); ConsoleHelpers.WriteLine($" {nondeterministicFaults.Length} faults are nondeterministically activated."); ConsoleHelpers.WriteLine(); _suppressedSet = new FaultSet(suppressedFaults); _forcedSet = new FaultSet(forcedFaults); var isComplete = true; // Remove information from previous analyses Reset(createModel.FaultsInBaseModel); // Initialize the backend, the model, and the analysis results switch (Backend) { case SafetyAnalysisBackend.FaultOptimizedOnTheFly: _backend = new FaultOptimizationBackend <TExecutableModel>(); break; case SafetyAnalysisBackend.FaultOptimizedStateGraph: _backend = new StateGraphBackend <TExecutableModel>(); break; default: throw new ArgumentOutOfRangeException(); } _backend.Output = Output; _backend.InitializeModel(Configuration, createModel, hazard); _results = new SafetyAnalysisResults <TExecutableModel>(createModel, hazard, suppressedFaults, forcedFaults, Heuristics, FaultActivationBehavior); // Remember all safe sets of current cardinality - we need them to generate the next power set level var currentSafe = new HashSet <FaultSet>(); // We check fault sets by increasing cardinality; this is, we check the empty set first, then // all singleton sets, then all sets with two elements, etc. We don't check sets that we // know are going to be critical sets due to monotonicity for (var cardinality = 0; cardinality <= nonSuppressedFaults.Length; ++cardinality) { // Generate the sets for the current level that we'll have to check var sets = GeneratePowerSetLevel(cardinality, nonSuppressedFaults, currentSafe); currentSafe.Clear(); // Remove all sets that conflict with the forced or suppressed faults; these sets are considered to be safe. // If no sets remain, skip to the next level sets = RemoveInvalidSets(sets, currentSafe); if (sets.Count == 0) { continue; } // Abort if we've exceeded the maximum fault set cardinality; doing the check here allows us // to report the analysis as complete if the maximum cardinality is never reached if (cardinality > maxCardinality) { isComplete = false; break; } if (cardinality == 0) { ConsoleHelpers.WriteLine("Checking the empty fault set..."); } else { ConsoleHelpers.WriteLine($"Checking {sets.Count} sets of cardinality {cardinality}..."); } // use heuristics var setsToCheck = new LinkedList <FaultSet>(sets); foreach (var heuristic in Heuristics) { var count = setsToCheck.Count; heuristicWatch.Restart(); heuristic.Augment((uint)cardinality, setsToCheck); count = setsToCheck.Count - count; if (count > 0) { ConsoleHelpers.WriteLine($" {heuristic.GetType().Name} made {count} suggestions in {heuristicWatch.Elapsed.TotalMilliseconds}ms."); } } // We have to check each set - heuristics may add further during the loop while (setsToCheck.Count > 0) { var set = setsToCheck.First.Value; var isCurrentLevel = sets.Remove(set); // returns true if set was actually contained setsToCheck.RemoveFirst(); // for current level, we already know the set is valid var isValid = isCurrentLevel || IsValid(set); // the set is invalid if it exceeds the maximum cardinality level isValid &= set.Cardinality <= maxCardinality; var isSafe = true; if (isValid) { isSafe = CheckSet(set, allFaults, !isCurrentLevel); } if (isSafe && isCurrentLevel) { currentSafe.Add(set); } // inform heuristics about result and give them the opportunity to add further sets foreach (var heuristic in Heuristics) { heuristic.Update(setsToCheck, set, isSafe); } if (StopOnFirstException && _exceptions.Count > 0) { goto returnResult; } } // in case heuristics removed a set (they shouldn't) foreach (var set in sets) { var isSafe = CheckSet(set, allFaults, false); if (isSafe) { currentSafe.Add(set); } if (StopOnFirstException && _exceptions.Count > 0) { goto returnResult; } } } returnResult: // Reset the nondeterministic faults so as to not influence subsequent analyses foreach (var fault in nondeterministicFaults) { fault.Activation = Activation.Nondeterministic; } // due to heuristics usage, we may have informatiuon on non-minimal critical sets var minimalCritical = RemoveNonMinimalCriticalSets(); _results.IsComplete = isComplete; _results.Time = stopwatch.Elapsed; _results.SetResult(minimalCritical, _checkedSetCount, _checkedSets, _counterExamples, _exceptions); return(_results); }
protected void CheckConsistencyAfterInitialization() { FaultSet.CheckFaultCount(Faults.Length); StateFormulaSet.CheckFormulaCount(AtomarPropositionFormulas.Length); }