Awesome
clarinet 🎵
(another) Open-source probabilistic graphical model library. Designed to be easy to use and interoperable with an internally developed C-based package at Bain and Company, Roma. ** Note: This project is in pre-alpha, so expect the whole thing to be one sharp edge. **
functionality roadmap:
Completed:
- basic DAG creation and manipulation via
Node
class BayesNet
class that wraps DAG logic- stringent runtime type-checking via
pydantic
- graph vizualisation capability
- on-the-fly construction of junction tree
- probability table naming and manipulation via
xarray
- exporting of network structure to lightweight json format
- network interoperability with:
- bnlearn-style modelstrings
- HBNet json specification (Bain package)
To-do:
- inference via probabilistic programming backend (e.g. numpyro)
usage:
Here's a basic look at the DAG-making functionality:
from clarinet import BayesNet
# bnlearn-style modelstring init
BayesNet.from_modelstring("[A][C][B|A][D|C][F|A:B:C][E|F]")
#> BayesNet(
# nodes=<immutables.Map(
# {
# 'C': Node(name='C', parents=(), children=('D', 'F')),
# 'F': Node(name='F', parents=('A', 'B', 'C'), children=('E',)),
# 'B': Node(name='B', parents=('A',), children=('F',)),
# 'D': Node(name='D', parents=('C',), children=()),
# 'A': Node(name='A', parents=(), children=('B', 'F')),
# 'E': Node(name='E', parents=('F',), children=())
# }
# ) at 0x16b5475c0>, modelstring=''
#)
# dict-style init
example_model_dict = {
"raining": {
"parents": ["cloudy"],
"children": ["wet grass"],
"states": ["raining", "not raining"],
},
"cloudy": {
"children": ["raining"],
},
"wet grass": {
"parents": ["raining"],
},
}
net = BayesNet.from_dict(example_model_dict)
net
#> BayesNet(
# nodes=<immutables.Map(
# {
# 'wet grass': Node(name='wet grass', parents=('raining',), children=()),
# 'cloudy': Node(name='cloudy', parents=(), children=('raining',)),
# 'raining': DiscreteNode(name='raining', parents=('cloudy',), children=('wet grass',), prob_table=array([], dtype=float32), states=('raining', 'not raining'))
# }
# ) at 0x16a6b2100>, modelstring=''
#)
# index into the network by name to look at a particular node
net["raining"]
#> DiscreteNode(name='raining', parents=('cloudy',), children=('wet grass',), prob_table=array([], dtype=float32), states=('raining', 'not raining'))
# let's add some state names that we forgot!
net.convert_nodes(
names=["wet grass", "cloudy"],
new_node_types=[
cn.DiscreteNode,
cn.DiscreteNode
],
new_node_kwargs=[
dict(states=["wet", "dry"]),
dict(states=["cloudy", "clear"]),
]
)
#> BayesNet(
# nodes={
# 'wet grass': DiscreteNode(name='wet grass', parents=('raining',), children=(), prob_table=array([], dtype=float32), states=('wet', 'dry')),
# 'cloudy': DiscreteNode(name='cloudy', parents=(), children=('raining',), prob_table=array([], dtype=float32), states=('cloudy', 'clear')),
# 'raining': DiscreteNode(name='raining', parents=('cloudy',), children=('wet grass',), prob_table=array([], dtype=float32), states=('raining', 'not raining'))
# }, modelstring=''
#)