def _update_messages(self, damp_ratio):
        temp_messages = dict()
        factor_order = copy(self.model.factors)
        random.shuffle(factor_order)
        for fac in factor_order:
            for var in fac.variables:
                next_message = (product_over_(
                    fac, *[
                        msg
                        for msg in self._message_to_(fac, except_objs=[var])
                    ]).marginalize_except_(
                        [var], inplace=False).normalize(inplace=False))
                self.messages[(
                    fac, var)] = (damp_ratio * self.messages[(fac, var)] +
                                  (1 - damp_ratio) * next_message)

        variable_order = copy(self.model.variables)
        random.shuffle(variable_order)
        for var in variable_order:
            for fac in self.factors_adj_to_[var]:
                messages_to_var_except_fac = self._message_to_(
                    var, except_objs=[fac])
                if messages_to_var_except_fac:
                    next_message = product_over_(
                        *messages_to_var_except_fac).normalize(inplace=False)
                    self.messages[(
                        var, fac)] = (damp_ratio * self.messages[(var, fac)] +
                                      (1 - damp_ratio) * next_message)
    def _is_converged(self, converge_thr, messages, new_messages):
        for var in self.model.variables:
            blf = (product_over_(
                *[messages[(fac, var)]
                  for fac in self.factors_adj_to_[var]]).normalize(
                      inplace=False))
            new_blf = (product_over_(*[
                new_messages[(fac, var)] for fac in self.factors_adj_to_[var]
            ]).normalize(inplace=False))
            if np.sum(np.abs(blf.values - new_blf.values)) > converge_thr:
                return False

        return True
Exemple #3
0
    def get_marginal_factor(self, elimination_order_method="random", **kwargs):
        if elimination_order_method == "random":
            elimination_order = copy(self.model.variables)
            random.shuffle(elimination_order)
        elif elimination_order_method == "not_random":
            elimination_order = copy(self.model.variables)
        elif elimination_order_method == "given":
            elimination_order = kwargs["elimination_order"]

        if "exception_variables" in kwargs:
            exception_variables = kwargs["exception_variables"]
        else:
            exception_variables = []

        eliminated_model = self.model.copy()
        max_ibound = 0
        for var in elimination_order:
            if var not in exception_variables:
                max_ibound = max(
                    max_ibound,
                    get_bucket_size([
                        fac for fac in eliminated_model.get_adj_factors(var)
                    ]),
                )
                eliminated_model.contract_variable(var)

        final_factor = product_over_(*eliminated_model.factors)
        if "exception_variables" in kwargs:
            final_factor.transpose_by_(exception_variables)

        return final_factor
Exemple #4
0
    def _backward_pass_for_(self, variable, lower_variable):
        message = product_over_(self.factor_upper_to_[variable],
                                *self._messages_to_(variable))
        message.pow(self.holder_weights_for_[lower_variable] /
                    self.holder_weights_for_[variable])
        message.div(self.messages[(lower_variable, variable)])

        #variables_in_factor_upper_to_lower_variable = copy(self.factor_upper_to_[lower_variable].variables)
        #variables_to_marginalize = list(set(message.variables)
        #                                - set(variables_in_factor_upper_to_lower_variable))
        #message.marginalize(variables_to_marginalize,
        #                    operator = 'weighted_sum',
        #                    weight = self.holder_weights_for_[lower_variable])
        lower_upper_factor = self.factor_upper_to_[lower_variable]
        variables_to_marginalize = list(
            set(message.variables) - set(lower_upper_factor.variables))
        message.marginalize(variables_to_marginalize,
                            operator='weighted_sum',
                            weight=self.holder_weights_for_[lower_variable])
        #variables_not_to_marginalize = self.upper_candidate_for_[lower_variable]
        #message.marginalize_except_(variables_not_to_marginalize,
        #                            operator = 'weighted_sum',
        #                            weight = self.holder_weights_for_[lower_variable])
        message.name = 'M_{}<-{}'.format(lower_variable, variable)
        self.messages[(variable, lower_variable)] = message
Exemple #5
0
 def get_marginals_upper_to_(self, variable):
     marginal = product_over_(self.factor_upper_to_[variable],
                              *self._messages_to_(variable))
     marginal.pow(1 / self.holder_weights_for_[variable])
     marginal.normalize()
     marginal.name = 'q_c_{}'.format(variable)
     return marginal
Exemple #6
0
    def _forward_pass_for_(self, variable):
        upper_variable = self.variable_upper_to_[variable]
        message = product_over_(self.factor_upper_to_[variable],
                                *self._upper_messages_to_(variable))
        message.marginalize([variable],
                            operator='weighted_sum',
                            weight=self.holder_weights_for_[variable])
        message.name = 'M_{}->{}'.format(variable, upper_variable)

        self.messages[(variable, upper_variable)] = message
    def contract_variable(self, variable, operator="sum", **kwargs):
        adj_factors = self.get_adj_factors(variable)
        new_factor = product_over_(*adj_factors).copy(rename=True)
        new_factor.marginalize([variable], operator=operator, **kwargs)
        for factor in adj_factors:
            self.remove_factor(factor)

        self.remove_variable(variable)
        self.add_factor(new_factor)

        return new_factor
    def get_logZ(self):
        logZ = 0
        for var in self.model.variables:
            logZ += entropy(self.mean_fields[var])

        for fac in self.model.factors:
            m = product_over_(*[self.mean_fields[var] for var in fac.variables])
            index_to_keep = m.values != 0
            logZ += np.sum(m.values[index_to_keep] * fac.log_values[index_to_keep])

        return logZ
    def run(self, max_iter=1000, converge_thr=1e-5, damp_ratio=0.1):
        for t in range(max_iter):
            old_messages = {
                key: item.copy()
                for key, item in self.messages.items()
            }
            self._update_messages(damp_ratio)
            if self._is_converged(converge_thr, self.messages, old_messages):
                break

        self.belief = {}
        for var in self.model.variables:
            self.belief[var] = (product_over_(
                *self._message_to_(var)).normalize(inplace=False))

        for fac in self.model.factors:
            self.belief[fac] = (product_over_(
                fac, *self._message_to_(fac)).normalize(inplace=False))

        return self.get_logZ()
    def _update_mean_fields(self):
        variable_order = np.random.permutation(self.model.variables)
        for var in variable_order:
            next_mean_field = Factor.full_like_(self.mean_fields[var], 0.0)
            for fac in self.model.get_adj_factors(var):
                tmp = Factor(name = 'tmp', variables = [var], values = np.ones(self.model.get_cardinality_for_(var)))
                tmp = product_over_(tmp, *[self.mean_fields[var1] for var1 in fac.variables if var1 != var])
                tmp.transpose_by_(fac.variables)
                tmp.log_values = fac.log_values * tmp.values
                next_mean_field = next_mean_field + tmp.marginalize_except_([var], inplace = False)

            self.mean_fields[var] = next_mean_field.exp(inplace = False).normalize(inplace = False)
            self.mean_fields[var].log_values = np.nan_to_num(self.mean_fields[var].log_values)
    def __init__(self, model, ibound):
        self.org_model = model.copy()
        model = model.copy()

        unelminated_variables = copy(model.variables)
        while unelminated_variables:

            def get_bucket_size(facs):
                adj_adj_vars = [fac.variables for fac in facs]
                a = set()
                for vars in adj_adj_vars:
                    a = a.union(vars)
                return len(a)

            get_key = lambda var: get_bucket_size(model.get_adj_factors(var))

            var = min(unelminated_variables, key=get_key)
            unelminated_variables.pop(unelminated_variables.index(var))
            if get_key(var) == 1:
                pass
            elif get_key(var) < ibound:
                model.contract_variable(var)
            else:
                facs = model.get_adj_factors(var)
                model.remove_factors_from(facs)
                mini_buckets = []
                for fac in facs:
                    mini_bucket = next(
                        (mb for mb in mini_buckets
                         if get_bucket_size(mb + [fac]) < ibound), False)
                    if mini_bucket:
                        mini_bucket.append(fac)
                    else:
                        mini_buckets.append([fac])

                for mini_bucket in mini_buckets:
                    if mini_bucket:
                        model.add_factor(product_over_(*mini_bucket))
                    else:
                        print('empty mini-bucket')

        super(IterativeJoinGraphPropagation, self).__init__(model)
Exemple #12
0
    def initialize_projectors(self):
        replications = dict()
        working_model = self.renormalized_model.copy()
        for var in self.elimination_order:
            main_rvar = self.variables_replicated_from_[var][-1]
            main_projectors = []
            for (i, rvar) in enumerate(self.variables_replicated_from_[var]):
                if i < len(self.variables_replicated_from_[var]) - 1:
                    fac = product_over_(*working_model.get_adj_factors(rvar))
                    replicated_projector = self._get_svd_projector(fac, rvar)
                    replicated_projector.name = "RP_{}".format(rvar)
                    projector = replicated_projector.copy()
                    projector.variables = [main_rvar]
                    projector.name = "P_{}".format(rvar)

                    replications[rvar] = (main_rvar, replicated_projector, projector)
                    main_projectors.append(projector)

                    working_model.add_factors_from([replicated_projector.copy(), projector.copy()])
                    self.renormalized_model.add_factors_from([replicated_projector, projector])

                working_model.contract_variable(rvar)

        self.replications = replications
Exemple #13
0
    def renormalize_model(self, **kwargs):
        ibound = kwargs['ibound']
        if 'elimination_order_method' in kwargs:
            if kwargs['elimination_order_method'] == 'random':
                elimination_order = copy(self.model.variables)
                use_min_fill = False
                random.shuffle(elimination_order)
            elif kwargs['elimination_order_method'] == 'not_random':
                elimination_order = copy(self.model.variables)
                use_min_fill = False
            elif kwargs['elimination_order_method'] == 'min_fill':
                elimination_order = []
                use_min_fill = True
        elif 'elimination_order' in kwargs:
            elimination_order = copy(kwargs['elimination_order'])
            use_min_fill = False
        else:
            elimination_order = copy(self.model.variables)
            use_min_fill = False
            random.shuffle(elimination_order)
            #elimination_order = []
            #use_min_fill = True

        renormalized_model = self.model.copy()
        renormalized_elimination_order = []

        variables_replicated_from_ = {var: [] for var in self.model.variables}
        factors_adj_to_ = dict()
        working_factorss = [[fac] for fac in renormalized_model.factors]
        eliminated_variables = []
        for t in range(len(self.model.variables)):
            uneliminated_variables = sorted(
                set(self.model.variables) - set(eliminated_variables))
            candidate_mini_buckets_for_ = dict()

            bucket_for_ = {cand_var: [] for cand_var in uneliminated_variables}
            for facs in working_factorss:
                for cand_var in self.get_variables_in_(
                    [[fac] for fac in facs], eliminated=eliminated_variables):
                    bucket_for_[cand_var].append(facs)

            for cand_var in uneliminated_variables:
                candidate_mini_buckets_for_[cand_var] = []
                for facs in bucket_for_[cand_var]:
                    mini_bucket = next(
                        (mb for mb in candidate_mini_buckets_for_[cand_var] if
                         self.get_bucket_size(mb + [facs],
                                              eliminated=eliminated_variables +
                                              [cand_var]) < ibound), False)
                    if mini_bucket:
                        mini_bucket.append(facs)
                    else:
                        candidate_mini_buckets_for_[cand_var].append([facs])

            if use_min_fill:
                var, mini_buckets = min(candidate_mini_buckets_for_.items(),
                                        key=lambda x: len(x[1]))
                elimination_order.append(var)
            else:
                var = elimination_order[t]
                mini_buckets = candidate_mini_buckets_for_[var]

            eliminated_variables.append(var)
            mini_buckets.sort(key=lambda mb: self.get_bucket_size(
                mb, eliminated=eliminated_variables))

            remove_idx = []
            for working_facs_idx, working_facs in enumerate(working_factorss):
                if var in self.get_variables_in_([[fac]
                                                  for fac in working_facs]):
                    remove_idx.append(working_facs_idx)

            for i in reversed(sorted(remove_idx)):
                working_factorss.pop(i)

            for (i, mb) in enumerate(mini_buckets):
                mb_facs = [fac for facs in mb for fac in facs]
                working_factorss.append(mb_facs)

                replicated_var = var + '_' + str(i)
                variables_replicated_from_[var].append(replicated_var)
                factors_adj_to_[replicated_var] = [
                    fac for fac in mb_facs if var in fac.variables
                ]

        for var in elimination_order:
            for replicated_var in variables_replicated_from_[var]:
                renormalized_model.add_variable(replicated_var)
                renormalized_elimination_order.append(replicated_var)
                for fac in factors_adj_to_[replicated_var]:
                    fac.variables[fac.variables.index(var)] = replicated_var

            renormalized_model.remove_variable(var)

        factors_upper_to_ = {var: [] for var in renormalized_model.variables}
        for fac in renormalized_model.factors:
            lower_var = min(fac.variables,
                            key=renormalized_elimination_order.index)
            factors_upper_to_[lower_var].append(fac)

        for var, facs in factors_upper_to_.items():
            if facs:
                new_fac = product_over_(*facs)
                for fac in facs:
                    renormalized_model.remove_factor(fac)
                renormalized_model.add_factor(new_fac)

        base_logZ = 0.0
        for fac in renormalized_model.factors:
            base_logZ += np.max(fac.log_values)
            fac.log_values -= np.max(fac.log_values)

        self.elimination_order = elimination_order
        self.renormalized_model = renormalized_model
        self.renormalized_elimination_order = renormalized_elimination_order
        self.variables_replicated_from_ = variables_replicated_from_
        self.base_logZ = base_logZ