def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ A = arg_objs[0] n, _ = A.size # Requires that A is symmetric. obj, constraints = transpose.graph_implementation([A], (n, n)) # A == A.T constraints.append(lu.create_eq(A, obj)) # SDP constraint. t = lu.create_var((1, 1)) prom_t = lu.promote(t, (n, 1)) # I*t - A expr = lu.sub_expr(A, lu.diag_vec(prom_t)) return (t, [SDP(expr)] + constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ t = lu.create_var(size) constraints = [] for obj in arg_objs: # Promote obj. if obj.size != size: obj = lu.promote(obj, size) constraints.append(lu.create_leq(obj, t)) return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] t = lu.create_var((1, 1)) # sum(exp(x - t)) prom_t = lu.promote(t, x.size) expr = lu.sub_expr(x, prom_t) obj, constraints = exp.graph_implementation([expr], x.size) obj = lu.sum_entries(obj) # obj <= 1 one = lu.create_const(1, (1, 1)) constraints += [lu.create_leq(obj, one)] return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # Promote scalars. for idx, arg in enumerate(arg_objs): if arg.size != size: arg_objs[idx] = lu.promote(arg, size) x = arg_objs[0] y = arg_objs[1] v = lu.create_var(x.size) two = lu.create_const(2, (1, 1)) # SOC(x + y, [y - x, 2*v]) constraints = [ SOC_Elemwise(lu.sum_expr([x, y]), [lu.sub_expr(y, x), lu.mul_expr(two, v, v.size)]) ] # 0 <= x, 0 <= y constraints += [lu.create_geq(x), lu.create_geq(y)] return (v, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] t = lu.create_var((1, 1)) # sum(exp(x - t)) prom_t = lu.promote(t, x.size) expr = lu.sub_expr(x, prom_t) obj, constraints = exp.graph_implementation([expr], x.size) obj, constr = sum_entries.graph_implementation([obj], (1, 1)) # obj <= 1 one = lu.create_const(1, (1, 1)) constraints += constr + [lu.create_leq(obj, one)] return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # min sum_entries(t) + kq # s.t. x <= t + q # 0 <= t x = arg_objs[0] k = lu.create_const(data[0], (1, 1)) q = lu.create_var((1, 1)) t = lu.create_var(x.size) sum_t = lu.sum_entries(t) obj = lu.sum_expr([sum_t, lu.mul_expr(k, q, (1, 1))]) prom_q = lu.promote(q, x.size) constr = [lu.create_leq(x, lu.sum_expr([t, prom_q])), lu.create_geq(t)] return (obj, constr)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ axis = data[0] if axis is None: t = lu.create_var((1, 1)) promoted_t = lu.promote(t, arg_objs[0].size) elif axis == 0: t = lu.create_var((1, arg_objs[0].size[1])) const_size = (arg_objs[0].size[0], 1) ones = lu.create_const(np.ones(const_size), const_size) promoted_t = lu.mul_expr(ones, t, arg_objs[0].size) else: # axis == 1 t = lu.create_var((arg_objs[0].size[0], 1)) const_size = (1, arg_objs[0].size[1]) ones = lu.create_const(np.ones(const_size), const_size) promoted_t = lu.rmul_expr(t, ones, arg_objs[0].size) constraints = [lu.create_leq(arg_objs[0], promoted_t)] return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ A = arg_objs[0] n, _ = A.size # SDP constraint. t = lu.create_var((1, 1)) prom_t = lu.promote(t, (n, 1)) # A - I*t expr = lu.sub_expr(A, lu.diag_vec(prom_t)) return (t, [SDP(expr)])
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # min sum_entries(t) + kq # s.t. x <= t + q # 0 <= t x = arg_objs[0] k = lu.create_const(data[0], (1, 1)) q = lu.create_var((1, 1)) t = lu.create_var(x.size) sum_t, constr = sum_entries.graph_implementation([t], (1, 1)) obj = lu.sum_expr([sum_t, lu.mul_expr(k, q, (1, 1))]) prom_q = lu.promote(q, x.size) constr.append( lu.create_leq(x, lu.sum_expr([t, prom_q])) ) constr.append( lu.create_geq(t) ) return (obj, constr)
def graph_implementation(arg_objs, shape, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. shape : tuple The shape of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ axis = data[0] if axis is None: t = lu.create_var((1, 1)) promoted_t = lu.promote(t, arg_objs[0].shape) elif axis == 0: t = lu.create_var((1, arg_objs[0].shape[1])) const_shape = (arg_objs[0].shape[0], 1) ones = lu.create_const(np.ones(const_shape), const_shape) promoted_t = lu.mul_expr(ones, t, arg_objs[0].shape) else: # axis == 1 t = lu.create_var((arg_objs[0].shape[0], 1)) const_shape = (1, arg_objs[0].shape[1]) ones = lu.create_const(np.ones(const_shape), const_shape) promoted_t = lu.rmul_expr(t, ones, arg_objs[0].shape) constraints = [lu.create_leq(arg_objs[0], promoted_t)] return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ A = arg_objs[0] n, _ = A.size # Requires that A is symmetric. # A == A.T obj, constraints = transpose.graph_implementation([A], (n, n)) constraints.append(lu.create_eq(A, obj)) # SDP constraint. t = lu.create_var((1, 1)) prom_t = lu.promote(t, (n, 1)) # I*t - A expr = lu.sub_expr(lu.diag_vec(prom_t), A) return (t, [SDP(expr)] + constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ A = arg_objs[0] n, _ = A.size # SDP constraint. t = lu.create_var((1, 1)) prom_t = lu.promote(t, (n, 1)) # I*t - A expr = lu.sub_expr(lu.diag_vec(prom_t), A) return (t, [SDP(expr)])
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] axis = data[0] t = lu.create_var(size) # sum(exp(x - t)) <= 1 if axis is None: prom_t = lu.promote(t, x.size) expr = lu.sub_expr(x, prom_t) obj, constraints = exp.graph_implementation([expr], x.size) obj = lu.sum_entries(obj) elif axis == 0: prom_size = (x.size[0], 1) ones = lu.create_const(np.ones(prom_size), prom_size) prom_t = lu.mul_expr(ones, t, x.size) expr = lu.sub_expr(x, prom_t) obj, constraints = exp.graph_implementation([expr], x.size) const_size = (1, x.size[0]) ones = lu.create_const(np.ones(const_size), const_size) obj = lu.mul_expr(ones, obj, size) else: # axis == 1 prom_size = (1, x.size[1]) ones = lu.create_const(np.ones(prom_size), prom_size) prom_t = lu.rmul_expr(t, ones, x.size) expr = lu.sub_expr(x, prom_t) obj, constraints = exp.graph_implementation([expr], x.size) const_size = (x.size[1], 1) ones = lu.create_const(np.ones(const_size), const_size) obj = lu.rmul_expr(obj, ones, size) ones = lu.create_const(np.ones(size), size) constraints += [lu.create_leq(obj, ones)] return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ A = arg_objs[0] # n by m matrix. n, m = A.size # Create a matrix with Schur complement I*t - (1/t)*A.T*A. X = lu.create_var((n+m, n+m)) t = lu.create_var((1, 1)) # Expand A.T. obj, constraints = transpose.graph_implementation([A], (m, n)) # Fix X using the fact that A must be affine by the DCP rules. # X[0:n, 0:n] == I_n*t prom_t = lu.promote(t, (n, 1)) index.block_eq(X, lu.diag_vec(prom_t), constraints, 0, n, 0, n) # X[0:n, n:n+m] == A index.block_eq(X, A, constraints, 0, n, n, n+m) # X[n:n+m, 0:n] == obj index.block_eq(X, obj, constraints, n, n+m, 0, n) # X[n:n+m, n:n+m] == I_m*t prom_t = lu.promote(t, (m, 1)) index.block_eq(X, lu.diag_vec(prom_t), constraints, n, n+m, n, n+m) # Add SDP constraint. return (t, constraints + [SDP(X)])
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ A = arg_objs[0] # n by m matrix. n, m = A.size # Create a matrix with Schur complement I*t - (1/t)*A.T*A. X = lu.create_var((n+m, n+m)) t = lu.create_var((1, 1)) constraints = [] # Fix X using the fact that A must be affine by the DCP rules. # X[0:n, 0:n] == I_n*t prom_t = lu.promote(t, (n, 1)) index.block_eq(X, lu.diag_vec(prom_t), constraints, 0, n, 0, n) # X[0:n, n:n+m] == A index.block_eq(X, A, constraints, 0, n, n, n+m) # X[n:n+m, n:n+m] == I_m*t prom_t = lu.promote(t, (m, 1)) # prom_t = lu.promote(lu.create_const(1, (1,1)), (m, 1)) index.block_eq(X, lu.diag_vec(prom_t), constraints, n, n+m, n, n+m) # Add SDP constraint. return (t, constraints + [SDP(X)])
def graph_implementation(arg_objs, shape, data=None): """Promote scalar to vector/matrix Parameters ---------- arg_objs : list LinExpr for each argument. shape : tuple The shape of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ return (lu.promote(arg_objs[0], shape), [])
def _promote(arg, shape): """Promotes the lin op if necessary. Parameters ---------- arg : LinOp LinOp to promote. shape : tuple The shape desired. Returns ------- tuple Promoted LinOp. """ if arg.shape != shape: return lu.promote(arg, shape) else: return arg
def _promote(arg, size): """Promotes the lin op if necessary. Parameters ---------- arg : LinOp LinOp to promote. size : tuple The size desired. Returns ------- tuple Promoted LinOp. """ if arg.size != size: return lu.promote(arg, size) else: return arg
def graph_implementation(arg_objs,size,data=None): x = arg_objs[0] beta,x0 = data[0],data[1] beta_val,x0_val = beta.value,x0.value if isinstance(beta,Parameter): beta = lu.create_param(beta,(1,1)) else: beta = lu.create_const(beta.value,(1,1)) if isinstance(x0,Parameter): x0 = lu.create_param(x0,(1,1)) else: x0 = lu.create_const(x0.value,(1,1)) xi,psi = lu.create_var(size),lu.create_var(size) one = lu.create_const(1,(1,1)) one_over_beta = lu.create_const(1/beta_val,(1,1)) k = np.exp(-beta_val*x0_val) k = lu.create_const(k,(1,1)) # 1/beta * (1 - exp(-beta*(xi+x0))) xi_plus_x0 = lu.sum_expr([xi,x0]) minus_beta_times_xi_plus_x0 = lu.neg_expr(lu.mul_expr(beta,xi_plus_x0,size)) exp_xi,constr_exp = exp.graph_implementation([minus_beta_times_xi_plus_x0],size) minus_exp_minus_etc = lu.neg_expr(exp_xi) left_branch = lu.mul_expr(one_over_beta, lu.sum_expr([one,minus_exp_minus_etc]),size) # psi*exp(-beta*r0) right_branch = lu.mul_expr(k,psi,size) obj = lu.sum_expr([left_branch,right_branch]) #x-x0 == xi + psi, xi >= 0, psi <= 0 zero = lu.create_const(0,size) constraints = constr_exp prom_x0 = lu.promote(x0, size) constraints.append(lu.create_eq(x,lu.sum_expr([prom_x0,xi,psi]))) constraints.append(lu.create_geq(xi,zero)) constraints.append(lu.create_leq(psi,zero)) return (obj, constraints)
def graph_implementation(arg_objs, size, data=None): """Sum the linear expressions. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ for i, arg in enumerate(arg_objs): if arg.size != size: arg_objs[i] = lu.promote(arg, size) return (lu.sum_expr(arg_objs), [])
def graph_implementation(arg_objs, size, data=None): """Multiply the linear expressions. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # Promote the right hand side to a diagonal matrix if necessary. if size[1] != 1 and arg_objs[1].size == (1, 1): arg = lu.promote(arg_objs[1], (size[1], 1)) arg_objs[1] = lu.diag_vec(arg) return (lu.mul_expr(arg_objs[0], arg_objs[1], size), [])
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] t = lu.create_var((1, 1)) promoted_t = lu.promote(t, x.size) constraints = [lu.create_leq(promoted_t, x)] return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] t = lu.create_var((1, 1)) promoted_t = lu.promote(t, x.size) constraints = [lu.create_leq(x, promoted_t)] return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Multiply the linear expressions. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # Promote the left hand side to a diagonal matrix if necessary. if size[0] != 1 and arg_objs[0].size == (1, 1): arg = lu.promote(arg_objs[0], (size[0], 1)) arg_objs[0] = lu.diag_vec(arg) return (lu.rmul_expr(arg_objs[0], arg_objs[1], size), [])
def graph_implementation(arg_objs, size, data=None): """Multiply the expressions elementwise. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # Promote arguments if necessary. for i, arg in enumerate(arg_objs): if arg.size != size: arg_objs[i] = lu.promote(arg, size) return (lu.mul_elemwise(arg_objs[0], arg_objs[1]), [])
def graph_implementation(self, arg_objs, shape: Tuple[int, ...], data=None) -> Tuple[lo.LinOp, List[Constraint]]: """Sum the linear expressions. Parameters ---------- arg_objs : list LinExpr for each argument. shape : tuple The shape of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ for i, arg in enumerate(arg_objs): if arg.shape != shape and lu.is_scalar(arg): arg_objs[i] = lu.promote(arg, shape) return (lu.sum_expr(arg_objs), [])
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ t = lu.create_var(size) for i, obj in enumerate(arg_objs): # Promote obj. if obj.size != size: arg_objs[i] = lu.promote(obj, size) return (t, [SOC_Elemwise(t, arg_objs)])
def graph_implementation(arg_objs, size, data=None): r"""Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) Notes ----- Implementation notes. For general ``p``, the p-norm is equivalent to the following convex inequalities: .. math:: x_i &\leq r_i\\ -x_i &\leq r_i\\ r_i &\leq s_i^{1/p} t^{1 - 1/p}\\ \sum_i s_i &\leq t, where :math:`p \geq 1`. These inequalities are also correct for :math:`p = +\infty` if we interpret :math:`1/\infty` as :math:`0`. Although the inequalities above are correct, for a few special cases, we can represent the p-norm more efficiently and with fewer variables and inequalities. - For :math:`p = 1`, we use the representation .. math:: x_i &\leq r_i\\ -x_i &\leq r_i\\ \sum_i r_i &\leq t - For :math:`p = \infty`, we use the representation .. math:: x_i &\leq t\\ -x_i &\leq t Note that we don't need the :math:`s` variables or the sum inequality. - For :math:`p = 2`, we use the natural second-order cone representation .. math:: \|x\|_2 \leq t Note that we could have used the set of inequalities given above if we wanted an alternate decomposition of a large second-order cone into into several smaller inequalities. """ p, w = data x = arg_objs[0] t = None # dummy value so linter won't complain about initialization if p != 1: t = lu.create_var((1, 1)) if p == 2: return t, [SOC(t, [x])] if p == np.inf: r = lu.promote(t, x.size) else: r = lu.create_var(x.size) constraints = [lu.create_geq(lu.sum_expr([x, r])), lu.create_leq(x, r)] if p == 1: return lu.sum_entries(r), constraints if p == np.inf: return t, constraints # otherwise do case of general p s = lu.create_var(x.size) # todo: no need to run gm_constr to form the tree each time. we only need to form the tree once constraints += gm_constrs(r, [s, lu.promote(t, x.size)], w) constraints += [lu.create_leq(lu.sum_entries(s), t)] return t, constraints
def graph_implementation(arg_objs, size, data=None): r"""Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) Notes ----- Implementation notes. - For general :math:`p \geq 1`, the inequality :math:`\|x\|_p \leq t` is equivalent to the following convex inequalities: .. math:: |x_i| &\leq r_i^{1/p} t^{1 - 1/p}\\ \sum_i r_i &= t. These inequalities happen to also be correct for :math:`p = +\infty`, if we interpret :math:`1/\infty` as :math:`0`. - For general :math:`0 < p < 1`, the inequality :math:`\|x\|_p \geq t` is equivalent to the following convex inequalities: .. math:: r_i &\leq x_i^{p} t^{1 - p}\\ \sum_i r_i &= t. - For general :math:`p < 0`, the inequality :math:`\|x\|_p \geq t` is equivalent to the following convex inequalities: .. math:: t &\leq x_i^{-p/(1-p)} r_i^{1/(1 - p)}\\ \sum_i r_i &= t. Although the inequalities above are correct, for a few special cases, we can represent the p-norm more efficiently and with fewer variables and inequalities. - For :math:`p = 1`, we use the representation .. math:: x_i &\leq r_i\\ -x_i &\leq r_i\\ \sum_i r_i &= t - For :math:`p = \infty`, we use the representation .. math:: x_i &\leq t\\ -x_i &\leq t Note that we don't need the :math:`r` variable or the sum inequality. - For :math:`p = 2`, we use the natural second-order cone representation .. math:: \|x\|_2 \leq t Note that we could have used the set of inequalities given above if we wanted an alternate decomposition of a large second-order cone into into several smaller inequalities. """ p = data[0] x = arg_objs[0] t = lu.create_var((1, 1)) constraints = [] # first, take care of the special cases of p = 2, inf, and 1 if p == 2: return t, [SOC(t, [x])] if p == np.inf: t_ = lu.promote(t, x.size) return t, [lu.create_leq(x, t_), lu.create_geq(lu.sum_expr([x, t_]))] # we need an absolute value constraint for the symmetric convex branches (p >= 1) # we alias |x| as x from this point forward to make the code pretty :) if p >= 1: absx = lu.create_var(x.size) constraints += [lu.create_leq(x, absx), lu.create_geq(lu.sum_expr([x, absx]))] x = absx if p == 1: return lu.sum_entries(x), constraints # now, we take care of the remaining convex and concave branches # to create the rational powers, we need a new variable, r, and # the constraint sum(r) == t r = lu.create_var(x.size) t_ = lu.promote(t, x.size) constraints += [lu.create_eq(lu.sum_entries(r), t)] # make p a fraction so that the input weight to gm_constrs # is a nice tuple of fractions. p = Fraction(p) if p < 0: constraints += gm_constrs(t_, [x, r], (-p / (1 - p), 1 / (1 - p))) if 0 < p < 1: constraints += gm_constrs(r, [x, t_], (p, 1 - p)) if p > 1: constraints += gm_constrs(x, [r, t_], (1 / p, 1 - 1 / p)) return t, constraints