def compute_g_from_parents(u_parents): # Compute weighted average of g over the clusters. # Shape(g) = [Nn,..,K,..,N0] # Shape(p) = [Nn,..,N0,K] # Shape(result) = [Nn,..,N0] # Compute g for clusters: # Shape(g) = [Nn,..,K,..,N0] g = distribution.compute_g_from_parents(u_parents[1:]) # Move cluster axis to last: # Shape(g) = [Nn,..,N0,K] g = utils.moveaxis(g, cluster_plate, -1) # Cluster assignments/contributions/probabilities/weights: # Shape(p) = [Nn,..,N0,K] p = u_parents[0][0] # Weighted average of g over the clusters. As p and g are # properly aligned, you can just sum p*g over the last # axis and utilize broadcasting: # Shape(result) = [Nn,..,N0] #print('mixture.compute_g_from_parents p and g:', np.shape(p), np.shape(g)) g = utils.sum_product(p, g, axes_to_sum=-1) #print('mixture.compute_g_from_parents g:', np.sum(g), np.shape(g)) return g
def compute_phi_from_parents(u_parents): # Compute weighted average of the parameters # Cluster parameters Phi = distribution.compute_phi_from_parents(u_parents[1:]) # Contributions/weights/probabilities P = u_parents[0][0] phi = list() for ind in range(len(Phi)): # Compute element-wise product and then sum over K clusters. # Note that the dimensions aren't perfectly aligned because # the cluster dimension (K) may be arbitrary for phi, and phi # also has dimensions (Dd,..,D0) of the parameters. # Shape(phi) = [Nn,..,K,..,N0,Dd,..,D0] # Shape(p) = [Nn,..,N0,K] # Shape(result) = [Nn,..,N0,Dd,..,D0] # General broadcasting rules apply for Nn,..,N0, that is, # preceding dimensions may be missing or dimension may be # equal to one. Probably, shape(phi) has lots of missing # dimensions and/or dimensions that are one. if cluster_plate < 0: cluster_axis = cluster_plate - distribution.ndims[ind] #else: # cluster_axis = cluster_plate # Move cluster axis to the last: # Shape(phi) = [Nn,..,N0,Dd,..,D0,K] phi.append(utils.moveaxis(Phi[ind], cluster_axis, -1)) # Add axes to p: # Shape(p) = [Nn,..,N0,K,1,..,1] p = utils.add_trailing_axes(P, distribution.ndims[ind]) # Move cluster axis to the last: # Shape(p) = [Nn,..,N0,1,..,1,K] p = utils.moveaxis(p, -(distribution.ndims[ind] + 1), -1) #print('Mixture.compute_phi, p:', np.sum(p, axis=-1)) #print('mixture.compute_phi shapes:') #print(np.shape(p)) #print(np.shape(phi[ind])) # Now the shapes broadcast perfectly and we can sum # p*phi over the last axis: # Shape(result) = [Nn,..,N0,Dd,..,D0] phi[ind] = utils.sum_product(p, phi[ind], axes_to_sum=-1) return phi
def compute_phi_from_parents(u_parents): # Compute weighted average of the parameters # Cluster parameters Phi = distribution.compute_phi_from_parents(u_parents[1:]) # Contributions/weights/probabilities P = u_parents[0][0] phi = list() for ind in range(len(Phi)): # Compute element-wise product and then sum over K clusters. # Note that the dimensions aren't perfectly aligned because # the cluster dimension (K) may be arbitrary for phi, and phi # also has dimensions (Dd,..,D0) of the parameters. # Shape(phi) = [Nn,..,K,..,N0,Dd,..,D0] # Shape(p) = [Nn,..,N0,K] # Shape(result) = [Nn,..,N0,Dd,..,D0] # General broadcasting rules apply for Nn,..,N0, that is, # preceding dimensions may be missing or dimension may be # equal to one. Probably, shape(phi) has lots of missing # dimensions and/or dimensions that are one. if cluster_plate < 0: cluster_axis = cluster_plate - distribution.ndims[ind] #else: # cluster_axis = cluster_plate # Move cluster axis to the last: # Shape(phi) = [Nn,..,N0,Dd,..,D0,K] phi.append(utils.moveaxis(Phi[ind], cluster_axis, -1)) # Add axes to p: # Shape(p) = [Nn,..,N0,K,1,..,1] p = utils.add_trailing_axes(P, distribution.ndims[ind]) # Move cluster axis to the last: # Shape(p) = [Nn,..,N0,1,..,1,K] p = utils.moveaxis(p, -(distribution.ndims[ind]+1), -1) #print('Mixture.compute_phi, p:', np.sum(p, axis=-1)) #print('mixture.compute_phi shapes:') #print(np.shape(p)) #print(np.shape(phi[ind])) # Now the shapes broadcast perfectly and we can sum # p*phi over the last axis: # Shape(result) = [Nn,..,N0,Dd,..,D0] phi[ind] = utils.sum_product(p, phi[ind], axes_to_sum=-1) return phi