Hide code cell source
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib_inline
matplotlib_inline.backend_inline.set_matplotlib_formats('svg')
import seaborn as sns
sns.set_context("paper")
sns.set_style("ticks");

import urllib.request
import os

def download(
    url : str,
    local_filename : str = None
):
    """Download a file from a url.
    
    Arguments
    url            -- The url we want to download.
    local_filename -- The filemame to write on. If not
                      specified 
    """
    if local_filename is None:
        local_filename = os.path.basename(url)
    urllib.request.urlretrieve(url, local_filename)

The Principle of Maximum Entropy for Continuous Random Variables#

Maximum Entropy Code#

Writing generic code for finding the maximum entropy distribution in continuous cases is a lot of work. Instead, we will use the PyMaxEnt Python module. This module is not set up for installation via pip, so we will have to do some manual work. All the code is contained in a single file called pymaxent.py which you can find here. All we need to do is make this file visible from the current working directory of this Jupyter Notebook. We could give OS-specific instructions on how to do this, but in Python, you could do it as follows:

url = 'https://raw.githubusercontent.com/saadgroup/PyMaxEnt/master/src/pymaxent.py'
download(url)

After running the code above you should be able to import the library:

# If this fails, please make sure you follow the instructions above to download the file
from pymaxent import *

Examples of maximum entropy distributions#

We work in a 1D random variable setting. The code by Saad requires that you specify the interval support of the distribution, i.e., an interval \([a,b]\) outside of which the probability density function should be zero, and the \(M\) moments of the distribution, i.e.,

\[ \mathbb{E}[X^m] = \mu_m, \]

for \(m=0,\dots,M\). Then, the maximum entropy distribution that satisfies these constraints is given by:

\[ p(x) = 1_{[a,b]}(x)\exp\left\{\sum_{m=1}^M\lambda_mx^m\right\}, \]

where the \(\lambda_0,\dots,\lambda_M\) are fitted so that the constraints are satisfied. Note that there is no need for the normalization constant here because it has been absorbed in \(\lambda_0\). Let’s do some examples to gain some intuition.

No constraints in [-1,1]#

The support is \([-1,1]\), and there are no moment constraints. You only have to specify the normalization constraint and the bounds:

mu = [1.0]
pdf, lambdas = reconstruct(mu, bnds=[-1.0, 1.0])

# plot the reconstructed solution
x = np.linspace(-1.0, 1.0, 100)

fig, ax = plt.subplots()
ax.plot(x, pdf(x))
ax.set_xlabel('$x$')
ax.set_ylabel('$p(x)$')
sns.despine(trim=True);
../_images/a55817bcf69d2bdfd317b07f5b3e594edca98743140d337ce28eb0a98ec8dbce.svg

Mean constraint [-1,1]#

Same as before, but we are now going to impose a mean constraint:

\[ \mathbb{E}[X] = \mu. \]
mu = [1.0, # The required normalization constraint
      0.0] # The mean constraint

pdf, lambdas = reconstruct(mu, bnds=[-1.0, 1.0])

# plot the reconstructed solution
x = np.linspace(-1.0, 1.0, 100)

fig, ax = plt.subplots()
ax.plot(x, pdf(x))
ax.set_xlabel('$x$')
ax.set_ylabel('$p(x)$');
../_images/38e16cae50e59c50efb546a21ca50ea6cb1a218588343d58780facee7e4e1a99.svg

Questions#

  • Modify the mean to \(\mu=0.1\) and observe the resulting maximum entropy pdf.

  • Modify the mean to \(\mu=-0.1\) and observe the resulting maximum entropy pdf.

  • Try \(\mu=0.9\). What happens to the maximum entropy pdf?

  • Try \(\mu=1.1\). Why does the code break down?

Variance constraint#

In addition to the mean constraint, we now include a variance constraint:

\[ \mathbb{V}[X] = \sigma^2. \]

However, note that PyMaxEnt works only with moment constraints. Therefore, we must connect the variance to the second and first moments. Here is how to do this:

\[ \mathbb{E}[X^2] = \mathbb{V}[X] + \left(\mathbb{E}[X]\right)^2 = \sigma^2 + \mu^2. \]
mu = 0.0
sigma2 = 0.1
mus = [
    1.0, # The required normalization constraint
    mu,  # The mean constraint
    sigma2 + mu ** 2
] # The second moment constraint 

pdf, lambdas = reconstruct(mus, bnds=[-1.0, 1.0])

# plot the reconstructed solution
x = np.linspace(-1.0, 1.0, 100)

fig, ax = plt.subplots()
ax.plot(x, pdf(x))
ax.set_xlabel('$x$')
ax.set_ylabel('$p(x)$')
sns.despine(trim=True);
../_images/02c21aab58c002ff7ba7992e0ad73b7e8478d39a80c0e6f3785b86565ec42418.svg

Questions#

  • Modify the variance to \(\sigma^2=0.3\) and observe the resulting maximum entropy pdf.

  • Modify the variance to \(\sigma^2=0.4\) and observe the resulting maximum entropy pdf. Why did you get this abrupt change?

  • Try \(\sigma^2=1\). Why does the code break down?