def test_norm_inf(self): exp = self.x + self.y atom = cp.norm_inf(exp) # self.assertEqual(atom.name(), "norm_inf(x + y)") self.assertEqual(atom.shape, tuple()) self.assertEqual(atom.curvature, s.CONVEX) assert atom.is_convex() assert (-atom).is_concave() self.assertEqual(cp.norm_inf(atom).curvature, s.CONVEX) self.assertEqual(cp.norm_inf(-atom).curvature, s.CONVEX)
def compute_min_norm_solution(x, y, norm_type): """Compute the min-norm solution using a convex-program solver.""" w = cp.Variable((x.shape[0], 1)) if norm_type == 'linf': # compute minimal L_infinity solution constraints = [cp.multiply(y, (w.T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.norm_inf(w)), constraints) elif norm_type == 'l2': # compute minimal L_2 solution constraints = [cp.multiply(y, (w.T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.norm2(w)), constraints) elif norm_type == 'l1': # compute minimal L_1 solution constraints = [cp.multiply(y, (w.T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.norm1(w)), constraints) elif norm_type[0] == 'l': # compute minimal Lp solution p = float(norm_type[1:]) constraints = [cp.multiply(y, (w.T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.pnorm(w, p)), constraints) elif norm_type == 'dft1': w = cp.Variable((x.shape[0], 1), complex=True) # compute minimal Fourier L1 norm (||F(w)||_1) solution dft = np.matrix(scipy.linalg.dft(x.shape[0], scale='sqrtn')) constraints = [cp.multiply(y, (cp.real(w).T @ x)) >= 1] prob = cp.Problem(cp.Minimize(cp.norm1(dft @ w)), constraints) prob.solve() logging.info('Min %s-norm solution found (norm=%.4f)', norm_type, float(norm_f(w.value, norm_type))) return cp.real(w).value
def bound_fit(A, b, norm=2): r""" solve a norm constrained problem .. math:: \min_{x} \| \mathbf{A}\mathbf{x} - \mathbf{b}\|_p \text{such that} \mathbf{A} \mathbf{x} -\mathbf{b} \ge 0 """ with warnings.catch_warnings(): warnings.simplefilter('ignore', PendingDeprecationWarning) x = cp.Variable(A.shape[1]) residual = x.__rmatmul__(A) - b if norm == 1: obj = cp.norm1(residual) elif norm == 2: obj = cp.norm(residual) elif norm == np.inf: obj = cp.norm_inf(residual) constraint = [residual >= 0] #constraint = [x.__rmatmul__(A) - b >= 0] problem = cp.Problem(cp.Minimize(obj), constraint) problem.solve(feastol=1e-10, solver=cp.ECOS) #problem.solve(eps = 1e-10, solver = cp.SCS) #problem.solve(feastol = 1e-10, solver = cp.CVXOPT) # TODO: The solution doesn't obey the constraints for 1 and inf norm, but does for 2-norm. return x.value
def linear_fit(A, b, norm=2, bound=None): r""" solve the linear optimization problem subject to constraints """ assert norm in [1, 2, np.inf], "Invalid norm specified" assert bound in [None, 'lower', 'upper'], "invalid bound specified" if norm == 2 and bound == None: return scipy.linalg.lstsq(A, b)[0] else: x = cp.Variable(A.shape[1]) residual = x.__rmatmul__(A) - b if norm == 1: obj = cp.norm1(residual) elif norm == 2: obj = cp.norm(residual) elif norm == np.inf: obj = cp.norm_inf(residual) if bound == 'lower': constraint = [residual <= 0] elif bound == 'upper': constraint = [residual >= 0] else: constraint = [] # Now actually solve the problem problem = cp.Problem(cp.Minimize(obj), constraint) problem.solve(feastol=1e-10, reltol=1e-8, abstol=1e-8, solver=cp.ECOS) return x.value
def _to_cvxpy(self): import cvxpy as cvx if self.order == 2 or self.order == None: return cvx.norm(self.fn._to_cvxpy()) if self.order == 1: return cvx.norm1(self.fn._to_cvxpy()) if self.order == np.inf: return cvx.norm_inf(self.fn._to_cvxpy())
def inf_norm_fit(A, b): r""" Solve inf-norm linear optimization problem .. math:: \min_{x} \| \mathbf{A} \mathbf{x} - \mathbf{b}\|_\infty """ with warnings.catch_warnings(): warnings.simplefilter('ignore', PendingDeprecationWarning) x = cp.Variable(A.shape[1]) obj = cp.norm_inf(A @ x - b.flatten()) problem = cp.Problem(cp.Minimize(obj)) problem.solve(solver='ECOS') return x.value
def construct_constraints( self, x: np.ndarray, y: np.ndarray, beta: Optional[cp.Variable] = None ) -> Optional[List[Expression]]: # type: ignore """ Dantzig selector constraints Args: x (np.ndarray): MxN input data array y (np.ndarray): M output targets beta (cp.Variable): dimension N vector for optimization Returns: List of constraints """ return [cp.norm_inf(x.T @ (y - x @ beta)) <= self.lambd * self.sigma]
def Example_4(): print("\n=======================================================") print("Example 4 minimize the infinite-norm of Ax-b in CVXPY:") # Problem data. m = 10 n = 5 np.random.seed(1) A = np.random.randn(m, n) b = np.random.randn(m) # Construct the problem. x = cp.Variable(n) # Notice that in numpy you use * for elementwise multiplication # However, in cvxpy * is matrix muliplication when two sizes are matricies or vectors # To do elementwise multiplication use cvxpy.multiply # You can still use the numpy @ operator for matmul as well, just substitute * with @ in next line objective = cp.Minimize(cp.norm_inf(A * x - b)) prob = cp.Problem(objective) print("Optimal value", prob.solve()) print("Optimal var") print(x.value) # A numpy ndarray.
def apply_atom_with_unity_weight(self, variable, weight, var_dim=None): return cvx.sum(cvx.norm_inf(variable.var_mat_N_tilde, axis=0))
def optim_stela(self, mu, threshold=None): self.val, self.st_x, self.error = st.stela_lasso( self.pathDic, self.signals, mu * cp.norm_inf(self.signals @ self.pathDic).value, 500)
def main(datafile=default_data_file, namesfile=default_volunteers_file, min_staff=5, alpha=1.0, beta=0.7, gamma=0.28, verbose=1, solver_options=None): '''Notação: M = min_staff: número mínimo de voluntários por turno. i = número (código) da pessoa. vai de 1 a N (talvez 28?) j = número (código) do turno. vai de 1 a T (provavelmente 14) A_ij = available[i, j] == True quando pessoa i está disponível no turno j P_ij = preference[i, j] == True quando pessoa i tem preferência pelo turno j w_i = prev_week[i] == número de turnos (almoços OU jantas) alocados à pessoa i na semana anterior Variável a ser otimizada: Z[i, j] == True quando pessoa i é alocada para colaborar no turno j. Variável auxiliar: L_i = load[i] == sum_j Z[i, j] == (soma da linha i de Z) == número de turnos alocados pra pessoa i. OBJETIVO: minimizar o máximo dos load[i], conforme disponibilidade das pessoas, orientando-se também pelas preferências. * Por enquanto, não estamos usando `preference` e `prev_week`, já que poucos usaram esses recursos na planilha. ''' table_string = read_data(datafile) names_string = read_data(namesfile) available, preference, prev_week, managers = data_to_array( table_string, names_string) N, T = available.shape Z = cp.Variable((N, T), name="Z", boolean=True) if verbose >= 1: print( "# Programa de otimização linear com variáveis inteiras (MIP)\n\nDados de Entrada:" ) print("\n[Array: AVAILABLE]", 0 + available, sep="\n", end="\n\n") print("\n[Array: PREFERENCE]", 0 + preference, sep="\n", end="\n\n") # load[i] == 'número de turnos alocados para a pessoa i' == sum(Z[i,j] para cada j) load = cp.sum(Z, axis=1) # Variável para induzir a preferência de soluções sem muita gente contribuindo em um só turno do dia: same_day = cp.Variable((N, T // 2)) constraints = [ # Sempre que A_ij==0, impõe-se Z_ij==0: Z <= available, # Somatório em i (somatório de cada coluna) deve ser, no mínimo, min_staff: cp.sum(Z, axis=0) == min_staff, # Restrição para garantir a presença de no mínimo um dos `responsáveis` (managers) a cada turno: cp.sum(Z[managers, :], axis=0) >= 1, # Forma matricial das desigualdades same_day[:, j//2] <= min(Z[:, j], Z[:, j+1]), com j em (0, 2, 4, ..., T-2): same_day <= Z[:, 0::2], same_day <= Z[:, 1::2] ] # Expressão para a carga média por pessoa, usando a igualdade cp.sum(load) == cp.sum(Z): mean_load = cp.sum(Z) / N # Função Objetivo (função a ser MINIMIZADA): load_cost = cp.norm_inf(load) # máximo das entradas do vetor `load` # PENALTY_1 DESATIVADO (substituído por zero), vide restrição `Z <= available` acima. penalty_1 = cp.Constant( 0 ) # alpha * cp.sum(cp.pos(Z - available)) # penalizava-se alpha para cada entrada Z[i,j] > available[i,j]. penalty_2 = beta * cp.sum( cp.scalene(load - mean_load, 1.8, 1.0) ) # penalizar cada load[i] longe da média (especialmente acima da média) same_day_bonus = gamma * cp.sum(same_day) objective = cp.Minimize( load_cost + penalty_1 + penalty_2 - same_day_bonus ) # minimize ('máximo das entradas' do vetor load) + penalidades problem = cp.Problem( objective, constraints) # <= problema de otimização sujeito às restrições acima. if verbose >= 1: print("# Solucionando problema de otimização.") if solver_options is None: solver_options = {"verbose": (verbose >= 2)} elif "TimeLimit" in solver_options: # GAMBIARRA: "cvxpy throws error when Gurobi solver encounters time limit" cp.settings.ERROR = [cp.settings.USER_LIMIT] cp.settings.SOLUTION_PRESENT = [ cp.settings.OPTIMAL, cp.settings.OPTIMAL_INACCURATE, cp.settings.SOLVER_ERROR ] # CONFERIR: https://github.com/cvxgrp/cvxpy/issues/735 if verbose >= 2: print("\n", "# # # # # " * 9, "\n", sep="") problem.solve(solver=cp.GUROBI, **solver_options) if verbose >= 2: print("\n", "# # # # # " * 9, "\n", sep="") results_dict = { "alpha": alpha, "beta": beta, "gamma": gamma, "Z": Z, "Z_array": None, "objective": objective, "constraints": constraints, "problem": problem, "load": load, "load_cost": load_cost, "penalty_1": penalty_1, "penalty_2": penalty_2, "same_day_bonus": same_day_bonus } if results_dict["Z"] is not None: results_dict["Z_array"] = np.asarray(Z.value + 0.1, dtype=int) if problem.status != cp.OPTIMAL: print( "# WARNING. Talvez tenha atingido o tempo limite sem otimalidade?" ) print("Status do problema: {}".format(problem.status)) if verbose: show_results(results_dict) else: print("# ERRO: o solver não encontrou uma solução!") print("Status do problema: {}".format(problem.status)) print("# Para as disponibilidades dadas, talvez não seja") print("# possível obter `min_staff` pessoas por turno?") return results_dict
def get_perturbation(source_vector, target_vector, convert_matrix, obj): n = source_vector.size # Declare variable named 'perturb' to optimize. It is a 1d array/vector of size same as source_vector # perturb is basically delta1 in 1dimension # This method is where all the magic happens so read the details below to understand # 1. perturb(or delta1) is an array/vector that can assume a lot of possible elements while being of size n # Further multiple sets(arrays) of n size can satisfy perturb # 2. This method computes all the possible elements and sets that perturb can have or be while maintaining some rules # 3. Rule a: Each element of (perturb when added with source_vector) should remain between 0 and 255(allowed pixel) # Rule b: delta2 should be bounded by(less than) 0.01*255 # This kinda denotes that the difference between target image and output image should not exceed this value # delta2 = CL(perturb + source_vector) - target_vector; since attack_vector = CL*(perturb + source_vector) # Rule c: As we know that there could be multiple sets of perturb that could satisfy Rule a and b, therefore we # find the Lsquare norm(which is basically squareroot of(sum of squares of all elements of perturb). # In a way it gives the magnitude of an array/vector, our job is to find the set that has the min/max # Lsquare Norm off all the possible sets perturb = cp.Variable(n) # Create the function to be Maximised/Minimised (||delta1||2 --> L^2 norm of delta1) function = cp.norm(perturb) # Declare objective function based on value of obj if obj == 'max': objective = cp.Maximize(function) # Rule c else: objective = cp.Minimize(function) # Rule c constraints = [] # set up constraints # Rule a: constraints += [source_vector + perturb >= 0] constraints += [source_vector + perturb <= 255] # Rule b: # if the number of columns of convert_matrix coincide with the number of rows of source_vector(when its column vector) if convert_matrix[0].size == source_vector.size: constraints += [ cp.norm_inf((convert_matrix * (source_vector + perturb)) - target_vector) <= (0.01 * 255) ] else: # else Transpose convert_matrix to make them coincide (usually happens when source_vector is a row vector) constraints += [ cp.norm_inf((convert_matrix.T * (source_vector + perturb)) - target_vector) <= (0.01 * 255) ] # Create problem with objective and constraints prob = cp.Problem(objective, constraints) # Launch the solver prob.solve() # Testing: print(prob.status) print(perturb.value.shape) # Solution array/vector is stored in the value field of perturb return perturb.value
def cvx_inequality_time_graphical_lasso(S, K_init, max_iter, loss, C, theta, psi, gamma, tol): """Inequality constrained time-varying graphical LASSO solver. Solves the following problem via ADMM: min sum_{i=1}^T ||K_i||_{od,1} + beta sum_{i=2}^T Psi(K_i - K_{i-1}) s.t. objective =< c_i for i = 1, ..., T where S_i = (1/n_i) X_i^T X_i is the empirical covariance of data matrix X (training observations by features). Parameters ---------- emp_cov : ndarray, shape (n_features, n_features) Empirical covariance of data. alpha, beta : float, optional Regularisation parameter. rho : float, optional Augmented Lagrangian parameter. max_iter : int, optional Maximum number of iterations. n_samples : ndarray Number of samples available for each time point. gamma: float, optional Kernel parameter when psi is chosen to be 'kernel'. tol : float, optional Absolute tolerance for convergence. rtol : float, optional Relative tolerance for convergence. return_history : bool, optional Return the history of computed values. return_n_iter : bool, optional Return the number of iteration before convergence. verbose : bool, default False Print info at each iteration. update_rho_options : dict, optional Arguments for the rho update. See regain.update_rules.update_rho function for more information. compute_objective : bool, default True Choose to compute the objective value. init : {'empirical', 'zero', ndarray} Choose how to initialize the precision matrix, with the inverse empirical covariance, zero matrix or precomputed. Returns ------- K : numpy.array, 3-dimensional (T x d x d) Solution to the problem for each time t=1...T . history : list If return_history, then also a structure that contains the objective value, the primal and dual residual norms, and tolerances for the primal and dual residual norms at each iteration. """ if loss == 'LL': loss_function = neg_logl else: loss_function = dtrace T, p, _ = S.shape K = [cp.Variable(shape=(p, p), PSD=True) for t in range(T)] # Z_1 = [cp.Variable(shape=(p, p), PSD=True) for t in range(T-1)] # Z_2 = [cp.Variable(shape=(p, p), PSD=True) for t in range(T-1)] if psi == 'laplacian': objective = cp.Minimize( theta * cp.sum( [cp.norm(K[t] - cp.diag(cp.diag(K[t])), 1) for t in range(T)]) + (1 - theta) * cp.sum([cp.norm(K[t] - K[t - 1], 'fro') for t in range(1, T)])) elif psi == 'l1': objective = cp.Minimize(theta * cp.sum([ cp.norm(K[t] - cp.diag(cp.diag(K[t])), 1) for t in range(T) ]) + (1 - theta) * cp.sum( [cp.sum(cp.norm1(K[t] - K[t - 1], axis=1)) for t in range(1, T)])) elif psi == 'l2': objective = cp.Minimize(theta * cp.sum( [cp.norm(K[t] - cp.diag(cp.diag(K[t])), 1) for t in range(T)]) + (1 - theta) * cp.sum([ cp.sum(cp.norm(K[t] - K[t - 1], p=2, axis=1)) for t in range(1, T) ])) elif psi == 'linf': objective = cp.Minimize(theta * cp.sum( [cp.norm(K[t] - cp.diag(cp.diag(K[t])), 1) for t in range(T)]) + (1 - theta) * cp.sum([ cp.sum(cp.norm_inf(K[t] - K[t - 1], axis=1)) for t in range(1, T) ])) # if loss_function == neg_logl: constraints = [(cp.sum(cp.multiply(K[t], S[t])) - cp.log_det(K[t]) <= C[t]) for t in range(T)] # [(cp.trace(K[t] @ S[t]) - cp.log_det(K[t]) <= C[t]) for t in range(T)] # + \ # [(Z_1[t] == K[t]) for t in range(T-1)] + \ # [(Z_2[t] == K[t+1]) for t in range(T-1)] # else: # constraints = [(cp.trace(K[t] @ K[t] @ S[t]) - cp.trace(K[t]) <= C[t]) for t in range(T)] # + \ # # [(Z_1[t] == K[t]) for t in range(T-1)] + \ # # [(Z_2[t] == K[t+1]) for t in range(T-1)] prob = cp.Problem(objective, constraints) # prob.solve(solver=cp.SCS, max_iters=np.int(max_iter), eps=tol, verbose=True) prob.solve(solver=cp.MOSEK, verbose=True) print(prob.status) print(prob.value) K = np.array([k.value for k in K]) covariance_ = np.array([linalg.pinvh(k) for k in K]) return_list = [K, covariance_] return return_list
def test_is_dcp(self): self.assertEqual(cp.Minimize(cp.norm_inf(self.x)).is_dcp(), True) self.assertEqual(cp.Minimize(-cp.norm_inf(self.x)).is_dcp(), False) self.assertEqual(cp.Maximize(cp.norm_inf(self.x)).is_dcp(), False) self.assertEqual(cp.Maximize(-cp.norm_inf(self.x)).is_dcp(), True)
def sequential_lp(f, x0, jac, search_constraints = None, norm = 2, trajectory = trajectory_linear, obj_lb = None, obj_ub = None, constraints = None, constraint_grads = None, constraints_lb = None, constraints_ub = None, maxiter = 100, bt_maxiter = 50, domain = None, tol_dx = 1e-10, tol_obj = 1e-10, verbose = False, **kwargs): r""" Solves a nonlinear optimization problem by a sequence of linear programs Given the optimization problem .. math:: \min{\mathbf{x} \in \mathbb{R}^m} &\ \| \mathbf{f}(\mathbf{x}) \|_p \\ \text{such that} & \ \text{lb} \le \mathbf{f} \le \text{ub} \\ & \ \text{constraint_lb} \le \mathbf{g} \le \text{constraint_ub} this function solves this problem by linearizing both the objective and constraints and solving a sequence of disciplined convex problems. Parameters ---------- norm: [1,2, np.inf, None, 'hinge'] If hinge, sum of values of the objective exceeding 0. References ---------- .. FS89 """ assert norm in [1,2,np.inf, None, 'hinge'], "Invalid norm specified." if search_constraints is None: search_constraints = lambda x, p: [] if domain is None: domain = UnboundedDomain(len(x0)) if constraints is None: constraints = [] if constraint_grads is None: constraint_grads = [] assert len(constraints) == len(constraint_grads), "Must provide same number of constraints as constraint gradients" if constraints_lb is None: constraints_lb = -np.inf*np.ones(len(constraints)) if constraints_ub is None: constraints_ub = np.inf*np.ones(len(constraints)) # The default solver for 1/inf-norm doesn't converge sharp enough, but ECOS does. if 'solver' not in kwargs: kwargs['solver'] = 'ECOS' if norm in [1,2, np.inf]: objfun = lambda fx: np.linalg.norm(fx, ord = norm) elif norm == 'hinge': objfun = lambda fx: np.sum(np.maximum(fx, 0)) else: objfun = lambda fx: float(fx) # evalutate KKT norm def kkt_norm(fx, jacx): kkt_norm = np.nan if norm == np.inf: # TODO: allow other constraints into the solution t = objfun(fx) obj_grad = np.zeros(len(x)+1) obj_grad[-1] = 1. con = np.hstack([fx - t, -fx -t]) con_grad = np.zeros((2*len(fx),len(x)+1)) con_grad[:len(fx),:-1] = jacx con_grad[:len(fx),-1] = -1. con_grad[len(fx):,:-1] = -jacx con_grad[len(fx):,-1] = -1. # Find the active constraints (which have non-zero Lagrange multipliers) I = np.abs(con) < 1e-10 lam, kkt_norm = scipy.optimize.nnls(con_grad[I,:].T, -obj_grad) elif norm == 1: t = np.abs(fx) obj_grad = np.zeros(len(x) + len(fx)) obj_grad[len(x):] = 1. con = np.hstack([fx - t, -fx-t]) con_grad = np.zeros((2*len(fx), len(x)+len(fx))) con_grad[:len(fx),:len(x)] = jacx con_grad[:len(fx),len(x):] = -1. con_grad[len(fx):,:len(x)] = -jacx con_grad[len(fx):,len(x):] = -1. I = np.abs(con) == 0. lam, kkt_norm = scipy.optimize.nnls(con_grad[I,:].T, -obj_grad) elif norm == 2: kkt_norm = np.linalg.norm(jacx.T.dot(fx)) # TODO: Should really orthogonalize against unallowed search directions #err = con_grad[I,:].T.dot(lam) + obj_grad #print err return kkt_norm # Start optimizaiton loop x = np.copy(x0) try: fx = np.array(f(x)) except TypeError: fx = np.array([fi(x) for fi in f]).reshape(-1,) objval = objfun(fx) try: jacx = jac(x) except TypeError: jacx = np.array([jaci(x) for jaci in jac]).reshape(len(fx), len(x)) if verbose: print('iter | objective | norm px | TR radius | KKT norm | violation |') print('-----|-------------------|----------|-----------|----------|-----------|') print('%4d | %+14.10e | | | %8.2e | |' % (0, objval, kkt_norm(fx, jacx))) Delta = 1. for it in range(maxiter): # Search direction p = cp.Variable(len(x)) # Linearization of the objective function f_lin = fx + p.__rmatmul__(jacx) if norm == 1: obj = cp.norm1(f_lin) elif norm == 2: obj = cp.norm(f_lin) elif norm == np.inf: obj = cp.norm_inf(f_lin) elif norm == 'hinge': obj = cp.sum(cp.pos(f_lin)) elif norm == None: obj = f_lin else: raise NotImplementedError # Now setup constraints nonlinear_constraints = [] # First, constraints on "f" if obj_lb is not None: nonlinear_constraints.append(obj_lb <= f_lin) if obj_ub is not None: nonlinear_constraints.append(f_lin <= obj_ub) # Next, we add other nonlinear constraints for con, congrad, con_lb, con_ub in zip(constraints, constraint_grads, constraints_lb, constraints_ub): conx = con(x) congradx = congrad(x) #print "conx", conx, congradx if np.isfinite(con_lb): nonlinear_constraints.append(con_lb <= conx + p.__rmatmul__(congradx) ) if np.isfinite(con_ub): nonlinear_constraints.append(conx + p.__rmatmul__(congradx) <= con_ub ) # Constraints on the search direction specified by user search_step_constraints = search_constraints(x, p) # Append constraints from the domain of x domain_constraints = domain._build_constraints(x + p) stop = False for it2 in range(bt_maxiter): active_constraints = nonlinear_constraints + domain_constraints + search_step_constraints if it2 > 0: trust_region_constraints = [cp.norm(p) <= Delta] active_constraints += trust_region_constraints # Solve for the search direction with warnings.catch_warnings(): warnings.simplefilter('ignore', PendingDeprecationWarning) try: problem = cp.Problem(cp.Minimize(obj), active_constraints) problem.solve(**kwargs) status = problem.status except cp.SolverError: if it2 == 0: status = 'unbounded' else: status = cp.SolverError if (status == 'unbounded' or status == 'unbounded_inaccurate') and it2 == 0: # On the first step, the trust region is off, allowing a potentially unbounded domain pass elif status in ['optimal', 'optimal_inaccurate']: # Otherwise, we've found a feasible step px = p.value # Evaluate new point along the trajectory x_new = trajectory(x, px, 1.) # Check for movement of the point if np.all(np.isclose(x, x_new, rtol = tol_dx, atol = 0)): stop = True break # Evaluate value at new point try: fx_new = np.array(f(x_new)) except TypeError: fx_new = np.array([fi(x_new) for fi in f]).reshape(-1,) objval_new = objfun(fx_new) constraint_violation = 0. if obj_lb is not None: I = ~(obj_lb <= fx_new) constraint_violation += np.linalg.norm((fx_new - obj_lb)[I], 1) if obj_ub is not None: I = ~(fx_new <= obj_ub) constraint_violation += np.linalg.norm((fx_new - obj_ub)[I], 1) if objval_new < objval and np.isclose(constraint_violation, 0., rtol = 1e-10, atol = 1e-10): x = x_new fx = fx_new if np.abs(objval_new - objval) < tol_obj: stop = True objval = objval_new Delta = max(1., np.linalg.norm(px)) break Delta *=0.5 else: warnings.warn("Could not find acceptible step; stopping prematurely; %s" % (status,) ) stop = True px = np.zeros(x.shape) #elif status in ['unbounded', 'unbounded_inaccurate']: # raise UnboundedException #elirf status in ['infeasible']: # raaise InfeasibleException #else: # raise Exception(status) if it2 == bt_maxiter-1: stop = True # Update the jacobian information try: jacx = jac(x) except TypeError: jacx = np.array([jaci(x) for jaci in jac]).reshape(len(fx), len(x)) if verbose: print('%4d | %+14.10e | %8.2e | %8.2e | %8.2e | %8.2e |' % (it+1, objval, np.linalg.norm(px), Delta, kkt_norm(fx, jacx), constraint_violation)) if stop: break return x