def solver(graph=None, update=False, full=False, data=None, SO=False): """Find the UE link flow Parameters ---------- graph: graph object update: if update==True: update link flows and link,path delays in graph full: if full=True, also return x (link flows per OD pair) data: (Aeq, beq, ffdelays, parameters, type) from get_data(graph) """ if data is None: data = get_data(graph) Aeq, beq, ffdelays, pm, type = data n = len(ffdelays) p = Aeq.size[1]/n A, b = spmatrix(-1.0, range(p*n), range(p*n)), matrix(0.0, (p*n,1)) if type == 'Polynomial': if not SO: pm = pm * spdiag([1.0/(j+2) for j in range(pm.size[1])]) def F(x=None, z=None): return objective_poly(x, z, matrix([[ffdelays], [pm]]), p) if type == 'Hyperbolic': if SO: def F(x=None, z=None): return objective_hyper_SO(x, z, matrix([[ffdelays-div(pm[:,0],pm[:,1])], [pm]]), p) else: def F(x=None, z=None): return objective_hyper(x, z, matrix([[ffdelays-div(pm[:,0],pm[:,1])], [pm]]), p) dims = {'l': p*n, 'q': [], 's': []} x = solvers.cp(F, G=A, h=b, A=Aeq, b=beq, kktsolver=get_kktsolver(A, dims, Aeq, F))['x'] linkflows = matrix(0.0, (n,1)) for k in range(p): linkflows += x[k*n:(k+1)*n] if update: logging.info('Update link flows, delays in Graph.'); graph.update_linkflows_linkdelays(linkflows) logging.info('Update path delays in Graph.'); graph.update_pathdelays() if full: return linkflows, x return linkflows
def feasible_pathflows(graph, l_obs, obs=None, update=False, with_cell_paths=False, with_ODs=False, x_true=None, wp_trajs=None): """Attempts to find feasible pathflows given partial of full linkflows Parameters: ---------- graph: Graph object l_obs: observations of link flows obs: indices of the observed links update: if True, update path flows in graph with_cell_paths: if True, include cell paths as constraints with_ODs: if True, include ODs in the constraints if no with_cell_paths or in the objective if with_cell_paths """ assert with_cell_paths or with_ODs # we must have some measurements! n = graph.numpaths # route to links flow constraints A, b = linkpath_incidence(graph), l_obs if obs: A = A[obs,:] # trim matrix if we have partial observations Aineq, bineq = spmatrix(-1.0, range(n), range(n)), matrix(0.0, (n,1)) # positive constraints if not with_cell_paths: # if just with ODs flow measurements: Aeq, beq = path_to_OD_simplex(graph) # route to OD flow constraints else: # if we have cellpath flow measurements: assert wp_trajs is not None Aeq, beq = WP.simplex(graph, wp_trajs) # route to cellpath flow constraints if with_ODs: # if we have ODs + cellpaths measurements T, d = path_to_OD_simplex(graph) # route to OD flow constraints included in objective A, b = matrix([A, T]), matrix([b, d]) # add the constraints to the objective if x_true is not None: err1 = np.linalg.norm(A * x_true - b, 1) / np.linalg.norm(b, 1) err2 = np.linalg.norm(Aeq * x_true - beq) / np.linalg.norm(beq, 1) assert err1 < TOL, 'Ax!=b' assert err2 < TOL, 'Aeq x!=beq' # construct objective for cvxopt.solvers.qp Q, c = A.trans()*A, -A.trans()*b #x = solvers.qp(Q + REG_EPS*spmatrix(1.0, range(n), range(n)), c, Aineq, bineq, Aeq, beq)['x'] # try with cvxopt.solvers.cp def qp_objective(x=None, z=None): if x is None: return 0, matrix(1.0, (n, 1)) f = 0.5 * x.trans()*Q*x + c.trans() * x Df = (Q*x + c).trans() if z is None: return f, Df return f, Df, z[0]*Q dims = {'l': n, 'q': [], 's': []} x = solvers.cp(qp_objective, G=Aineq, h=bineq, A=Aeq, b=beq, kktsolver=get_kktsolver(Aineq, dims, Aeq, qp_objective))['x'] if update: logging.info('Update link flows, delays in Graph.'); graph.update_linkflows_linkdelays(P*x) logging.info('Update path delays in Graph.'); graph.update_pathdelays() logging.info('Update path flows in Graph object.'); graph.update_pathflows(x) #import ipdb #rank = 5 #if with_ODs == False: # ipdb.set_trace() return x, rn.rank(matrix([A, Aeq])), n
def _solve(self, solver=s.ECOS, ignore_dcp=False, verbose=False): if not self.is_dcp(): if ignore_dcp: print ("Problem does not follow DCP rules. " "Solving a convex relaxation.") else: raise Exception("Problem does not follow DCP rules.") objective,constr_map,dims = self.canonicalize() var_offsets,x_length = self.variables(objective, constr_map[s.EQ] + constr_map[s.INEQ]) c,obj_offset = self.constraints_matrix([objective], var_offsets, x_length, self.dense_interface, self.dense_interface) A,b = self.constraints_matrix(constr_map[s.EQ], var_offsets, x_length, self.interface, self.dense_interface) G,h = self.constraints_matrix(constr_map[s.INEQ], var_offsets, x_length, self.interface, self.dense_interface) # ECHU: get the nonlinear constraints F = self.nonlinear_constraint_function(constr_map[s.NONLIN], var_offsets, x_length) # Save original cvxopt solver options. old_options = cvxopt.solvers.options # Silence cvxopt if verbose is False. cvxopt.solvers.options['show_progress'] = verbose # Always do one step of iterative refinement after solving KKT system. cvxopt.solvers.options['refinement'] = 1 # Target cvxopt clp if nonlinear constraints exist if constr_map[s.NONLIN]: # Get custom kktsolver. kktsolver = get_kktsolver(G, dims, A, F) results = cvxopt.solvers.cpl(c.T,F,G,h,A=A,b=b, dims=dims,kktsolver=kktsolver) status = s.SOLVER_STATUS[s.CVXOPT][results['status']] primal_val = results['primal objective'] # Target cvxopt solver if SDP or invalid for ECOS. elif solver == s.CVXOPT or len(dims['s']) > 0 or min(G.size) == 0: # Get custom kktsolver. kktsolver = get_kktsolver(G, dims, A) # Adjust tolerance to account for regularization. cvxopt.solvers.options['feastol'] = 2*1e-6 results = cvxopt.solvers.conelp(c.T,G,h,A=A,b=b, dims=dims,kktsolver=kktsolver) status = s.SOLVER_STATUS[s.CVXOPT][results['status']] primal_val = results['primal objective'] else: # If possible, target ECOS. # ECHU: ecos interface has changed and no longer relies on CVXOPT # as a result, we have to convert cvxopt data structures into # numpy arrays # # ideally, CVXPY would no longer user CVXOPT, except when calling # conelp # cnp, hnp, bnp = map(lambda x: np.fromiter(iter(x),dtype=np.double,count=len(x)), (c, h, b)) Gp,Gi,Gx = G.CCS m,n1 = G.size Ap,Ai,Ax = A.CCS p,n2 = A.size Gp, Gi, Ap, Ai = map(lambda x: np.fromiter(iter(x),dtype=np.int32,count=len(x)), (Gp,Gi,Ap,Ai)) Gx, Ax = map(lambda x: np.fromiter(iter(x),dtype=np.double,count=len(x)), (Gx, Ax)) Gsp = sp.csc_matrix((Gx,Gi,Gp),shape=(m,n1)) if p == 0: Asp = None bnp = None else: Asp = sp.csc_matrix((Ax,Ai,Ap),shape=(p,n2)) # ECHU: end conversion results = ecos.solve(cnp,Gsp,hnp,dims,Asp,bnp,verbose=verbose) status = s.SOLVER_STATUS[s.ECOS][results['info']['exitFlag']] primal_val = results['info']['pcost'] # Restore original cvxopt solver options. cvxopt.solvers.options = old_options if status == s.SOLVED: self.save_values(results['x'], sorted(var_offsets.keys())) self.save_values(results['y'], constr_map[s.EQ]) if constr_map[s.NONLIN]: self.save_values(results['zl'], constr_map[s.INEQ]) else: self.save_values(results['z'], constr_map[s.INEQ]) return self.objective.value(primal_val - obj_offset[0]) else: return status
def _cvxopt_solve(self, objective, constr_map, dims, sorted_vars, var_offsets, x_length, verbose): """Calls the CVXOPT conelp or cpl solver and returns the result. Parameters ---------- objective: Expression The canonicalized objective. constr_map: dict A dict of the canonicalized constraints. dims: dict A dict with information about the types of constraints. sorted_vars: list An ordered list of the problem variables. var_offsets: dict A dict mapping variable id to offset in the stacked variable x. x_length: int The height of x. verbose: bool Should the solver show output? Returns ------- tuple (status, optimal objective, optimal x, optimal equality constraint dual, optimal inequality constraint dual) """ c, obj_offset = self._constr_matrix([objective], var_offsets, x_length, self._CVXOPT_DENSE_INTF, self._CVXOPT_DENSE_INTF) # Convert obj_offset to a scalar. obj_offset = self._CVXOPT_DENSE_INTF.scalar_value(obj_offset) A, b = self._constr_matrix(constr_map[s.EQ], var_offsets, x_length, self._CVXOPT_SPARSE_INTF, self._CVXOPT_DENSE_INTF) G, h = self._constr_matrix(constr_map[s.INEQ], var_offsets, x_length, self._CVXOPT_SPARSE_INTF, self._CVXOPT_DENSE_INTF) # Save original cvxopt solver options. old_options = cvxopt.solvers.options # Silence cvxopt if verbose is False. cvxopt.solvers.options['show_progress'] = verbose # Always do one step of iterative refinement after solving KKT system. cvxopt.solvers.options['refinement'] = 1 # Target cvxopt clp if nonlinear constraints exist if constr_map[s.EXP]: # Get the nonlinear constraints. F = self._merge_nonlin(constr_map[s.EXP], var_offsets, x_length) # Get custom kktsolver. kktsolver = get_kktsolver(G, dims, A, F) results = cvxopt.solvers.cpl(c.T, F, G, h, A=A, b=b, dims=dims, kktsolver=kktsolver) else: # Get custom kktsolver. kktsolver = get_kktsolver(G, dims, A) results = cvxopt.solvers.conelp(c.T, G, h, A=A, b=b, dims=dims, kktsolver=kktsolver) status = s.SOLVER_STATUS[s.CVXOPT][results['status']] if status == s.OPTIMAL: primal_val = results['primal objective'] value = self.objective._primal_to_result( primal_val - obj_offset) # Restore original cvxopt solver options. cvxopt.solvers.options = old_options if constr_map[s.EXP]: ineq_dual = results['zl'] else: ineq_dual = results['z'] return (status, value, results['x'], results['y'], ineq_dual) else: return (status, None, None, None, None)
def _solve(self, solver=s.ECOS, ignore_dcp=False, verbose=False): """Solves a DCP compliant optimization problem. Saves the values of primal and dual variables in the variable and constraint objects, respectively. Args: solver: The solver to use. Defaults to ECOS. ignore_dcp: Overrides the default of raising an exception if the problem is not DCP. verbose: Overrides the default of hiding solver output. Returns: The optimal value for the problem, or a string indicating why the problem could not be solved. """ if not self.is_dcp(): if ignore_dcp: print ("Problem does not follow DCP rules. " "Solving a convex relaxation.") else: raise Exception("Problem does not follow DCP rules.") objective, constr_map, dims = self.canonicalize() all_ineq = itertools.chain(constr_map[s.EQ], constr_map[s.INEQ]) var_offsets, x_length = self._get_var_offsets(objective, all_ineq) c, obj_offset = self._constr_matrix([objective], var_offsets, x_length, self._DENSE_INTF, self._DENSE_INTF) A, b = self._constr_matrix(constr_map[s.EQ], var_offsets, x_length, self._SPARSE_INTF, self._DENSE_INTF) G, h = self._constr_matrix(constr_map[s.INEQ], var_offsets, x_length, self._SPARSE_INTF, self._DENSE_INTF) # Save original cvxopt solver options. old_options = cvxopt.solvers.options # Silence cvxopt if verbose is False. cvxopt.solvers.options['show_progress'] = verbose # Always do one step of iterative refinement after solving KKT system. cvxopt.solvers.options['refinement'] = 1 # Target cvxopt clp if nonlinear constraints exist if constr_map[s.NONLIN]: # Get the nonlinear constraints. F = self._merge_nonlin(constr_map[s.NONLIN], var_offsets, x_length) # Get custom kktsolver. kktsolver = get_kktsolver(G, dims, A, F) results = cvxopt.solvers.cpl(c.T, F, G, h, A=A, b=b, dims=dims,kktsolver=kktsolver) status = s.SOLVER_STATUS[s.CVXOPT][results['status']] primal_val = results['primal objective'] # Target cvxopt solver if SDP or invalid for ECOS. elif solver == s.CVXOPT or len(dims['s']) > 0 or min(G.size) == 0: # Get custom kktsolver. kktsolver = get_kktsolver(G, dims, A) # Adjust tolerance to account for regularization. cvxopt.solvers.options['feastol'] = 2*1e-6 results = cvxopt.solvers.conelp(c.T, G, h, A=A, b=b, dims=dims, kktsolver=kktsolver) status = s.SOLVER_STATUS[s.CVXOPT][results['status']] primal_val = results['primal objective'] else: # If possible, target ECOS. # ECHU: ecos interface has changed and no longer relies on CVXOPT # as a result, we have to convert cvxopt data structures into # numpy arrays # # ideally, CVXPY would no longer user CVXOPT, except when calling # conelp # cnp, hnp, bnp = (np.fromiter(iter(x), dtype=np.double, count=len(x)) for x in (c, h, b)) Gp, Gi, Gx = G.CCS m, n1 = G.size Ap, Ai, Ax = A.CCS p, n2 = A.size Gp, Gi, Ap, Ai = (np.fromiter(iter(x), dtype=np.int32, count=len(x)) for x in (Gp, Gi, Ap, Ai)) Gx, Ax = (np.fromiter(iter(x), dtype=np.double, count=len(x)) for x in (Gx, Ax)) Gsp = sp.csc_matrix((Gx, Gi, Gp), shape=(m, n1)) if p == 0: Asp = None bnp = None else: Asp = sp.csc_matrix((Ax, Ai, Ap), shape=(p, n2)) # ECHU: end conversion results = ecos.solve(cnp, Gsp, hnp, dims, Asp, bnp, verbose=verbose) status = s.SOLVER_STATUS[s.ECOS][results['info']['exitFlag']] primal_val = results['info']['pcost'] # Restore original cvxopt solver options. cvxopt.solvers.options = old_options if status == s.SOLVED: self._save_values(results['x'], var_offsets.keys()) self._save_values(results['y'], constr_map[s.EQ]) if constr_map[s.NONLIN]: self._save_values(results['zl'], constr_map[s.INEQ]) else: self._save_values(results['z'], constr_map[s.INEQ]) return self.objective._primal_to_result(primal_val - obj_offset[0]) else: return status
def _solve(self, solver=s.ECOS, ignore_dcp=False, verbose=False): """Solves a DCP compliant optimization problem. Saves the values of primal and dual variables in the variable and constraint objects, respectively. Parameters ---------- solver : str, optional The solver to use. Defaults to ECOS. ignore_dcp : bool, optional Overrides the default of raising an exception if the problem is not DCP. verbose : bool, optional Overrides the default of hiding solver output. Returns ------- float The optimal value for the problem, or a string indicating why the problem could not be solved. """ if not self.is_dcp(): if ignore_dcp: print ("Problem does not follow DCP rules. " "Solving a convex relaxation.") else: raise Exception("Problem does not follow DCP rules.") objective, constr_map, dims = self.canonicalize() all_ineq = itertools.chain(constr_map[s.EQ], constr_map[s.INEQ]) var_offsets, x_length = self._get_var_offsets(objective, all_ineq) c, obj_offset = self._constr_matrix([objective], var_offsets, x_length, self._DENSE_INTF, self._DENSE_INTF) # Convert obj_offset to a scalar. obj_offset = self._DENSE_INTF.scalar_value(obj_offset) A, b = self._constr_matrix(constr_map[s.EQ], var_offsets, x_length, self._SPARSE_INTF, self._DENSE_INTF) G, h = self._constr_matrix(constr_map[s.INEQ], var_offsets, x_length, self._SPARSE_INTF, self._DENSE_INTF) # Save original cvxopt solver options. old_options = cvxopt.solvers.options # Silence cvxopt if verbose is False. cvxopt.solvers.options['show_progress'] = verbose # Always do one step of iterative refinement after solving KKT system. cvxopt.solvers.options['refinement'] = 1 # Target cvxopt solver if SDP or invalid for ECOS. if solver == s.CVXOPT or len(dims['s']) > 0 \ or min(G.shape) == 0 or constr_map[s.NONLIN]: # Convert c,A,b,G,h to cvxopt matrices. c, b, h = map(lambda vec: self._CVXOPT_DENSE_INTF.const_to_matrix(vec, convert_scalars=True), [c, b, h]) A, G = map(lambda mat: self._CVXOPT_SPARSE_INTF.const_to_matrix(mat, convert_scalars=True), [A, G]) # Target cvxopt clp if nonlinear constraints exist if constr_map[s.NONLIN]: # Get the nonlinear constraints. F = self._merge_nonlin(constr_map[s.NONLIN], var_offsets, x_length) # Get custom kktsolver. kktsolver = get_kktsolver(G, dims, A, F) results = cvxopt.solvers.cpl(c.T, F, G, h, A=A, b=b, dims=dims,kktsolver=kktsolver) status = s.SOLVER_STATUS[s.CVXOPT][results['status']] primal_val = results['primal objective'] else: # Get custom kktsolver. kktsolver = get_kktsolver(G, dims, A) # Adjust tolerance to account for regularization. cvxopt.solvers.options['feastol'] = 2*1e-6 results = cvxopt.solvers.conelp(c.T, G, h, A=A, b=b, dims=dims, kktsolver=kktsolver) status = s.SOLVER_STATUS[s.CVXOPT][results['status']] primal_val = results['primal objective'] else: # If possible, target ECOS. # Convert c,h,b to 1D arrays. c, h, b = map(lambda mat: np.asarray(mat)[:, 0], [c.T, h, b]) results = ecos.solve(c, G, h, dims, A, b, verbose=verbose) status = s.SOLVER_STATUS[s.ECOS][results['info']['exitFlag']] primal_val = results['info']['pcost'] # Restore original cvxopt solver options. cvxopt.solvers.options = old_options if status == s.OPTIMAL: self._save_values(results['x'], var_offsets.keys()) self._save_values(results['y'], constr_map[s.EQ]) if constr_map[s.NONLIN]: self._save_values(results['zl'], constr_map[s.INEQ]) else: self._save_values(results['z'], constr_map[s.INEQ]) self._value = self.objective._primal_to_result( primal_val - obj_offset) else: self._handle_failure(status, var_offsets.keys(), itertools.chain(constr_map[s.EQ], constr_map[s.INEQ])) self._status = status return self.value
def feasible_pathflows(graph, l_obs, obs=None, update=False, with_cell_paths=False, with_ODs=False, x_true=None, wp_trajs=None): """Attempts to find feasible pathflows given partial of full linkflows Parameters: ---------- graph: Graph object l_obs: observations of link flows obs: indices of the observed links update: if True, update path flows in graph with_cell_paths: if True, include cell paths as constraints with_ODs: if True, include ODs in the constraints if no with_cell_paths or in the objective if with_cell_paths """ assert with_cell_paths or with_ODs # we must have some measurements! n = graph.numpaths # route to links flow constraints A, b = linkpath_incidence(graph), l_obs if obs: A = A[obs, :] # trim matrix if we have partial observations Aineq, bineq = spmatrix(-1.0, range(n), range(n)), matrix(0.0, (n, 1)) # positive constraints if not with_cell_paths: # if just with ODs flow measurements: Aeq, beq = path_to_OD_simplex(graph) # route to OD flow constraints else: # if we have cellpath flow measurements: assert wp_trajs is not None Aeq, beq = WP.simplex(graph, wp_trajs) # route to cellpath flow constraints if with_ODs: # if we have ODs + cellpaths measurements T, d = path_to_OD_simplex( graph) # route to OD flow constraints included in objective A, b = matrix([A, T]), matrix( [b, d]) # add the constraints to the objective if x_true is not None: err1 = np.linalg.norm(A * x_true - b, 1) / np.linalg.norm(b, 1) err2 = np.linalg.norm(Aeq * x_true - beq) / np.linalg.norm(beq, 1) assert err1 < TOL, 'Ax!=b' assert err2 < TOL, 'Aeq x!=beq' # construct objective for cvxopt.solvers.qp Q, c = A.trans() * A, -A.trans() * b #x = solvers.qp(Q + REG_EPS*spmatrix(1.0, range(n), range(n)), c, Aineq, bineq, Aeq, beq)['x'] # try with cvxopt.solvers.cp def qp_objective(x=None, z=None): if x is None: return 0, matrix(1.0, (n, 1)) f = 0.5 * x.trans() * Q * x + c.trans() * x Df = (Q * x + c).trans() if z is None: return f, Df return f, Df, z[0] * Q dims = {'l': n, 'q': [], 's': []} x = solvers.cp(qp_objective, G=Aineq, h=bineq, A=Aeq, b=beq, kktsolver=get_kktsolver(Aineq, dims, Aeq, qp_objective))['x'] if update: logging.info('Update link flows, delays in Graph.') graph.update_linkflows_linkdelays(P * x) logging.info('Update path delays in Graph.') graph.update_pathdelays() logging.info('Update path flows in Graph object.') graph.update_pathflows(x) #import ipdb #rank = 5 #if with_ODs == False: # ipdb.set_trace() return x, rn.rank(matrix([A, Aeq])), n