def scp(p,bad_constr,sol): """ Description: Sequential convex programming algorithm. Solve program p and try to enforce equality on the bad constraints. Argument p: cvxpy_program is assumed to be in expanded and equivalent format. Argument bad_constr: List of nonconvex constraints, also in expanded and equivalent format. Argument sol: Solution of relaxation. """ # Quit if program is linear if(len(bad_constr) == 0): if(not p.options['quiet']): print 'Tightening not needed' return True # Get parameters tight_tol = p.options['SCP_ALG']['tight tol'] starting_lambda = p.options['SCP_ALG']['starting lambda'] max_scp_iter = p.options['SCP_ALG']['max scp iter'] lambda_multiplier = p.options['SCP_ALG']['lambda multiplier'] max_lambda = p.options['SCP_ALG']['max lambda'] top_residual = p.options['SCP_ALG']['top residual'] # Construct slacks slacks = [abs(c.left-c.right) for c in bad_constr] # Print header if(not p.options['quiet']): print 'Iter\t:', print 'Max Slack\t:', print 'Objective\t:', print 'Solver Status\t:', print 'Pres\t\t:', print 'Dres\t\t:', print 'Lambda Max/Min' # SCP Loop lam = starting_lambda*np.ones(len(slacks)) for i in range(0,max_scp_iter,1): # Calculate max slack max_slack = max(map(lambda x:x.get_value(), slacks)) # Quit if status is primal infeasible if(sol['status'] == 'primal infeasible'): if(not p.options['quiet']): print 'Unable to tighten: Problem became infeasible' return False # Check if dual infeasible if(sol['status'] == 'dual infeasible'): sol['status'] = 'dual inf' sol['primal infeasibility'] = np.NaN sol['dual infeasibility'] = np.NaN # Print values if(not p.options['quiet']): print '%d\t:' %i, print '%.3e\t:' %max_slack, print '%.3e\t:' %p.obj.get_value(), print ' '+sol['status']+'\t:', if(sol['primal infeasibility'] is not np.NaN): print '%.3e\t:' %sol['primal infeasibility'], else: print '%.3e\t\t:' %sol['primal infeasibility'], if(sol['dual infeasibility'] is not np.NaN): print '%.3e\t:' %sol['dual infeasibility'], else: print '%.3e\t\t:' %sol['dual infeasibility'], print '(%.1e,%.1e)' %(np.max(lam),np.min(lam)) # Quit if max slack is small if(max_slack < tight_tol and sol['status'] == 'optimal'): if(not p.options['quiet']): print 'Tightening successful' return True # Quit if residual is too large if(sol['primal infeasibility'] >= top_residual or sol['dual infeasibility'] >= top_residual): if(not p.options['quiet']): print 'Unable to tighten: Residuals are too large' return False # Linearize slacks linear_slacks = [] for c in bad_constr: fn = c.left.item args = c.left.children right = c.right line = fn._linearize(args,right) linear_slacks += [line] # Add linearized slacks to objective sum_lin_slacks = 0.0 for j in range(0,len(slacks),1): sum_lin_slacks += lam[j]*linear_slacks[j] if(p.action == MINIMIZE): new_obj = p.obj + sum_lin_slacks else: new_obj = p.obj - sum_lin_slacks new_t0, obj_constr = expand(new_obj) new_p = prog((p.action,new_t0), obj_constr+p.constr,[],p.options) # Solve new problem sol = solve_convex(new_p,'scp') # Update lambdas for j in range(0,len(slacks),1): if(slacks[j].get_value() >= tight_tol): if(lam[j] < max_lambda): lam[j] = lam[j]*lambda_multiplier # Maxiters reached if(not p.options['quiet']): print 'Unable to tighten: Maximum iterations reached' if(sol['status'] == 'optimal'): return True else: return False
def solve_prog(p): """ Description ----------- Solve optimization program. Arguments --------- p: cvxpy_program """ # Reset variable counter var_reset() # Check parameters if (len(p.get_params()) != 0): if (not p.options['quiet']): print 'Error: Parameters present' return np.NaN, np.NaN # Original if (p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Original *' print '****************************' p.show() # Expanded p_expanded = p._get_expanded() if (p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Expanded *' print '****************************' p_expanded.show() # Equivalent p_equivalent = p_expanded._get_equivalent() if (p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Equivalent *' print '****************************' p_equivalent.show() # Nonconvex constraints bad_constr = p_equivalent.constr._get_nonconvex() if (p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Nonconvex Constraints *' print '****************************\n' print bad_constr # Convex Relaxation p_cvx_relaxation = p_equivalent._get_cvx_relaxation() if (p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Convex Relaxation *' print '****************************' p_cvx_relaxation.show() # Solve convex relaxation if (not p.options['quiet']): print '\nSolving convex relaxation ...' sol = solve_convex(p_cvx_relaxation, 'rel') lagrange_mul_eq = matrix(sol['y']) if (not p.options['quiet']): print 'Relaxation status: ', sol['status'] # Relaxation status: primal infeasible if (sol['status'] == 'primal infeasible'): if (not p.options['quiet']): print 'Original program is primal infeasible' if (p.action == MINIMIZE): return np.inf, lagrange_mul_eq else: return -np.inf, lagrange_mul_eq # Relaxation status: uknown elif (sol['status'] == 'unknown'): relaxation_obj = None # Relaxation status: dual infeasible elif (sol['status'] == 'dual infeasible'): if (p.action == MINIMIZE): relaxation_obj = -np.inf else: relaxation_obj = np.inf # Relaxacion status: optimal else: relaxation_obj = p_cvx_relaxation.obj.get_value() # Report max slack if (len(bad_constr) != 0 and not p.options['quiet']): print 'Max Slack: ', print max( map(lambda x: x.get_value(), [abs(c.left - c.right) for c in bad_constr])) # Tighten if (p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Tightening Stage *' print '****************************' elif (not p.options['quiet']): print '\nAttempting tightening ...' valid_scp = scp(p_cvx_relaxation, bad_constr, sol) if (not valid_scp): return np.NaN, np.NaN # Prepare results if (len(bad_constr) == 0): obj = relaxation_obj else: obj = p.obj.get_value() if (p.action == MINIMIZE): bound_str = 'Lower Bound' if (relaxation_obj != None): bound = np.min([relaxation_obj, obj]) gap = np.max([obj - relaxation_obj, 0.0]) else: bound_str = 'Upper Bound' if (relaxation_obj != None): bound = np.max([relaxation_obj, obj]) gap = np.max([relaxation_obj - obj, 0.0]) # Show results if (p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Results *' print '****************************' elif (not p.options['quiet']): print '\nResults' if (not p.options['quiet']): print 'Objective =\t%.5e' % obj if (relaxation_obj != None): print bound_str + ' =\t%.5e' % bound print 'Gap =\t\t%.5e' % gap else: print bound_str + ' =\tUnknown' print 'Gap =\t\tUnknown' if (len(bad_constr) != 0): ms = max( map(lambda x: x.get_value(), [abs(c.left - c.right) for c in bad_constr])) print 'Max Slack =\t%.5e' % ms # Return objective and dual var return obj, lagrange_mul_eq
def solve_prog(p): """ Description ----------- Solve optimization program. Arguments --------- p: cvxpy_program """ # Reset variable counter var_reset() # Check parameters if(len(p.get_params()) != 0): if(not p.options['quiet']): print 'Error: Parameters present' return np.NaN,np.NaN # Original if(p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Original *' print '****************************' p.show() # Expanded p_expanded = p._get_expanded() if(p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Expanded *' print '****************************' p_expanded.show() # Equivalent p_equivalent = p_expanded._get_equivalent() if(p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Equivalent *' print '****************************' p_equivalent.show() # Nonconvex constraints bad_constr = p_equivalent.constr._get_nonconvex() if(p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Nonconvex Constraints *' print '****************************\n' print bad_constr # Convex Relaxation p_cvx_relaxation = p_equivalent._get_cvx_relaxation() if(p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Convex Relaxation *' print '****************************' p_cvx_relaxation.show() # Solve convex relaxation if(not p.options['quiet']): print '\nSolving convex relaxation ...' sol = solve_convex(p_cvx_relaxation,'rel') lagrange_mul_eq = matrix(sol['y']) if(not p.options['quiet']): print 'Relaxation status: ',sol['status'] # Relaxation status: primal infeasible if(sol['status'] == 'primal infeasible'): if(not p.options['quiet']): print 'Original program is primal infeasible' if(p.action == MINIMIZE): return np.inf,lagrange_mul_eq else: return -np.inf,lagrange_mul_eq # Relaxation status: uknown elif(sol['status'] == 'unknown'): relaxation_obj = None # Relaxation status: dual infeasible elif(sol['status'] == 'dual infeasible'): if(p.action == MINIMIZE): relaxation_obj = -np.inf else: relaxation_obj = np.inf # Relaxacion status: optimal else: relaxation_obj = p_cvx_relaxation.obj.get_value() # Report max slack if(len(bad_constr) != 0 and not p.options['quiet']): print 'Max Slack: ', print max(map(lambda x:x.get_value(), [abs(c.left-c.right) for c in bad_constr])) # Tighten if(p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Tightening Stage *' print '****************************' elif(not p.options['quiet']): print '\nAttempting tightening ...' valid_scp = scp(p_cvx_relaxation,bad_constr,sol) if(not valid_scp): return np.NaN,np.NaN # Prepare results if(len(bad_constr) == 0): obj = relaxation_obj else: obj = p.obj.get_value() if(p.action == MINIMIZE): bound_str = 'Lower Bound' if(relaxation_obj != None): bound = np.min([relaxation_obj,obj]) gap = np.max([obj-relaxation_obj,0.0]) else: bound_str = 'Upper Bound' if(relaxation_obj != None): bound = np.max([relaxation_obj,obj]) gap = np.max([relaxation_obj-obj,0.0]) # Show results if(p.options['show steps'] and not p.options['quiet']): print '\n' print '****************************' print '* Results *' print '****************************' elif(not p.options['quiet']): print '\nResults' if(not p.options['quiet']): print 'Objective =\t%.5e' %obj if(relaxation_obj != None): print bound_str+' =\t%.5e' %bound print 'Gap =\t\t%.5e' %gap else: print bound_str+' =\tUnknown' print 'Gap =\t\tUnknown' if(len(bad_constr) != 0): ms = max(map(lambda x:x.get_value(), [abs(c.left-c.right) for c in bad_constr])) print 'Max Slack =\t%.5e' %ms # Return objective and dual var return obj,lagrange_mul_eq