Esempio n. 1
0
    def cls_sumout_var(cls, f: Factor, Y: NumCatRVariable):
        """!
        \brief Sum the variable out of factor as per Koller, Friedman 2009, p. 297

        Summing out, or factor marginalization, is defined as the following by
        Koller, Friedman:

        <blockquote>

        Let X be a set of variables and Y \f$\not \in \f$ X a variable. Let
        \f$\phi(X, Y)\f] be a factor. We define the factor marginalization of Y
        in phi, denoted \f$ \sum_Y \phi \f$, to be a factor psi over X such
        that: \f$ \psi(X) = \sum_Y \phi(X,Y) \f$

        </blockquote>


        \param Y the variable that we are going to sum out.

        \throw ValueError We raise a value error if the argument is not in
        the scope of this factor

        \return Factor
        """
        if Y not in f:
            msg = "Argument " + str(Y)
            msg += " is not in scope of this factor: "
            msg += " ".join(f.scope_vars())
            raise ValueError(msg)

        # Y_vals = Y.value_set()
        products = f.factor_domain()
        fn = f.factor_fn

        def psi(scope_product: Set[Tuple[str, NumericValue]]):
            """"""
            s = set(scope_product)
            diffs = set([p for p in products if s.issubset(p) is True])
            return sum([fn(d) for d in diffs])

        return Factor(
            gid=str(uuid4()),
            scope_vars=f.scope_vars().difference({Y}),
            factor_fn=psi,
        )
Esempio n. 2
0
    def _compare_prob_value(
            cls,
            f: Factor,
            comp_fn: Callable[[float, float],
                              bool] = lambda phi_s, mx: phi_s > mx,
            comp_v: float = float("-inf"),
    ):
        """"""
        if not isinstance(f, Factor):
            raise TypeError("The object must be of Factor type")

        cval = comp_v
        out_val = None
        for sp in f.factor_domain():
            ss = frozenset(sp)
            phi_s = f.phi(ss)
            if comp_fn(phi_s, cval):
                cval = phi_s
                out_val = ss
        return out_val, cval
Esempio n. 3
0
    def cls_maxout_var(cls, f: Factor, Y: NumCatRVariable):
        """!
        \brief max the variable out of factor as per Koller, Friedman 2009, p. 555

        Maxing out a variable, or factor maximization is defined by Koller,
        Friedman as:
        <blockquote>
        Let X be a set of variables, and Y \f$ \not \in \f$ X, a random
        variable. Let \f$ \phi(X, Y) \f$ be a factor. We define the factor
        maximization of Y in \f$ \phi \f$ to be factor \f$ \psi \f$ over X such
        that: \f$ \psi(X) = max_{Y}\phi(X, Y) \f$
        </blockquote>

        \param Y random variable who is going to be maxed out.

        \throw ValueError If the argument is not in scope of this factor, we
        throw a value error

        \return Factor
        """
        if Y not in f:
            raise ValueError("argument is not in scope of this factor")

        # Y_vals = Y.value_set()
        products = f.factor_domain()
        fn = f.factor_fn

        def psi(scope_product: Set[Tuple[str, NumericValue]]):
            """"""
            s = set(scope_product)
            diffs = set([p for p in products if s.issubset(p) is True])
            return max([fn(d) for d in diffs])

        return Factor(
            gid=str(uuid4()),
            scope_vars=f.scope_vars().difference({Y}),
            factor_fn=psi,
        )
Esempio n. 4
0
    def cls_product(
        cls,
        f: Factor,
        other: Factor,
        product_fn=lambda x, y: x * y,
        accumulator=lambda added, accumulated: added * accumulated,
    ) -> Tuple[Factor, float]:
        """!
        \brief Factor product operation from Koller, Friedman 2009, p. 107
        \f$ \psi(X,Y,Z) =  \phi(X,Y) \cdot \phi(Y,Z) \f$
        \f$ \prod_i phi(X_i) \f$

        Point wise product of two different factor functions.

        \param product_fn actual function for computing product. This function
        can be exchanged with another function to compute log-sum for example.

        \param accumulator this function decides how to accumulate resulting product.
        \param product_fn
        \parblock

        product function. Default case is that it multiplies
        its two arguments. In case of a floating precision problem it can be
        changed into summation.

        \endparblock

        \return tuple whose first element is the resulting factor and second
        element is the accumulated product.
        """
        if not isinstance(f, Factor):
            raise TypeError("f argument needs to be a factor")

        if not isinstance(other, Factor):
            raise TypeError("other needs to be a factor")
        #
        svar = f.scope_vars()
        ovar = other.scope_vars()
        var_inter = svar.intersection(ovar)
        var_inter = list(var_inter)
        vsets = [v.value_set() for v in var_inter]
        inter_products = list(product(*vsets))
        smatch = f.factor_domain()
        omatch = other.factor_domain()
        prod = 1.0
        common_match = set()
        for iproduct in inter_products:
            for o in omatch:
                for s in smatch:
                    ss = set(s)
                    ost = set(o)
                    prod_s = set(iproduct)
                    if prod_s.issubset(ss) and prod_s.issubset(ost):
                        common = ss.union(ost)
                        multi = product_fn(f.factor_fn(ss),
                                           other.factor_fn(ost))
                        common_match.add((multi, tuple(common)))
                        prod = accumulator(multi, prod)

        def fx(scope_product: Set[Tuple[str, NumericValue]]):
            """"""
            for multip, match in common_match:
                if set(match) == set(scope_product):
                    return multip

        f = Factor(gid=str(uuid4()), scope_vars=svar.union(ovar), factor_fn=fx)
        return f, prod