def update_u(self, u, mask=True): # Store the computed moments u but do not change moments for # observations, i.e., utilize the mask. for ind in range(len(u)): # Add axes to the mask for the variable dimensions (mask # contains only axes for the plates). u_mask = utils.add_trailing_axes(mask, self.ndims[ind]) # Enlarge self.u[ind] as necessary so that it can store the # broadcasted result. sh = utils.broadcasted_shape_from_arrays(self.u[ind], u[ind], u_mask) self.u[ind] = utils.repeat_to_shape(self.u[ind], sh) # Use mask to update only unobserved plates and keep the # observed as before np.copyto(self.u[ind], u[ind], where=u_mask) # Make sure u has the correct number of dimensions: shape = self.get_shape(ind) ndim = len(shape) ndim_u = np.ndim(self.u[ind]) if ndim > ndim_u: self.u[ind] = utils.add_leading_axes(u[ind], ndim - ndim_u) elif ndim < np.ndim(self.u[ind]): raise Exception("Weird, this shouldn't happen.. :)")
def get_message(self, index, u_parents): (m, mask) = self.message_from_children() parent = self.parents[index] # Compute both messages for i in range(2): # Add extra axes to the message from children #m_shape = np.shape(m[i]) + (1,) * (i+1) #m[i] = np.reshape(m[i], m_shape) # Put masked elements to zero np.copyto(m[i], 0, where=np.logical_not(mask)) # Add extra axes to the mask from children #mask_shape = np.shape(mask) + (1,) * (i+1) #mask_i = np.reshape(mask, mask_shape) #mask_i = mask m[i] = utils.add_trailing_axes(m[i], i+1) #for k in range(i+1): #m[i] = np.expand_dims(m[i], axis=-1) #mask_i = np.expand_dims(mask_i, axis=-1) # List of elements to multiply together A = [m[i]] for k in range(len(u_parents)): if k != index: A.append(u_parents[k][i]) # Find out which axes are summed over. Also, full_shape = utils.broadcasted_shape_from_arrays(*A) axes = utils.axes_to_collapse(full_shape, parent.get_shape(i)) # Compute the multiplier for cancelling the # plate-multiplier. Because we are summing over the # dimensions already in this function (for efficiency), we # need to cancel the effect of the plate-multiplier # applied in the message_to_parent function. r = 1 for j in axes: r *= full_shape[j] # Compute dot product (and cancel plate-multiplier) m[i] = utils.sum_product(*A, axes_to_sum=axes, keepdims=True) / r # Compute the mask s = utils.axes_to_collapse(np.shape(mask), parent.plates) mask = np.any(mask, axis=s, keepdims=True) mask = utils.squeeze_to_dim(mask, len(parent.plates)) return (m, mask)
def get_message(self, index, u_parents): (m, mask) = self.message_from_children() parent = self.parents[index] # Compute both messages for i in range(2): # Add extra axes to the message from children #m_shape = np.shape(m[i]) + (1,) * (i+1) #m[i] = np.reshape(m[i], m_shape) # Put masked elements to zero np.copyto(m[i], 0, where=np.logical_not(mask)) # Add extra axes to the mask from children #mask_shape = np.shape(mask) + (1,) * (i+1) #mask_i = np.reshape(mask, mask_shape) #mask_i = mask m[i] = utils.add_trailing_axes(m[i], i + 1) #for k in range(i+1): #m[i] = np.expand_dims(m[i], axis=-1) #mask_i = np.expand_dims(mask_i, axis=-1) # List of elements to multiply together A = [m[i]] for k in range(len(u_parents)): if k != index: A.append(u_parents[k][i]) # Find out which axes are summed over. Also, full_shape = utils.broadcasted_shape_from_arrays(*A) axes = utils.axes_to_collapse(full_shape, parent.get_shape(i)) # Compute the multiplier for cancelling the # plate-multiplier. Because we are summing over the # dimensions already in this function (for efficiency), we # need to cancel the effect of the plate-multiplier # applied in the message_to_parent function. r = 1 for j in axes: r *= full_shape[j] # Compute dot product (and cancel plate-multiplier) m[i] = utils.sum_product(*A, axes_to_sum=axes, keepdims=True) / r # Compute the mask s = utils.axes_to_collapse(np.shape(mask), parent.plates) mask = np.any(mask, axis=s, keepdims=True) mask = utils.squeeze_to_dim(mask, len(parent.plates)) return (m, mask)
def OLD_get_message(self, index, u_parents): (m, mask) = self.message_from_children() parent = self.parents[index] # Compute both messages for i in range(2): # Add extra axes to the message from children #m_shape = np.shape(m[i]) + (1,) * (i+1) #m[i] = np.reshape(m[i], m_shape) # Add extra axes to the mask from children mask_shape = np.shape(mask) + (1,) * (i+1) mask_i = np.reshape(mask, mask_shape) mask_i = mask for k in range(i+1): m[i] = np.expand_dims(m[i], axis=-1) mask_i = np.expand_dims(mask_i, axis=-1) # List of elements to multiply together A = [m[i], mask_i] for k in range(len(u_parents)): if k != index: A.append(u_parents[k][i]) # Find out which axes are summed over. Also, because # we are summing over the dimensions already in this # function (for efficiency), we need to cancel the # effect of the plate-multiplier applied in the # message_to_parent function. full_shape = utils.broadcasted_shape_from_arrays(*A) axes = utils.axes_to_collapse(full_shape, parent.get_shape(i)) r = 1 for j in axes: r *= full_shape[j] # Compute dot product m[i] = utils.sum_product(*A, axes_to_sum=axes, keepdims=True) / r # Compute the mask s = utils.axes_to_collapse(np.shape(mask), parent.plates) mask = np.any(mask, axis=s, keepdims=True) mask = utils.squeeze_to_dim(mask, len(parent.plates)) return (m, mask)
def OLD_get_message(self, index, u_parents): (m, mask) = self.message_from_children() parent = self.parents[index] # Compute both messages for i in range(2): # Add extra axes to the message from children #m_shape = np.shape(m[i]) + (1,) * (i+1) #m[i] = np.reshape(m[i], m_shape) # Add extra axes to the mask from children mask_shape = np.shape(mask) + (1, ) * (i + 1) mask_i = np.reshape(mask, mask_shape) mask_i = mask for k in range(i + 1): m[i] = np.expand_dims(m[i], axis=-1) mask_i = np.expand_dims(mask_i, axis=-1) # List of elements to multiply together A = [m[i], mask_i] for k in range(len(u_parents)): if k != index: A.append(u_parents[k][i]) # Find out which axes are summed over. Also, because # we are summing over the dimensions already in this # function (for efficiency), we need to cancel the # effect of the plate-multiplier applied in the # message_to_parent function. full_shape = utils.broadcasted_shape_from_arrays(*A) axes = utils.axes_to_collapse(full_shape, parent.get_shape(i)) r = 1 for j in axes: r *= full_shape[j] # Compute dot product m[i] = utils.sum_product(*A, axes_to_sum=axes, keepdims=True) / r # Compute the mask s = utils.axes_to_collapse(np.shape(mask), parent.plates) mask = np.any(mask, axis=s, keepdims=True) mask = utils.squeeze_to_dim(mask, len(parent.plates)) return (m, mask)
def _set_moments(self, u, mask=True): # Store the computed moments u but do not change moments for # observations, i.e., utilize the mask. for ind in range(len(u)): # Add axes to the mask for the variable dimensions (mask # contains only axes for the plates). u_mask = utils.add_trailing_axes(mask, self._distribution.ndims[ind]) # Enlarge self.u[ind] as necessary so that it can store the # broadcasted result. sh = utils.broadcasted_shape_from_arrays(self.u[ind], u[ind], u_mask) self.u[ind] = utils.repeat_to_shape(self.u[ind], sh) # TODO/FIXME/BUG: The mask of observations is not used, observations # may be overwritten!!! ??? # Hah, this function is used to set the observations! The caller # should be careful what mask he uses! If you want to set only # latent variables, then use such a mask. # Use mask to update only unobserved plates and keep the # observed as before np.copyto(self.u[ind], u[ind], where=u_mask) # Make sure u has the correct number of dimensions: # TODO/FIXME: Maybe it would be good to also check that u has a # shape that is a sub-shape of get_shape. shape = self.get_shape(ind) ndim = len(shape) ndim_u = np.ndim(self.u[ind]) if ndim > ndim_u: self.u[ind] = utils.add_leading_axes(u[ind], ndim - ndim_u) elif ndim < ndim_u: raise RuntimeError( "The size of the variable %s's %s-th moment " "array is %s which is larger than it should " "be, that is, %s, based on the plates %s and " "dimension %s. Check that you have provided " "plates properly." % (self.name, ind, np.shape(self.u[ind]), shape, self.plates, self.dims[ind]))
def _set_moments(self, u, mask=True): # Store the computed moments u but do not change moments for # observations, i.e., utilize the mask. for ind in range(len(u)): # Add axes to the mask for the variable dimensions (mask # contains only axes for the plates). u_mask = utils.add_trailing_axes(mask, self._distribution.ndims[ind]) # Enlarge self.u[ind] as necessary so that it can store the # broadcasted result. sh = utils.broadcasted_shape_from_arrays(self.u[ind], u[ind], u_mask) self.u[ind] = utils.repeat_to_shape(self.u[ind], sh) # TODO/FIXME/BUG: The mask of observations is not used, observations # may be overwritten!!! ??? # Hah, this function is used to set the observations! The caller # should be careful what mask he uses! If you want to set only # latent variables, then use such a mask. # Use mask to update only unobserved plates and keep the # observed as before np.copyto(self.u[ind], u[ind], where=u_mask) # Make sure u has the correct number of dimensions: # TODO/FIXME: Maybe it would be good to also check that u has a # shape that is a sub-shape of get_shape. shape = self.get_shape(ind) ndim = len(shape) ndim_u = np.ndim(self.u[ind]) if ndim > ndim_u: self.u[ind] = utils.add_leading_axes(u[ind], ndim - ndim_u) elif ndim < ndim_u: raise RuntimeError( "The size of the variable %s's %s-th moment " "array is %s which is larger than it should " "be, that is, %s, based on the plates %s and " "dimension %s. Check that you have provided " "plates properly." % (self.name, ind, np.shape( self.u[ind]), shape, self.plates, self.dims[ind]))