Ah, I posted old code that used to work in slightly different circumstances. Lesson for next time: Always execute code before posting…
This should work (tested on master):
class Ordered(pm.distributions.transforms.ElemwiseTransform):
name = "ordered"
def forward(self, x):
out = tt.zeros(x.shape)
out = tt.inc_subtensor(out[0], x[0])
out = tt.inc_subtensor(out[1:], tt.log(x[1:] - x[:-1]))
return out
def forward_val(self, x, point=None):
x, = pm.distributions.distribution.draw_values([x], point=point)
return self.forward(x)
def backward(self, y):
out = tt.zeros(y.shape)
out = tt.inc_subtensor(out[0], y[0])
out = tt.inc_subtensor(out[1:], tt.exp(y[1:]))
return tt.cumsum(out)
def jacobian_det(self, y):
return tt.sum(y[1:])
class Composed(pm.distributions.transforms.Transform):
def __init__(self, trafo1, trafo2):
self._trafo1 = trafo1
self._trafo2 = trafo2
self.name = '_'.join([trafo1.name, trafo2.name])
def forward(self, x):
return self._trafo2.forward(self._trafo1.forward(x))
def forward_val(self, x, point=None):
return self.forward(x)
def backward(self, y):
return self._trafo1.backward(self._trafo2.backward(y))
def jacobian_det(self, y):
y2 = self._trafo2.backward(y)
det1 = self._trafo1.jacobian_det(y2)
det2 = self._trafo2.jacobian_det(y)
return det1 + det2
with pm.Model() as model:
trafo = Composed(pm.distributions.transforms.LogOdds(), Ordered())
rates = pm.Beta('rates', 2, 2, shape=3, transform=trafo,
testval=[0.3, 0.4, 0.5])