예제 #1
0
def get_const_valuation_with_v(v, variables, is_log):
    """ return a constant valuation with scope v, (all ones, all zero) """
    for var in variables:
        if var.label == v:
            if is_log:  # transform back to log scale
                # return Valuation(Factor({var}, ONE), Factor({var}, ONE)).log()
                return Valuation(Factor({var}, ONE), Factor({var}, ZERO)).log()
            else:
                # return Valuation(Factor({var}, ONE), Factor({var}, ONE))
                return Valuation(Factor({var}, ONE), Factor({var}, ZERO))
예제 #2
0
def get_const_with_vars(var_labels, variables, is_valuation, is_log):
    var_set = {var for var in variables if var.label in var_labels}
    if is_valuation:
        const_linear = Valuation(Factor(var_set.copy(), ONE),
                                 Factor(var_set.copy(), ZERO))
    else:
        const_linear = Factor(var_set.copy(), ONE)
    if is_log:
        return const_linear.log()
    else:
        return const_linear
예제 #3
0
 def eu_from_bounds(self, bounds, scale_prob_max=True):
     temp = Valuation(1.0, 0.0)  # bounds[0].copy()  # first valuation
     for el in bounds:
         temp = temp * el  # combine bounds
     if scale_prob_max:
         return temp.util * self.prob_const  # result is in linear scale
     else:
         return temp.util
예제 #4
0
 def _array_to_val(self, var_obj, x, edges):
     prob_tables, util_tables = np.split(x.copy(), 2)
     valuations = []
     for p, u in zip(np.split(prob_tables, len(edges)),
                     np.split(util_tables, len(edges))):
         valuations.append(Valuation(Factor(var_obj, p), Factor(var_obj,
                                                                u)))
     return valuations
예제 #5
0
 def _set_cost(self, node_from, node_to, prob_gradient, util_gradient, step):
     prob_shift = -step*prob_gradient
     util_shift = -step*util_gradient
     va_shift = Valuation(prob_shift.exp(), util_shift)
     np.clip(va_shift.prob.t, a_min=TOL, a_max=None, out=va_shift.prob.t)  # fix numerical error cannot div by zero
     va_from = self.mg.message_graph.node[node_from]['fs'][0]
     va_to = self.mg.message_graph.node[node_to]['fs'][0]
     self.mg.message_graph.node[node_from]['fs_old'] = va_from
     self.mg.message_graph.node[node_to]['fs_old'] = va_to
     self.mg.set_factor(node_from, va_from/va_shift)
     self.mg.set_factor(node_to, va_to*va_shift)
예제 #6
0
 def __init__(self, verbose_level, message_graph, elim_order, weights, is_log, epsilon, log_file_name, ibound,
              mini_buckets, gm_variables):
     super(WeightedMBE4, self).__init__(verbose_level, message_graph, elim_order, weights, is_log, log_file_name)
     self.epsilon = epsilon  # WEPS smallest weight
     self.ibound = ibound
     self.mini_buckets = mini_buckets    # defaultdict(SortedSet) mini_buckets[var] : SortedSet( [(var, m_id), ...] )
     self.prob_const_per_layer = {v: 1.0 for v in self.elim_order}
     self.global_meu_bound = 1.0     # meu is in linear scale
     self.gm_variables = gm_variables        # list of Var objects from gm class     Var0 at index 0 of list
     self.processed_nodes = set()
     self.const_msg_at = {v: Valuation(1.0, 0.0) for v in self.elim_order}
예제 #7
0
    def _set_util_const(self, node, util_gradient, step):
        util_const_shift = -step * util_gradient
        self.mg.message_graph.node[node]['util_const_old'] = self.mg.message_graph.node[node]['util_const']
        self.mg.message_graph.node[node]['util_const'] += util_const_shift
        self.mg.message_graph.node[node]['fs_old'] = self.mg.message_graph.node[node]['fs'][0]

        p = self.mg.message_graph.node[node]['fs'][0].prob
        eu = self.mg.message_graph.node[node]['fs'][0].util
        u_shifted = eu/p + util_const_shift     # creates a new object
        eu_shifted = p*u_shifted                # creates a new object
        self.mg.set_factor(node, Valuation(p, eu_shifted))
        self.util_const += util_const_shift
예제 #8
0
    def read_decomposed_bounds(self, nodes=[]):
        if not nodes:
            nodes = self.mg.message_graph.nodes()
        temp = Valuation(1.0, 0.0)
        for node in nodes: #self.mg.message_graph.nodes_iter():
            if node in self.processed_nodes:
                continue

            val = self.mg.message_graph.node[node]['bound']
            temp = temp * val  # combine bounds
            assert not np.isnan(temp.util)
        return temp.util
예제 #9
0
    def _eval_pseudo_belief_node(self, node):
        pr = self.mg.message_graph.node[node]['fs'][0].prob
        pr = pr.log()
        mu_p = self._eval_pseudo_belief(node, pr)

        eu = self.mg.message_graph.node[node]['fs'][0].util.copy()
        np.clip(eu.t, a_min=ZERO, a_max=None, out=eu.t)
        eu = eu.log()
        mu_u = self._eval_pseudo_belief(node, eu)

        if self.mg.message_graph.node[node]['pseudo_belief'] is None:
            self.mg.message_graph.node[node]['pseudo_belief'] = Valuation(mu_p, mu_u)
        else:
            self.mg.message_graph.node[node]['pseudo_belief'].prob = mu_p
            self.mg.message_graph.node[node]['pseudo_belief'].util = mu_u
예제 #10
0
    def _construct_tree(self):
        def add_vertex(stage):
            vertex = self._graph.add_vertex()
            index = self._graph.vertex_index[vertex]

            self._vertices[index] = stage

            return index

        root_formula = Formula()
        root_formula.assert_some_states_present(self._protocol.initial_states)
        root_formula.assert_all_states_absent(self._protocol.states -
                                              self._protocol.initial_states)

        root_stage = Stage(root_formula, Valuation(), set(), speed=Speed.ZERO)
        root_index = add_vertex(root_stage)
        unexplored = [(root_index, root_stage)]
        mem = {}  # for memoization in computation of J

        while len(unexplored) > 0:
            index, stage = unexplored.pop()
            valuations = stage.formula.solutions()
            has_children = False

            for val in valuations:
                child_stage = new_stage(self._protocol, stage, val, mem)

                if not child_stage.is_redundant():
                    child_index = add_vertex(child_stage)
                    self._graph.add_edge(index, child_index)
                    unexplored.append((child_index, child_stage))
                    has_children = True

            if not has_children:
                self._leaves.add(index)

            self._speed = max(self._speed, stage.speed)
예제 #11
0
    def solutions(self):
        solver = z3.Solver()
        solver.add(self._consistency_constraints())
        solver.add(self._assertions)

        sol = []

        while (solver.check() == z3.sat):
            model = solver.model()
            valuation = Valuation()

            for var in self:
                valuation[var] = z3.is_true(model[Formula._id(var)])

            sol.append(valuation)

            # Forbid solution in future checks
            solver.add(
                z3.Or([
                    z3.Not(Formula._id(v)) if valuation[v] else Formula._id(v)
                    for v in valuation
                ]))

        return sol
예제 #12
0
    def _propagate_one_pass(self, time_limit, iter_limit, optimize_weight, optimize_cost):
        """
        wmbe_id: initialize weights by 1 iteration of gdd -> inherit weights
        """
        const_valuations = []
        for ord_ind, var in enumerate(self.elim_order):
            var_obj = self.gm_variables[var]
            nodes_at_the_current_layer = self.mini_buckets[var]

            # pull message and combine before cost shifting
            self.print_log("process var:{}\nmini_buckets:{}".format(var, nodes_at_the_current_layer))
            for node in nodes_at_the_current_layer:
                if debug: assert node[0] == var
                for n_from, n_cur  in self.mg.message_graph.in_edges_iter([node]):
                    if debug:
                        assert n_cur == node
                    if self.elim_order.index( n_from[0] ) < self.elim_order.index( n_cur[0] ):
                        in_msgs = self.mg.pull_msg_from(n_from, node)
                        combined_factor = self.mg.combine_factors(node, in_msgs, self.is_log)
                        self.mg.set_factor(node, combined_factor)

            # optimize bound
            time_0, iter, cost_updated, weight_updated = time.time(), 1, False, False
            while len(nodes_at_the_current_layer) > 1 and iter <= iter_limit and (time.time() - time_0) < time_limit:
                if optimize_cost:
                    cost_updated = self._optimize_costs(var_obj, nodes_at_the_current_layer)
                if optimize_weight:
                    weight_updated = self._optimize_weights(var_obj, nodes_at_the_current_layer)
                if not cost_updated and not weight_updated: # both not updated within iter limit escape
                    self.print_log("\toptimizing mini_buckets iter:{} no improvement".format(iter))
                    break
                else:
                    self.print_log("\toptimizing mini_buckets iter:{}\tbound:{}".format(iter, self.read_decomposed_bounds()))
                    self.print_log("\t\tc_updated:{}\tw_updated:{}".format(cost_updated, weight_updated))
                    iter += 1

            # push message downward along the edge
            nodes_changed = []
            for node in nodes_at_the_current_layer:
                # if node == (20,0):
                #     print("watch")        first mini bucket split in mdp1
                w = self.mg.message_graph.node[node]['w'][var]
                w_inv = np.inf if w <= self.epsilon else ONE/w
                F = self.mg.message_graph.node[node]['fs'][0].abs()
                lnF = F.log()
                lnmsg = lnF.lsePower(elim={var_obj}, power=w_inv)
                msg = lnmsg.exp()
                next_node = self._get_next_node(node)
                if next_node:
                    nodes_changed.append(next_node)
                    self.print_log("\tsend msg from {} to {}".format(node, next_node))
                    self.mg.push_msg(node, next_node, msg)
                    ### inherit weights, recompute bounds, pseudo belief at receiving nodes
                    sc_from = self.mg.message_graph.node[node]['sc']
                    sc_to = self.mg.message_graph.node[next_node]['sc']
                    w_from = self.mg.message_graph.node[node]['w']
                    w_to = self.mg.message_graph.node[next_node]['w']
                    if debug:
                        sc_msg = sc_from - {var}
                        assert sc_msg.issubset(sc_to)
                    for vv in sc_from:
                        if vv == var:   # skip weight for the current layer
                            continue
                        # inherit weigths
                        self.mg.message_graph.node[next_node]['w'][vv] += self.mg.message_graph.node[node]['w'][vv]
                else:
                    self.print_log("\tconstant msg from {} with valuation:{}".format(node, msg))
                    self.mg.push_msg(node, None, msg)
                    const_valuations.append(msg)

            if nodes_changed:
                self._reset_node_bounds(nodes_changed)
                self._reset_pseudo_beliefs(nodes_changed)
            self.processed_nodes.update(nodes_at_the_current_layer)

            # if var == 19:     for mdp1 problem debugging first decision
            #     exit()
        bound_valuation = Valuation(1.0, 0.0)
        print(const_valuations)
        for val in const_valuations:
            bound_valuation = bound_valuation * val
        return float(bound_valuation.util), float(bound_valuation.prob)
예제 #13
0
def new_stage_valuation(protocol, valuation, disabled):
    def f(M, N):
        M_, N_ = set(M), set(N)

        def cannot_occur(t):
            return (len(t.preset & M) > 0 or (t.pre in disabled)
                    or (len(t.preset) == 1 and t.pre.some() in N))

        for q in M:
            T = {t for t in protocol.transitions if q in t.post}
            to_remove = any(not cannot_occur(t) for t in T)

            if to_remove:
                M_.remove(q)

        for q in N:
            S = {
                t
                for t in protocol.transitions if (q in t.pre) and (
                    t.pre.other(q) != q) and (not t.unchanged(q))
            }
            T = {t for t in protocol.transitions if q not in t.pre}

            to_remove = any(not ((t.pre.other(q) in M) or (t.pre in disabled))
                            for t in S)
            to_remove = to_remove or any(not cannot_occur(t) for t in T)

            if to_remove:
                N_.remove(q)

        return (M_, N_)

    # Compute greatest fixed point (M, N) of f
    M, N = valuation.absent_states(), valuation.unique_states()
    M_, N_ = f(M, N)

    while (M, N) != (M_, N_):
        M, N = M_, N_
        M_, N_ = f(M, N)

    # Compute E
    E = set()
    P = valuation.present_states()

    for q in P:
        T = {
            t
            for t in protocol.transitions if (q in t.pre and q not in t.post)
        }

        if all((t.pre.other(q) in M) or (t.pre in disabled) or (
                t.pre.other(q) == q and q in N) for t in T):
            E.add(q)

    # Construct new valuation
    new_valuation = Valuation()

    for q in M:
        new_valuation[Var(q)] = False
    for q in E:
        new_valuation[Var(q)] = True
    for q in N:
        new_valuation[Var(q, True)] = True

    return new_valuation
예제 #14
0
    def _propagate_one_pass(self, time_limit, iter_limit, optimize_weight,
                            optimize_cost):
        """
        wmbe_id: initialize weight uniformly -> reset all remaining weights uniformly after passing messages
        """
        const_valuations = [
        ]  # todo this constant should be multiplied per layer to be a heuristic

        for var in self.elim_order:
            var_obj = self.gm_variables[var]
            nodes_at_the_current_layer = self.mini_buckets[var]
            self._reset_uniform_weights()
            self._reset_node_bounds()
            self._reset_pseudo_beliefs()

            # pull message and combine before cost shifting
            self.print_log("process var:{}\nmini_buckets:{}".format(
                var, nodes_at_the_current_layer))
            for node in nodes_at_the_current_layer:
                if debug: assert node[0] == var
                for n_from, n_cur in self.mg.message_graph.in_edges_iter(
                    [node]):
                    if debug:
                        assert n_cur == node
                    if self.elim_order.index(
                            n_from[0]) < self.elim_order.index(n_cur[0]):
                        in_msgs = self.mg.pull_msg_from(n_from, node)
                        combined_factor = self.mg.combine_factors(
                            node, in_msgs, self.is_log)
                        self.mg.set_factor(node, combined_factor)

            # optimize bound
            time_0, iter, cost_updated, weight_updated = time.time(
            ), 1, False, False
            while len(nodes_at_the_current_layer
                      ) > 1 and iter <= iter_limit and (time.time() -
                                                        time_0) < time_limit:
                if optimize_cost:
                    cost_updated = self._optimize_costs(
                        var_obj, nodes_at_the_current_layer)
                if optimize_weight:
                    weight_updated = self._optimize_weights(
                        var_obj, nodes_at_the_current_layer)
                if not cost_updated and not weight_updated:  # both not updated within iter limit escape
                    self.print_log(
                        "\toptimizing mini_buckets iter:{} no improvement".
                        format(iter))
                    break
                else:
                    self.print_log(
                        "\toptimizing mini_buckets iter:{}\tbound:{}".format(
                            iter, self.read_decomposed_bounds()))
                    self.print_log("\t\tc_updated:{}\tw_updated:{}".format(
                        cost_updated, weight_updated))
                    iter += 1

            # push message downward along the edge; uniform weight
            for node in nodes_at_the_current_layer:
                # if node == (20,0):
                #     print("watch")        first mini bucket split in mdp1
                w = self.mg.message_graph.node[node]['w'][var]
                w_inv = np.inf if w <= self.epsilon else ONE / w
                F = self.mg.message_graph.node[node]['fs'][0].abs()
                lnF = F.log()
                lnmsg = lnF.lsePower(elim={var_obj}, power=w_inv)
                msg = lnmsg.exp()
                next_node = self._get_next_node(node)
                if next_node:
                    self.print_log("\tsend msg from {} to {}".format(
                        node, next_node))
                    self.mg.push_msg(node, next_node, msg)
                else:
                    self.print_log(
                        "\tconstant msg from {} with valuation:{}".format(
                            node, msg))
                    self.mg.push_msg(node, None, msg)
                    const_valuations.append(msg)
            self.processed_nodes.update(nodes_at_the_current_layer)

            # if var == 19:     for mdp1 problem debugging first decision
            #     exit()
        bound_valuation = Valuation(1.0, 0.0)
        print(const_valuations)
        for val in const_valuations:
            bound_valuation = bound_valuation * val
        return float(bound_valuation.util), float(bound_valuation.prob)