Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

PyMC3 was renamed to PyMC #5

Closed
wants to merge 4 commits into from
Closed
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
9 changes: 5 additions & 4 deletions .github/workflows/ci-fenics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

- name: Setup Miniconda
uses: conda-incubator/setup-miniconda@v2
with:
with:
auto-update-conda: true
python-version: 3.8

Expand Down Expand Up @@ -50,9 +50,10 @@ jobs:
python -m pip install fdm
python -m pip install git+https://github.com/dolfin-adjoint/pyadjoint.git@master
python -m pip install git+https://github.com/IvanYashchuk/fecr.git@master
python -m pip install pymc3
python -m pip install pymc
python -m pip install theano-pymc

- name: Install fenics-pymc3
- name: Install fenics-pymc
shell: bash -l {0}
run: |
conda activate fenicsproject
Expand All @@ -66,7 +67,7 @@ jobs:
conda activate fenicsproject
python -c "import sys; print('\n'.join(sys.path))"
export HDF5_DISABLE_VERSION_CHECK=1
python -m pytest --cov=fenics_pymc3 --cov-config=tests/.coveragerc tests/fenics -vvv
python -m pytest --cov=fenics_pymc --cov-config=tests/.coveragerc tests/fenics -vvv

- name: Send coverage
shell: bash -l {0}
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/ci-firedrake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ jobs:
python -m pip install git+https://github.com/dolfin-adjoint/pyadjoint.git@master
python -m pip install git+https://github.com/IvanYashchuk/fecr.git@master
python -m pip install arviz==0.10.0
python -m pip install pymc3
python -m pip install pymc
python -m pip install theano-pymc

- name: Install current package
shell: bash -l {0}
Expand All @@ -59,7 +60,7 @@ jobs:
source /home/firedrake/firedrake/bin/activate
python -c "import sys; print('\n'.join(sys.path))"
export HDF5_DISABLE_VERSION_CHECK=1
python -m pytest --cov=fenics_pymc3 --cov-config=tests/.coveragerc tests/firedrake -vvv
python -m pytest --cov=fenics_pymc --cov-config=tests/.coveragerc tests/firedrake -vvv

- name: Send coverage
shell: bash -l {0}
Expand Down
32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# fenics-pymc3 · [![Build FEniCS](https://github.com/ivanyashchuk/fenics-pymc3/workflows/FEniCS/badge.svg)](https://github.com/ivanyashchuk/fenics-pymc3/actions?query=workflow%3AFEniCS+branch%3Amaster) [![Build Firedrake](https://github.com/ivanyashchuk/fenics-pymc3/workflows/Firedrake/badge.svg)](https://github.com/ivanyashchuk/fenics-pymc3/actions?query=workflow%3AFiredrake+branch%3Amaster) [![codecov](https://codecov.io/gh/IvanYashchuk/fenics-pymc3/branch/master/graph/badge.svg?token=Y5ULDQD9L8)](https://codecov.io/gh/IvanYashchuk/fenics-pymc3) [![DOI](https://zenodo.org/badge/269920875.svg)](https://zenodo.org/badge/latestdoi/269920875)
# fenics-pymc · [![Build FEniCS](https://github.com/ivanyashchuk/fenics-pymc/workflows/FEniCS/badge.svg)](https://github.com/ivanyashchuk/fenics-pymc/actions?query=workflow%3AFEniCS+branch%3Amaster) [![Build Firedrake](https://github.com/ivanyashchuk/fenics-pymc/workflows/Firedrake/badge.svg)](https://github.com/ivanyashchuk/fenics-pymc/actions?query=workflow%3AFiredrake+branch%3Amaster) [![codecov](https://codecov.io/gh/IvanYashchuk/fenics-pymc/branch/master/graph/badge.svg?token=Y5ULDQD9L8)](https://codecov.io/gh/IvanYashchuk/fenics-pymc) [![DOI](https://zenodo.org/badge/269920875.svg)](https://zenodo.org/badge/latestdoi/269920875)

This package enables use of [FEniCS](https://fenicsproject.org/) or [Firedrake](https://firedrakeproject.org/) for solving differentiable variational problems in [PyMC3](https://docs.pymc.io/).
This package enables use of [FEniCS](https://fenicsproject.org/) or [Firedrake](https://firedrakeproject.org/) for solving differentiable variational problems in [PyMC](https://docs.pymc.io/).

Automatic adjoint solvers for FEniCS programs are generated with [dolfin-adjoint/pyadjoint](http://www.dolfin-adjoint.org/en/latest/).
These solvers make it possible to use Theano's (PyMC3 backend) reverse mode automatic differentiation with FEniCS/Firedrake.
These solvers make it possible to use Theano's (PyMC backend) reverse mode automatic differentiation with FEniCS/Firedrake.

Current limitations:
* Differentiation wrt Dirichlet boundary conditions and mesh coordinates is not implemented yet.

## Example
Here is the demonstration of fitting coefficients of a variant of the [Poisson's PDE](https://en.wikipedia.org/wiki/Poisson%27s_equation)
using PyMC3's NUTS sampler.
using PyMC's NUTS sampler.

```python
import numpy as np
Expand All @@ -19,8 +19,8 @@ fenics.set_log_level(fenics.LogLevel.ERROR)
import fenics_adjoint as fa
import ufl

from fenics_pymc3 import create_fem_theano_op
from fenics_pymc3 import to_numpy
from fenics_pymc import create_fem_theano_op
from fenics_pymc import to_numpy

# Create mesh for the unit square domain
n = 10
Expand Down Expand Up @@ -63,8 +63,8 @@ templates = (fa.Constant(0.0), fa.Constant(0.0))
# Now let's create Theano wrapper of `solve_fenics` function
theano_fem_solver = create_fem_theano_op(templates)(solve_fenics)

# `theano_fem_solver` can now be used inside PyMC3's model
import pymc3 as pm
# `theano_fem_solver` can now be used inside PyMC's model
import pymc as pm
import theano.tensor as tt

with pm.Model() as fit_poisson:
Expand Down Expand Up @@ -100,38 +100,38 @@ Then install [fecr](https://github.com/IvanYashchuk/fecr) with:

python -m pip install git+https://github.com/IvanYashchuk/fecr@master

Then install [PyMC3](https://docs.pymc.io/) with:
Then install [PyMC](https://docs.pymc.io/) with:

python -m pip install pymc3
python -m pip install pymc

After that install fenics-pymc3 with:
After that install fenics-pymc with:

python -m pip install git+https://github.com/IvanYashchuk/fenics-pymc3.git@master
python -m pip install git+https://github.com/IvanYashchuk/fenics-pymc.git@master

## Reporting bugs

If you found a bug, create an [issue].

[issue]: https://github.com/IvanYashchuk/fenics-pymc3/issues/new
[issue]: https://github.com/IvanYashchuk/fenics-pymc/issues/new

## Asking questions and general discussion

If you have a question or anything else, create a new [discussion]. Using issues is also fine!

[discussion]: https://github.com/IvanYashchuk/fenics-pymc3/discussions/new
[discussion]: https://github.com/IvanYashchuk/fenics-pymc/discussions/new

## Contributing

Pull requests are welcome from everyone.

Fork, then clone the repository:

git clone https://github.com/IvanYashchuk/fenics-pymc3.git
git clone https://github.com/IvanYashchuk/fenics-pymc.git

Make your change. Add tests for your change. Make the tests pass:

pytest tests/

Check the formatting with `black` and `flake8`. Push to your fork and [submit a pull request][pr].

[pr]: https://github.com/IvanYashchuk/fenics-pymc3/pulls
[pr]: https://github.com/IvanYashchuk/fenics-pymc/pulls
3 changes: 3 additions & 0 deletions fenics_pymc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .core import create_fenics_theano_op, create_fem_theano_op
from .core import FenicsOp, FenicsVJPOp
from fecr import to_numpy, from_numpy
110 changes: 110 additions & 0 deletions fenics_pymc/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import theano

try:
from theano.graph.op import Op, Apply
from theano.graph import type
except ModuleNotFoundError:
# older version of theano
from theano.gof import Op, Apply, type


import functools

from fecr import evaluate_primal, evaluate_pullback


class FenicsVJPOp(Op):
params_type = type.Generic()
__props__ = ("ofunc", "templates", "fenics_output", "fenics_inputs", "tape")

def __init__(self, ofunc, templates, fenics_output, fenics_inputs, tape):
self.ofunc = ofunc
self.templates = templates
self.fenics_output = fenics_output
self.fenics_inputs = fenics_inputs
self.tape = tape

def get_params(self, node):
return (self.fenics_output, self.fenics_inputs, self.tape)

def make_node(self, *inputs):
return Apply(
self,
[theano.tensor.as_tensor_variable(x) for x in inputs],
[theano.tensor.dvector() for x in self.templates],
)

def perform(self, node, inputs, outputs, params):
Δfenics_output = inputs[0]
fenics_output, fenics_inputs, tape = params
numpy_grads = evaluate_pullback(
fenics_output, fenics_inputs, tape, Δfenics_output
)

theano_grads = (
theano.gradient.grad_undefined(self, i, inputs[i]) if ng is None else ng
for i, ng in enumerate(numpy_grads)
)

for i, tg in enumerate(theano_grads):
outputs[i][0] = tg


class FenicsOp(Op):
__props__ = ("ofunc", "templates")

def __init__(self, ofunc, templates):
self.ofunc = ofunc
self.templates = templates

def make_node(self, *inputs):
n_inputs = len(self.templates)
assert n_inputs == len(inputs)
return Apply(
self,
[theano.tensor.as_tensor_variable(x) for x in inputs],
[theano.tensor.dvector()],
)

def perform(self, node, inputs, outputs):
numpy_output, fenics_output, fenics_inputs, tape = evaluate_primal(
self.ofunc, self.templates, *inputs
)

self.vjp_op = FenicsVJPOp(
self.ofunc, self.templates, fenics_output, tuple(fenics_inputs), tape
)
outputs[0][0] = numpy_output

def grad(self, inputs, output_grads):
theano_grads = self.vjp_op(output_grads[0])
return theano_grads


def create_fem_theano_op(fenics_templates):
"""Return `f(*args) = create_fem_theano_op(*args)(ofunc(*args))`.
Given the FEniCS/Firedrake-side function ofunc(*args), return the Theano Op,
that is callable and differentiable in Theano programs,
`f(*args) = create_fem_theano_op(*args)(ofunc(*args))` with
the VJP of `f`, where:
`*args` are all arguments to `ofunc`.
Args:
ofunc: The FEniCS/Firedrake-side function to be wrapped.
Returns:
`f(args) = create_fem_theano_op(*args)(ofunc(*args))`
"""

def decorator(fenics_function):

theano_op = FenicsOp(fenics_function, fenics_templates)

@functools.wraps(fenics_function)
def theano_fem_eval(*args):
return theano_op(*args)

return theano_fem_eval

return decorator


create_fenics_theano_op = create_fem_theano_op
8 changes: 4 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
version = "1.0.0"

setup(
name="fenics_pymc3",
description="FEniCS + PyMC3",
name="fenics_pymc",
description="FEniCS + PyMC",
version=version,
author="Ivan Yashchuk",
license="MIT",
packages=["fenics_pymc3"],
install_requires=["pymc3", "fdm", "fecr"],
packages=["fenics_pymc"],
install_requires=["pymc", "fdm", "fecr", "theano"],
)
2 changes: 1 addition & 1 deletion tests/.coveragerc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# .coveragerc to control coverage.py
[run]
branch = True
source = fenics_pymc3
source = fenics_pymc

[report]
ignore_errors = True
Expand Down
4 changes: 2 additions & 2 deletions tests/fenics/test_assemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

import theano

from fenics_pymc3 import create_fenics_theano_op
from fenics_pymc3 import FenicsVJPOp
from fenics_pymc import create_fenics_theano_op
from fenics_pymc import FenicsVJPOp

from fecr import evaluate_primal, evaluate_pullback

Expand Down
6 changes: 3 additions & 3 deletions tests/fenics/test_pymc3.py → tests/fenics/test_pymc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

import fdm

from fenics_pymc3 import create_fenics_theano_op
from fenics_pymc3 import to_numpy
from fenics_pymc import create_fenics_theano_op
from fenics_pymc import to_numpy

import pymc3 as pm
import pymc as pm
import theano.tensor as tt

fenics.set_log_level(fenics.LogLevel.ERROR)
Expand Down
4 changes: 2 additions & 2 deletions tests/firedrake/test_assemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

import theano

from fenics_pymc3 import create_fenics_theano_op
from fenics_pymc3 import FenicsVJPOp
from fenics_pymc import create_fenics_theano_op
from fenics_pymc import FenicsVJPOp

from fecr import evaluate_primal, evaluate_pullback

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import firedrake_adjoint
import ufl

import pymc3 as pm
import pymc as pm
import theano.tensor as tt

import fdm

from fenics_pymc3 import create_fenics_theano_op
from fenics_pymc3 import to_numpy
from fenics_pymc import create_fenics_theano_op
from fenics_pymc import to_numpy

n = 25
mesh = firedrake.UnitSquareMesh(n, n)
Expand Down