Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions examples/coin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,30 @@
import matplotlib.pyplot as plt
import seaborn as sns


with treeppl.Model(filename="coin.tppl", samples=100000) as coin:
with treeppl.Model(filename="coin.tppl", m="smc-bpf", particles=100000) as coin:
res = coin(
outcomes=[
True, True, True, False, True, False, False, True, True, False,
False, False, True, False, True, False, False, False, False, False,
True,
True,
True,
False,
True,
False,
False,
True,
True,
False,
False,
False,
True,
False,
True,
False,
False,
False,
False,
False,
]
)
sns.histplot(
x=res.samples, weights=res.nweights, bins=100, stat="density", kde=True
)
sns.histplot(x=res.samples, weights=res.nweights, bins=100, stat="density", kde=True)
plt.show()
14 changes: 6 additions & 8 deletions examples/crbd.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@
import matplotlib.pyplot as plt
import seaborn as sns


alcedinidae = treeppl.Tree.load("trees/Alcedinidae.phyjson", format="phyjson")
samples = None
with treeppl.Model(filename="crbd.tppl", samples=10000, subsamples=10) as crbd:
with treeppl.Model(
filename="crbd.tppl", m="smc-bpf", particles=10000, resample="align", subsample=True, subsample_size=10
) as crbd:
for i in range(1000):
res = crbd(tree=alcedinidae)
samples = pd.concat([
samples,
pd.DataFrame({
"lambda": res.items(0), "mu": res.items(1), "lweight": res.norm_const
})
])
samples = pd.concat(
[samples, pd.DataFrame({"lambda": res.items(0), "mu": res.items(1), "lweight": res.norm_const})]
)
weights = np.exp(samples.lweight - samples.lweight.max())
plt.clf()
sns.kdeplot(data=samples, x="lambda", weights=weights)
Expand Down
11 changes: 4 additions & 7 deletions examples/generative_crbd.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@
import treeppl
from Bio import Phylo

args = {"time": 5.0, "lambda": 1.0, "mu": 0.1}

params = {"time": 5.0, "lambda": 1.0, "mu": 0.1}

with treeppl.Model(filename="generative_crbd.tppl", samples=1) as generative_crbd:
result = generative_crbd(**params)
with treeppl.Model(filename="generative_crbd.tppl", particles=1) as generative_crbd:
result = generative_crbd(args)
tree = result.samples[0]
tree = Phylo.BaseTree.Clade(
branch_length=params["time"] - tree.age, clades=[tree.to_biopython()]
)
tree = Phylo.BaseTree.Clade(branch_length=args["time"] - tree.age, clades=[tree.to_biopython()])
Phylo.draw(tree)
32 changes: 14 additions & 18 deletions examples/treeppl_in_jupyter.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@
"id": "a67a0418",
"metadata": {},
"source": [
"Once the extension is loaded, users can use the `%%treeppl` cell magic to write and compile a TreePPL program. Executing the cell creates a `treeppl.Model` object, which allows interaction with the compiled program directly in Python. This object is stored in a Python variable specified as an argument to the `%%treeppl` magic (i.e., immediately following `%%treeppl` on the first line). Optionally, the variable name can be followed by parameters and values. Most of these are passed to the TreePPL compiler, except for the `samples` parameter, which specifies the number of samples to draw when the program is executed. Examples are provided below.\n",
"\n",
"The extension also supports basic syntax highlighting for TreePPL programs.\n",
"Once the extension is loaded, users can use the `%%treeppl` cell magic to write and compile a TreePPL program. Executing the cell creates a `treeppl.Model` object, which allows interaction with the compiled program directly in Python. This object is stored in a Python variable specified as an argument to the `%%treeppl` magic (i.e., immediately following `%%treeppl` on the first line). The variable name can be followed by arguments and values, all of which are passed directly to the TreePPL compiler. Examples are provided below.\n",
"\n",
"For example, the following cell demonstrates a simple TreePPL program for simulating the flip of a fair coin:"
]
Expand All @@ -71,7 +69,7 @@
"metadata": {},
"outputs": [],
"source": [
"%%treeppl flip samples=10\n",
"%%treeppl flip --particles 10\n",
"\n",
"model function flip() => Bool {\n",
" assume p ~ Bernoulli(0.5);\n",
Expand All @@ -84,9 +82,9 @@
"id": "d71e9d44",
"metadata": {},
"source": [
"In this example, a `treeppl.Model` instance is created, and the program is compiled. The variable name `flip` (specified after `%%treeppl`) provides an interface for interacting with the model. The argument `samples=10` specifies the number of samples to generate when the program is executed.\n",
"In this example, a `treeppl.Model` instance is created, and the program is compiled. The variable name `flip` (specified after `%%treeppl`) provides an interface for interacting with the model. The argument `--particles 10` sets the number of particles used when executing the program. If no inference method is specified via the `--m` parameter, the default is importance sampling.\n",
"\n",
"To run the TreePPL program, simply call the variable as a function (e.g., `flip()`). This executes the program and returns a `treeppl.InferenceResult` object, which includes a `samples` attribute containing the generated samples. While samples may have different weights in more complex programs, they are equally weighted in this simple example. We will cover programs with weighted samples later.\n",
"To run the TreePPL program, simply call the variable as a function (e.g., `flip()`). This executes the program and returns a `treeppl.InferenceResult` object, which includes a `samples` attribute containing the generated samples. While samples may have different weights in more complex programs, they are equally weighted in this simple example. Programs with weighted samples will be demonstrated later.\n",
"\n",
"Here’s an example of how to use the compiled program:"
]
Expand Down Expand Up @@ -125,7 +123,7 @@
"metadata": {},
"outputs": [],
"source": [
"%%treeppl coin samples=100000\n",
"%%treeppl coin -m smc-bpf --particles 100000\n",
"\n",
"model function coin(outcomes: Bool[]) => Real {\n",
" assume p ~ Uniform(0.0, 1.0);\n",
Expand Down Expand Up @@ -169,7 +167,7 @@
"metadata": {},
"outputs": [],
"source": [
"%%treeppl generative_crbd samples=1\n",
"%%treeppl generative_crbd --particles 1\n",
"\n",
"model function generativeCrbd(time: Real, lambda: Real, mu: Real) => Tree {\n",
" assume waitingTime ~ Exponential(lambda + mu);\n",
Expand Down Expand Up @@ -198,16 +196,16 @@
"metadata": {},
"outputs": [],
"source": [
"params = {\n",
"args = {\n",
" \"time\": 5.0,\n",
" \"lambda\": 1.0,\n",
" \"mu\": 0.1\n",
"}\n",
"\n",
"result = generative_crbd(**params)\n",
"result = generative_crbd(args)\n",
"tree = result.samples[0]\n",
"tree = Phylo.BaseTree.Clade(\n",
" branch_length=params[\"time\"] - tree.age,\n",
" branch_length=args[\"time\"] - tree.age,\n",
" clades=[tree.to_biopython()]\n",
")\n",
"Phylo.draw(tree)"
Expand All @@ -228,7 +226,7 @@
"metadata": {},
"outputs": [],
"source": [
"%%treeppl crbd samples=10000 subsamples=10\n",
"%%treeppl crbd -m smc-bpf --particles 10000 --resample align --subsample --subsample-size 10\n",
"\n",
"function simulateExtinctSubtree(time: Real, lambda: Real, mu: Real) {\n",
" assume waitingTime ~ Exponential(lambda + mu);\n",
Expand Down Expand Up @@ -275,9 +273,7 @@
"cell_type": "code",
"execution_count": null,
"id": "00bfd918",
"metadata": {
"scrolled": false
},
"metadata": {},
"outputs": [],
"source": [
"alcedinidae = treeppl.Tree.load(\"trees/Alcedinidae.phyjson\", format=\"phyjson\")\n",
Expand Down Expand Up @@ -306,9 +302,9 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": "Python [conda env:base] *",
"language": "python",
"name": "python3"
"name": "conda-base-py"
},
"language_info": {
"codemirror_mode": {
Expand All @@ -320,7 +316,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
"version": "3.13.9"
}
},
"nbformat": 4,
Expand Down
14 changes: 7 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from setuptools import setup

setup(
name='treeppl',
version='0.1',
description='Python Interface to TreePPL',
author='Jan Kudlicka',
author_email='github@kudlicka.eu',
packages=['treeppl'],
name="treeppl",
version="0.1",
description="Python Interface to TreePPL",
author="Jan Kudlicka",
author_email="github@kudlicka.eu",
packages=["treeppl"],
install_requires=[
'numpy',
"numpy",
],
)
21 changes: 8 additions & 13 deletions tests/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,20 @@

def test_compilation_error():
with pytest.raises(treeppl.CompileError):
with treeppl.Model(
source="""\
with treeppl.Model(source="""\
model incorrect() {
return result;
}
""",
samples=1,
) as model:
""") as model:
model()


def test_coin():
nsamples = 100
with treeppl.Model(filename="examples/coin.tppl", samples=nsamples) as coin:
particles = 100
with treeppl.Model(filename="examples/coin.tppl", m="smc-bpf", particles=particles) as coin:
res = coin(outcomes=(np.random.random(10) < 0.5).tolist())
assert isinstance(res, treeppl.InferenceResult)
assert len(res.samples) == nsamples
assert len(res.samples) == particles


def test_matrix_mul():
Expand All @@ -35,17 +32,15 @@ def test_matrix_mul():
return a *@ b;
}
""",
samples=1,
particles=1,
) as matrix_mul:
result = matrix_mul(a=a, b=b).samples[0]
assert (result == expected).all()


def test_tree_input():
tree = treeppl.Tree.Node(
left=treeppl.Tree.Node(
left=treeppl.Tree.Leaf(age=0.0), right=treeppl.Tree.Leaf(age=0.0), age=0.5
),
left=treeppl.Tree.Node(left=treeppl.Tree.Leaf(age=0.0), right=treeppl.Tree.Leaf(age=0.0), age=0.5),
right=treeppl.Tree.Leaf(age=0.0),
age=1.0,
)
Expand All @@ -62,7 +57,7 @@ def test_tree_input():
return count_leaves(tree);
}
""",
samples=1,
particles=1,
) as count_tree_leaves:
res = count_tree_leaves(tree=tree)
assert res.samples[0] == 3
2 changes: 1 addition & 1 deletion treeppl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .base import Model, InferenceResult
from .base import Model, InferenceResult, CompileArguments, RunArguments
from .exceptions import CompileError, InferenceError
from .serialization import Object, constructor
from .stdlib import Tree
Loading