'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'

def __init__(self, x, p=None, max_denom=1024):

    super(geo_mean, self).__init__(x)
    x = self.args[0]
    if (x.size[0] == 1):
        n = x.size[1]
    elif (x.size[1] == 1):
        n = x.size[0]
    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)
    self.cone_lb = lower_bound(self.w_dyad)
    self.cone_num_over = over_bound(self.w_dyad, self.tree)
    self.cone_num = (self.cone_lb + self.cone_num_over)
