def vstack(seq): """ | Stacks objects vertically. :param seq: tuple or list of numbers, :ref:`scalar objects<scalar_ref>` or :ref:`multidimensional objects<multi_ref>`. :return: :ref:`array<array_obj>` or :ref:`matrix<matrix_obj>`. """ # Check input if (type(seq) is not tuple and type(seq) is not list): raise TypeError('Invalid argument') # Process input new_list = [] numeric = True for x in seq: if np.isscalar(x): new_list += [matrix(x)] elif type(x) is cvxpy_obj: new_list += [matrix(x.value)] elif type(x).__name__ in SCALAR_OBJS: numeric = False new_x = cvxpy_array(1, 1) new_x[0, 0] = x new_list += [new_x] elif type(x).__name__ in ARRAY_OBJS: numeric = False new_list += [x] elif type(x) is cvxpy_matrix: new_list += [x] else: raise TypeError('Invalid Input') # Input is numeric if numeric: return np.vstack(new_list) # Verify dimensions n = new_list[0].shape[1] for x in new_list: if x.shape[1] != n: raise ValueError('Invalid Dimensions') # Allocate new array m = int(np.sum([x.shape[0] for x in new_list])) new_ar = cvxpy_array(m, n) # Fill new array k = 0 for x in new_list: for i in range(0, x.shape[0], 1): for j in range(0, x.shape[1], 1): new_ar[i + k, j] = x[i, j] k = k + x.shape[0] # Return new array return new_ar
def diag(v): """ | Extracts diagonal or constructs a diagonal array. :param v: number, :ref:`scalar object<scalar_ref>`, square or one dimensional :ref:`multidimensional object<multi_ref>`. :return: number, :ref:`scalar object<scalar_ref>` or :ref:`multidimensional object<multi_ref>`. """ # Check input if (np.isscalar(v) or type(v).__name__ in SCALAR_OBJS): return v elif (type(v) is cvxpy_matrix or type(v).__name__ in ARRAY_OBJS): if v.shape[1]==1: v = v.T else: raise TypeError('Invalid argument type') # Get shape (m,n) = v.shape # Input is 2D if m!=1 and n!=1: # Must be square if m!=n: raise ValueError('Invalid dimensions') # cvxpy matrix if type(v) is cvxpy_matrix: return matrix(np.diag(v)).T # Object array else: new_ar = cvxpy_array(m,1) for i in range(0,m,1): new_ar[i,0] = v[i,i] return new_ar # Input is 1D else: # cvxpy matrix if type(v) is cvxpy_matrix: return matrix(np.diagflat(v)) # Object array else: new_ar = cvxpy_array(n,n) for i in range(0,n,1): new_ar[i,i] = v[0,i] return new_ar
def diag(v): """ | Extracts diagonal or constructs a diagonal array. :param v: number, :ref:`scalar object<scalar_ref>`, square or one dimensional :ref:`multidimensional object<multi_ref>`. :return: number, :ref:`scalar object<scalar_ref>` or :ref:`multidimensional object<multi_ref>`. """ # Check input if (np.isscalar(v) or type(v).__name__ in SCALAR_OBJS): return v elif (type(v) is cvxpy_matrix or type(v).__name__ in ARRAY_OBJS): if v.shape[1] == 1: v = v.T else: raise TypeError('Invalid argument type') # Get shape (m, n) = v.shape # Input is 2D if m != 1 and n != 1: # Must be square if m != n: raise ValueError('Invalid dimensions') # cvxpy matrix if type(v) is cvxpy_matrix: return matrix(np.diag(v)).T # Object array else: new_ar = cvxpy_array(m, 1) for i in range(0, m, 1): new_ar[i, 0] = v[i, i] return new_ar # Input is 1D else: # cvxpy matrix if type(v) is cvxpy_matrix: return matrix(np.diagflat(v)) # Object array else: new_ar = cvxpy_array(n, n) for i in range(0, n, 1): new_ar[i, i] = v[0, i] return new_ar
def compare(obj1, constraint_type, obj2): """ Compares obj1 with obj2. :param obj1: Left hand side obejct. :param constraint_type: Keyword (See cvxpy.defs.). :param obj2: Right hand side object. """ # Both scalars if ((np.isscalar(obj1) or type(obj1).__name__ in SCALAR_OBJS) and (np.isscalar(obj2) or type(obj2).__name__ in SCALAR_OBJS)): # Upgrade scalars to cvxpy_obj if np.isscalar(obj1): obj1 = cvxpy_obj(CONSTANT, obj1, str(obj1)) if np.isscalar(obj2): obj2 = cvxpy_obj(CONSTANT, obj2, str(obj2)) # Construct and return constraint return cvxpy_constr(obj1, constraint_type, obj2) # Upgrate scalars to arrays if ((type(obj1) is cvxpy_matrix or type(obj1).__name__ in ARRAY_OBJS) and (np.isscalar(obj2) or type(obj2).__name__ in SCALAR_OBJS)): (m, n) = obj1.shape new_ar = cvxpy_array(m, n) for i in range(0, m, 1): for j in range(0, n, 1): new_ar[i, j] = obj2 obj2 = new_ar if ((type(obj2) is cvxpy_matrix or type(obj2).__name__ in ARRAY_OBJS) and (np.isscalar(obj1) or type(obj1).__name__ in SCALAR_OBJS)): (m, n) = obj2.shape new_ar = cvxpy_array(m, n) for i in range(0, m, 1): for j in range(0, n, 1): new_ar[i, j] = obj1 obj1 = new_ar # Both arrays if ((type(obj1) is cvxpy_matrix or type(obj1).__name__ in ARRAY_OBJS) and (type(obj2) is cvxpy_matrix or type(obj2).__name__ in ARRAY_OBJS)): constr = [] if obj1.shape != obj2.shape: raise ValueError('Invalid dimensions') (m, n) = obj1.shape for i in range(0, m, 1): for j in range(0, n, 1): constr += [compare(obj1[i, j], constraint_type, obj2[i, j])] return cvxpy_list(constr) # Invalid arguments raise TypeError('Objects not comparable')
def compare(obj1,constraint_type,obj2): """ Compares obj1 with obj2. :param obj1: Left hand side obejct. :param constraint_type: Keyword (See cvxpy.defs.). :param obj2: Right hand side object. """ # Both scalars if ((np.isscalar(obj1) or type(obj1).__name__ in SCALAR_OBJS) and (np.isscalar(obj2) or type(obj2).__name__ in SCALAR_OBJS)): # Upgrade scalars to cvxpy_obj if np.isscalar(obj1): obj1 = cvxpy_obj(CONSTANT,obj1,str(obj1)) if np.isscalar(obj2): obj2 = cvxpy_obj(CONSTANT,obj2,str(obj2)) # Construct and return constraint return cvxpy_constr(obj1,constraint_type,obj2) # Upgrate scalars to arrays if ((type(obj1) is cvxpy_matrix or type(obj1).__name__ in ARRAY_OBJS) and (np.isscalar(obj2) or type(obj2).__name__ in SCALAR_OBJS)): (m,n) = obj1.shape new_ar = cvxpy_array(m,n) for i in range(0,m,1): for j in range(0,n,1): new_ar[i,j] = obj2 obj2 = new_ar if ((type(obj2) is cvxpy_matrix or type(obj2).__name__ in ARRAY_OBJS) and (np.isscalar(obj1) or type(obj1).__name__ in SCALAR_OBJS)): (m,n) = obj2.shape new_ar = cvxpy_array(m,n) for i in range(0,m,1): for j in range(0,n,1): new_ar[i,j] = obj1 obj1 = new_ar # Both arrays if ((type(obj1) is cvxpy_matrix or type(obj1).__name__ in ARRAY_OBJS) and (type(obj2) is cvxpy_matrix or type(obj2).__name__ in ARRAY_OBJS)): constr = [] if obj1.shape != obj2.shape: raise ValueError('Invalid dimensions') (m,n) = obj1.shape for i in range(0,m,1): for j in range(0,n,1): constr += [compare(obj1[i,j],constraint_type,obj2[i,j])] return cvxpy_list(constr) # Invalid arguments raise TypeError('Objects not comparable')
def sqrt(x): """ | :math:`\mbox{sqrt} : \mathbb{R}_+^{m \\times n} \\to \mathbb{R}^{m \\times n}, \ \mbox{sqrt}(X)_{ij} = \sqrt{X_{ij}}`. | Concave and increasing. :param x: number, :ref:`scalar object<scalar_ref>` or :ref:`multidimensional object<multi_ref>`. :return: number, :ref:`tree<tree_obj>`, :ref:`matrix<matrix_obj>` or :ref:`array<array_obj>`. """ # Prepare input if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS): arg = vstack([x]) elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS): arg = x else: raise TypeError('Invalid argument') # Prepare output if type(arg) is cvxpy_matrix: output = zeros(arg.shape) else: output = cvxpy_array(arg.shape[0],arg.shape[1]) # Construct program for i in range(0,arg.shape[0],1): for j in range(0,arg.shape[1],1): t = variable() z = variable() v = variable() p = program(maximize(t), [belongs(vstack((hstack((1.,t)), hstack((t,v)))), semidefinite_cone), greater_equals(z,v)], [z], name='sqrt') output[i,j] = p(arg[i,j]) # Return output if output.shape == (1,1): return output[0,0] else: return output
def log_norm_cdf(x): """ | :math:`\mbox{log\_norm\_cdf} : \mathbb{R}^{m \\times n} \\to \mathbb{R}^{m \\times n}, \ \mbox{log\_norm\_cdf}(X)_{ij} = \mbox{log} \\big( \int_{-\infty}^{X_{ij}} \\frac{1}{\sqrt{2\pi}} e^{-\\frac{1}{2}u^2} \mathrm{d}u \\big)`. | Concave and increasing. :param x: number, :ref:`scalar object<scalar_ref>` or :ref:`multidimensional object<multi_ref>`. :return: number, :ref:`tree<tree_obj>`, :ref:`matrix<matrix_obj>` or :ref:`array<array_obj>`. """ # Prepare input if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS): arg = vstack([x]) elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS): arg = x else: raise TypeError('Invalid argument') # Prepare output if type(arg) is cvxpy_matrix: output = zeros(arg.shape) else: output = cvxpy_array(arg.shape[0], arg.shape[1]) # Construct program for i in range(0, arg.shape[0], 1): for j in range(0, arg.shape[1], 1): t = variable() v = variable() z = variable() p = program(maximize(t), [ belongs(vstack((v, t)), log_norm_cdf_hypo), less_equals(v, z) ], [z], name='log_norm_cdf') output[i, j] = p(arg[i, j]) # Return output if output.shape == (1, 1): return output[0, 0] else: return output
def sqrt(x): """ | :math:`\mbox{sqrt} : \mathbb{R}_+^{m \\times n} \\to \mathbb{R}^{m \\times n}, \ \mbox{sqrt}(X)_{ij} = \sqrt{X_{ij}}`. | Concave and increasing. :param x: number, :ref:`scalar object<scalar_ref>` or :ref:`multidimensional object<multi_ref>`. :return: number, :ref:`tree<tree_obj>`, :ref:`matrix<matrix_obj>` or :ref:`array<array_obj>`. """ # Prepare input if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS): arg = vstack([x]) elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS): arg = x else: raise TypeError('Invalid argument') # Prepare output if type(arg) is cvxpy_matrix: output = zeros(arg.shape) else: output = cvxpy_array(arg.shape[0], arg.shape[1]) # Construct program for i in range(0, arg.shape[0], 1): for j in range(0, arg.shape[1], 1): t = variable() z = variable() v = variable() p = program(maximize(t), [ belongs(vstack((hstack((1., t)), hstack( (t, v)))), semidefinite_cone), greater_equals(z, v) ], [z], name='sqrt') output[i, j] = p(arg[i, j]) # Return output if output.shape == (1, 1): return output[0, 0] else: return output
def dub_step(x): #print 'input: ', x #print 'input.value: ', x.value # # Prepare input if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS): arg = vstack([x]) elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS): arg = x else: raise TypeError('Invalid argument') # Prepare output if type(arg) is cvxpy_matrix: output = zeros(arg.shape) else: output = cvxpy_array(arg.shape[0],arg.shape[1]) # helper parameter p = parameter(name = 'p') # Construct program for i in range(0,arg.shape[0],1): for j in range(0,arg.shape[1],1): t = variable() v = variable() p = program(minimize(t), [less_equals(v,t),less_equals(-t,v)], [v], name='abs') output[i,j] = p(arg[i,j]) """ print 'arg[0,0]: ', arg[0,0] print 'arg[0,0].value: ', arg[0,0].value if arg[0,0].value >= 0: p.value = 1 output[i,j] = p else: p.value = -1 output[i,j] = p """ # Return output if output.shape == (1,1): return output[0,0] else: return output
def abs(x): """ | :math:`\mbox{abs} : \mathbb{R}^{m \\times n} \\to \mathbb{R}^{m \\times n}, \ \mbox{abs}(X)_{ij} = |X_{ij}|`. | Convex. :param x: number, :ref:`scalar object<scalar_ref>` or :ref:`multidimensional object<multi_ref>`. :return: number, :ref:`tree<tree_obj>`, :ref:`matrix<matrix_obj>` or :ref:`array<array_obj>`. """ # Prepare input if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS): arg = vstack([x]) elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS): arg = x else: raise TypeError('Invalid argument') # Prepare output if type(arg) is cvxpy_matrix: output = zeros(arg.shape) else: output = cvxpy_array(arg.shape[0],arg.shape[1]) # Construct program for i in range(0,arg.shape[0],1): for j in range(0,arg.shape[1],1): t = variable() v = variable() p = program(minimize(t), [less_equals(v,t),less_equals(-t,v)], [v], name='abs') output[i,j] = p(arg[i,j]) # Return output if output.shape == (1,1): return output[0,0] else: return output
def dub_step(x): #print 'input: ', x #print 'input.value: ', x.value # # Prepare input if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS): arg = vstack([x]) elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS): arg = x else: raise TypeError('Invalid argument') # Prepare output if type(arg) is cvxpy_matrix: output = zeros(arg.shape) else: output = cvxpy_array(arg.shape[0], arg.shape[1]) # helper parameter p = parameter(name='p') # Construct program for i in range(0, arg.shape[0], 1): for j in range(0, arg.shape[1], 1): t = variable() v = variable() p = program( minimize(t), [less_equals(v, t), less_equals(-t, v)], [v], name='abs') output[i, j] = p(arg[i, j]) """ print 'arg[0,0]: ', arg[0,0] print 'arg[0,0].value: ', arg[0,0].value if arg[0,0].value >= 0: p.value = 1 output[i,j] = p else: p.value = -1 output[i,j] = p """ # Return output if output.shape == (1, 1): return output[0, 0] else: return output
def reshape(v, newshape): """ | Reshapes the array to dimensions newshape (see np.reshape) | in FORTRAN (column-major) order. :param v: :ref:`array<array_obj>` or :ref:`matrix<matrix_obj>`. :param newshape: tuple with two integers. :return: the reshaped variable or matrix, :ref:`array<array_obj>` or :ref:`matrix<matrix_obj>`. """ # Check input if (type(v) is cvxpy_matrix or type(v).__name__ in ARRAY_OBJS): pass else: raise TypeError('Invalid argument type') if not (hasattr(newshape, '__iter__') and len(newshape) == 2): raise TypeError('Invalid argument for newshape') # Get shape (m,n) = v.shape # Get new shape (mn,nn) = newshape if mn*nn != m*n: raise ValueError('Output dimension size does not match input dimension') # cvxpy matrix if type(v) is cvxpy_matrix: return matrix(np.reshape(v, newshape, order='F')) # Object array else: new_ar = cvxpy_array(mn,nn) for j in range(0,n,1): for i in range(0,m,1): k = j*m + i new_ar[k % mn,k / mn] = v[i,j] return new_ar
def reshape(v, newshape): """ | Reshapes the array to dimensions newshape (see np.reshape) | in FORTRAN (column-major) order. :param v: :ref:`array<array_obj>` or :ref:`matrix<matrix_obj>`. :param newshape: tuple with two integers. :return: the reshaped variable or matrix, :ref:`array<array_obj>` or :ref:`matrix<matrix_obj>`. """ # Check input if (type(v) is cvxpy_matrix or type(v).__name__ in ARRAY_OBJS): pass else: raise TypeError('Invalid argument type') if not (hasattr(newshape, '__iter__') and len(newshape) == 2): raise TypeError('Invalid argument for newshape') # Get shape (m, n) = v.shape # Get new shape (mn, nn) = newshape if mn * nn != m * n: raise ValueError( 'Output dimension size does not match input dimension') # cvxpy matrix if type(v) is cvxpy_matrix: return matrix(np.reshape(v, newshape, order='F')) # Object array else: new_ar = cvxpy_array(mn, nn) for j in range(0, n, 1): for i in range(0, m, 1): k = j * m + i new_ar[k % mn, k / mn] = v[i, j] return new_ar
def huber(x,M=1): """ | :math:`\mbox{huber} : \mathbb{R}^{m \\times n} \\times \mathbb{R}_{++} \\to \mathbb{R}^{m \\times n}, \ \mbox{huber}(X,M)_{ij} = \\left\{ \\begin{array}{ll} X_{ij}^2, & |X_{ij}| \leq M \\\\ M(2|X_{ij}| - M), & |X_{ij}| > M \\end{array} \\right.`. | Convex. :param x: number, :ref:`scalar object<scalar_ref>` or :ref:`multidimensional object<multi_ref>`. :param M: number. :return: number, :ref:`tree<tree_obj>`, :ref:`matrix<matrix_obj>` or :ref:`array<array_obj>`. """ # Prepare input if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS): arg = vstack([x]) elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS): arg = x else: raise TypeError('Invalid first argument') # M must be a positive constant if not np.isscalar(M): raise TypeError('Invalid second argument') if M <= 0: raise ValueError('Second argument must be positive') # Prepare output if type(arg) is cvxpy_matrix: output = zeros(arg.shape) else: output = cvxpy_array(arg.shape[0],arg.shape[1]) # Construct program for i in range(0,arg.shape[0],1): for j in range(0,arg.shape[1],1): v = variable() w = variable() z = variable() p = program(minimize(2*v+square(w)), [less_equals(abs(z),w+v), greater_equals(v,0), greater_equals(w,0), less_equals(w,1)], [z], name='huber') output[i,j] = (M**2.)*p((1./(M*1.))*arg[i,j]) # Return output if output.shape == (1,1): return output[0,0] else: return output
def __mulhandle__(self,other): """ Handles left and right multiply. Important: If other is a constant, the multiplication tree formed has the constant object as the first child. :param other: Other operand. """ # Create operator operator = cvxpy_obj(OPERATOR,np.NaN,MULTIPLICATION) # Number if np.isscalar(other): # Multiplication by 0 if other == 0.0: return 0.0 # Multiplication by 1 elif other == 1.0: return self # Distribution over addition elif (type(self) is cvxpy_tree and self.item.name == SUMMATION): new_children = [] for child in self.children: new_children += [other*child] return cvxpy_tree(self.item,new_children) # Associativity elif (type(self) is cvxpy_tree and self.item.name == MULTIPLICATION and self.children[0].type == CONSTANT): new_object = other*self.children[0] if new_object.value == 1.0: return self.children[1] else: return cvxpy_tree(self.item,[new_object, self.children[1]]) # Constant times constant elif type(self) is cvxpy_obj: new_const = cvxpy_obj(CONSTANT,self.value*other, str(self.value*other)) return new_const # Else else: constant = cvxpy_obj(CONSTANT,other,str(other)) return cvxpy_tree(operator,[constant,self]) # Matrix elif type(other) is cvxpy_matrix: (m,n) = other.shape new_ar = cvxpy_array(m,n) for i in range(0,m,1): for j in range(0,n,1): new_ar[i,j] = other[i,j]*self return new_ar # Sparse matrix elif type(other) is cvxpy_spmatrix: (m,n) = other.shape new_ar = cvxpy_sparray(m,n) for i in range(0,m,1): rowi_indeces = other.rows[i] rowi_values = other.data[i] for k in range(0,len(rowi_indeces)): new_ar[i,rowi_indeces[k]] = rowi_values[k]*self return new_ar # Scalar param elif type(other) is cvxpy_scalar_param: return cvxpy_tree(operator,[other,self]) # Tree elif type(other) is cvxpy_tree: if not len(self.variables): return cvxpy_tree(operator,[self,other]) elif not len(other.variables): return cvxpy_tree(operator,[other,self]) else: return NotImplemented # Not implemented else: return NotImplemented
def vstack(seq): """ | Stacks objects vertically. :param seq: tuple or list of numbers, :ref:`scalar objects<scalar_ref>` or :ref:`multidimensional objects<multi_ref>`. :return: :ref:`array<array_obj>` or :ref:`matrix<matrix_obj>`. """ # Check input if (type(seq) is not tuple and type(seq) is not list): raise TypeError('Invalid argument') # Process input new_list = [] numeric = True for x in seq: if np.isscalar(x): new_list += [matrix(x)] elif type(x) is cvxpy_obj: new_list += [matrix(x.value)] elif type(x).__name__ in SCALAR_OBJS: numeric = False new_x = cvxpy_array(1,1) new_x[0,0] = x new_list += [new_x] elif type(x).__name__ in ARRAY_OBJS: numeric = False new_list += [x] elif type(x) is cvxpy_matrix: new_list += [x] else: raise TypeError('Invalid Input') # Input is numeric if numeric: return np.vstack(new_list) # Verify dimensions n = new_list[0].shape[1] for x in new_list: if x.shape[1] != n: raise ValueError('Invalid Dimensions') # Allocate new array m = int(np.sum([x.shape[0] for x in new_list])) new_ar = cvxpy_array(m,n) # Fill new array k = 0 for x in new_list: for i in range(0,x.shape[0],1): for j in range(0,x.shape[1],1): new_ar[i+k,j] = x[i,j] k = k + x.shape[0] # Return new array return new_ar
def __raddsub__(self,other,op): """ Handles right add and right subtract. :param other: Left hand side. :param op: Keyword (See cvxpy.defs) """ # Create operator operator = cvxpy_obj(OPERATOR,np.NaN,SUMMATION) # Create args to combine if (type(self) is cvxpy_tree and self.item.name == SUMMATION): if op == SUMMATION: args = self.children else: args = [-x for x in self.children] else: if op == SUMMATION: args = [self] else: args = [-self] # Number if np.isscalar(other): if other == 0.0: if op == SUMMATION: return self else: return -self constant = cvxpy_obj(CONSTANT,other,str(other)) return cvxpy_tree(operator,[constant]+args) # Scalar variable or scalar param elif (type(other) is cvxpy_scalar_var or type(other) is cvxpy_scalar_param): return cvxpy_tree(operator,[other]+args) # Tree elif type(other) is cvxpy_tree: if other.item.name == SUMMATION: return cvxpy_tree(operator,other.children+args) else: return cvxpy_tree(operator,[other]+args) # Matrix elif type(other) is cvxpy_matrix: (m,n) = other.shape new_ar = cvxpy_array(m,n) for i in range(0,m,1): for j in range(0,n,1): if op == SUMMATION: new_ar[i,j] = other[i,j]+self else: new_ar[i,j] = other[i,j]-self return new_ar # Not implemented else: return NotImplemented
def power_abs(x, p): """ | :math:`\mbox{power\_abs} : \mathbb{R}^{m \\times n} \\times [1,\infty) \\to \mathbb{R}^{m \\times n}, \ \mbox{power\_abs}(X,p)_{ij} = |X_{ij}|^p`. | Convex. :param x: number, :ref:`scalar object<scalar_ref>` or :ref:`multidimensional object<multi_ref>`. :param p: number, greater than or equal to one. :return: number, :ref:`tree<tree_obj>`, :ref:`matrix<matrix_obj>` or :ref:`array<array_obj>`. """ # Prepare input if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS): arg = vstack([x]) elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS): arg = x else: raise TypeError('Invalid argument') # Check p if not (np.isscalar(p)): raise TypeError('Invalid argument') elif p < 1.: raise ValueError('Invalid argument value') # Prepare output if type(arg) is cvxpy_matrix: output = zeros(arg.shape) else: output = cvxpy_array(arg.shape[0], arg.shape[1]) # Construct program for i in range(0, arg.shape[0], 1): for j in range(0, arg.shape[1], 1): t = variable() v = variable() z = variable() if p > 1.: prog = program(minimize(t), [ belongs(vstack((v, t)), power_pos_epi(p)), less_equals(-z, v), less_equals(z, v) ], [z], name='power_abs') else: prog = program( minimize(t), [less_equals(z, t), less_equals(-z, t)], [z], name='power_abs') output[i, j] = prog(arg[i, j]) # Return output if output.shape == (1, 1): return output[0, 0] else: return output
def power_p(x,p): """ | :math:`\mbox{power\_p} : \mathbb{R}^{m \\times n} \\times [1,\infty) \\to \mathbb{R}^{m \\times n}, \ \mbox{power\_p}(X,p)_{ij} = \\left\{ \\begin{array}{ll} X_{ij}^p, & X_{ij} \geq 0 \\\\ +\infty, & X_{ij} < 0. \\end{array} \\right.` | Convex. :param x: number, :ref:`scalar object<scalar_ref>` or :ref:`multidimensional object<multi_ref>`. :param p: number, greater than or equal to one. :return: number, :ref:`tree<tree_obj>`, :ref:`matrix<matrix_obj>` or :ref:`array<array_obj>`. """ # Prepare input if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS): arg = vstack([x]) elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS): arg = x else: raise TypeError('Invalid argument') # Check p if not (np.isscalar(p)): raise TypeError('Invalid argument') elif p < 1.: raise ValueError('Invalid argument value') # Prepare output if type(arg) is cvxpy_matrix: output = zeros(arg.shape) else: output = cvxpy_array(arg.shape[0],arg.shape[1]) # Construct program for i in range(0,arg.shape[0],1): for j in range(0,arg.shape[1],1): t = variable() z = variable() if p > 1.: prog = program(minimize(t), [belongs(vstack((z,t)), power_pos_epi(p)), greater_equals(z,0)], [z], name='power_p') else: prog = program(minimize(t), [less_equals(z,t), greater_equals(z,0)], [z], name='power_p') if np.isscalar(arg[i,j]) and arg[i,j] < 0.: output[i,j] = np.inf else: output[i,j] = prog(arg[i,j]) # Return output if output.shape == (1,1): return output[0,0] else: return output
def expand(arg): # Constant if type(arg) is cvxpy_obj: return arg, [] # Scalar variable elif type(arg) is cvxpy_scalar_var: return arg, [] # Summation elif (type(arg) is cvxpy_tree and arg.item.type == OPERATOR and arg.item.name == SUMMATION): # Get item and children item = arg.item children = arg.children # New variale v = variable() # Expand children new_children = [] new_constr = [] for child in children: # Multiplication if (child.type == TREE and child.item.type == OPERATOR and child.item.name == MULTIPLICATION): child_var, child_constr = expand(child.children[1]) new_children += [child.children[0].value * child_var] new_constr += child_constr # Else else: child_var, child_constr = expand(child) new_children += [child_var] new_constr += child_constr # Return (Always right side is the new variable) new_tree = cvxpy_tree(item, new_children) return v, [equals(new_tree, v)] + new_constr # Multiplication elif (type(arg) is cvxpy_tree and arg.item.type == OPERATOR and arg.item.name == MULTIPLICATION): # Get item and children item = arg.item children = arg.children # New variable v = variable() # Apply expand to second operand (first is a constant) child_var, child_constr = expand(children[1]) # Return result (Always right side is the new variable) new_tree = cvxpy_tree(item, [children[0], child_var]) new_eq = [equals(new_tree, v)] new_eq += child_constr return v, new_eq # Function elif (type(arg) is cvxpy_tree and arg.item.type == FUNCTION): # Get item and children item = arg.item children = arg.children # New varibale v = variable() # Analyze children new_children = [] new_constr = [] for child in children: child_var, child_constr = expand(child) new_children += [child_var] new_constr += child_constr # Return (Always right side is the new variable) new_tree = cvxpy_tree(item, new_children) if arg.is_convex(): new_constr += [less_equals(new_tree, v)] else: new_constr += [greater_equals(new_tree, v)] return v, new_constr # Constraint elif type(arg) is cvxpy_constr: # Not set membership if arg.type != BELONGS: # Apply expand to left and right side obj1, constr_list1 = expand(arg.left) obj2, constr_list2 = expand(arg.right) # Return new constraints new_constr = cvxpy_constr(obj1, arg.type, obj2) new_list = [new_constr] new_list += constr_list1 new_list += constr_list2 return new_list # Set membership else: obj, constr_list = expand(arg.left) new_constr = cvxpy_constr(obj, arg.type, arg.right) return [new_constr] + constr_list # Array elif (type(arg) is cvxpy_array or type(arg) is cvxpy_var): (m, n) = arg.shape new_list = [] new_ar = cvxpy_array(m, n) for i in range(0, m, 1): for j in range(0, n, 1): # Number: Upgrade if np.isscalar(arg[i, j]): new_ar[i, j] = cvxpy_obj(CONSTANT, arg[i, j], str(arg[i, j])) # Not a number else: obj, constr_list = expand(arg[i, j]) new_ar[i, j] = obj new_list += constr_list return new_ar, new_list # List of constraints elif (type(arg) is list or type(arg) is cvxpy_list): return reduce(lambda x, y: x + y, list(map(expand, arg)), []) # Invalid else: raise TypeError('Invalid argument')