Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #4
0
    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)
Exemple #5
0
    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)
Exemple #6
0
    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)
Exemple #7
0
    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)
Exemple #9
0
    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)
Exemple #10
0
    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)
Exemple #12
0
    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)