1#ifndef LIBTEDDY_DETAILS_RELIABILITY_MANAGER_HPP
2#define LIBTEDDY_DETAILS_RELIABILITY_MANAGER_HPP
4#include <libteddy/details/diagram_manager.hpp>
5#include <libteddy/details/dplds.hpp>
6#include <libteddy/details/probabilities.hpp>
10#include <unordered_map>
20concept is_bss = std::same_as<degrees::fixed<2>, Degree>;
41template<
class Degree,
class Domain>
63 template<probs::prob_vector Ps>
79 template<probs::prob_matrix Ps>
94 template<probs::prob_vector Ps>
111 template<probs::prob_matrix Ps>
143 template<probs::prob_vector Ps,
class Foo =
void>
146 -> utils::second_t<Foo, double>;
160 template<probs::prob_matrix Ps>
179 template<
class Foo =
void>
182 -> utils::second_t<Foo, double>;
211 template<probs::prob_matrix Ps,
class Foo =
void>
214 -> utils::second_t<Foo, double>;
228 template<probs::prob_matrix Ps>
247 template<
class Foo =
void>
268#ifdef LIBTEDDY_SYMBOLIC_RELIABILITY
275 auto symbolic_probability (
279 ) -> symprobs::expression;
285 auto symbolic_availability (
289 ) -> symprobs::expression;
295 auto unsymbolic_availability (
299 ) -> symprobs::expression;
317 template<
class FChange>
328 auto to_dpld_e (int32 varFrom, int32 varIndex, diagram_t
const& dpld)
352 template<probs::prob_matrix Ps>
368 template<probs::prob_matrix Ps>
371 diagram_t
const& dpld,
372 double unavailability,
373 int32 componentState,
390 template<out_var_values Vars>
391 auto mcvs (diagram_t
const&
diagram, int32 state) -> std::vector<Vars>;
406 template<out_var_values Vars>
407 auto mpvs (diagram_t
const&
diagram, int32 state) -> std::vector<Vars>;
423 template<out_var_values Vars, std::output_iterator<Vars> Out>
440 template<out_var_values Vars, std::output_iterator<Vars> Out>
447 int64 overflowNodePoolSize,
448 std::vector<int32> order
455 int64 overflowNodePoolSize,
457 std::vector<int32> order
462 using node_t =
typename diagram_manager<double, Degree, Domain>::node_t;
463 using son_conainer =
typename node_t::son_container;
468 struct dpld_cache_entry
474 struct cache_entry_hash
476 auto operator() (dpld_cache_entry
const& entry)
const
478 return utils::pack_hash(entry.lhs_, entry.rhs_);
482 struct cache_entry_equals
485 dpld_cache_entry
const& lhs,
486 dpld_cache_entry
const& rhs
489 return lhs.lhs_ == rhs.lhs_ && lhs.rhs_ == rhs.rhs_;
493 using dpld_cache = std::unordered_map<
500 auto to_mnf (diagram_t
const& diagram) -> diagram_t;
502 auto to_mnf_impl (std::unordered_map<node_t*, node_t*>& memo, node_t* node)
505 template<
class FChange>
508 var_change varChange,
514 auto to_dpld_e_impl (
515 std::unordered_map<node_t*, node_t*>& memo,
521 template<probs::prob_matrix Ps>
522 auto calculate_ntps_post_impl (
523 std::vector<int32>
const& selected,
528 template<probs::prob_matrix Ps>
529 auto calculate_ntps_level_impl (Ps
const& probs, node_t* root) -> void;
532template<
class Degree,
class Domain>
533template<probs::prob_vector Ps>
534requires(details::is_bss<Degree>)
540 this->calculate_probabilities(
546template<
class Degree,
class Domain>
547template<probs::prob_matrix Ps>
556template<
class Degree,
class Domain>
557template<probs::prob_vector Ps>
558requires(details::is_bss<Degree>)
564 return this->calculate_probability(
571template<
class Degree,
class Domain>
572template<probs::prob_matrix Ps>
583template<
class Degree,
class Domain>
587 node_t*
const node = this->nodes_.get_terminal_node(state);
588 return node ?
node->get_data() : 0.0;
591template<
class Degree,
class Domain>
592template<probs::prob_vector Ps,
class Foo>
597) -> utils::second_t<Foo, double>
599 return this->calculate_availability(
606template<
class Degree,
class Domain>
607template<probs::prob_matrix Ps>
614 std::vector<int32> states;
615 this->nodes_.for_each_terminal_node(
616 [state, &states] (node_t*
const node)
618 if (
node->get_value() >= state)
620 states.push_back(node->get_value());
628template<
class Degree,
class Domain>
632 -> utils::second_t<Foo, double>
634 node_t*
const node = this->nodes_.get_terminal_node(1);
638template<
class Degree,
class Domain>
643 this->nodes_.for_each_terminal_node(
644 [state, &result] (node_t*
const node)
646 if (
node->get_value() >= state)
648 result += node->get_data();
655template<
class Degree,
class Domain>
656template<probs::prob_matrix Ps,
class Foo>
661) -> utils::second_t<Foo, double>
663 return this->calculate_unavailability(1, probs,
diagram);
666template<
class Degree,
class Domain>
667template<probs::prob_matrix Ps>
674 std::vector<int32> states;
675 this->nodes_.for_each_terminal_node(
676 [state, &states] (node_t*
const node)
678 if (
node->get_value() < state)
680 states.emplace_back(node->get_value());
688template<
class Degree,
class Domain>
692 -> utils::second_t<Foo, double>
694 return this->get_unavailability(1);
697template<
class Degree,
class Domain>
702 this->nodes_.for_each_terminal_node(
703 [state, &result] (node_t*
const node)
705 if (
node->get_value() < state)
707 result += node->get_data();
714#ifdef LIBTEDDY_SYMBOLIC_RELIABILITY
719template<
class Degree,
class Domain>
725) -> symprobs::expression
728 std::unordered_map<node_t*, GiNaC::ex> exprMap;
730 this->nodes_.for_each_terminal_node(
731 [&exprMap, state] (node_t*
const node)
733 GiNaC::ex val(
static_cast<double>(
734 static_cast<int32
>(
node->get_value() >= state)
736 exprMap.emplace(std::make_pair(
node, val));
740 node_t*
const root = diagram.unsafe_get_root();
741 this->nodes_.traverse_post(
743 [
this, &probs, &exprMap] (node_t*
const node)
mutable
745 if (not node->is_terminal())
748 = exprMap.emplace(std::make_pair(node, GiNaC::ex(0.0)));
750 GiNaC::ex& expr = it->second;
751 int32
const nodeIndex = node->get_index();
752 int32
const domain = this->nodes_.get_domain(nodeIndex);
753 for (int32 k = 0; k < domain; ++k)
755 node_t*
const son = node->get_son(k);
756 expr += exprMap.find(son)->second
757 * probs[as_uindex(nodeIndex)][as_uindex(k)]
758 .as_underlying_unsafe();
763 return symprobs::expression(exprMap.find(root)->second);
768template<
class Degree,
class Domain>
774 int32
const indexFrom = 0;
775 int32
const indexTo = this->get_var_count();
776 int64
const domainSize = this->nodes_.domain_product(indexFrom, indexTo);
777 return static_cast<double>(this->satisfy_count(state,
diagram))
778 /
static_cast<double>(domainSize);
781template<
class Degree,
class Domain>
782template<
class FChange>
792 node_t* lhsRoot = oldRoot;
793 node_t* rhsRoot = oldRoot;
794 if (not oldRoot->is_terminal() && oldRoot->get_index() == varChange.index_)
796 lhsRoot = oldRoot->get_son(varChange.from_);
797 rhsRoot = oldRoot->get_son(varChange.to_);
799 node_t*
const newRoot
800 = this->dpld_impl(cache, varChange, fChange, lhsRoot, rhsRoot);
801 this->nodes_.run_deferred();
802 return diagram_t(newRoot);
805template<
class Degree,
class Domain>
806template<
class FChange>
815 constexpr auto get_son = [] (node_t*
const node,
817 int32
const varIndex,
818 int32
const varValue)
820 auto const son =
node->get_son(k);
821 return son->is_internal() && son->get_index() == varIndex
822 ? son->get_son(varValue)
826 auto const cached = cache.find(dpld_cache_entry(lhs, rhs));
827 if (cached != cache.end())
829 return cached->second;
832 node_t* result =
nullptr;
834 if (lhs->is_terminal() && rhs->is_terminal())
836 result = this->nodes_.make_terminal_node(
837 static_cast<int32
>(fChange(lhs->get_value(), rhs->get_value()))
842 int32
const lhsLevel = this->nodes_.get_level(lhs);
843 int32
const rhsLevel = this->nodes_.get_level(rhs);
844 int32
const topLevel = utils::min(lhsLevel, rhsLevel);
845 int32
const topIndex = this->nodes_.get_index(topLevel);
846 int32
const domain = this->nodes_.get_domain(topIndex);
847 son_conainer sons = this->nodes_.make_son_container(domain);
848 for (int32 k = 0; k < domain; ++k)
851 = lhsLevel == topLevel
852 ? get_son(lhs, k, varChange.index_, varChange.from_)
856 = rhsLevel == topLevel
857 ? get_son(rhs, k, varChange.index_, varChange.to_)
859 sons[k] = this->dpld_impl(cache, varChange, fChange, fst, snd);
862 result = this->nodes_.make_internal_node(topIndex, sons);
865 cache.emplace(dpld_cache_entry(lhs, rhs), result);
870template<
class Degree,
class Domain>
873 int32
const varIndex,
874 diagram_t
const& dpld
877 node_t*
const root = dpld.unsafe_get_root();
878 int32
const rootLevel = this->nodes_.get_level(root);
879 int32
const varLevel = this->nodes_.get_level(varIndex);
880 node_t* newRoot =
nullptr;
882 if (varLevel < rootLevel)
884 int32
const varDomain = this->nodes_.get_domain(varIndex);
885 son_conainer sons = this->nodes_.make_son_container(varDomain);
886 for (int32 k = 0; k < varDomain; ++k)
888 sons[k] = k == varFrom ? root
889 : this->nodes_.make_terminal_node(Undefined);
891 newRoot = this->nodes_.make_internal_node(varIndex, sons);
892 return diagram_t(newRoot);
896 std::unordered_map<node_t*, node_t*> memo;
897 newRoot = this->to_dpld_e_impl(memo, varFrom, varIndex, root);
902 this->nodes_.run_deferred();
903 return diagram_t(newRoot);
906template<
class Degree,
class Domain>
908 std::unordered_map<node_t*, node_t*>& memo,
910 int32
const varIndex,
914 if (
node->is_terminal())
919 auto const memoIt = memo.find(node);
920 if (memoIt != memo.end())
922 return memoIt->second;
925 int32
const varDomain = this->nodes_.get_domain(varIndex);
926 int32
const varLevel = this->nodes_.get_level(varIndex);
927 int32
const nodeLevel = this->nodes_.get_level(node);
928 int32
const nodeIndex = this->nodes_.get_index(nodeLevel);
929 int32
const nodeDomain = this->nodes_.get_domain(nodeIndex);
930 son_conainer sons = this->nodes_.make_son_container(nodeDomain);
931 for (int32 k = 0; k < nodeDomain; ++k)
933 node_t*
const son = node->get_son(k);
934 int32
const sonLevel = this->nodes_.get_level(son);
935 if (varLevel > nodeLevel && varLevel < sonLevel)
939 son_conainer newSons = this->nodes_.make_son_container(varDomain);
940 for (int32 l = 0; l < varDomain; ++l)
942 newSons[l] = l == varFrom
944 : this->nodes_.make_terminal_node(Undefined);
946 sons[k] = this->nodes_.make_internal_node(varIndex, newSons);
951 sons[k] = this->to_dpld_e_impl(memo, varFrom, varIndex, son);
954 node_t*
const newNode = this->nodes_.make_internal_node(nodeIndex, sons);
955 memo.emplace(node, newNode);
959template<
class Degree,
class Domain>
961 diagram_t
const& dpld
964 int32
const indexFrom = 0;
965 int32
const indexTo = this->get_var_count();
966 int64
const domainSize = this->nodes_.domain_product(indexFrom, indexTo);
967 return static_cast<double>(this->satisfy_count(1, dpld))
968 /
static_cast<double>(domainSize);
971template<
class Degree,
class Domain>
972template<probs::prob_matrix Ps>
975 diagram_t
const& dpld
978 return this->calculate_probability(1, probs, dpld);
981template<
class Degree,
class Domain>
982template<probs::prob_matrix Ps>
985 diagram_t
const& dpld,
986 double const unavailability,
987 int32
const componentState,
988 int32
const componentIndex
991 diagram_t
const mnf = this->to_mnf(dpld);
992 double const mnfProbability = this->calculate_probability(1, probs, mnf);
993 double nominator = 0;
994 for (int32 lowerState = 0; lowerState < componentState; ++lowerState)
996 nominator += probs[as_uindex(componentIndex)][as_uindex(lowerState)];
998 nominator *= mnfProbability;
999 return nominator / unavailability;
1002template<
class Degree,
class Domain>
1003template<out_var_values Vars>
1007) -> std::vector<Vars>
1009 std::vector<Vars> cuts;
1010 this->mcvs_g<Vars>(
diagram, state, std::back_inserter(cuts));
1014template<
class Degree,
class Domain>
1015template<out_var_values Vars>
1019) -> std::vector<Vars>
1021 auto cuts = std::vector<Vars>();
1022 this->mcvs_g<Vars>(
diagram, state, std::back_inserter(cuts));
1026template<
class Degree,
class Domain>
1027template<out_var_values Vars, std::output_iterator<Vars> Out>
1034 int32
const varCount = this->get_var_count();
1035 std::vector<diagram_t> dpldes;
1037 for (int32 varIndex = 0; varIndex < varCount; ++varIndex)
1039 int32
const varDomain = this->nodes_.get_domain(varIndex);
1040 for (int32 varFrom = 0; varFrom < varDomain - 1; ++varFrom)
1042 var_change varChange {varIndex, varFrom, varFrom + 1};
1043 diagram_t
const dpld
1044 = this->dpld(varChange, dpld::type_3_increase(state),
diagram);
1045 dpldes.push_back(this->to_dpld_e(varFrom, varIndex, dpld));
1049 diagram_t
const conj = this->
template tree_fold<ops::PI_CONJ>(dpldes);
1050 this->
template satisfy_all_g<Vars, Out>(1, conj, out);
1053template<
class Degree,
class Domain>
1054template<out_var_values Vars, std::output_iterator<Vars> Out>
1061 int32
const varCount = this->get_var_count();
1062 std::vector<diagram_t> dpldes;
1064 for (int32 varIndex = 0; varIndex < varCount; ++varIndex)
1066 int32
const varDomain = this->nodes_.get_domain(varIndex);
1067 for (int32 varFrom = 1; varFrom < varDomain; ++varFrom)
1069 var_change varChange {varIndex, varFrom, varFrom - 1};
1070 diagram_t
const dpld
1071 = this->dpld(varChange, dpld::type_3_decrease(state),
diagram);
1072 dpldes.push_back(this->to_dpld_e(varFrom, varIndex, dpld));
1076 diagram_t
const conj = this->
template tree_fold<ops::PI_CONJ>(dpldes);
1077 this->
template satisfy_all_g<Vars, Out>(1, conj, out);
1080template<
class Degree,
class Domain>
1081template<probs::prob_matrix Ps>
1083 std::vector<int32>
const& selectedValues,
1088 this->nodes_.for_each_terminal_node([] (node_t*
const node)
1089 {
node->get_data() = 0.0; });
1091 for (int32
const selectedValue : selectedValues)
1093 node_t*
const node = this->nodes_.get_terminal_node(selectedValue);
1096 node->get_data() = 1.0;
1100 this->nodes_.traverse_post(
1102 [
this, &probs] (node_t*
const node)
mutable
1104 if (not node->is_terminal())
1106 node->get_data() = 0.0;
1107 int32 const nodeIndex = node->get_index();
1108 int32 const domain = this->nodes_.get_domain(nodeIndex);
1109 for (int32 k = 0; k < domain; ++k)
1111 node_t* const son = node->get_son(k);
1114 * probs[as_uindex(nodeIndex)][as_uindex(k)];
1119 return root->get_data();
1122template<
class Degree,
class Domain>
1123template<probs::prob_matrix Ps>
1124auto reliability_manager<Degree, Domain>::calculate_ntps_level_impl(
1129 this->nodes_.traverse_pre(
1131 [] (node_t*
const node) { node->get_data() = 0.0; }
1133 this->nodes_.for_each_terminal_node([] (node_t*
const node)
1134 { node->get_data() = 0.0; });
1135 root->get_data() = 1.0;
1137 this->nodes_.traverse_level(
1139 [
this, &probs] (node_t*
const node)
1141 if (node->is_internal())
1143 int32 const nodeIndex = node->get_index();
1144 int32 const domain = this->nodes_.get_domain(nodeIndex);
1145 for (int32 k = 0; k < domain; ++k)
1147 node_t* const son = node->get_son(k);
1150 * probs[as_uindex(nodeIndex)][as_uindex(k)];
1157template<
class Degree,
class Domain>
1158auto reliability_manager<Degree, Domain>::to_mnf(diagram_t
const& diagram)
1161 std::unordered_map<node_t*, node_t*> memo;
1162 node_t*
const newRoot = this->to_mnf_impl(memo, diagram.unsafe_get_root());
1163 this->nodes_.run_deferred();
1164 return diagram_t(newRoot);
1167template<
class Degree,
class Domain>
1168auto reliability_manager<Degree, Domain>::to_mnf_impl(
1169 std::unordered_map<node_t*, node_t*>& memo,
1173 if (node->is_terminal())
1178 auto const memoIt = memo.find(node);
1179 if (memoIt != memo.end())
1181 return memoIt->second;
1184 int32
const nodeIndex = node->get_index();
1185 int32
const domain = this->nodes_.get_domain(nodeIndex);
1186 son_conainer sons = this->nodes_.make_son_container(domain);
1187 for (int32 k = 0; k < domain; ++k)
1189 node_t*
const son = node->get_son(k);
1190 sons[k] = this->to_mnf_impl(memo, son);
1193 for (int32 k = domain - 1; k > 0; --k)
1195 node_t*
const son = sons[k];
1196 if (son->is_terminal() && son->get_value() == 1)
1198 for (int32 l = 0; l < k; ++l)
1206 for (int32 k = domain - 2; k >= 0; --k)
1208 node_t*
const son = sons[k];
1209 if (son->is_terminal() && son->get_value() == 0)
1211 sons[k] = sons[k + 1];
1215 node_t*
const newNode = this->nodes_.make_internal_node(nodeIndex, sons);
1216 memo.emplace(node, newNode);
1220template<
class Degree,
class Domain>
1221reliability_manager<Degree, Domain>::reliability_manager(
1222 int32
const varCount,
1223 int64
const nodePoolSize,
1224 int64
const overflowNodePoolSize,
1225 std::vector<int32> order
1227requires(domains::is_fixed<Domain>::value)
1229 diagram_manager<double, Degree, Domain>(
1232 overflowNodePoolSize,
1233 static_cast<std::vector<int32>&&>(order)
1238template<
class Degree,
class Domain>
1239reliability_manager<Degree, Domain>::reliability_manager(
1240 int32
const varCount,
1241 int64
const nodePoolSize,
1242 int64
const overflowNodePoolSize,
1243 domains::mixed domain,
1244 std::vector<int32> order
1246requires(domains::is_mixed<Domain>::value)
1248 diagram_manager<double, Degree, Domain>(
1251 overflowNodePoolSize,
1252 static_cast<domains::mixed&&>(domain),
1253 static_cast<std::vector<int32>&&>(order)
Base class for all diagram managers that generically implements all of the algorithms.
Definition diagram_manager.hpp:91
Cheap wrapper for the internal diagram node type.
Definition diagram.hpp:20
auto unsafe_get_root() const -> node_t *
Returns pointer to internal node type. You should probably don't use this one unless you know what yo...
Definition diagram.hpp:178
Wraps prob. vector so that it can be used as matrix.
Definition probabilities.hpp:52
Base class for reliability managers.
Definition reliability_manager.hpp:43
auto mpvs_g(diagram_t const &diagram, int32 state, Out out) -> void
Finds all Minimal Path Vector (MPVs) of the system with respect to the system state state.
Definition reliability_manager.hpp:1055
auto mcvs_g(diagram_t const &diagram, int32 state, Out out) -> void
Finds all Minimal Cut Vector of the system with respect to the system state state.
Definition reliability_manager.hpp:1028
auto calculate_availability(Ps const &probs, diagram_t const &diagram) -> utils::second_t< Foo, double >
Calculates and returns availability of a BSS.
Definition reliability_manager.hpp:594
auto mcvs(diagram_t const &diagram, int32 state) -> std::vector< Vars >
Finds all Minimal Cut Vector (MCVs) of the system with respect to the system state State.
Definition reliability_manager.hpp:1004
auto fussell_vesely_importance(Ps const &probs, diagram_t const &dpld, double unavailability, int32 componentState, int32 componentIndex) -> double
Calculates Fussell-Vesely importance (FVI) of a component.
Definition reliability_manager.hpp:983
auto calculate_unavailability(Ps const &probs, diagram_t const &diagram) -> utils::second_t< Foo, double >
Calculates and returns unavailability of a BSS.
Definition reliability_manager.hpp:658
auto birnbaum_importance(Ps const &probs, diagram_t const &dpld) -> double
Calculates Birnbaum importance (BI) of a component.
Definition reliability_manager.hpp:973
auto calculate_unavailability(int32 state, Ps const &probs, diagram_t const &diagram) -> double
Calculates and returns system availability with respect to the system state state.
Definition reliability_manager.hpp:668
auto get_availability() const -> utils::second_t< Foo, double >
Returns availability of a BSS.
Definition reliability_manager.hpp:631
auto get_probability(int32 state) const -> double
Returns probability of given system state.
Definition reliability_manager.hpp:584
auto calculate_probabilities(Ps const &probs, diagram_t const &diagram) -> void
Calculates probabilities of all system states.
auto mpvs(diagram_t const &diagram, int32 state) -> std::vector< Vars >
Finds all Minimal Path Vector (MPVs) of the system with respect to the system state state.
Definition reliability_manager.hpp:1016
auto dpld(var_change varChange, FChange fChange, diagram_t const &diagram) -> diagram_t
Calculates Direct Partial Boolean Derivative.
Definition reliability_manager.hpp:783
auto calculate_probabilities(Ps const &probs, diagram_t const &diagram) -> void
Calculates probabilities of system states 0 and 1.
Definition reliability_manager.hpp:535
auto to_dpld_e(int32 varFrom, int32 varIndex, diagram_t const &dpld) -> diagram_t
Transforms dpld into Extended DPLD.
Definition reliability_manager.hpp:871
auto get_unavailability() -> utils::second_t< Foo, double >
Returns system unavailability of a BSS.
Definition reliability_manager.hpp:691
auto get_availability(int32 state) const -> double
Returns system availability with respect to the system state state.
Definition reliability_manager.hpp:639
auto state_frequency(diagram_t const &diagram, int32 state) -> double
Returns system state frequency of state state.
Definition reliability_manager.hpp:769
auto get_unavailability(int32 state) -> double
Returns system unavailability with respect to the system state state.
Definition reliability_manager.hpp:698
auto calculate_probability(Ps const &probs, diagram_t const &diagram) -> double
Calculates and returns probability of system state 1.
Definition reliability_manager.hpp:559
auto calculate_probability(int32 state, Ps const &probs, diagram_t const &diagram) -> double
Calculates and returns probability of a system state state.
Definition reliability_manager.hpp:573
auto calculate_availability(int32 state, Ps const &probs, diagram_t const &diagram) -> double
Calculates and returns system availability with respect to the system state state.
Definition reliability_manager.hpp:608
auto structural_importance(diagram_t const &dpld) -> double
Calculates Structural Importace (SI) of a component.
Definition reliability_manager.hpp:960
Definition reliability_manager.hpp:20
Definition node_manager.hpp:57
Definition node_manager.hpp:69
Definition node_manager.hpp:25
Describes change in a value of a variable.
Definition reliability_manager.hpp:28