Skip to content

Commit

Permalink
Enable doc testing
Browse files Browse the repository at this point in the history
  • Loading branch information
dglmoore committed Aug 12, 2019
1 parent 8d232a5 commit af24c51
Show file tree
Hide file tree
Showing 17 changed files with 352 additions and 202 deletions.
4 changes: 2 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os
import sys

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
Expand All @@ -31,9 +31,9 @@
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
'sphinx.ext.doctest',
]

# Add any paths that contain templates here, relative to this directory.
Expand Down
68 changes: 50 additions & 18 deletions docs/source/dist.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
.. _dist:

.. testsetup:: Dist

from pyinform import Dist


Empirical Distributions
=======================

Expand All @@ -15,7 +20,9 @@ Example 1: Construction
^^^^^^^^^^^^^^^^^^^^^^^
You can construct a distribution with a specified number of unique observables.
This construction method results in an *invalid* distribution as no
observations have been made thus far. ::
observations have been made thus far.

.. doctest:: Dist

>>> d = Dist(5)
>>> d.valid()
Expand All @@ -26,7 +33,9 @@ observations have been made thus far. ::
5

Alternatively you can construct a distribution given a list (or NumPy array)
of observation counts: ::
of observation counts:

.. doctest:: Dist

>>> d = Dist([0,0,1,2,1,0,0])
>>> d.valid()
Expand All @@ -41,16 +50,20 @@ Example 2: Making Observations

Once a distribution has been constructed, we can begin making observations.
There are two methods for doing so. The first uses the standard indexing
operations, treating the distribution similarly to a list: ::
operations, treating the distribution similarly to a list:

.. doctest:: Dist

>>> d = Dist(5)
>>> for i in range(len(d)):
... d[i] = i*i
>>> list(d)
[0, 1, 4, 9, 25]
[0, 1, 4, 9, 16]

The second method is to make *incremental* changes to the distribution. This
is useful when making observations of timeseries: ::
is useful when making observations of timeseries:

.. doctest:: Dist

>>> obs = [1,0,1,2,2,1,2,3,2,2]
>>> d = Dist(max(obs) + 1)
Expand All @@ -61,7 +74,9 @@ is useful when making observations of timeseries: ::
[1, 3, 5, 1]

It is important to remember that :py:class:`~.dist.Dist` keeps track of your
events as you provide them. For example: ::
events as you provide them. For example:

.. doctest:: Dist

>>> obs = [1, 1, 3, 5, 1, 3, 7, 9]
>>> d = Dist(max(obs) + 1)
Expand All @@ -77,12 +92,13 @@ events as you provide them. For example: ::

If you know there are "gaps" in your time series, e.g. no even numbers, then you
can use the utility function :py:func:`~.utils.coalesce.coalesce_series` to get
rid of them: ::
rid of them:

.. doctest:: Dist

>>> from pyinform import utils
>>> obs = [1, 1, 3, 5, 1, 3, 7, 9]
>>> coal, b = utils.coalesce_series(obs)
(array([0, 0, 1, 2, 0, 1, 3, 4], dtype=int32), 5)
>>> d = Dist(b)
>>> for event in coal:
... assert(d[event] == d.tick(event) - 1)
Expand All @@ -92,7 +108,7 @@ rid of them: ::
>>> d[1]
2
>>> d[3]
7
1

This can significantly improve memory usage in situations where the range of
possible states is large, but is sparsely sampled in the time series.
Expand All @@ -102,7 +118,9 @@ Example 3: Probabilities

Once some observations have been made, we can start asking for probabilities.
As in the previous examples, there are multiple ways of doing this. The first
is to just ask for the probability of a given event. ::
is to just ask for the probability of a given event.

.. doctest:: Dist

>>> d = Dist([3,0,1,2])
>>> d.probability(0)
Expand All @@ -114,18 +132,22 @@ is to just ask for the probability of a given event. ::
>>> d.probability(3)
0.3333333333333333

Sometimes it is nice to just dump the probabilities out to an array: ::
Sometimes it is nice to just dump the probabilities out to an array:

.. doctest:: Dist

>>> d = Dist([3,0,1,2])
>>> d.dump()
array([ 0.5 , 0. , 0.16666667, 0.33333333])
array([0.5 , 0. , 0.16666667, 0.33333333])

Example 4: Shannon Entropy
^^^^^^^^^^^^^^^^^^^^^^^^^^

Once you have a distribution you can do lots of fun things with it. In
this example, we will compute the shannon entropy of a timeseries of
observed values. ::
observed values.

.. testcode:: Dist

from math import log2
from pyinform.dist import Dist
Expand All @@ -134,15 +156,21 @@ observed values. ::
d = Dist(max(obs) + 1)
for event in obs:
d.tick(event)

h = 0.
for p in d.dump():
h -= p * log2(p)

print(h) # 1.68547529723
print(h)

.. testoutput:: Dist

1.6854752972273344

Of course **PyInform** provides a function for this:
:py:func:`pyinform.shannon.entropy`. ::
:py:func:`pyinform.shannon.entropy`.

.. testcode:: Dist

from pyinform.dist import Dist
from pyinform.shannon import entropy
Expand All @@ -151,8 +179,12 @@ Of course **PyInform** provides a function for this:
d = Dist(max(obs) + 1)
for event in obs:
d.tick(event)
print(entropy(dist)) # 1.6854752972273344

print(entropy(d))

.. testoutput:: Dist

1.6854752972273344


API Documentation
Expand Down
65 changes: 48 additions & 17 deletions docs/source/shannon.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
.. _shannon:

.. testsetup:: shannon

from pyinform import Dist
from pyinform import shannon

Shannon Information Measures
============================

Expand All @@ -16,16 +21,26 @@ Example 1: Entropy and Random Numbers

The :py:func:`pyinform.shannon.entropy` function allows us to calculate the
Shannon entropy of a distributions. Let's try generating a random distribution
and see what the entropy looks like? ::
and see what the entropy looks like?

.. testcode::

import numpy as np
from pyinform.dist import Dist
from pyinform.shannon import entropy

np.random.seed(2019)
xs = np.random.randint(0,10,10000)
d = Dist(10)
for x in xs:
d.tick(x)
print(entropy(d)) # 3.32137023165359
print(entropy(d, b=10)) # 0.9998320664331565
print(entropy(d))
print(entropy(d, b=10))

.. testoutput::

3.3216276921709724
0.9999095697715877

This is exactly what you should expect; the pseudo-random number generate does
a decent job producing integers in a uniform fashion.
Expand All @@ -34,14 +49,17 @@ Example 2: Mutual Information
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

How correlated are consecutive integers? Let's find out using
:py:func:`mutual_info`. ::
:py:func:`mutual_info`.

.. testcode::

import numpy as np
from pyinform.dist import Dist
from pyinform.shannon import mutual_info
import numpy as np

obs = np.random.randint(0, 10, 10000)
np.random.seed(2019)
obs = np.random.randint(0, 10, 100)

p_xy = Dist(100)
p_x = Dist(10)
p_y = Dist(10)
Expand All @@ -52,8 +70,13 @@ How correlated are consecutive integers? Let's find out using
p_y.tick(y)
p_xy.tick(10*x + y)

print(mutual_info(p_xy, p_x, p_y)) # -1.7763568394002505e-15
print(mutual_info(p_xy, p_x, p_y, b=10)) # -6.661338147750939e-16
print(mutual_info(p_xy, p_x, p_y))
print(mutual_info(p_xy, p_x, p_y, b=10))

.. testoutput::

1.3322676295501878e-15
4.440892098500626e-16

Due to the subtlties of floating-point computation we don't get zero. Really,
though the mutual information is zero.
Expand All @@ -62,26 +85,34 @@ Example 3: Relative Entropy and Biased Random Numbers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Okay. Now let's generate some binary sequences. The first will be roughly
uniform, but the second will be biased toward 0. ::
uniform, but the second will be biased toward 0.

.. testcode::

import numpy as np
from pyinform.dist import Dist
from pyinform.shannon import relative_entropy
import numpy as np

p = Dist(2)
q = Dist(2)

ys = np.random.randint(0, 2, 10000)
np.random.seed(2019)
ys = np.random.randint(0, 2, 100)
for y in ys:
p.tick(y)

xs = np.random.randint(0, 6, 10000)
xs = np.random.randint(0, 6, 100)
for i, _ in enumerate(xs):
xs[i] = (((xs[i] % 5) % 4) % 3) % 2
xs[i] = (((xs[i] % 5) % 4) % 3) % 2
q.tick(xs[i])

print(relative_entropy(q,p)) # 0.3338542254583825
print(relative_entropy(p,q)) # 0.40107198925821924
print(relative_entropy(q,p))
print(relative_entropy(p,q))

.. testoutput::

0.3810306585586593
0.4924878808808457

API Documentation
-----------------
Expand Down
29 changes: 29 additions & 0 deletions docs/source/timeseries.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
.. _timeseries:

.. testsetup:: active_info

from pyinform import active_info

.. testsetup:: block_entropy

from pyinform import block_entropy

.. testsetup:: conditional_entropy

from pyinform import conditional_entropy

.. testsetup:: entropy_rate

from pyinform import entropy_rate

.. testsetup:: mutual_info

from pyinform import mutual_info

.. testsetup:: relative_entropy

from pyinform import relative_entropy

.. testsetup:: transfer_entropy

from pyinform import transfer_entropy


Time Series Measures
====================

Expand Down
24 changes: 14 additions & 10 deletions docs/source/utils.rst
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
Utilities
=========

.. testsetup:: utils

from pyinform import utils

.. automodule:: pyinform.utils

State Binning
-------------

.. automodule:: pyinform.utils.binning

.. autofunction:: series_range

.. autofunction:: bin_series

State Coalescing
----------------

.. automodule:: pyinform.utils.coalesce

.. autofunction:: coalesce_series

State Encoding
--------------

.. automodule:: pyinform.utils.encoding

.. autofunction:: encode

.. autofunction:: decode
Loading

0 comments on commit af24c51

Please sign in to comment.