Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scan meta op #105

Merged
merged 9 commits into from
Mar 27, 2020
Merged
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
4 changes: 1 addition & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,8 @@ coverage: test
diff-cover coverage.xml --compare-branch=master --fail-under=100

docs:
# latesttag=$(git describe --tags `git rev-list --tags --max-count=1`)
# echo checking out ${latesttag}
# git checkout ${latesttag}
pushd docs && \
sphinx-apidoc ../symbolic_pymc/ -o source --force && \
make html && \
ghp-import -n -p -r upstream -b gh-pages build/html && \
popd
Expand Down
16 changes: 0 additions & 16 deletions conftest.py

This file was deleted.

6 changes: 2 additions & 4 deletions docs/source/symbolic-pymc-tour.org
Original file line number Diff line number Diff line change
Expand Up @@ -1126,10 +1126,8 @@ like src_python[:eval never]{enable_lvar_defaults}, or by updates to the
defaults of meta object creation.

Likewise, there are tools available in Symbolic PyMC that make it easier to
determine why to objects won't unify
(i.e. src_python[:eval never]{symbolic_pymc.unify.debug_unify}) and exactly
which components are unequal between two meta objects
(i.e. src_python[:eval never]{symbolic_pymc.utils.meta_parts_unequal}).
determine which components are unequal between two meta objects
(e.g. src_python[:eval never]{symbolic_pymc.utils.meta_parts_unequal}).

Symbolic PyMC's library of relevant mathematical and statistical relations is
intended to evolve over time. These relations will reflect useful properties
Expand Down
6 changes: 2 additions & 4 deletions docs/source/symbolic-pymc-tour.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1071,10 +1071,8 @@ like \ ``enable_lvar_defaults``\ , or by updates to the
defaults of meta object creation.

Likewise, there are tools available in Symbolic PyMC that make it easier to
determine why to objects won't unify
(i.e. \ ``symbolic_pymc.unify.debug_unify``\ ) and exactly
which components are unequal between two meta objects
(i.e. \ ``symbolic_pymc.utils.meta_parts_unequal``\ ).
determine which components are unequal between two meta objects
(e.g. \ ``symbolic_pymc.utils.meta_parts_unequal``\ ).

Symbolic PyMC's library of relevant mathematical and statistical relations is
intended to evolve over time. These relations will reflect useful properties
Expand Down
12 changes: 6 additions & 6 deletions docs/source/symbolic_pymc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ Subpackages
Submodules
----------

symbolic\_pymc.meta module
--------------------------
symbolic\_pymc.dispatch module
------------------------------

.. automodule:: symbolic_pymc.meta
.. automodule:: symbolic_pymc.dispatch
:members:
:undoc-members:
:show-inheritance:

symbolic\_pymc.unify module
---------------------------
symbolic\_pymc.meta module
--------------------------

.. automodule:: symbolic_pymc.unify
.. automodule:: symbolic_pymc.meta
:members:
:undoc-members:
:show-inheritance:
Expand Down
24 changes: 16 additions & 8 deletions docs/source/symbolic_pymc.tensorflow.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ symbolic\_pymc.tensorflow package
Submodules
----------

symbolic\_pymc.tensorflow.dispatch module
-----------------------------------------

.. automodule:: symbolic_pymc.tensorflow.dispatch
:members:
:undoc-members:
:show-inheritance:

symbolic\_pymc.tensorflow.graph module
--------------------------------------

.. automodule:: symbolic_pymc.tensorflow.graph
:members:
:undoc-members:
:show-inheritance:

symbolic\_pymc.tensorflow.meta module
-------------------------------------

Expand All @@ -20,14 +36,6 @@ symbolic\_pymc.tensorflow.printing module
:undoc-members:
:show-inheritance:

symbolic\_pymc.tensorflow.unify module
--------------------------------------

.. automodule:: symbolic_pymc.tensorflow.unify
:members:
:undoc-members:
:show-inheritance:


Module contents
---------------
Expand Down
16 changes: 8 additions & 8 deletions docs/source/symbolic_pymc.theano.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ symbolic\_pymc.theano package
Submodules
----------

symbolic\_pymc.theano.dispatch module
-------------------------------------

.. automodule:: symbolic_pymc.theano.dispatch
:members:
:undoc-members:
:show-inheritance:

symbolic\_pymc.theano.meta module
---------------------------------

Expand Down Expand Up @@ -52,14 +60,6 @@ symbolic\_pymc.theano.random\_variables module
:undoc-members:
:show-inheritance:

symbolic\_pymc.theano.unify module
----------------------------------

.. automodule:: symbolic_pymc.theano.unify
:members:
:undoc-members:
:show-inheritance:

symbolic\_pymc.theano.utils module
----------------------------------

Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
setuptools>=45.2.0
six>=1.14.0
-e ./
sympy>=1.3
coveralls
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def get_long_description():
author_email=AUTHOR_EMAIL,
url=URL,
install_requires=[
"numpy>=1.18.1",
"scipy>=1.4.0",
"Theano>=1.0.4",
"tf-estimator-nightly==2.1.0.dev2020012309",
Expand Down
2 changes: 1 addition & 1 deletion symbolic_pymc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# We need this so that `multipledispatch` initialization occurs
from .unify import *
from .dispatch import *

from ._version import get_versions

Expand Down
34 changes: 0 additions & 34 deletions symbolic_pymc/unify.py → symbolic_pymc/dispatch.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from functools import wraps
from collections.abc import Mapping

from cons.core import _car, _cdr, ConsError
Expand All @@ -13,36 +12,6 @@
from .meta import MetaSymbol, MetaVariable


class UnificationFailure(Exception):
pass


def debug_unify(enable=True): # pragma: no cover
"""Wrap unify functions so that they raise a `UnificationFailure` exception when unification fails."""
if enable:

def set_debug(f):
@wraps(f)
def wrapper(*args, **kwargs):
s = f(*args, **kwargs)
if s is False:
import pdb

pdb.set_trace()
raise UnificationFailure()
return s

return wrapper

_unify.funcs = {
sig: set_debug(getattr(f, "__wrapped__", f)) for sig, f in _unify.funcs.items()
}
_unify._cache.clear()
else:
_unify.funcs = {sig: getattr(f, "__wrapped__", f) for sig, f in _unify.funcs.items()}
_unify._cache.clear()


def unify_MetaSymbol(u, v, s):
if type(u) != type(v):
return False
Expand Down Expand Up @@ -157,6 +126,3 @@ def cdr_MetaVariable(x):

# arguments.add((MetaSymbol,), cdr_MetaSymbol)
arguments.add((MetaVariable,), cdr_MetaVariable)


__all__ = ["debug_unify"]
7 changes: 6 additions & 1 deletion symbolic_pymc/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,12 @@ def __ne__(self, other):
return not self.__eq__(other)

def __hash__(self):
return hash((self.base, self.rands))
try:
rands = self.rands
except NotImplementedError: # pragma: no cover
return NotImplemented

return hash((self.base, rands))

def __str__(self):
return self.__repr__(show_obj=False, _repr=str)
Expand Down
38 changes: 36 additions & 2 deletions symbolic_pymc/relations/theano/__init__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,56 @@
import numpy as np
import theano.tensor as tt

from unification import var
from unification.utils import transitive_get as walk

from kanren import eq
from kanren.core import lall, Zzz
from kanren.facts import fact
from kanren.graph import applyo, walko
from kanren.assoccomm import commutative, associative
from kanren.constraints import neq

from etuples import etuple

from ...theano.meta import mt

from ...utils import HashableNDArray
from ...theano.meta import TheanoMetaConstant, mt

# Establish some Theano `Op`s as commutative and/or associative
fact(commutative, mt.add)
fact(commutative, mt.mul)
fact(associative, mt.add)
fact(associative, mt.mul)


def constant_neq(lvar, val):
"""Assert that a constant graph variable is not equal to a specific value.

Scalar values are broadcast across arrays.

XXX: This goal is non-relational.
TODO: Rewrite this as an actual constraint.
"""

if isinstance(val, np.ndarray):
val = val.view(HashableNDArray)

def constant_neq_goal(S):
lvar_rf = walk(lvar, S)
if isinstance(lvar_rf, (tt.Constant, TheanoMetaConstant)):
# Although `neq` is an actual constraint, the preceding type check
# and alternative success--when not a constant type--make the
# entire goal non-relational/not a true constraint, since the
# aforementioned check will only occur once per goal-stream/state
# and never again.
yield from neq(lvar_rf.data, val)(S)
else:
# When the value isn't a Theano constant, consider it satisfied
yield S

return constant_neq_goal


def non_obs_walko(relation, a, b):
"""Construct a goal that applies a relation to all nodes above an observed random variable.

Expand Down
31 changes: 2 additions & 29 deletions symbolic_pymc/relations/theano/distributions.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
"""Relations pertaining to probability distributions."""
import numpy as np
import theano.tensor as tt

from unification import var
from unification.utils import transitive_get as walk

from etuples import etuple

from kanren import conde, eq
from kanren.facts import fact, Relation
from kanren.constraints import neq

from . import constant_neq
from .. import concat
from ...utils import HashableNDArray
from ...theano.meta import TheanoMetaConstant, mt
from ...theano.meta import mt


derived_dist = Relation("derived_dist")
Expand Down Expand Up @@ -57,28 +52,6 @@
# None)


def constant_neq(lvar, val):
"""Assert that a constant graph variable is not equal to a specific value.

Scalar values are broadcast across arrays.

XXX: This goal is non-relational
"""

if isinstance(val, np.ndarray):
val = val.view(HashableNDArray)

def constant_neq_goal(S):
lvar_rf = walk(lvar, S)
if isinstance(lvar_rf, (tt.Constant, TheanoMetaConstant)):
# TODO: Can we get away with `neq(lvar_rf, val)` alone?
yield from neq(lvar_rf.data, val)(S)
else:
yield S

return constant_neq_goal


def scale_loc_transform(in_expr, out_expr):
"""Create relations for lifting and sinking scale and location parameters of distributions.

Expand Down
2 changes: 1 addition & 1 deletion symbolic_pymc/tensorflow/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Needed to register generic functions
from .unify import *
from .dispatch import *
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from .meta import TFlowMetaSymbol
from ..meta import metatize
from ..unify import unify_MetaSymbol
from ..dispatch import unify_MetaSymbol

tf_class_abstractions = tuple(c.base for c in TFlowMetaSymbol.base_subclasses())

Expand Down
2 changes: 1 addition & 1 deletion symbolic_pymc/theano/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Needed to register generic functions
from .unify import *
from .dispatch import *
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from .meta import TheanoMetaSymbol
from ..meta import metatize
from ..unify import unify_MetaSymbol
from ..dispatch import unify_MetaSymbol


tt_class_abstractions = tuple(c.base for c in TheanoMetaSymbol.base_subclasses())
Expand Down
Loading