def get_res(nofun, morefun, nexp, xhat, ft, constraintT, sign=1., rank=0): w = np.ones(ft.shape) w[0] *= 10. print('rank {}'.format(rank), end='') res = so.minimize(lambda z: nl.norm(np.multiply(w, nofun(z) - ft))**2, xhat, bounds=[(None, None), (2**-11, None)] * nexp, jac='2-point', hess=so.BFGS(), method='trust-constr', options={ 'verbose': 1, 'maxiter': 2048, 'xtol': 1e-8 }) print('rank {}'.format(rank), end='') res = so.minimize(lambda z: nl.norm(np.multiply(w, nofun(z) - ft))**2, xhat, constraints=so.NonlinearConstraint( lambda z: sign * (nofun(z, constraintT) - morefun(constraintT)), 0, np.inf), bounds=[(None, None), (2**-11, None)] * nexp, jac='2-point', hess=so.BFGS(), method='trust-constr', options={ 'verbose': 1, 'maxiter': 2048, 'xtol': 1e-8 }) i = 1 while res.status == 3 or res.fun > 5e-1: print('rank {}'.format(rank), end='') alpha = 1. / np.sqrt(++i) res = so.minimize(lambda z: nl.norm(np.multiply(w, nofun(z) - ft))**2, res.x * (1. - alpha) + alpha * nr.uniform(-1e-1, 1e-1, xhat.shape[0]), constraints=so.NonlinearConstraint( lambda z: sign * (nofun(z, constraintT) - morefun(constraintT)), 0, np.inf), bounds=[(None, None), (2**-11, None)] * nexp, jac='2-point', hess=so.BFGS(), method='trust-constr', options={ 'verbose': 1, 'maxiter': 2048, 'xtol': 1e-8 }) return res
def optimize(self, graph, demands, initial=None): options = { 'maxiter': self.max_iters, 'factorization_method': 'SVDFactorization' } initial = initial if initial is not None else np.zeros(shape=(graph.number_of_edges(),), dtype=float) bounds = optimize.Bounds(lb=0, ub=np.inf) constraint = self._constraint(graph, demands) flows_per_iter = [] def callback(x, state): flows_per_iter.append(x) return False hess = optimize.BFGS() result = optimize.minimize(fun=self.cost_fn, x0=initial, callback=callback, bounds=bounds, method='trust-constr', constraints=[constraint], jac='2-point', hess=hess, options=options) return np.array(flows_per_iter), result
def __init__(self, game, dist_measures=None, dist_tensor=None, messages=None, epsilon=1e-4): """ Parameters ---------- dist_measures: A list of integers with the distortions from self.dist_tensor to be considered """ RDT.__init__(self, game, dist_tensor, epsilon) self.states = len(self.pmf) if dist_measures: self.dist_measures = dist_measures else: self.dist_measures = range(self.dist_tensor.shape[0]) if messages: self.messages = messages else: self.messages = self.states self.enc_dec_length = self.messages * (self.states + self.outcomes) # length of the encoder_decoder vector we optimize over. self.hess = opt.BFGS(exception_strategy='skip_update') self.bounds = opt.Bounds(0, 1) self.constraint = self.lin_constraint(self.dist_measures) self.default_enc_dec_init = self.enc_dec_init()
def run_optim_fixed_x0(datavox): res = opt.minimize(func_vox_ls, x0=x0, args=(b, bd, datavox), jac='3-point', hess=opt.BFGS(), method='trust-constr', constraints=[cons, fa_cons]) return res
def add_nonlinear_eq_con(self, poly=None, custom=None): """ Adds nonlinear inequality constraints :math:`g(x) = value` (for poly option) or :math:`g(x) = 0` (for function option) to the optimisation routine. Only ``trust-constr`` and ``SLSQP`` methods can handle equality constraints. If poly object is providedin the poly dictionary, gradients and Hessians will be computed automatically. :param dict poly: Arguments for poly dictionary. :param Poly poly: An instance of the Poly class. :param float value: Value of the nonlinear constraint. :param dict custom: Additional custom callable arguments. :callable function: The constraint function to be called. :callable jac_function: The gradient (or derivative) of the constraint. :callable hess_function: The Hessian of the constraint function. """ assert self.method == 'trust-constr' or 'SLSQP' assert poly is not None or custom is not None if poly is not None: assert 'value' in poly value = poly['value'] g = poly.get_polyfit_function() jac = poly.get_polyfit_grad_function() hess = poly.get_polyfit_hess_function() constraint = lambda x: np.asscalar(g(x)) constraint_deriv = lambda x: jac(x)[:, 0] constraint_hess = lambda x, v: hess(x)[:, :, 0] if self.method == 'trust-constr': self.constraints.append(optimize.NonlinearConstraint(constraint, value, value, jac=constraint_deriv, \ hess=constraint_hess)) else: self.constraints.append({'type':'eq', 'fun': lambda x: constraint(x) - value, \ 'jac': constraint_deriv}) elif custom is not None: assert 'function' in custom constraint = custom['function'] if 'jac_function' in custom: constraint_deriv = custom['jac_function'] else: constraint_deriv = '2-point' if 'hess_function' in custom: constraint_hess = lambda x, v: custom['hess_function'](x) else: constraint_hess = optimize.BFGS() if self.method == 'trust-constr': self.constraints.append(optimize.NonlinearConstraint(constraint, 0.0, 0.0, jac=constraint_deriv, \ hess=constraint_hess)) else: if 'jac_function' in custom: self.constraints.append({ 'type': 'eq', 'fun': constraint, 'jac': constraint_deriv }) else: self.constraints.append({'type': 'eq', 'fun': constraint})
def _optimizer(obj_func, initial_theta, bounds, method): constraints = [ optimize.LinearConstraint(np.eye(initial_theta.shape[0]), bounds[:, 0], bounds[:, 1]) ] res = optimize.minimize( lambda theta: obj_func(theta=theta, eval_gradient=False), initial_theta, constraints=constraints, method=method, jac=lambda theta: obj_func(theta=theta, eval_gradient=True)[1], hess=optimize.BFGS(), options={'gtol': 1e-6}) return res.x, res.fun
def nonlinearConstraintBuilder(model, min_scaling_aspect_val, max_scaling_aspect_val, forecasted_metric_val, compose_model_input, jacobian='2-point', hessian=opt.BFGS()): cons_f = nonlinearConstraintFunctionBuilder(model, forecasted_metric_val, compose_model_input) return opt.NonlinearConstraint(cons_f, min_scaling_aspect_val, max_scaling_aspect_val, jac=jacobian, hess=hessian)
def add_objective(self, poly=None, custom=None, maximise=False): """ Adds objective function to be optimised. :param poly poly: A Poly object. :param dict custom: Optional arguments centered around the custom option. :callable function: The objective function to be called. :callable jac_function: The gradient (or derivative) of the objective. :callable hess_function: The Hessian of the objective function. :param bool maximise: A flag to specify if the user would like to maximise the function instead of minimising it. """ assert poly is not None or custom is not None if self.method == 'trust-region': assert poly is None assert custom is not None self.maximise = maximise k = 1.0 if self.maximise: k = -1.0 if poly is not None: f = poly.get_polyfit_function() jac = poly.get_polyfit_grad_function() hess = poly.get_polyfit_hess_function() objective = lambda x: k * np.asscalar(f(x)) objective_deriv = lambda x: k * jac(x)[:, 0] objective_hess = lambda x: k * hess(x)[:, :, 0] elif custom is not None: assert 'function' in custom objective = lambda s: k * custom['function'](s) if 'jac_function' in custom: objective_deriv = lambda s: k * custom['jac_function'](s) else: objective_deriv = '2-point' if 'hess_function' in custom: objective_hess = lambda s: k * custom['hess_function'](s) else: objective_hess = optimize.BFGS() self.objective = { 'function': objective, 'gradient': objective_deriv, 'hessian': objective_hess }
def __init__(self, game, dist_measures=None, dist_tensor=None, epsilon=1e-4): """ Parameters ---------- dist_measures: A list of integers with the distortions from self.dist_tensor to be considered """ RDT.__init__(self, game, dist_tensor, epsilon) self.states = len(self.pmf) if dist_measures: self.dist_measures = dist_measures else: self.dist_measures = range(self.dist_tensor.shape[0]) self.hess = opt.BFGS(exception_strategy='skip_update') self.bounds = opt.Bounds(0, 1) self.constraint = self.lin_constraint(self.dist_measures) self.default_cond_init = self.cond_init()
def train(self, dataset): ''' doc ''' self.train_times += 1 state_batch, action_batch, old_log_prob, advantages, ret_batch = self.data_process_MLP( dataset) # obj_data = self.data_process_MLP_old(dataset) # train_batch_ = obj_data # train_batch = [] # for x in train_batch_: # for y in x: # train_batch.append(y) # state_batch_old = np.array([x[0] for x in train_batch]) # action_batch_old = np.array([x[1] for x in train_batch]) # old_log_prob_old = np.array([x[2] for x in train_batch]) # advantages_old = np.array([x[3] for x in train_batch]) ###### note shape # ret_old = np.array([x[4] for x in train_batch]) # # print('ret_old shape is: ', ret_old.shape) # Return = torch.tensor([x[4] for x in train_batch], dtype = torch.float, device = self.device).unsqueeze(1) # print('state diff: ', np.sum(np.abs(state_batch - state_batch_old))) # print('action diff: ', np.sum(np.abs(action_batch - action_batch_old))) # print('old log prob diff: ', np.sum(np.abs(old_log_prob - old_log_prob_old))) # print('return diff: ', np.sum(np.abs(ret_batch - ret_old))) # exit() def ppo_obj(w, w1_num, state_dim, sigma, w1_shape, w2_shape, s_batch, a_batch, prev_log_prob_batch, adv_batch, eps, device): w1 = w[:w1_num] w2 = w[w1_num:] w1 = w1.reshape(w1_shape, order='F') w2 = w2.reshape(w2_shape, order='F') left_s_batch = s_batch[:, :state_dim] right_s_batch = s_batch[:, 1:] left_a_batch = a_batch[:, 0].reshape(-1, 1) right_a_batch = a_batch[:, 1].reshape(-1, 1) left_mean_batch = np.dot(0.5 * (np.dot(left_s_batch, w1))**2, w2) right_mean_batch = np.dot(0.5 * (np.dot(right_s_batch, w1))**2, w2) left_new_log_prob_batch = -0.5 * np.log(2 * np.pi) - 0.5 * ( left_a_batch - left_mean_batch)**2 / sigma**2 - np.log(sigma) right_new_log_prob_batch = -0.5 * np.log(2 * np.pi) - 0.5 * ( right_a_batch - right_mean_batch)**2 / sigma**2 - np.log(sigma) new_log_prob_batch = left_new_log_prob_batch + right_new_log_prob_batch ratio = np.exp(new_log_prob_batch - prev_log_prob_batch) obj1 = ratio * adv_batch obj2 = np.clip(ratio, 1 - eps, 1 + eps) * adv_batch ppo_obj = -np.mean(np.minimum(obj1, obj2)) return ppo_obj def ppo_obj_grad(w, w1_num, state_dim, sigma, w1_shape, w2_shape, s_batch, a_batch, prev_log_prob_batch, adv_batch, eps, device): ori_len = len(w) assert w1_num == w1_shape[0] * w1_shape[1] assert ori_len == w1_num + w2_shape[0] * w2_shape[1] w1 = w[:w1_num] w2 = w[w1_num:] w1 = w1.reshape(w1_shape, order='F') w2 = w2.reshape(w2_shape, order='F') w1 = torch.tensor(w1, dtype=torch.float, requires_grad=True, device=device) w2 = torch.tensor(w2, dtype=torch.float, requires_grad=True, device=device) left_s_batch = s_batch[:, :state_dim] right_s_batch = s_batch[:, 1:] left_a_batch = a_batch[:, 0].reshape(-1, 1) right_a_batch = a_batch[:, 1].reshape(-1, 1) left_s_batch = torch.tensor(left_s_batch, dtype=torch.float, device=device) right_s_batch = torch.tensor(right_s_batch, dtype=torch.float, device=device) left_a_batch = torch.tensor(left_a_batch, dtype=torch.float, device=device) right_a_batch = torch.tensor(right_a_batch, dtype=torch.float, device=device) prev_log_prob_batch = torch.tensor(prev_log_prob_batch, dtype=torch.float, device=device) adv_batch = torch.tensor(adv_batch, dtype=torch.float, device=device) sigma_tensor = torch.tensor(sigma, dtype=torch.float, device=device) pi_tensor = torch.tensor(-0.5 * np.log(2 * np.pi), dtype=torch.float, device=device) left_mean_batch = torch.mm(0.5 * (torch.mm(left_s_batch, w1))**2, w2) right_mean_batch = torch.mm(0.5 * (torch.mm(right_s_batch, w1))**2, w2) left_new_log_prob_batch = pi_tensor - 0.5 * ( left_a_batch - left_mean_batch)**2 / ( sigma_tensor**2) - torch.log(sigma_tensor) right_new_log_prob_batch = pi_tensor - 0.5 * ( right_a_batch - right_mean_batch)**2 / ( sigma_tensor**2) - torch.log(sigma_tensor) new_log_prob_batch = left_new_log_prob_batch + right_new_log_prob_batch ratio = torch.exp(new_log_prob_batch - prev_log_prob_batch) obj1 = ratio * adv_batch obj2 = torch.clamp(ratio, 1 - eps, 1 + eps) * adv_batch ppo_obj = -torch.min(obj1, obj2).mean() ppo_obj.backward() with torch.no_grad(): w1_grad = w1.grad.cpu().numpy() w2_grad = w2.grad.cpu().numpy() w1_grad = w1_grad.reshape((-1, ), order='F') w2_grad = w2_grad.reshape((-1, ), order='F') grad = np.concatenate((w1_grad, w2_grad)) assert len(grad) == ori_len return grad if self.train_times > self.args.value_pre_train_time: w1_ = self.w1.reshape((-1, ), order='F') w2_ = self.w2.reshape((-1, ), order='F') w0 = np.concatenate((w1_, w2_)) # w, w1_num, w1_shape, w2_shape, s_batch, a_batch, prev_log_prob_batch, adv_batch, eps # w, w1_num, state_dim, sigma, w1_shape, w2_shape, s_batch, a_batch, prev_log_prob_batch, adv_batch, eps, device): res = soptim.minimize( ppo_obj, w0, method='trust-constr', jac=ppo_obj_grad, hess=soptim.BFGS(), constraints=[self.linear_constraint], args=(self.w1_num, self.state_dim, self.sigma, self.w1_shape, self.w2_shape, state_batch, action_batch, old_log_prob, advantages, self.eps, self.device), options={'verbose': self.args.scipy_verbose}) new_w = res.x self.w1 = new_w[:self.w1_num] self.w2 = new_w[self.w1_num:] self.w1 = self.w1.reshape(self.w1_shape, order='F') self.w2 = self.w2.reshape(self.w2_shape, order='F') # tb_value_loss = 0 # value_states_old = self.expand_value_state(state_batch_old) # state_batch_tensor = torch.tensor(value_states_old, dtype = torch.float, device = self.device) # for i in range(self.args.constrained_ppo_value_train_iter): # state_values = self.value_net(state_batch_tensor) # closs = (Return - state_values) ** 2 # closs = closs.mean() # tb_value_loss += closs.detach().cpu().item() # self.c_optimizer.zero_grad() # closs.backward() # self.c_optimizer.step() # tb_value_loss /= self.args.constrained_ppo_value_train_iter # if self.tb_writter is not None: # self.tb_writter.add_scalar('value_loss', tb_value_loss, self.train_times) constraint_violence = self.check_constraint() if self.tb_writter is not None: self.tb_writter.add_scalar('constraint_violence', constraint_violence, self.train_times)
def add_nonlinear_ineq_con(self, poly=None, custom=None): """ Adds nonlinear inequality constraints :math:`lb <= g(x) <= ub` (for poly option) with :math:`lb`, :math:`ub = bounds` or :math:`g(x) >= 0` (for function option) to the optimisation problem. Only ``trust-constr``, ``COBYLA``, and ``SLSQP`` methods can handle general constraints. If Poly object is provided in the poly dictionary, gradients and Hessians will be computed automatically. If a lambda function is provided in the ``function`` dictionary, the user may also provide ``jac_function`` for gradients and ``hess_function`` for Hessians; otherwise, a 2-point differentiation rule will be used to approximate the derivative and a BFGS update will be used to approximate the Hessian. :param dict poly: Arguments for poly dictionary. :param Poly poly: An instance of the Poly class. :param numpy.ndarray bounds: An array with two entries specifying the lower and upper bounds of the inequality. If there is no lower bound, set bounds[0] = -np.inf.If there is no upper bound, set bounds[1] = np.inf. :param dict custom: Additional custom callable arguments. :callable function: The constraint function to be called. :callable jac_function: The gradient (or derivative) of the constraint. :callable hess_function: The Hessian of the constraint function. """ assert self.method in ['SLSQP', 'trust-constr', 'COBYLA'] assert poly is not None or custom is not None if poly is not None: assert 'bounds' in poly bounds = poly['bounds'] assert 'poly' in poly gpoly = poly['poly'] # Get lambda functions for function, gradient, and Hessians from poly object g = gpoly.get_polyfit_function() jac = gpoly.get_polyfit_grad_function() hess = gpoly.get_polyfit_hess_function() constraint = lambda x: g(x)[0] constraint_deriv = lambda x: jac(x)[:, 0] constraint_hess = lambda x, v: hess(x)[:, :, 0] if self.method == 'trust-constr': self.constraints.append( optimize.NonlinearConstraint(constraint, bounds[0], bounds[1], jac=constraint_deriv, hess=constraint_hess)) # other methods add inequality constraints using dictionary files elif self.method == 'SLSQP': if not np.isinf(bounds[0]): self.constraints.append({ 'type': 'ineq', 'fun': lambda x: constraint(x) - bounds[0], 'jac': constraint_deriv }) if not np.isinf(bounds[1]): self.constraints.append({ 'type': 'ineq', 'fun': lambda x: -constraint(x) + bounds[1], 'jac': lambda x: -constraint_deriv(x) }) else: if not np.isinf(bounds[0]): self.constraints.append({ 'type': 'ineq', 'fun': lambda x: constraint(x) - bounds[0] }) if not np.isinf(bounds[1]): self.constraints.append({ 'type': 'ineq', 'fun': lambda x: -constraint(x) + bounds[1] }) elif custom is not None: assert 'function' in custom constraint = custom['function'] if 'jac_function' in custom: constraint_deriv = custom['jac_function'] else: constraint_deriv = '2-point' if 'hess_function' in custom: constraint_hess = lambda x, v: custom['hess_function'](x) else: constraint_hess = optimize.BFGS() if self.method == 'trust-constr': self.constraints.append( optimize.NonlinearConstraint(constraint, 0.0, np.inf, jac=constraint_deriv, hess=constraint_hess)) elif self.method == 'SLSQP': if 'jac_function' in custom: self.constraints.append({ 'type': 'ineq', 'fun': constraint, 'jac': constraint_deriv }) else: self.constraints.append({ 'type': 'ineq', 'fun': constraint }) else: self.constraints.append({'type': 'ineq', 'fun': constraint})
# # FA ~ 0.2425 # ratio_min = 1.5 # FA ~ 0.0 ratio_min = 1. # FA ~ 0.8111 ratio_max = 6.0 ################################################# ## nonlinear ratio constraint object fa_cons = opt.NonlinearConstraint(ratio, np.array([ratio_min]), np.array([ratio_max]), jac=ratio_jac, hess=opt.BFGS()) ## uFA for this type of models def microFA(d1, d2, d3, fin, fex, fcsf): # if (fin < 0) or (fex < 0) or (fin + fex > 1): # return np.nan microAx = fin * d1 + fex * d2 + fcsf * 3 microRad = fex * d3 + fcsf * 3 microMean = (microAx + 2 * microRad) / 3. microFA = np.sqrt( (3 / 2.) * ((microAx - microMean)**2 + 2 * (microRad - microMean)**2) / (microAx**2 + 2 * microRad**2)) return microFA
N = 50 delta = np.linspace(0.001, 0.75, N) #Create empty array for solutions q_optimal = np.array([]) cmu_optimal = np.array([]) #Find solutions for every delta for i in range(N): R = delta[i] * 2 while np.abs(R - delta[i]) > 1E-4: print(R, delta[i]) x0 = initialize_x(1, init_type='normal') #Must be length of one nonlinear_constraint = optimize.NonlinearConstraint( cons_c, lb=0.0, ub=delta[i], jac='3-point', hess=optimize.BFGS()) res = optimize.minimize(cmu_Q, x0, method='trust-constr', constraints=[nonlinear_constraint], tol=1E-12, options={ 'verbose': 1, 'xtol': 1E-12, 'gtol': 1E-12, 'maxiter': 2500 }, bounds=bounds) q = np.asarray(np.real(res.x)) R = cons_c(q)
def optimize( self ): res = so.minimize( self.loss, self.w, constraints=self.constraints, jac='2-point', hess=so.BFGS(), method='trust-constr', options={'verbose':1,'maxiter':1024,'xtol':1e-8} ) self.w = res.x