# Buggy code
def _random(self, n, p, size=None):
    original_dtype = p.dtype
    # Set float type to float64 for numpy. This change is related to numpy issue #8317 (https://github.com/numpy/numpy/issues/8317)
    p = p.astype("float64")
    # Now, re-normalize all of the values in float64 precision. This is done inside the conditionals
    if size == p.shape:
        size = None
    if p.ndim == 1:
        p = p / p.sum()
        randnum = np.random.multinomial(n, p.squeeze(), size=size)
    elif p.ndim == 2:
        p = p / p.sum(axis=1, keepdims=True)
        randnum = np.asarray(
            [np.random.multinomial(nn, pp, size=size) for (nn, pp) in zip(n, p)]
        )
    else:
        raise ValueError(
            "Outcome probabilities must be 1- or 2-dimensional "
            "(supplied `p` has {} dimensions)".format(p.ndim)
        )
    return randnum.astype(original_dtype)


# Traceback (TypeError)
import numpy as np
import pandas as pd
import pymc3 as pm
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(color_codes=True)

import theano

from scipy.stats import norm

def hierarchical_normal(name, shape, mu=0.,cs=5.):
delta = pm.Normal('delta_{}'.format(name), 0., 1., shape=shape)
sigma = pm.HalfCauchy('sigma_{}'.format(name), cs)

return pm.Deterministic(name, mu + delta * sigma)

NUTS_KWARGS = {'target_accept': 0.99}
SEED = 4260026 # from random.org, for reproducibility

np.random.seed(SEED)

ndraws = 1000

counts =[[19, 50, 37],
[21, 67, 55],
[11, 53, 38],
[17, 54, 45],
[24, 93, 66],
[27, 53, 70]]

counts = pd.DataFrame(counts,columns=["A","B","C"])

counts["n"]    = counts[["A","B","C"]].sum(axis=1)
print counts

group   = counts.index.values
n_group = np.unique(group).size

obs_n    = np.reshape(counts.n.values,(6,1))

obs_n_ = theano.shared(obs_n)

obs_ABC = counts[["A","B","C"]].values
with pm.Model() as model:
#Zeros for coefficients for A
ref = pm.Flat("ref",shape=n_group)

#For B
beta0      = pm.Normal('beta0', 0.,sd=5.)
beta_group = hierarchical_normal('beta_group', n_group)


#For C
#alpha0      = pm.Normal('alpha0', 0.,sd=5.)
alpha_group = hierarchical_normal('alpha_group', n_group)

eta_B   = beta0  + beta_group [group]
#eta_C   = alpha0 + alpha_group[group]
eta_C   = alpha_group[group]
p = theano.tensor.nnet.softmax(theano.tensor.stack(ref,eta_B,eta_C).T)
like = pm.Multinomial('obs_ABC', obs_n, p, observed=obs_ABC)

trace  = pm.sample(draws=ndraws, random_seed=SEED,nuts_kwargs=NUTS_KWARGS)

plt.figure()
axs = pm.forestplot(trace,varnames=['beta0','beta_group','alpha_group'])
plt.savefig("Forest.png")
plt.close()

plt.figure()
axs = pm.traceplot(trace,varnames=['beta0','beta_group','alpha_group'])
plt.savefig("Trace.png")
plt.close()

obs_n_.set_value(np.reshape(np.array([10000]*6),(6,1)))
pp_trace = pm.sample_ppc(trace, model=model)

with open('softmax_PP.pkl', 'wb') as buff:
pickle.dump(pp_trace, buff)

with open('softmax_PP.pkl', 'rb') as buff:
pp_trace = pickle.load(buff)

print pp_trace["obs_ABC"]



_________________________________________________________________________________

A   B   C    n
0  19  50  37  106
1  21  67  55  143
2  11  53  38  102
3  17  54  45  116
4  24  93  66  183
5  27  53  70  150
Auto-assigning NUTS sampler...
Initializing NUTS using ADVI...
Average Loss = 49.994:  12%|█████████▍                                                                        | 23062/200000 [00:04<00:36, 4843.61it/s]
Convergence archived at 23500
Interrupted at 23,500 [11%]: Average Loss = 195
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1500/1500 [00:18<00:00, 81.01it/s]
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/tight_layout.py:222: UserWarning: tight_layout : falling back to Agg renderer
warnings.warn("tight_layout : falling back to Agg renderer")
0%|                                                                                                                         | 0/1000 [00:00<?, ?it/s]
Traceback (most recent call last):
File "softmax.py", line 77, in <module>
pp_trace = pm.sample_ppc(trace, model=model)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pymc3/sampling.py", line 539, in sample_ppc
vals = var.distribution.random(point=param, size=size)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pymc3/distributions/multivariate.py", line 506, in random
size=size)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pymc3/distributions/distribution.py", line 397, in generate_samples
*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pymc3/distributions/distribution.py", line 322, in replicate_samples
samples = generator(size=size, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pymc3/distributions/multivariate.py", line 500, in _random
return np.random.multinomial(n, p, size=size)
File "mtrand.pyx", line 4530, in mtrand.RandomState.multinomial (numpy/random/mtrand/mtrand.c:37665)
TypeError: only length-1 arrays can be converted to Python scalars

# Fixed code
def _random(self, n, p, size=None):
    original_dtype = p.dtype
    # Set float type to float64 for numpy. This change is related to numpy issue #8317 (https://github.com/numpy/numpy/issues/8317)
    p = p.astype("float64")
    # Now, re-normalize all of the values in float64 precision. This is done inside the conditionals
    if size == p.shape:
        size = None
    if (n.ndim == 0) and (p.ndim == 1):
        p = p / p.sum()
        randnum = np.random.multinomial(n, p.squeeze(), size=size)
    elif (n.ndim == 0) and (p.ndim > 1):
        p = p / p.sum(axis=1, keepdims=True)
        randnum = np.asarray(
            [np.random.multinomial(n.squeeze(), pp, size=size) for pp in p]
        )
    elif (n.ndim > 0) and (p.ndim == 1):
        p = p / p.sum()
        randnum = np.asarray(
            [np.random.multinomial(nn, p.squeeze(), size=size) for nn in n]
        )
    else:
        p = p / p.sum(axis=1, keepdims=True)
        randnum = np.asarray(
            [np.random.multinomial(nn, pp, size=size) for (nn, pp) in zip(n, p)]
        )
    return randnum.astype(original_dtype)