Example #1
0
class BayesNetStructure(Space, PreBayesSpace):
    """Space for Bayesian network structure search.
    
    Built on top of a variable space that determines the variables of the
    Bayes net. For example, a Euclidean space, say $\mathbb{R}^d$, would have
    $d$ :class:`GaussianVariable`s. Or, a Binary space would have
    :class:`BinaryVariable`s.
    
    The default choice of variable is controlled by the ``_mapping`` class
    variable based on the ``type`` field of the variable space. To have mixed
    networks, use a :class:`Product` space.
    
    :param space: The space of variables
    :type space: :class:`Space`
    
    """
    _mappings = {  # map space types to bayesian variables
        np.ndarray: GaussianVariable,
        TernaryString: BinaryVariable,
    }

    def __init__(self, space):
        super(BayesNetStructure, self).__init__(BayesNet)
        self.space = space
        self.sampler = DAGSampler()

        if hasattr(space, 'dim'):
            self.numVariables = space.dim
        else:
            raise ValueError("Cannot determine the number of dimensions "
                             "for BayesNetStructure space based on given "
                             "space; expected space to have property dim "
                             "indicating the number of required variables. ")

        self.config = Config(numVariables=self.numVariables,
                             variableGenerator=self.variable,
                             randomizer=self.randomize,
                             sampler=self.sample)
        self.proposal = StructureProposal(**self.config.__properties__)
        self.config.structureGenerator = self.proposal

        self.edges = []
        self.nedges = []

    def in_bounds(self, network, **kwargs):
        c = network.config
        return (isinstance(network, BayesNet)
                and len(network.variables) == self.numVariables and np.all([
                    v.__class__ == self.variable(v.index, c).__class__
                    for v in network.variables
                ]))

    def proportion(self, smaller, larger, index):
        return 2.0**((len(smaller.edges) + len(smaller.nedges)) -
                     (len(larger.edges) + len(larger.nedges)))

    def area(self, **kwargs):
        return 1.0

    def random(self):
        network = BayesNet(**self.config.__properties__)
        for i in xrange(5):
            self.proposal.search(network)
        return network

    def extent(self):
        return self.nedges, self.edges
        #raise NotImplementedError("Bayesian networks do not have a "
        #                          "well-defined notion of spatial extent; "
        #                          "If you have something in mind, please "
        #                          "subclass the space or submit a pull "
        #                          "request.")

    def hash(self, point):
        point.computeEdgeStatistics()
        return str(point.edges)
Example #2
0
class BayesNetStructure(Space, PreBayesSpace):
    """Space for Bayesian network structure search.
    
    Built on top of a variable space that determines the variables of the
    Bayes net. For example, a Euclidean space, say $\mathbb{R}^d$, would have
    $d$ :class:`GaussianVariable`s. Or, a Binary space would have
    :class:`BinaryVariable`s.
    
    The default choice of variable is controlled by the ``_mapping`` class
    variable based on the ``type`` field of the variable space. To have mixed
    networks, use a :class:`Product` space.
    
    :param space: The space of variables
    :type space: :class:`Space`
    
    """
    _mappings = {  # map space types to bayesian variables
        np.ndarray: GaussianVariable,
        TernaryString: BinaryVariable,
    }
    
    def __init__(self, space):
        super(BayesNetStructure, self).__init__(BayesNet)
        self.space = space
        self.sampler = DAGSampler()
        
        if hasattr(space, 'dim'):
            self.numVariables = space.dim
        else:
            raise ValueError("Cannot determine the number of dimensions "
                             "for BayesNetStructure space based on given "
                             "space; expected space to have property dim "
                             "indicating the number of required variables. ")
        
        self.config = Config(numVariables=self.numVariables,
                             variableGenerator=self.variable,
                             randomizer=self.randomize,
                             sampler=self.sample)
        self.proposal = StructureProposal(**self.config.__properties__)
        self.config.structureGenerator = self.proposal
        
        self.edges = []
        self.nedges = []
    
    def in_bounds(self, network, **kwargs):
        c = network.config
        return (isinstance(network, BayesNet) and
                len(network.variables) == self.numVariables and
                np.all([v.__class__ == self.variable(v.index,c).__class__
                        for v in network.variables]))
        
    def proportion(self, smaller, larger, index):
        return  2.0 ** ((len(smaller.edges) + len(smaller.nedges)) -
                        (len(larger.edges) + len(larger.nedges)))
    
    def area(self, **kwargs):
        return 1.0
    
    def random(self):
        network = BayesNet(**self.config.__properties__)
        for i in xrange(5):
            self.proposal.search(network)
        return network
    
    def extent(self):
        return self.nedges, self.edges
        #raise NotImplementedError("Bayesian networks do not have a "
        #                          "well-defined notion of spatial extent; "
        #                          "If you have something in mind, please "
        #                          "subclass the space or submit a pull "
        #                          "request.")

    def hash(self, point):
        point.computeEdgeStatistics()
        return str(point.edges)