Struct BayesNet

Source
pub struct BayesNet { /* private fields */ }
Expand description

Representation of a Bayesian Network

Once built by adding the nodes one by one, you can use it for inference computation on the graph given some evidence.

Implementations§

Source§

impl BayesNet

Source

pub fn new() -> BayesNet

Create a new empty Bayesian Network

Examples found in repository?
examples/simple_net.rs (line 4)
3fn main() {
4    let mut net = BayesNet::new();
5
6    // create a small graph from the classic example:
7    //
8    // +----------+          +----------------------+
9    // | It rains | -------> | Sprinkler is running |
10    // +----------+          +----------------------+
11    //       |                 |
12    //       +----+     +------+
13    //            |     |
14    //            v     v
15    //        +--------------+
16    //        | Grass is Wet |
17    //        +--------------+
18
19    // Rain has no parents, it is a prior
20    // We have P(not Rain) = 0.8, P(Rain) = 0.8
21    let rain = net.add_node_from_probabilities(&[], ndarray::Array1::from(vec![0.8, 0.2]));
22
23    // Sprinkler has a parent (Rain)
24    // We have P(not Sprinkler | not Rain) = 0.60, P(not Sprinkler | Rain) = 0.99
25    //         P(    Sprinkler | not Rain) = 0.40, P(    Sprinkler | Rain) = 0.01
26    let sprinkler = net.add_node_from_probabilities(
27        &[rain],
28        ndarray::Array2::from(vec![[0.60, 0.99], [0.40, 0.01]]),
29    );
30
31    // Wet has 2 parents (Rain and Sprinkler)
32    // We have P(not Wet | not Rain, not Sprinkler) = 1.0, P(not Wet | not Rain, Sprinkler) = 0.1
33    //         P(not Wet | Rain,     not Sprinkler) = 0.2, P(not Wet | Rain,     Sprinkler) = 0.01
34    //         P(    Wet | not Rain, not Sprinkler) = 0.0, P(    Wet | not Rain, Sprinkler) = 0.9
35    //         P(    Wet | Rain,     not Sprinkler) = 0.8, P(    Wet | Rain,     Sprinkler) = 0.99
36    let wet = net.add_node_from_probabilities(
37        &[rain, sprinkler],
38        ndarray::Array3::from(vec![[[1.0, 0.1], [0.2, 0.01]], [[0.0, 0.9], [0.8, 0.99]]]),
39    );
40    /*
41        // We can now do some inferences
42        // First, compute the marginal probabilities of the network without any evidence
43        net.reset_state();
44        net.set_evidence(&[]);
45        println!("===== raw marginal probabilities =====");
46        for _ in 1..10 {
47            // this net converges pretty quickly
48            net.step();
49        }
50        let beliefs = net.beliefs();
51        println!(
52            "    P(Rain)      = {:.2}",
53            beliefs[rain].as_probabilities()[1]
54        );
55        println!(
56            "    P(Sprinkler) = {:.2}",
57            beliefs[sprinkler].as_probabilities()[1]
58        );
59        println!(
60            "    P(Wet)       = {:.2}",
61            beliefs[wet].as_probabilities()[1]
62        );
63    */
64    println!();
65    println!("===== marginal probabilities assuming the grass is wet =====");
66    // Now, assuming we see the grass we, what can we infer from this ?
67    net.reset_state();
68    net.set_evidence(&[(wet, 1)]);
69    for i in 1..21 {
70        // this net is slower to converge
71        net.step();
72        let beliefs = net.beliefs();
73        println!("After iteration {}", i);
74        println!(
75            "    P(Rain | Wet)      = {:.2}",
76            beliefs[rain].as_probabilities()[1]
77        );
78        println!(
79            "    P(Sprinkler | Wet) = {:.2}",
80            beliefs[sprinkler].as_probabilities()[1]
81        );
82        println!(
83            "    P(Wet | Wet)       = {:.2}",
84            beliefs[wet].as_probabilities()[1]
85        );
86    }
87    /*
88        println!();
89        println!("===== marginal probabilities assuming the sprinkler is running =====");
90        // Evidence doesn't need to be at the last node
91        net.reset_state();
92        net.set_evidence(&[(sprinkler, 1)]);
93        for _ in 1..10 {
94            // this one is quick to converge too
95            net.step();
96        }
97        let beliefs = net.beliefs();
98        println!(
99            "    P(Rain | Sprinkler)      = {:.2}",
100            beliefs[rain].as_probabilities()[1]
101        );
102        println!(
103            "    P(Sprinkler | Sprinkler) = {:.2}",
104            beliefs[sprinkler].as_probabilities()[1]
105        );
106        println!(
107            "    P(Wet | Sprinkler)       = {:.2}",
108            beliefs[wet].as_probabilities()[1]
109        );
110
111        println!();
112        println!("===== marginal probabilities assuming it's not rainning =====");
113        // Evidence can even be at the prior !
114        net.reset_state();
115        net.set_evidence(&[(rain, 0)]);
116        for _ in 1..10 {
117            // this one is quick to converge too
118            net.step();
119        }
120        let beliefs = net.beliefs();
121        println!(
122            "    P(Rain | not Rain)      = {:.2}",
123            beliefs[rain].as_probabilities()[1]
124        );
125        println!(
126            "    P(Sprinkler | not Rain) = {:.2}",
127            beliefs[sprinkler].as_probabilities()[1]
128        );
129        println!(
130            "    P(Wet | not Rain)       = {:.2}",
131            beliefs[wet].as_probabilities()[1]
132        );
133    */
134}
Source

pub fn add_node_from_probabilities<D: Dimension + RemoveAxis>( &mut self, parents: &[usize], probabilities: Array<f32, D>, ) -> usize

Add a new node to the network

You need to specify the list of its parents, and an array of probabilities representing p(x | parents). If the parents are (p1, ... pk), the shape of the array should thus be: (N, N_p1, ... N_pk), where N is the number of possible values for the current variables, and N_pi is the number of values of parent pi.

If the node has no parents, the propabilities must be single-dimenstionnal and represents a prior.

All values of probabilities should be finite, but the probabilities array does not need to be normalized, as it will be during the construction process.

Examples found in repository?
examples/simple_net.rs (line 21)
3fn main() {
4    let mut net = BayesNet::new();
5
6    // create a small graph from the classic example:
7    //
8    // +----------+          +----------------------+
9    // | It rains | -------> | Sprinkler is running |
10    // +----------+          +----------------------+
11    //       |                 |
12    //       +----+     +------+
13    //            |     |
14    //            v     v
15    //        +--------------+
16    //        | Grass is Wet |
17    //        +--------------+
18
19    // Rain has no parents, it is a prior
20    // We have P(not Rain) = 0.8, P(Rain) = 0.8
21    let rain = net.add_node_from_probabilities(&[], ndarray::Array1::from(vec![0.8, 0.2]));
22
23    // Sprinkler has a parent (Rain)
24    // We have P(not Sprinkler | not Rain) = 0.60, P(not Sprinkler | Rain) = 0.99
25    //         P(    Sprinkler | not Rain) = 0.40, P(    Sprinkler | Rain) = 0.01
26    let sprinkler = net.add_node_from_probabilities(
27        &[rain],
28        ndarray::Array2::from(vec![[0.60, 0.99], [0.40, 0.01]]),
29    );
30
31    // Wet has 2 parents (Rain and Sprinkler)
32    // We have P(not Wet | not Rain, not Sprinkler) = 1.0, P(not Wet | not Rain, Sprinkler) = 0.1
33    //         P(not Wet | Rain,     not Sprinkler) = 0.2, P(not Wet | Rain,     Sprinkler) = 0.01
34    //         P(    Wet | not Rain, not Sprinkler) = 0.0, P(    Wet | not Rain, Sprinkler) = 0.9
35    //         P(    Wet | Rain,     not Sprinkler) = 0.8, P(    Wet | Rain,     Sprinkler) = 0.99
36    let wet = net.add_node_from_probabilities(
37        &[rain, sprinkler],
38        ndarray::Array3::from(vec![[[1.0, 0.1], [0.2, 0.01]], [[0.0, 0.9], [0.8, 0.99]]]),
39    );
40    /*
41        // We can now do some inferences
42        // First, compute the marginal probabilities of the network without any evidence
43        net.reset_state();
44        net.set_evidence(&[]);
45        println!("===== raw marginal probabilities =====");
46        for _ in 1..10 {
47            // this net converges pretty quickly
48            net.step();
49        }
50        let beliefs = net.beliefs();
51        println!(
52            "    P(Rain)      = {:.2}",
53            beliefs[rain].as_probabilities()[1]
54        );
55        println!(
56            "    P(Sprinkler) = {:.2}",
57            beliefs[sprinkler].as_probabilities()[1]
58        );
59        println!(
60            "    P(Wet)       = {:.2}",
61            beliefs[wet].as_probabilities()[1]
62        );
63    */
64    println!();
65    println!("===== marginal probabilities assuming the grass is wet =====");
66    // Now, assuming we see the grass we, what can we infer from this ?
67    net.reset_state();
68    net.set_evidence(&[(wet, 1)]);
69    for i in 1..21 {
70        // this net is slower to converge
71        net.step();
72        let beliefs = net.beliefs();
73        println!("After iteration {}", i);
74        println!(
75            "    P(Rain | Wet)      = {:.2}",
76            beliefs[rain].as_probabilities()[1]
77        );
78        println!(
79            "    P(Sprinkler | Wet) = {:.2}",
80            beliefs[sprinkler].as_probabilities()[1]
81        );
82        println!(
83            "    P(Wet | Wet)       = {:.2}",
84            beliefs[wet].as_probabilities()[1]
85        );
86    }
87    /*
88        println!();
89        println!("===== marginal probabilities assuming the sprinkler is running =====");
90        // Evidence doesn't need to be at the last node
91        net.reset_state();
92        net.set_evidence(&[(sprinkler, 1)]);
93        for _ in 1..10 {
94            // this one is quick to converge too
95            net.step();
96        }
97        let beliefs = net.beliefs();
98        println!(
99            "    P(Rain | Sprinkler)      = {:.2}",
100            beliefs[rain].as_probabilities()[1]
101        );
102        println!(
103            "    P(Sprinkler | Sprinkler) = {:.2}",
104            beliefs[sprinkler].as_probabilities()[1]
105        );
106        println!(
107            "    P(Wet | Sprinkler)       = {:.2}",
108            beliefs[wet].as_probabilities()[1]
109        );
110
111        println!();
112        println!("===== marginal probabilities assuming it's not rainning =====");
113        // Evidence can even be at the prior !
114        net.reset_state();
115        net.set_evidence(&[(rain, 0)]);
116        for _ in 1..10 {
117            // this one is quick to converge too
118            net.step();
119        }
120        let beliefs = net.beliefs();
121        println!(
122            "    P(Rain | not Rain)      = {:.2}",
123            beliefs[rain].as_probabilities()[1]
124        );
125        println!(
126            "    P(Sprinkler | not Rain) = {:.2}",
127            beliefs[sprinkler].as_probabilities()[1]
128        );
129        println!(
130            "    P(Wet | not Rain)       = {:.2}",
131            beliefs[wet].as_probabilities()[1]
132        );
133    */
134}
Source

pub fn add_node_from_log_probabilities<D: Dimension + RemoveAxis>( &mut self, parents: &[usize], log_probabilities: Array<f32, D>, ) -> usize

Add a new node to the network from log-probabilities

Same as add_node_from_probabilities, but the input is in the form of log-probabilities, for greated precision.

All values of log-probas should be strictly smaller than +inf. -inf is valid and represents a probability of 0. The probabilities array does not need to be normalized, as it will be during the construction process. For example, the log-vector [0.0, -inf] will represent a vector of probabilities of [1.0, 0.0].

Log-probabilities are intepreted as computed with the natural logarithm (base e).

Source

pub fn set_evidence(&mut self, evidence: &[(usize, usize)])

Sets the evidence for the network

Input is interpreted as a list of (node_id, node_value). Out-of-range evidence is not checked, but will result into a probability of 0.

Examples found in repository?
examples/simple_net.rs (line 68)
3fn main() {
4    let mut net = BayesNet::new();
5
6    // create a small graph from the classic example:
7    //
8    // +----------+          +----------------------+
9    // | It rains | -------> | Sprinkler is running |
10    // +----------+          +----------------------+
11    //       |                 |
12    //       +----+     +------+
13    //            |     |
14    //            v     v
15    //        +--------------+
16    //        | Grass is Wet |
17    //        +--------------+
18
19    // Rain has no parents, it is a prior
20    // We have P(not Rain) = 0.8, P(Rain) = 0.8
21    let rain = net.add_node_from_probabilities(&[], ndarray::Array1::from(vec![0.8, 0.2]));
22
23    // Sprinkler has a parent (Rain)
24    // We have P(not Sprinkler | not Rain) = 0.60, P(not Sprinkler | Rain) = 0.99
25    //         P(    Sprinkler | not Rain) = 0.40, P(    Sprinkler | Rain) = 0.01
26    let sprinkler = net.add_node_from_probabilities(
27        &[rain],
28        ndarray::Array2::from(vec![[0.60, 0.99], [0.40, 0.01]]),
29    );
30
31    // Wet has 2 parents (Rain and Sprinkler)
32    // We have P(not Wet | not Rain, not Sprinkler) = 1.0, P(not Wet | not Rain, Sprinkler) = 0.1
33    //         P(not Wet | Rain,     not Sprinkler) = 0.2, P(not Wet | Rain,     Sprinkler) = 0.01
34    //         P(    Wet | not Rain, not Sprinkler) = 0.0, P(    Wet | not Rain, Sprinkler) = 0.9
35    //         P(    Wet | Rain,     not Sprinkler) = 0.8, P(    Wet | Rain,     Sprinkler) = 0.99
36    let wet = net.add_node_from_probabilities(
37        &[rain, sprinkler],
38        ndarray::Array3::from(vec![[[1.0, 0.1], [0.2, 0.01]], [[0.0, 0.9], [0.8, 0.99]]]),
39    );
40    /*
41        // We can now do some inferences
42        // First, compute the marginal probabilities of the network without any evidence
43        net.reset_state();
44        net.set_evidence(&[]);
45        println!("===== raw marginal probabilities =====");
46        for _ in 1..10 {
47            // this net converges pretty quickly
48            net.step();
49        }
50        let beliefs = net.beliefs();
51        println!(
52            "    P(Rain)      = {:.2}",
53            beliefs[rain].as_probabilities()[1]
54        );
55        println!(
56            "    P(Sprinkler) = {:.2}",
57            beliefs[sprinkler].as_probabilities()[1]
58        );
59        println!(
60            "    P(Wet)       = {:.2}",
61            beliefs[wet].as_probabilities()[1]
62        );
63    */
64    println!();
65    println!("===== marginal probabilities assuming the grass is wet =====");
66    // Now, assuming we see the grass we, what can we infer from this ?
67    net.reset_state();
68    net.set_evidence(&[(wet, 1)]);
69    for i in 1..21 {
70        // this net is slower to converge
71        net.step();
72        let beliefs = net.beliefs();
73        println!("After iteration {}", i);
74        println!(
75            "    P(Rain | Wet)      = {:.2}",
76            beliefs[rain].as_probabilities()[1]
77        );
78        println!(
79            "    P(Sprinkler | Wet) = {:.2}",
80            beliefs[sprinkler].as_probabilities()[1]
81        );
82        println!(
83            "    P(Wet | Wet)       = {:.2}",
84            beliefs[wet].as_probabilities()[1]
85        );
86    }
87    /*
88        println!();
89        println!("===== marginal probabilities assuming the sprinkler is running =====");
90        // Evidence doesn't need to be at the last node
91        net.reset_state();
92        net.set_evidence(&[(sprinkler, 1)]);
93        for _ in 1..10 {
94            // this one is quick to converge too
95            net.step();
96        }
97        let beliefs = net.beliefs();
98        println!(
99            "    P(Rain | Sprinkler)      = {:.2}",
100            beliefs[rain].as_probabilities()[1]
101        );
102        println!(
103            "    P(Sprinkler | Sprinkler) = {:.2}",
104            beliefs[sprinkler].as_probabilities()[1]
105        );
106        println!(
107            "    P(Wet | Sprinkler)       = {:.2}",
108            beliefs[wet].as_probabilities()[1]
109        );
110
111        println!();
112        println!("===== marginal probabilities assuming it's not rainning =====");
113        // Evidence can even be at the prior !
114        net.reset_state();
115        net.set_evidence(&[(rain, 0)]);
116        for _ in 1..10 {
117            // this one is quick to converge too
118            net.step();
119        }
120        let beliefs = net.beliefs();
121        println!(
122            "    P(Rain | not Rain)      = {:.2}",
123            beliefs[rain].as_probabilities()[1]
124        );
125        println!(
126            "    P(Sprinkler | not Rain) = {:.2}",
127            beliefs[sprinkler].as_probabilities()[1]
128        );
129        println!(
130            "    P(Wet | not Rain)       = {:.2}",
131            beliefs[wet].as_probabilities()[1]
132        );
133    */
134}
Source

pub fn reset_state(&mut self)

Resets the internal state of the inference algorithm, to begin a new inference

Examples found in repository?
examples/simple_net.rs (line 67)
3fn main() {
4    let mut net = BayesNet::new();
5
6    // create a small graph from the classic example:
7    //
8    // +----------+          +----------------------+
9    // | It rains | -------> | Sprinkler is running |
10    // +----------+          +----------------------+
11    //       |                 |
12    //       +----+     +------+
13    //            |     |
14    //            v     v
15    //        +--------------+
16    //        | Grass is Wet |
17    //        +--------------+
18
19    // Rain has no parents, it is a prior
20    // We have P(not Rain) = 0.8, P(Rain) = 0.8
21    let rain = net.add_node_from_probabilities(&[], ndarray::Array1::from(vec![0.8, 0.2]));
22
23    // Sprinkler has a parent (Rain)
24    // We have P(not Sprinkler | not Rain) = 0.60, P(not Sprinkler | Rain) = 0.99
25    //         P(    Sprinkler | not Rain) = 0.40, P(    Sprinkler | Rain) = 0.01
26    let sprinkler = net.add_node_from_probabilities(
27        &[rain],
28        ndarray::Array2::from(vec![[0.60, 0.99], [0.40, 0.01]]),
29    );
30
31    // Wet has 2 parents (Rain and Sprinkler)
32    // We have P(not Wet | not Rain, not Sprinkler) = 1.0, P(not Wet | not Rain, Sprinkler) = 0.1
33    //         P(not Wet | Rain,     not Sprinkler) = 0.2, P(not Wet | Rain,     Sprinkler) = 0.01
34    //         P(    Wet | not Rain, not Sprinkler) = 0.0, P(    Wet | not Rain, Sprinkler) = 0.9
35    //         P(    Wet | Rain,     not Sprinkler) = 0.8, P(    Wet | Rain,     Sprinkler) = 0.99
36    let wet = net.add_node_from_probabilities(
37        &[rain, sprinkler],
38        ndarray::Array3::from(vec![[[1.0, 0.1], [0.2, 0.01]], [[0.0, 0.9], [0.8, 0.99]]]),
39    );
40    /*
41        // We can now do some inferences
42        // First, compute the marginal probabilities of the network without any evidence
43        net.reset_state();
44        net.set_evidence(&[]);
45        println!("===== raw marginal probabilities =====");
46        for _ in 1..10 {
47            // this net converges pretty quickly
48            net.step();
49        }
50        let beliefs = net.beliefs();
51        println!(
52            "    P(Rain)      = {:.2}",
53            beliefs[rain].as_probabilities()[1]
54        );
55        println!(
56            "    P(Sprinkler) = {:.2}",
57            beliefs[sprinkler].as_probabilities()[1]
58        );
59        println!(
60            "    P(Wet)       = {:.2}",
61            beliefs[wet].as_probabilities()[1]
62        );
63    */
64    println!();
65    println!("===== marginal probabilities assuming the grass is wet =====");
66    // Now, assuming we see the grass we, what can we infer from this ?
67    net.reset_state();
68    net.set_evidence(&[(wet, 1)]);
69    for i in 1..21 {
70        // this net is slower to converge
71        net.step();
72        let beliefs = net.beliefs();
73        println!("After iteration {}", i);
74        println!(
75            "    P(Rain | Wet)      = {:.2}",
76            beliefs[rain].as_probabilities()[1]
77        );
78        println!(
79            "    P(Sprinkler | Wet) = {:.2}",
80            beliefs[sprinkler].as_probabilities()[1]
81        );
82        println!(
83            "    P(Wet | Wet)       = {:.2}",
84            beliefs[wet].as_probabilities()[1]
85        );
86    }
87    /*
88        println!();
89        println!("===== marginal probabilities assuming the sprinkler is running =====");
90        // Evidence doesn't need to be at the last node
91        net.reset_state();
92        net.set_evidence(&[(sprinkler, 1)]);
93        for _ in 1..10 {
94            // this one is quick to converge too
95            net.step();
96        }
97        let beliefs = net.beliefs();
98        println!(
99            "    P(Rain | Sprinkler)      = {:.2}",
100            beliefs[rain].as_probabilities()[1]
101        );
102        println!(
103            "    P(Sprinkler | Sprinkler) = {:.2}",
104            beliefs[sprinkler].as_probabilities()[1]
105        );
106        println!(
107            "    P(Wet | Sprinkler)       = {:.2}",
108            beliefs[wet].as_probabilities()[1]
109        );
110
111        println!();
112        println!("===== marginal probabilities assuming it's not rainning =====");
113        // Evidence can even be at the prior !
114        net.reset_state();
115        net.set_evidence(&[(rain, 0)]);
116        for _ in 1..10 {
117            // this one is quick to converge too
118            net.step();
119        }
120        let beliefs = net.beliefs();
121        println!(
122            "    P(Rain | not Rain)      = {:.2}",
123            beliefs[rain].as_probabilities()[1]
124        );
125        println!(
126            "    P(Sprinkler | not Rain) = {:.2}",
127            beliefs[sprinkler].as_probabilities()[1]
128        );
129        println!(
130            "    P(Wet | not Rain)       = {:.2}",
131            beliefs[wet].as_probabilities()[1]
132        );
133    */
134}
Source

pub fn beliefs(&self) -> Vec<LogProbVector>

Compute the current state belief of each node according to the current internal messages

Examples found in repository?
examples/simple_net.rs (line 72)
3fn main() {
4    let mut net = BayesNet::new();
5
6    // create a small graph from the classic example:
7    //
8    // +----------+          +----------------------+
9    // | It rains | -------> | Sprinkler is running |
10    // +----------+          +----------------------+
11    //       |                 |
12    //       +----+     +------+
13    //            |     |
14    //            v     v
15    //        +--------------+
16    //        | Grass is Wet |
17    //        +--------------+
18
19    // Rain has no parents, it is a prior
20    // We have P(not Rain) = 0.8, P(Rain) = 0.8
21    let rain = net.add_node_from_probabilities(&[], ndarray::Array1::from(vec![0.8, 0.2]));
22
23    // Sprinkler has a parent (Rain)
24    // We have P(not Sprinkler | not Rain) = 0.60, P(not Sprinkler | Rain) = 0.99
25    //         P(    Sprinkler | not Rain) = 0.40, P(    Sprinkler | Rain) = 0.01
26    let sprinkler = net.add_node_from_probabilities(
27        &[rain],
28        ndarray::Array2::from(vec![[0.60, 0.99], [0.40, 0.01]]),
29    );
30
31    // Wet has 2 parents (Rain and Sprinkler)
32    // We have P(not Wet | not Rain, not Sprinkler) = 1.0, P(not Wet | not Rain, Sprinkler) = 0.1
33    //         P(not Wet | Rain,     not Sprinkler) = 0.2, P(not Wet | Rain,     Sprinkler) = 0.01
34    //         P(    Wet | not Rain, not Sprinkler) = 0.0, P(    Wet | not Rain, Sprinkler) = 0.9
35    //         P(    Wet | Rain,     not Sprinkler) = 0.8, P(    Wet | Rain,     Sprinkler) = 0.99
36    let wet = net.add_node_from_probabilities(
37        &[rain, sprinkler],
38        ndarray::Array3::from(vec![[[1.0, 0.1], [0.2, 0.01]], [[0.0, 0.9], [0.8, 0.99]]]),
39    );
40    /*
41        // We can now do some inferences
42        // First, compute the marginal probabilities of the network without any evidence
43        net.reset_state();
44        net.set_evidence(&[]);
45        println!("===== raw marginal probabilities =====");
46        for _ in 1..10 {
47            // this net converges pretty quickly
48            net.step();
49        }
50        let beliefs = net.beliefs();
51        println!(
52            "    P(Rain)      = {:.2}",
53            beliefs[rain].as_probabilities()[1]
54        );
55        println!(
56            "    P(Sprinkler) = {:.2}",
57            beliefs[sprinkler].as_probabilities()[1]
58        );
59        println!(
60            "    P(Wet)       = {:.2}",
61            beliefs[wet].as_probabilities()[1]
62        );
63    */
64    println!();
65    println!("===== marginal probabilities assuming the grass is wet =====");
66    // Now, assuming we see the grass we, what can we infer from this ?
67    net.reset_state();
68    net.set_evidence(&[(wet, 1)]);
69    for i in 1..21 {
70        // this net is slower to converge
71        net.step();
72        let beliefs = net.beliefs();
73        println!("After iteration {}", i);
74        println!(
75            "    P(Rain | Wet)      = {:.2}",
76            beliefs[rain].as_probabilities()[1]
77        );
78        println!(
79            "    P(Sprinkler | Wet) = {:.2}",
80            beliefs[sprinkler].as_probabilities()[1]
81        );
82        println!(
83            "    P(Wet | Wet)       = {:.2}",
84            beliefs[wet].as_probabilities()[1]
85        );
86    }
87    /*
88        println!();
89        println!("===== marginal probabilities assuming the sprinkler is running =====");
90        // Evidence doesn't need to be at the last node
91        net.reset_state();
92        net.set_evidence(&[(sprinkler, 1)]);
93        for _ in 1..10 {
94            // this one is quick to converge too
95            net.step();
96        }
97        let beliefs = net.beliefs();
98        println!(
99            "    P(Rain | Sprinkler)      = {:.2}",
100            beliefs[rain].as_probabilities()[1]
101        );
102        println!(
103            "    P(Sprinkler | Sprinkler) = {:.2}",
104            beliefs[sprinkler].as_probabilities()[1]
105        );
106        println!(
107            "    P(Wet | Sprinkler)       = {:.2}",
108            beliefs[wet].as_probabilities()[1]
109        );
110
111        println!();
112        println!("===== marginal probabilities assuming it's not rainning =====");
113        // Evidence can even be at the prior !
114        net.reset_state();
115        net.set_evidence(&[(rain, 0)]);
116        for _ in 1..10 {
117            // this one is quick to converge too
118            net.step();
119        }
120        let beliefs = net.beliefs();
121        println!(
122            "    P(Rain | not Rain)      = {:.2}",
123            beliefs[rain].as_probabilities()[1]
124        );
125        println!(
126            "    P(Sprinkler | not Rain) = {:.2}",
127            beliefs[sprinkler].as_probabilities()[1]
128        );
129        println!(
130            "    P(Wet | not Rain)       = {:.2}",
131            beliefs[wet].as_probabilities()[1]
132        );
133    */
134}
Source

pub fn step(&mut self)

Compute one step of the Loopy Belief Propagation Algorithm

The algorithm can be run for any number of steps. it is up to you to decide when to stop.

A classic stopping criterion is when the yielded beliefs stop significantly changing.

Examples found in repository?
examples/simple_net.rs (line 71)
3fn main() {
4    let mut net = BayesNet::new();
5
6    // create a small graph from the classic example:
7    //
8    // +----------+          +----------------------+
9    // | It rains | -------> | Sprinkler is running |
10    // +----------+          +----------------------+
11    //       |                 |
12    //       +----+     +------+
13    //            |     |
14    //            v     v
15    //        +--------------+
16    //        | Grass is Wet |
17    //        +--------------+
18
19    // Rain has no parents, it is a prior
20    // We have P(not Rain) = 0.8, P(Rain) = 0.8
21    let rain = net.add_node_from_probabilities(&[], ndarray::Array1::from(vec![0.8, 0.2]));
22
23    // Sprinkler has a parent (Rain)
24    // We have P(not Sprinkler | not Rain) = 0.60, P(not Sprinkler | Rain) = 0.99
25    //         P(    Sprinkler | not Rain) = 0.40, P(    Sprinkler | Rain) = 0.01
26    let sprinkler = net.add_node_from_probabilities(
27        &[rain],
28        ndarray::Array2::from(vec![[0.60, 0.99], [0.40, 0.01]]),
29    );
30
31    // Wet has 2 parents (Rain and Sprinkler)
32    // We have P(not Wet | not Rain, not Sprinkler) = 1.0, P(not Wet | not Rain, Sprinkler) = 0.1
33    //         P(not Wet | Rain,     not Sprinkler) = 0.2, P(not Wet | Rain,     Sprinkler) = 0.01
34    //         P(    Wet | not Rain, not Sprinkler) = 0.0, P(    Wet | not Rain, Sprinkler) = 0.9
35    //         P(    Wet | Rain,     not Sprinkler) = 0.8, P(    Wet | Rain,     Sprinkler) = 0.99
36    let wet = net.add_node_from_probabilities(
37        &[rain, sprinkler],
38        ndarray::Array3::from(vec![[[1.0, 0.1], [0.2, 0.01]], [[0.0, 0.9], [0.8, 0.99]]]),
39    );
40    /*
41        // We can now do some inferences
42        // First, compute the marginal probabilities of the network without any evidence
43        net.reset_state();
44        net.set_evidence(&[]);
45        println!("===== raw marginal probabilities =====");
46        for _ in 1..10 {
47            // this net converges pretty quickly
48            net.step();
49        }
50        let beliefs = net.beliefs();
51        println!(
52            "    P(Rain)      = {:.2}",
53            beliefs[rain].as_probabilities()[1]
54        );
55        println!(
56            "    P(Sprinkler) = {:.2}",
57            beliefs[sprinkler].as_probabilities()[1]
58        );
59        println!(
60            "    P(Wet)       = {:.2}",
61            beliefs[wet].as_probabilities()[1]
62        );
63    */
64    println!();
65    println!("===== marginal probabilities assuming the grass is wet =====");
66    // Now, assuming we see the grass we, what can we infer from this ?
67    net.reset_state();
68    net.set_evidence(&[(wet, 1)]);
69    for i in 1..21 {
70        // this net is slower to converge
71        net.step();
72        let beliefs = net.beliefs();
73        println!("After iteration {}", i);
74        println!(
75            "    P(Rain | Wet)      = {:.2}",
76            beliefs[rain].as_probabilities()[1]
77        );
78        println!(
79            "    P(Sprinkler | Wet) = {:.2}",
80            beliefs[sprinkler].as_probabilities()[1]
81        );
82        println!(
83            "    P(Wet | Wet)       = {:.2}",
84            beliefs[wet].as_probabilities()[1]
85        );
86    }
87    /*
88        println!();
89        println!("===== marginal probabilities assuming the sprinkler is running =====");
90        // Evidence doesn't need to be at the last node
91        net.reset_state();
92        net.set_evidence(&[(sprinkler, 1)]);
93        for _ in 1..10 {
94            // this one is quick to converge too
95            net.step();
96        }
97        let beliefs = net.beliefs();
98        println!(
99            "    P(Rain | Sprinkler)      = {:.2}",
100            beliefs[rain].as_probabilities()[1]
101        );
102        println!(
103            "    P(Sprinkler | Sprinkler) = {:.2}",
104            beliefs[sprinkler].as_probabilities()[1]
105        );
106        println!(
107            "    P(Wet | Sprinkler)       = {:.2}",
108            beliefs[wet].as_probabilities()[1]
109        );
110
111        println!();
112        println!("===== marginal probabilities assuming it's not rainning =====");
113        // Evidence can even be at the prior !
114        net.reset_state();
115        net.set_evidence(&[(rain, 0)]);
116        for _ in 1..10 {
117            // this one is quick to converge too
118            net.step();
119        }
120        let beliefs = net.beliefs();
121        println!(
122            "    P(Rain | not Rain)      = {:.2}",
123            beliefs[rain].as_probabilities()[1]
124        );
125        println!(
126            "    P(Sprinkler | not Rain) = {:.2}",
127            beliefs[sprinkler].as_probabilities()[1]
128        );
129        println!(
130            "    P(Wet | not Rain)       = {:.2}",
131            beliefs[wet].as_probabilities()[1]
132        );
133    */
134}

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.