# Buggy code
def __init__(self, n, p, *args, **kwargs):
    super(Multinomial, self).__init__(*args, **kwargs)

    p = p / tt.sum(p, axis=-1, keepdims=True)

    lst = range(self.shape[-1])
    if len(self.shape) > 1:
        m = self.shape[-2]
        try:
            assert n.shape == (m,)
        except AttributeError:
            n *= tt.ones(m)
        self.n = tt.shape_padright(n)
        self.p = p if p.ndim > 1 else tt.shape_padleft(p)
        lst = list(lst for _ in range(m))
    else:
        # n is a scalar, p is a 1d array
        self.n = tt.as_tensor_variable(n)
        self.p = tt.as_tensor_variable(p)

    self.mean = self.n * self.p
    mode = tt.cast(tt.round(self.mean), "int32")
    diff = self.n - tt.sum(mode, axis=-1, keepdims=True)
    inc_bool_arr = tt.as_tensor_variable(lst) < diff
    mode = tt.inc_subtensor(mode[inc_bool_arr.nonzero()], 1)
    dec_bool_arr = tt.as_tensor_variable(lst) < -diff
    mode = tt.inc_subtensor(mode[dec_bool_arr.nonzero()], -1)
    self.mode = mode


# 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 __init__(self, n, p, *args, **kwargs):
    super(Multinomial, self).__init__(*args, **kwargs)

    p = p / tt.sum(p, axis=-1, keepdims=True)
    n = np.squeeze(n)  # works also if n is a tensor

    if len(self.shape) > 1:
        m = self.shape[-2]
        try:
            assert n.shape == (m,)
        except (AttributeError, AssertionError):
            n = n * tt.ones(m)
        self.n = tt.shape_padright(n)
        self.p = p if p.ndim > 1 else tt.shape_padleft(p)
    elif n.ndim == 1:
        self.n = tt.shape_padright(n)
        self.p = p if p.ndim > 1 else tt.shape_padleft(p)
    else:
        # n is a scalar, p is a 1d array
        self.n = tt.as_tensor_variable(n)
        self.p = tt.as_tensor_variable(p)

    self.mean = self.n * self.p
    mode = tt.cast(tt.round(self.mean), "int32")
    diff = self.n - tt.sum(mode, axis=-1, keepdims=True)
    inc_bool_arr = tt.abs_(diff) > 0
    mode = tt.inc_subtensor(mode[inc_bool_arr.nonzero()], diff[inc_bool_arr.nonzero()])
    self.mode = mode