Skip to content

packages/engine/scram/src/fault_tree_analysis.h

Fault Tree Analysis.

Namespaces

Name
scram
scram::mef
scram::core

Classes

Name
structscram::core::Literal <br>Event or its complement that may appear in products.
structscram::core::ProductSummary <br>Summary information about generated products.
classscram::core::Product <br>Collection of unique literals.
classscram::core::ProductContainer <br>A container of analysis result products with Literals.
classscram::core::FaultTreeAnalysis <br>Fault tree analysis functionality.
classscram::core::FaultTreeAnalyzer <br>Fault tree analysis facility with specific algorithms.

Source code

cpp
/*
 * Copyright (C) 2014-2018 Olzhas Rakhimov
 * Copyright (C) 2023 OpenPRA ORG Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#pragma once

#include <cstdlib>

#include <memory>
#include <optional>
#include <vector>

#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/transform_iterator.hpp>

#include "analysis.h"
#include "pdag.h"
#include "preprocessor.h"
#include "settings.h"
#include "zbdd.h"

namespace scram::mef {  // Decouple from the analysis code.
class Model;  // Provider of substitutions.
class Gate;
class BasicEvent;
}  // namespace scram::mef

namespace scram::core {

struct Literal {
  bool complement;  
  const mef::BasicEvent& event;  
};

struct ProductSummary {
  using ProductList = std::vector<std::vector<int>>;

  int product_count = 0;  
  int original_product_count = 0;  
  int pruned_products = 0;  
  std::vector<int> distribution;  
  std::vector<int> event_indices;  
  bool cut_off_applied = false;  
  double applied_cut_off = 0.0;  
};

class Product {
  struct LiteralExtractor {
    Literal operator()(int index) const {
      return {index < 0, *graph.basic_events()[std::abs(index)]};
    }
    const Pdag& graph;  
  };

 public:
  Product(const std::vector<int>& data, const Pdag& graph)
      : data_(data), graph_(graph) {}

  bool empty() const { return data_.empty(); }

  int size() const { return data_.size(); }

  int order() const { return empty() ? 1 : size(); }

  double p() const;

  auto begin() const {
    return boost::make_transform_iterator(data_.begin(),
                                          LiteralExtractor{graph_});
  }

  auto end() const {
    return boost::make_transform_iterator(data_.end(),
                                          LiteralExtractor{graph_});
  }

 private:
  const std::vector<int>& data_;  
  const Pdag& graph_;  
};

class ProductContainer {
  using ProductList = ProductSummary::ProductList;

  class Iterator
      : public boost::iterator_facade<Iterator, Product,
                                      boost::forward_traversal_tag,
                                      const Product&> {
   public:
    Iterator();

   private:
    friend class ProductContainer;
    friend class boost::iterator_core_access;

    enum class Source { kZbdd, kFiltered };

    Iterator(const Pdag& graph, Zbdd::const_iterator it);
    Iterator(const Pdag& graph, std::shared_ptr<const ProductList> filtered,
         ProductList::const_iterator it);

    void increment();
    bool equal(const Iterator& other) const;
    const Product& dereference() const;

  Source source_ = Source::kZbdd;
  std::optional<Zbdd::const_iterator> zbdd_it_;
    std::shared_ptr<const ProductList> filtered_;
    ProductList::const_iterator filtered_it_;
    const Pdag* graph_ = nullptr;
    mutable std::optional<Product> cache_;
  };

 public:
  ProductContainer(const Zbdd& products, const Pdag& graph,
                   const ProductSummary* summary = nullptr,
                   std::shared_ptr<const ProductList> filtered_products = nullptr) ;

  const std::vector<const mef::BasicEvent*>& product_events() const {
    return product_events_;
  }

  const Pdag& graph() const { return graph_; }

  Iterator begin() const;
  Iterator end() const;

  bool empty() const { return size_ == 0; }

  int size() const { return size_; }

  const std::vector<int>& distribution() const { return distribution_; }

 private:
  const Zbdd& products_;  
  const Pdag& graph_;  
  int size_;  
  std::vector<int> distribution_;  
  std::vector<const mef::BasicEvent*> product_events_;
  std::shared_ptr<const ProductList> filtered_products_;
};

void Print(const ProductContainer& products);

class FaultTreeAnalysis : public Analysis {
 public:
  FaultTreeAnalysis(const mef::Gate& root, const Settings& settings,
                    const mef::Model* model = nullptr);

  virtual ~FaultTreeAnalysis() = default;

  const mef::Gate& top_event() const { return top_event_; }

  void Analyze() ;

  const ProductContainer& products() const {
    assert(products_ && "The analysis is not done!");
    return *products_;
  }

  [[nodiscard]] bool has_products() const { return static_cast<bool>(products_); }

  [[nodiscard]] std::shared_ptr<Pdag> pdag() { return std::move(graph_); }

  [[nodiscard]] const ProductSummary* last_product_summary() const {
    return last_summary_ ? &last_summary_.value() : nullptr;
  }

  [[nodiscard]] bool adaptive_mode_used() const { return adaptive_mode_used_; }

  [[nodiscard]] double adaptive_target_probability() const { return adaptive_target_probability_; }

  void initiating_event_frequency(double frequency) { initiating_event_frequency_ = frequency; }

 protected:
  [[nodiscard]] Pdag* graph() const { return graph_.get(); }

 private:
  virtual void Preprocess(Pdag* graph)  = 0;

  virtual const Zbdd& GenerateProducts(const Pdag* graph)  = 0;

  void Store(const Zbdd& products, const Pdag& graph,
             const ProductSummary& summary,
             std::shared_ptr<const ProductSummary::ProductList> filtered_products) ;

  double GetExactProbabilityValue() const;
  double ComputeAdaptiveTargetProbability() const;

  const mef::Gate& top_event_;  
  const mef::Model* model_;  
  std::unique_ptr<Pdag> graph_;  
  std::unique_ptr<const ProductContainer> products_;  
  std::shared_ptr<const ProductSummary::ProductList> filtered_products_;
  double initiating_event_frequency_ = 1.0;  
  std::optional<ProductSummary> last_summary_;
  bool adaptive_mode_used_ = false;
  double adaptive_target_probability_ = -1.0;
};

template <class Algorithm>
class FaultTreeAnalyzer : public FaultTreeAnalysis {
 public:
  using FaultTreeAnalysis::FaultTreeAnalysis;
  using FaultTreeAnalysis::graph;  // Provide access to other analyses.

  const Algorithm* algorithm() const { return algorithm_.get(); }
  Algorithm* algorithm() { return algorithm_.get(); }

 private:
  void Preprocess(Pdag* graph)  override {
    std::optional<Settings>  settings_opt = std::optional<Settings>(settings());
    CustomPreprocessor<Algorithm>{graph,settings_opt}();
  }

  const Zbdd& GenerateProducts(const Pdag* graph)  override {
    algorithm_ = std::make_unique<Algorithm>(graph, Analysis::settings());
    algorithm_->Analyze(graph);
    return algorithm_->products();
  }

  std::unique_ptr<Algorithm> algorithm_;  
};

}  // namespace scram::core

Updated on 2026-01-09 at 21:59:13 +0000