Пример #1
0
    def __init__(self, x, p=None, max_denom=1024):
        """ Implementation details of geo_mean.

        Attributes
        ----------

        w_dyad : tuple of ``Fractions`` whose denominators are all a power of two
            The dyadic completion of ``w``, which is used internally to form the
            inequalities representing the geometric mean.

        tree : ``dict``
            keyed by dyadic tuples, whose values are Sequences of children.
            The children are also dyadic tuples.
            This represents the graph that needs to be formed to represent the
            weighted geometric mean.

        cone_lb : int
            A known lower bound (which is not always tight) on the number of cones
            needed to represent this geometric mean.

        cone_num_over : int
            The number of cones beyond the lower bound that this geometric mean used.
            If 0, we know that it used the minimum possible number of cones.
            Since cone_lb is not always tight, it may be using the minimum number of cones even if
            cone_num_over is not 0.

        cone_num : int
            The number of second order cones used to form this geometric mean

        """
        super(geo_mean, self).__init__(x)

        x = self.args[0]
        if x.is_vector():
            n = 1 if x.ndim == 0 else max(x.shape)
        else:
            raise ValueError('x must be a row or column vector.')

        if p is None:
            p = [1]*n

        if len(p) != n:
            raise ValueError('x and p must have the same number of elements.')

        if any(v < 0 for v in p) or sum(p) <= 0:
            raise ValueError('powers must be nonnegative and not all zero.')

        self.w, self.w_dyad = fracify(p, max_denom)
        self.approx_error = approx_error(p, self.w)

        self.tree = decompose(self.w_dyad)

        # known lower bound on number of cones needed to represent w_dyad
        self.cone_lb = lower_bound(self.w_dyad)

        # number of cones used past known lower bound
        self.cone_num_over = over_bound(self.w_dyad, self.tree)

        # number of cones used
        self.cone_num = self.cone_lb + self.cone_num_over
Пример #2
0
def gm_constrs(t_expr, x_exprs, p):
    assert power_tools.is_weight(p)
    w = power_tools.dyad_completion(p)
    tree = power_tools.decompose(w)

    # Sigh Python variable scoping..
    gm_vars = [0]
    def create_gm_var():
        var = epi_var(t_expr, "gm_var_%d" % gm_vars[0])
        gm_vars[0] += 1
        return var

    d = defaultdict(create_gm_var)
    d[w] = t_expr
    if len(x_exprs) < len(w):
        x_exprs += [t_expr]

    assert len(x_exprs) == len(w)
    for i, (p, v) in enumerate(zip(w, x_exprs)):
        if p > 0:
            tmp = [0]*len(w)
            tmp[i] = 1
            d[tuple(tmp)] = v

    constraints = []
    for elem, children in tree.items():
        if 1 not in elem:
            constraints += [gm(d[elem], d[children[0]], d[children[1]])]

    return constraints
Пример #3
0
def gm_constrs(t_expr, x_exprs, p):
    assert power_tools.is_weight(p)
    w = power_tools.dyad_completion(p)
    tree = power_tools.decompose(w)

    # Sigh Python variable scoping..
    gm_vars = [0]

    def create_gm_var():
        var = epi_var(t_expr, "gm_var_%d" % gm_vars[0])
        gm_vars[0] += 1
        return var

    d = defaultdict(create_gm_var)
    d[w] = t_expr
    if len(x_exprs) < len(w):
        x_exprs += [t_expr]

    assert len(x_exprs) == len(w)
    for i, (p, v) in enumerate(zip(w, x_exprs)):
        if p > 0:
            tmp = [0] * len(w)
            tmp[i] = 1
            d[tuple(tmp)] = v

    constraints = []
    for elem, children in list(tree.items()):
        if 1 not in elem:
            constraints += [gm(d[elem], d[children[0]], d[children[1]])]

    return constraints
Пример #4
0
def transform_geo_mean(expr):
    w = [Fraction(x.a, x.b) for x in expr.geo_mean_params.w]
    w_dyad = [Fraction(x.a, x.b) for x in expr.geo_mean_params.w_dyad]
    tree = power_tools.decompose(w_dyad)

    t = epi_var(expr, "geo_mean")
    x = only_arg(expr)
    x_list = [expression.index(x, i, i+1) for i in range(len(w))]
    return t, gm_constrs(t, x_list, w)
Пример #5
0
def transform_geo_mean(expr):
    w = [Fraction(x.a, x.b) for x in expr.geo_mean_params.w]
    w_dyad = [Fraction(x.a, x.b) for x in expr.geo_mean_params.w_dyad]
    tree = power_tools.decompose(w_dyad)

    t = epi_var(expr, "geo_mean")
    x = only_arg(expr)
    x_list = [expression.index(x, i, i + 1) for i in range(len(w))]
    return t, gm_constrs(t, x_list, w)