61 ApproximationScheme::operator=(from);
67 ApproximationScheme::operator=(std::move(from));
79 return e1.second > e2.second;
83 const std::pair< std::tuple< NodeId, NodeId, NodeId >*,
double >& e1,
84 const std::pair< std::tuple< NodeId, NodeId, NodeId >*,
double >& e2)
86 return std::abs(e1.second) > std::abs(e2.second);
91 tuple< std::tuple< NodeId, NodeId, NodeId >*,
double,
double,
double >&
94 tuple< std::tuple< NodeId, NodeId, NodeId >*,
double,
double,
double >&
96 double p1xz = std::get< 2 >(e1);
97 double p1yz = std::get< 3 >(e1);
98 double p2xz = std::get< 2 >(e2);
99 double p2yz = std::get< 3 >(e2);
100 double I1 = std::get< 1 >(e1);
101 double I2 = std::get< 1 >(e2);
102 if (std::max(p1xz, p1yz) == std::max(p2xz, p2yz)) {
105 return std::max(p1xz, p1yz) > std::max(p2xz, p2yz);
120 std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
151 HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >& sep_set,
160 for (
const Edge& edge : edges) {
163 double Ixy = I.
score(x, y);
189 HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >& sep_set,
195 std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
200 Size steps_iter = _rank.size();
203 while (_rank.top().second > 0.5) {
206 const NodeId x = std::get< 0 >(*(best.first));
207 const NodeId y = std::get< 1 >(*(best.first));
208 const NodeId z = std::get< 2 >(*(best.first));
209 std::vector< NodeId > ui = std::move(std::get< 3 >(*(best.first)));
212 const double Ixy_ui = I.
score(x, y, ui);
215 sep_set.insert(std::make_pair(x, y), std::move(ui));
246 const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >&
248 std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId >*,
double > >
250 Size steps_orient = triples.size();
258 if (graph.
existsEdge(iter.key().first, iter.key().second)
259 && iter.val() ==
'>') {
261 graph.
addArc(iter.key().first, iter.key().second);
270 while (i < triples.size()) {
272 std::pair< std::tuple< NodeId, NodeId, NodeId >*,
double > triple =
275 x = std::get< 0 >(*triple.first);
276 y = std::get< 1 >(*triple.first);
277 z = std::get< 2 >(*triple.first);
279 std::vector< NodeId > ui;
280 std::pair< NodeId, NodeId > key = {x, y};
281 std::pair< NodeId, NodeId > rev_key = {y, x};
282 if (sep_set.exists(key)) {
284 }
else if (sep_set.exists(rev_key)) {
285 ui = sep_set[rev_key];
287 double Ixyz_ui = triple.second;
292 if (std::find(ui.begin(), ui.end(), z) == ui.end()) {
434 const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >&
436 std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId >*,
double > >
438 Size steps_orient = triples.size();
446 while (i < triples.size()) {
448 std::pair< std::tuple< NodeId, NodeId, NodeId >*,
double > triple =
451 x = std::get< 0 >(*triple.first);
452 y = std::get< 1 >(*triple.first);
453 z = std::get< 2 >(*triple.first);
455 std::vector< NodeId > ui;
456 std::pair< NodeId, NodeId > key = {x, y};
457 std::pair< NodeId, NodeId > rev_key = {y, x};
458 if (sep_set.exists(key)) {
460 }
else if (sep_set.exists(rev_key)) {
461 ui = sep_set[rev_key];
463 double Ixyz_ui = triple.second;
467 if (std::find(ui.begin(), ui.end(), z) == ui.end()) {
585 const HashTable< std::pair< NodeId, NodeId >,
586 std::vector< NodeId > >& sep_set) {
594 for (
auto iter = marks.
begin(); iter != marks.
end(); ++iter) {
595 if (graph.
existsEdge(iter.key().first, iter.key().second)
596 && iter.val() ==
'>') {
598 graph.
addArc(iter.key().first, iter.key().second);
602 std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId >*,
608 Size steps_orient = proba_triples.size();
611 std::tuple< std::tuple< NodeId, NodeId, NodeId >*, double, double,
double >
613 if (steps_orient > 0) { best = proba_triples[0]; }
615 while (!proba_triples.empty()
616 && std::max(std::get< 2 >(best), std::get< 3 >(best)) > 0.5) {
618 x = std::get< 0 >(*std::get< 0 >(best));
619 y = std::get< 1 >(*std::get< 0 >(best));
620 z = std::get< 2 >(*std::get< 0 >(best));
622 const double i3 = std::get< 1 >(best);
626 if (marks[{x, z}] ==
'o' && marks[{y, z}] ==
'o') {
655 }
else if (marks[{x, z}] ==
'>' && marks[{y, z}] ==
'o') {
670 }
else if (marks[{y, z}] ==
'>' && marks[{x, z}] ==
'o') {
689 if (marks[{x, z}] ==
'>' && marks[{y, z}] ==
'o' 690 && marks[{z, y}] !=
'-') {
707 }
else if (marks[{y, z}] ==
'>' && marks[{x, z}] ==
'o' 708 && marks[{z, x}] !=
'-') {
728 delete std::get< 0 >(best);
729 proba_triples.erase(proba_triples.begin());
733 best = proba_triples[0];
750 graph.
addArc(iter->head(), iter->tail());
752 *iter =
Arc(iter->head(), iter->tail());
765 const std::vector< NodeId >& ui,
777 const double Ixy_ui = I.
score(x, y, ui);
779 for (
const NodeId z : graph) {
781 if (z != x && z != y && std::find(ui.begin(), ui.end(), z) == ui.end()) {
786 const double Ixyz_ui = I.
score(x, y, z, ui);
787 double calc_expo1 = -Ixyz_ui *
M_LN2;
791 }
else if (calc_expo1 < -
__maxLog) {
794 Pnv = 1 / (1 + std::exp(calc_expo1));
798 const double Ixz_ui = I.
score(x, z, ui);
799 const double Iyz_ui = I.
score(y, z, ui);
801 calc_expo1 = -(Ixz_ui - Ixy_ui) * M_LN2;
802 double calc_expo2 = -(Iyz_ui - Ixy_ui) * M_LN2;
814 expo1 = std::exp(calc_expo1);
819 expo2 = std::exp(calc_expo2);
821 Pb = 1 / (1 + expo1 + expo2);
825 const double min_pnv_pb = std::min(Pnv, Pb);
826 if (min_pnv_pb > maxP) {
833 std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >*,
836 auto tup =
new std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > >{
845 std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId >*,
double > >
849 const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >&
851 std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId >*,
double > >
854 for (
NodeId x : graph.neighbours(z)) {
855 for (
NodeId y : graph.neighbours(z)) {
856 if (y < x && !graph.existsEdge(x, y)) {
857 std::vector< NodeId > ui;
858 std::pair< NodeId, NodeId > key = {x, y};
859 std::pair< NodeId, NodeId > rev_key = {y, x};
860 if (sep_set.exists(key)) {
862 }
else if (sep_set.exists(rev_key)) {
863 ui = sep_set[rev_key];
866 const auto iter_z_place = std::find(ui.begin(), ui.end(), z);
867 if (iter_z_place != ui.end()) { ui.erase(iter_z_place); }
869 double Ixyz_ui = I.
score(x, y, z, ui);
870 std::pair< std::tuple< NodeId, NodeId, NodeId >*,
double > triple;
871 auto tup =
new std::tuple< NodeId, NodeId, NodeId >{x, y, z};
873 triple.second = Ixyz_ui;
874 triples.push_back(triple);
887 tuple< std::tuple< NodeId, NodeId, NodeId >*,
double, double,
double > >
891 const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > >&
893 HashTable< std::pair< NodeId, NodeId >,
char >& marks) {
894 std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId >*,
900 for (
NodeId x : graph.neighbours(z)) {
901 for (
NodeId y : graph.neighbours(z)) {
902 if (y < x && !graph.existsEdge(x, y)) {
903 std::vector< NodeId > ui;
904 std::pair< NodeId, NodeId > key = {x, y};
905 std::pair< NodeId, NodeId > rev_key = {y, x};
906 if (sep_set.exists(key)) {
908 }
else if (sep_set.exists(rev_key)) {
909 ui = sep_set[rev_key];
912 const auto iter_z_place = std::find(ui.begin(), ui.end(), z);
913 if (iter_z_place != ui.end()) { ui.erase(iter_z_place); }
915 const double Ixyz_ui = I.
score(x, y, z, ui);
916 auto tup =
new std::tuple< NodeId, NodeId, NodeId >{x, y, z};
917 std::tuple< std::tuple< NodeId, NodeId, NodeId >*,
921 triple{tup, Ixyz_ui, 0.5, 0.5};
922 triples.push_back(triple);
923 if (!marks.exists({x, z})) { marks.insert({x, z},
'o'); }
924 if (!marks.exists({z, x})) { marks.insert({z, x},
'o'); }
925 if (!marks.exists({y, z})) { marks.insert({y, z},
'o'); }
926 if (!marks.exists({z, y})) { marks.insert({z, y},
'o'); }
939 tuple< std::tuple< NodeId, NodeId, NodeId >*, double, double,
double > >
942 std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId >*,
945 double > > proba_triples) {
946 for (
auto& triple : proba_triples) {
948 x = std::get< 0 >(*std::get< 0 >(triple));
949 y = std::get< 1 >(*std::get< 0 >(triple));
950 z = std::get< 2 >(*std::get< 0 >(triple));
951 const double Ixyz = std::get< 1 >(triple);
952 double Pxz = std::get< 2 >(triple);
953 double Pyz = std::get< 3 >(triple);
956 const double expo = std::exp(Ixyz);
957 const double P0 = (1 + expo) / (1 + 3 * expo);
959 if (Pxz == Pyz && Pyz == 0.5) {
960 std::get< 2 >(triple) = P0;
961 std::get< 3 >(triple) = P0;
963 if (graph.
existsArc(x, z) && Pxz >= P0) {
964 std::get< 3 >(triple) = Pxz * (1 / (1 + expo) - 0.5) + 0.5;
965 }
else if (graph.
existsArc(y, z) && Pyz >= P0) {
966 std::get< 2 >(triple) = Pyz * (1 / (1 + expo) - 0.5) + 0.5;
970 const double expo = std::exp(-Ixyz *
__N);
971 if (graph.
existsArc(x, z) && Pxz >= 0.5) {
972 std::get< 3 >(triple) = Pxz * (1 / (1 + expo) - 0.5) + 0.5;
973 }
else if (graph.
existsArc(y, z) && Pyz >= 0.5) {
974 std::get< 2 >(triple) = Pyz * (1 / (1 + expo) - 0.5) + 0.5;
979 return proba_triples;
1005 for (
auto node : essentialGraph) {
1008 for (
const Arc& arc : essentialGraph.arcs()) {
1009 dag.
addArc(arc.tail(), arc.head());
1017 const auto neighbours = graph.
neighbours(node);
1018 for (
auto& neighbour : neighbours) {
1026 graph.
addArc(node, neighbour);
1033 graph.
addArc(neighbour, node);
1037 graph.
addArc(node, neighbour);
1051 template <
typename GUM_SCALAR,
1052 typename GRAPH_CHANGES_SELECTOR,
1053 typename PARAM_ESTIMATOR >
1055 PARAM_ESTIMATOR& estimator,
1065 HashTable< std::pair< NodeId, NodeId >,
char > constraints) {
1083 while (!nodeFIFO.
empty()) {
1084 current = nodeFIFO.
front();
1089 for (
const auto new_one : graph.
parents(current)) {
1090 if (mark.
exists(new_one))
1097 mark.
insert(new_one, current);
1099 if (new_one == n1) {
return true; }
A class that, given a structure and a parameter estimator returns a full Bayes net.
iterator begin()
Returns an unsafe iterator pointing to the beginning of the hashtable.
void _iteration(CorrectedMutualInformation<> &I, MixedGraph &graph, HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set, Heap< std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double >, GreaterPairOn2nd > &_rank)
Iteration phase.
bool empty() const noexcept
Returns a boolean indicating whether the chained list is empty.
Class representing a Bayesian Network.
ArcProperty< double > __arc_probas
Storing the propabilities for each arc set in the graph.
void _findBestContributor(NodeId x, NodeId y, const std::vector< NodeId > &ui, const MixedGraph &graph, CorrectedMutualInformation<> &I, Heap< std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double >, GreaterPairOn2nd > &_rank)
finds the best contributor node for a pair given a conditioning set
virtual void addNodeWithId(const NodeId id)
try to insert a node with the given id
virtual void addArc(const NodeId tail, const NodeId head)
insert a new arc into the directed graph
double step() const
Returns the delta time between now and the last reset() call (or the constructor).
Signaler3< Size, double, double > onProgress
Progression, error and time.
const iterator & end() noexcept
Returns the unsafe iterator pointing to the end of the hashtable.
bool empty() const noexcept
Indicates whether the set is the empty set.
void set3off2Behaviour()
Sets the orientation phase to follow the one of the 3off2 algorithm.
MixedGraph learnMixedStructure(CorrectedMutualInformation<> &I, MixedGraph graph)
learns the structure of an Essential Graph
virtual void eraseArc(const Arc &arc)
removes an arc from the ArcGraphPart
Miic & operator=(const Miic &from)
copy operator
void addConstraints(HashTable< std::pair< NodeId, NodeId >, char > constraints)
Set a ensemble of constraints for the orientation phase.
void _orientation_latents(CorrectedMutualInformation<> &I, MixedGraph &graph, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set)
Modified version of the orientation phase that tries to propagate orientations from both orientations...
bool exists(const Key &key) const
Checks whether there exists an element with a given key in the hashtable.
void _orientation_miic(CorrectedMutualInformation<> &I, MixedGraph &graph, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set)
Orientation phase from the MIIC algorithm, returns a mixed graph that may contain circles...
Generic doubly linked lists.
Class used to compute response times for benchmark purposes.
const std::vector< Arc > latentVariables() const
get the list of arcs hiding latent variables
gum is the global namespace for all aGrUM entities
bool __usemiic
wether to use the miic algorithm or not
void popFront()
Removes the first element of a List, if any.
void setMiicBehaviour()
Sets the orientation phase to follow the one of the MIIC algorithm.
void _propagatesHead(MixedGraph &graph, NodeId node)
Propagates the orientation from a node to its neighbours.
The class for generic Hash Tables.
const NodeSet & neighbours(const NodeId id) const
returns the set of edges adjacent to a given node
bool operator()(const std::pair< std::tuple< NodeId, NodeId, NodeId > *, double > &e1, const std::pair< std::tuple< NodeId, NodeId, NodeId > *, double > &e2) const
void reset()
Reset the timer.
const EdgeSet & edges() const
returns the set of edges stored within the EdgeGraphPart
HashTable< std::pair< NodeId, NodeId >, char > __initial_marks
Initial marks for the orientation phase, used to convey constraints.
std::vector< Arc > __latent_couples
an empty vector of arcs
bool existsEdge(const Edge &edge) const
indicates whether a given edge exists
The base class for all directed edgesThis class is used as a basis for manipulating all directed edge...
std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > > _getUnshieldedTriplesMIIC(const MixedGraph &graph, CorrectedMutualInformation<> &I, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set, HashTable< std::pair< NodeId, NodeId >, char > &marks)
gets the list of unshielded triples in the graph in decreasing value of |I'(x, y, z|{ui})|...
const NodeSet & parents(const NodeId id) const
returns the set of nodes with arc ingoing to a given node
Val & pushBack(const Val &val)
Inserts a new element (a copy) at the end of the chained list.
Size _current_step
The current step.
const std::vector< NodeId > directedPath(const NodeId node1, const NodeId node2) const
returns a directed path from node1 to node2 belonging to the set of arcs
virtual void addArc(const NodeId tail, const NodeId head)
insert a new arc into the directed graph
const Sequence< NodeId > & topologicalOrder(bool clear=true) const
The topological order stays the same as long as no variable or arcs are added or erased src the topol...
void _initiation(CorrectedMutualInformation<> &I, MixedGraph &graph, HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set, Heap< std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double >, GreaterPairOn2nd > &_rank)
Initiation phase.
std::vector< std::pair< std::tuple< NodeId, NodeId, NodeId > *, double > > _getUnshieldedTriples(const MixedGraph &graph, CorrectedMutualInformation<> &I, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set)
gets the list of unshielded triples in the graph in decreasing value of |I'(x, y, z|{ui})| ...
Val & front() const
Returns a reference to first element of a list, if any.
The base class for all undirected edges.
Miic()
default constructor
std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > > _updateProbaTriples(const MixedGraph &graph, std::vector< std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > > proba_triples)
Gets the orientation probabilities like MIIC for the orientation phase.
Base classes for mixed directed/undirected graphs.
bool operator()(const std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > &e1, const std::tuple< std::tuple< NodeId, NodeId, NodeId > *, double, double, double > &e2) const
int __maxLog
Fixes the maximum log that we accept in exponential computations.
The miic learning algorithm.
const bool __existsDirectedPath(const MixedGraph &graph, const NodeId n1, const NodeId n2) const
checks for directed paths in a graph, consider double arcs like edges
A class that, given a structure and a parameter estimator returns a full Bayes net.
bool operator()(const std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double > &e1, const std::pair< std::tuple< NodeId, NodeId, NodeId, std::vector< NodeId > > *, double > &e2) const
Heap data structureThis structure is a basic heap data structure, i.e., it is a container in which el...
std::size_t Size
In aGrUM, hashed values are unsigned long int.
const std::vector< NodeId > __empty_set
an empty conditioning set
virtual void eraseEdge(const Edge &edge)
removes an edge from the EdgeGraphPart
Size size() const noexcept
Returns the number of elements in the set.
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
#define GUM_EMIT3(signal, arg1, arg2, arg3)
Size __N
size of the database
BayesNet< GUM_SCALAR > learnBN(GRAPH_CHANGES_SELECTOR &selector, PARAM_ESTIMATOR &estimator, DAG initial_dag=DAG())
learns the structure and the parameters of a BN
bool existsArc(const Arc &arc) const
indicates whether a given arc exists
Class hash tables iterators.
Size NodeId
Type for node ids.
DAG learnStructure(CorrectedMutualInformation<> &I, MixedGraph graph)
learns the structure of an Bayesian network, ie a DAG, by first learning an Essential graph and then ...
Base class for mixed graphs.
void _orientation_3off2(CorrectedMutualInformation<> &I, MixedGraph &graph, const HashTable< std::pair< NodeId, NodeId >, std::vector< NodeId > > &sep_set)
Orientation phase from the 3off2 algorithm, returns a CPDAG.