from causalinfo import *

# You only need this if you want to draw pretty pictures of the Networks
from nxpd import draw, nxpdParams
nxpdParams['show'] = 'ipynb'

"""
Explanation: An introduction to using causalinfo
Setup
We need to import the library, and a few other useful things for displaying the graphs.
End of explanation
"""


s = Variable('s', 2)
a = Variable('a', 2)
b = Variable('b', 2)

"""
Explanation: Creating Variables & Distributions
We start by creating some variables. They each have a name, and a number of states. All our variables have 2 states, 0 and 1. For the purposes of our equations below, we can treat these like False and True.
Note that:
* We can have any number of discrete states, we just using two for these examples.
* I'm using the convention of naming the python variables the same as our causal Variables. It might get confusing otherwise.
End of explanation
"""


ds = UniformDist(s)

"""
Explanation: Variables just provide a way to identifying or naming something we want to track in causalinfo. Rather than assigning them a particular value, we generate a Distribution over one or more variables. The easiest way to do this is using a UniformDist.
End of explanation
"""


ds

dsa = UniformDist(s, a)
dsa

"""
Explanation: These objects are smart in ipython notebook, and can display themselves.
End of explanation
"""


dsa2 = JointDist({s: [.2, .8], a: [.4, .6]})
dsa2

"""
Explanation: We can specify the exact probabilities in a distribution to...
End of explanation
"""


same_eq = Equation('SAME', [s], [a], equations.same_)
xnor_eq = Equation('XNOR', [s, a], [b], equations.xnor_)

"""
Explanation: Creating Equations (Conditional Probability Distributions)
We can now relate these variables using equations that map an input distribution to an output distribution. Some common Equations are already available, especially for simple binary states. But you can also create your own mappings --- a topic for later.
End of explanation
"""


same_eq

xnor_eq

"""
Explanation: We can also examine these equations to see what mappings they give...
End of explanation
"""


isinstance(same_eq, Equation)

gr = CausalGraph([same_eq, xnor_eq])

"""
Explanation: Creating Causal Graphs
We can now put these equations together to form causal networks.
End of explanation
"""


draw(gr.full_network)

draw(gr.causal_network)

"""
Explanation: We can also look at these (if you have the right things installed... more later).
End of explanation
"""


root_dist = UniformDist(s)
j = gr.generate_joint(root_dist)
j

"""
Explanation: Generating Joint Distributions
These networks can now be used to generate joint distributions over all the variables. The one thing we need to supply is a distribution over the root variables (those with no parents).
End of explanation
"""


j.joint(a, b)

"""
Explanation: We can look at the joint distribution of just some of those variables...
End of explanation
"""


j.mutual_info(a, b)

j.mutual_info(s, a)

j.mutual_info(a, b, s)

"""
Explanation: ...and we can calculate the mutual information, and conditional mutual information
End of explanation
"""


j_do = gr.generate_joint(root_dist,
                          do_dist=UniformDist(a))

j_do.mutual_info(a, b)

j_do.mutual_info(a, b, s)

"""
Explanation: Interventions
We can also intervene on this graph. We'll need a distribution over the intervention variable if we want to do this.
End of explanation
"""


j_do

"""
Explanation: Note the last calculation is not the same as above (it was 0.0). That is because the joint distribution is different under interventions, as we can see...
End of explanation
"""


