示例#1
0
    def message_upperbound(self, tree, spins, subtheta):
        """Determine an upper bound on the energy of the elimination tree.

        Args:
            tree (dict): The current elimination tree
            spins (dict): The current fixed spins
            subtheta (dict): Theta with spins fixed.

        Returns:
            The formula for the energy of the tree.

        """
        energy_sources = set()
        for v, subtree in tree.items():

            assert all(u in spins for u in self._ancestors[v])

            # build an iterable over all of the energies contributions
            # that we can exactly determine given v and our known spins
            # in these contributions we assume that v is positive
            def energy_contributions():
                yield subtheta.linear[v]

                for u, bias in subtheta.adj[v].items():
                    if u in spins:
                        yield Times(limitReal(spins[u]), bias)

            energy = Plus(energy_contributions())

            # if there are no more variables in the order, we can stop
            # otherwise we need the next message variable
            if subtree:
                spins[v] = 1.
                plus = self.message_upperbound(subtree, spins, subtheta)
                spins[v] = -1.
                minus = self.message_upperbound(subtree, spins, subtheta)
                del spins[v]
            else:
                plus = minus = limitReal(0.0)

            # we now need a real-valued smt variable to be our message
            m = FreshSymbol(REAL)

            self.assertions.update({
                LE(m, Plus(energy, plus)),
                LE(m, Plus(Times(energy, limitReal(-1.)), minus))
            })

            energy_sources.add(m)

        return Plus(energy_sources)
示例#2
0
    def gap_bound_assertion(self, gap_lowerbound):
        """The formula that lower bounds the gap.

        Args:
            gap_lowerbound (float): Return the formula that sets a lower
                bound on the gap.

        """
        return GE(self.gap, limitReal(gap_lowerbound))
示例#3
0
    def test_energy_ranges_K5(self):
        """Check that the energy ranges were set the way we expect"""
        linear_ranges = defaultdict(lambda: (-2., 2.))
        quadratic_ranges = defaultdict(lambda: (-1., 1.))

        graph = nx.complete_graph(5)
        theta = Theta.from_graph(graph, linear_ranges, quadratic_ranges)

        for v, bias in theta.linear.items():
            min_, max_ = linear_ranges[v]
            self.assertUnsat(
                And(GT(bias, limitReal(max_)), And(theta.assertions)))
            self.assertUnsat(
                And(LT(bias, limitReal(min_)), And(theta.assertions)))

        for (u, v), bias in theta.quadratic.items():
            min_, max_ = quadratic_ranges[(u, v)]
            self.assertUnsat(
                And(GT(bias, limitReal(max_)), And(theta.assertions)))
            self.assertUnsat(
                And(LT(bias, limitReal(min_)), And(theta.assertions)))
示例#4
0
    def set_energy(self, spins, target_energy):
        """Set the energy of Theta with spins fixed to target_energy.

        Args:
            spins (dict): Spin values for a subset of the variables in Theta.
            target_energy (float): The desired energy for Theta with spins fixed.

        Notes:
            Add equality constraint to assertions.

        """
        spin_energy = self.energy(spins)
        self.assertions.add(Equals(spin_energy, limitReal(target_energy)))
示例#5
0
            def energy_contributions():
                yield subtheta.linear[v]

                for u, bias in subtheta.adj[v].items():
                    if u in spins:
                        yield Times(limitReal(spins[u]), bias)