def __init__(self, A, X, **kwargs): # Convert arrays to constant nodes if utils.is_numeric(A): A = Constant(Gaussian)(A) if utils.is_numeric(X): X = Constant(Gaussian)(X) MN = A.dims[0][0] N = X.dims[0][0] # Check parents if A.dims != ( (MN,), (MN, MN) ): raise ValueError("Invalid dimensionality of the first parent.") if X.dims != ( (N,), (N, N) ): raise ValueError("Invalid dimensionality of the second parent.") if (MN % N) != 0: raise ValueError("The dimensionality of the first parent should be " "a multiple of the second parent.") # Dimensionality of the output M = int(MN / N) dims = ( (M,), (M,M) ) Node.__init__(self, A, X, dims=dims, **kwargs)
def __init__(self, A, X, **kwargs): # Convert arrays to constant nodes if utils.is_numeric(A): A = Constant(Gaussian)(A) if utils.is_numeric(X): X = Constant(Gaussian)(X) MN = A.dims[0][0] N = X.dims[0][0] # Check parents if A.dims != ((MN, ), (MN, MN)): raise ValueError("Invalid dimensionality of the first parent.") if X.dims != ((N, ), (N, N)): raise ValueError("Invalid dimensionality of the second parent.") if (MN % N) != 0: raise ValueError( "The dimensionality of the first parent should be " "a multiple of the second parent.") # Dimensionality of the output M = int(MN / N) dims = ((M, ), (M, M)) Node.__init__(self, A, X, dims=dims, **kwargs)
def __init__(self, mu, Lambda, A, v, n=None, **kwargs): """ `mu` is the mean of x_0 `Lambda` is the precision of x_0 `A` is the dynamic matrix `v` is the diagonal precision of the innovation """ self.parameter_distributions = (Gaussian, Wishart, Gaussian, Gamma) # Check for constant mu if utils.is_numeric(mu): mu = Constant(Gaussian)(np.atleast_1d(mu)) # Check for constant Lambda if utils.is_numeric(Lambda): Lambda = Constant(Wishart)(np.atleast_2d(Lambda)) # Check for constant A if utils.is_numeric(A): A = Constant(Gaussian)(np.atleast_2d(A)) # Check for constant V if utils.is_numeric(v): v = Constant(Gamma)(np.atleast_1d(v)) # A dummy wrapper for the number of time instances. n_A = 1 if len(A.plates) >= 2: n_A = A.plates[-2] n_v = 1 if len(v.plates) >= 2: n_v = v.plates[-2] if n_v != n_A and n_v != 1 and n_A != 1: raise Exception("Plates of A and v are giving different number of time instances") n_A = max(n_v, n_A) if n is None: if n_A == 1: raise Exception("""The number of time instances could not be determined automatically. Give the number of time instances.""") n = n_A + 1 elif n_A != 1 and n_A+1 != n: raise Exception("The number of time instances must match " "the number of last plates of parents: " "%d != %d+1" % (n, n_A)) # Construct super().__init__(mu, Lambda, A, v, n=n, **kwargs)
def __init__(self, *parents, **kwargs): # For now, do not use plates other than from the parents, # although it would be possible (it would mean that you'd # create several "datasets" with identical "PCA # distribution"). Maybe it is better to create such plates in # children nodes? #plates = [] parents = list(parents) # Convert constant arrays to constant nodes for n in range(len(parents)): if utils.is_numeric(parents[n]): parents[n] = Constant(Gaussian)(parents[n]) parent_dims = [parent.dims for parent in parents] parent_plates = [parent.plates for parent in parents] # Check that the parents have equal dimensions for n in range(len(parent_dims) - 1): if parent_dims[n] != parent_dims[n + 1]: raise ValueError("Dimensions of the Gaussians do not " "match: %s" % (parent_dims, )) ## try: ## plates = utils.broadcasted_shape(*parent_plates) ## except ValueError: ## raise ValueError("The plates of the parents are " ## "incompatible: %s" % (parent_plates,)) super().__init__( *parents, #plates=tuple(plates), dims=((), ()), **kwargs)
def __init__(self, *parents, **kwargs): # For now, do not use plates other than from the parents, # although it would be possible (it would mean that you'd # create several "datasets" with identical "PCA # distribution"). Maybe it is better to create such plates in # children nodes? #plates = [] parents = list(parents) # Convert constant arrays to constant nodes for n in range(len(parents)): if utils.is_numeric(parents[n]): parents[n] = Constant(Gaussian)(parents[n]) parent_dims = [parent.dims for parent in parents] parent_plates = [parent.plates for parent in parents] # Check that the parents have equal dimensions for n in range(len(parent_dims)-1): if parent_dims[n] != parent_dims[n+1]: raise ValueError("Dimensions of the Gaussians do not " "match: %s" % (parent_dims,)) ## try: ## plates = utils.broadcasted_shape(*parent_plates) ## except ValueError: ## raise ValueError("The plates of the parents are " ## "incompatible: %s" % (parent_plates,)) super().__init__(*parents, #plates=tuple(plates), dims=((),()), **kwargs)
def __init__(self, a, b, **kwargs): self.parameter_distributions = (GammaPrior, Gamma) # TODO: USE asarray(a) # Check for constant a if utils.is_numeric(a): a = Constant(GammaPrior)(a) # Check for constant b if utils.is_numeric(b): b = Constant(Gamma)(b) #b = NodeConstant([b, np.log(b)], plates=np.shape(b), dims=[(),()]) # Construct super().__init__(a, b, **kwargs)
def __init__(self, X, **kwargs): # Check for constant n if utils.is_numeric(X): X = Constant(GaussianMarkovChain)(X) # Make the time dimension a plate dimension... #plates = X.plates + (X.dims[0][0],) # ... and remove it from the variable dimensions dims = ( X.dims[0][-1:], X.dims[1][-2:] ) super().__init__(X, #plates=plates, dims=dims, **kwargs)
def __init__(self, alpha, **kwargs): # Check for constant if utils.is_numeric(alpha): alpha = Constant(Gamma)(alpha) # Remove the last plate... #plates = alpha.plates[:-1] # ... and use it as the dimensionality of the Wishart # distribution if len(alpha.plates) == 0: raise Exception("Gamma variable needs to have plates in " "order to be used as a diagonal Wishart.") D = alpha.plates[-1] dims = ( (D,D), () ) # Construct the node super().__init__(alpha, #plates=plates, dims=dims, **kwargs)
def __init__(self, mu, Lambda, B, S, v, n=None, **kwargs): """ `mu` is the mean of x_0, (...)x(D) `Lambda` is the precision of x_0, (...)x(D,D) `B` is the dynamic matrices, (...,D)x(D,K) `S` is the temporal weights for the dynamic matrices, (...,N)x(K) `v` is the diagonal precision of the innovation, (...,D)x() """ # TODO/FIXME: Check these self.parameter_distributions = (Gaussian, Wishart, GaussianArrayARD, Gaussian, Gamma) # Check for constant mu if utils.is_numeric(mu): mu = Constant(Gaussian)(np.atleast_1d(mu)) # Check for constant Lambda if utils.is_numeric(Lambda): Lambda = Constant(Wishart)(np.atleast_2d(Lambda)) # Check for constant S if utils.is_numeric(S): S = Constant(Gaussian)(np.atleast_2d(S)) # Check for constant B if utils.is_numeric(B): D = Lambda.dims[0][-1] K = S.dims[0][-1] B = Constant(_GaussianArrayARD((D,K)))(np.atleast_3d(B)) # Check for constant V if utils.is_numeric(v): v = Constant(Gamma)(np.atleast_1d(v)) # A dummy wrapper for the number of time instances. n_S = 1 if len(S.plates) >= 1: n_S = S.plates[-1] n_v = 1 if len(v.plates) >= 2: n_v = v.plates[-2] if n_v != n_S and n_v != 1 and n_S != 1: raise Exception( "Plates of A and v are giving different number of time " "instances") n_S = max(n_v, n_S) if n is None: if n_S == 1: raise Exception( "The number of time instances could not be determined " "automatically. Give the number of time instances.") n = n_S + 1 elif n_S != 1 and n_S+1 != n: raise Exception( "The number of time instances must match the number of last " "plates of parents:" "%d != %d+1" % (n, n_S)) # Construct super().__init__(mu, Lambda, B, S, v, n=n, **kwargs)
def __init__(self, *args, iterator_axis=None, **kwargs): """ SumMultiply(Node1, map1, Node2, map2, ..., NodeN, mapN [, map_out]) """ args = list(args) if len(args) < 2: raise ValueError("Not enough inputs") if iterator_axis is not None: raise NotImplementedError("Iterator axis not implemented yet") if iterator_axis is not None and not isinstance(iterator_axis, int): raise ValueError("Iterator axis must be integer") # Two different parsing methods, depends on how the arguments are given if utils.is_string(args[0]): # This is the format: # SumMultiply('ik,k,kj->ij', X, Y, Z) strings = args[0] nodes = args[1:] # Remove whitespace strings = utils.remove_whitespace(strings) # Split on '->' (should contain only one '->' or none) strings = strings.split('->') if len(strings) > 2: raise ValueError('The string contains too many ->') strings_in = strings[0] if len(strings) == 2: string_out = strings[1] else: string_out = '' # Split former part on ',' (the number of parts should be equal to # nodes) strings_in = strings_in.split(',') if len(strings_in) != len(nodes): raise ValueError('Number of given input nodes is different ' 'from the input keys in the string') # Split strings into key lists using single character keys keysets = [list(string_in) for string_in in strings_in] keys_out = list(string_out) else: # This is the format: # SumMultiply(X, [0,2], Y, [2], Z, [2,1], [0,1]) # If given, the output mapping is the last argument if len(args) % 2 == 0: keys_out = [] else: keys_out = args.pop(-1) # Node and axis mapping are given in turns nodes = args[::2] keysets = args[1::2] # Find all the keys (store only once each) full_keyset = [] for keyset in keysets: full_keyset += keyset #full_keyset += list(keyset.keys()) full_keyset = list(set(full_keyset)) # # Check the validity of each node # for n in range(len(nodes)): # Convert constant arrays to constant nodes if utils.is_numeric(nodes[n]): # TODO/FIXME: Use GaussianArray and infer the dimensionality # from the length of the axis mapping! nodes[n] = Constant(Gaussian)(nodes[n]) # Check that the maps and the size of the variable are consistent if len(nodes[n].dims[0]) != len(keysets[n]): raise ValueError("Wrong number of keys (%d) for the node " "number %d with %d dimensions" % (len(keysets[n]), n, len(nodes[n].dims[0]))) # Check that the keys are unique if len(set(keysets[n])) != len(keysets[n]): raise ValueError("Axis keys for node number %d are not unique" % n) # Check that the dims are proper Gaussians if len(nodes[n].dims) != 2: raise ValueError("Node %d is not Gaussian" % n) if nodes[n].dims[0] + nodes[n].dims[0] != nodes[n].dims[1]: raise ValueError("Node %d is not Gaussian" % n) # Check the validity of output keys: each output key must be included in # the input keys if len(keys_out) != len(set(keys_out)): raise ValueError("Output keys are not unique") for key in keys_out: if key not in full_keyset: raise ValueError("Output key %s does not appear in any input" % key) # Check the validity of the nodes with respect to the key mapping. # Check that the node dimensions map and broadcast properly, that is, # all the nodes using the same key for axes must have equal size for # those axes (or size 1). broadcasted_size = {} for key in full_keyset: broadcasted_size[key] = 1 for (node, keyset) in zip(nodes, keysets): try: # Find the axis for the key index = keyset.index(key) except ValueError: # OK, this node doesn't use this key for any axis pass else: # Length of the axis for that key node_size = node.dims[0][index] if node_size != broadcasted_size[key]: if broadcasted_size[key] == 1: # Apply broadcasting broadcasted_size[key] = node_size elif node_size != 1: # Different sizes and neither has size 1 raise ValueError("Axes using key %s do not " "broadcast properly" % key) # Compute the shape of the output dim0 = [broadcasted_size[key] for key in keys_out] dim1 = dim0 + dim0 # Rename the keys to [0,1,...,N-1] where N is the total number of keys self.N_keys = len(full_keyset) self.out_keys = [full_keyset.index(key) for key in keys_out] self.in_keys = [ [full_keyset.index(key) for key in keyset] for keyset in keysets ] super().__init__(*nodes, dims=(tuple(dim0),tuple(dim1)), **kwargs)