def test_isAcceptable(self): fe = FilterElement(0.5, 0.25) # A sufficiently feasible element self.assertTrue(self.tmpFilter.isAcceptable(fe, self.theta_max)) fe = FilterElement(10.0, 15.0) # A sufficiently infeasible element self.assertFalse(self.tmpFilter.isAcceptable(fe, self.theta_max))
def trust_region_method(model, decision_variables, ext_fcn_surrogate_map_rule, config): """ The main driver of the Trust Region algorithm method. Parameters ---------- model : ConcreteModel The user's model to be solved. degrees_of_freedom_variables : List of Vars User-supplied input. The user must provide a list of vars which are the degrees of freedom or decision variables within the model. ext_fcn_surrogate_map_rule : Function, optional In the 2020 Yoshio/Biegler paper, this is refered to as the basis function `b(w)`. This is the low-fidelity model with which to solve the original process model problem and which is integrated into the surrogate model. The default is 0 (i.e., no basis function rule.) config : ConfigDict This holds the solver and TRF-specific configuration options. """ # Initialize necessary TRF methods TRFLogger = IterationLogger() TRFilter = Filter() interface = TRFInterface(model, decision_variables, ext_fcn_surrogate_map_rule, config) # Initialize the problem rebuildSM = False obj_val, feasibility = interface.initializeProblem() # Initialize first iteration feasibility/objective value to enable # termination check feasibility_k = feasibility obj_val_k = obj_val # Initialize step_norm_k to a bogus value to enable termination check step_norm_k = 0 # Initialize trust region radius trust_radius = config.trust_radius iteration = 0 TRFLogger.newIteration(iteration, feasibility_k, obj_val_k, trust_radius, step_norm_k) TRFLogger.logIteration() if config.verbose: TRFLogger.printIteration() while iteration < config.maximum_iterations: iteration += 1 # Check termination conditions if ((feasibility_k <= config.feasibility_termination) and (step_norm_k <= config.step_size_termination)): print('EXIT: Optimal solution found.') interface.model.display() break # If trust region very small and no progress is being made, # terminate. The following condition must hold for two # consecutive iterations. if ((trust_radius <= config.minimum_radius) and (abs(feasibility_k - feasibility) < config.feasibility_termination)): if subopt_flag: logger.warning('WARNING: Insufficient progress.') print('EXIT: Feasible solution found.') break else: subopt_flag = True else: # This condition holds for iteration 0, which will declare # the boolean subopt_flag subopt_flag = False # Set bounds to enforce the trust region interface.updateDecisionVariableBounds(trust_radius) # Generate suggorate model r_k(w) if rebuildSM: interface.updateSurrogateModel() # Solve the Trust Region Subproblem (TRSP) obj_val_k, step_norm_k, feasibility_k = interface.solveModel() TRFLogger.newIteration(iteration, feasibility_k, obj_val_k, trust_radius, step_norm_k) # Check filter acceptance filterElement = FilterElement(obj_val_k, feasibility_k) if not TRFilter.isAcceptable(filterElement, config.maximum_feasibility): # Reject the step TRFLogger.iterrecord.rejected = True trust_radius = max( config.minimum_radius, step_norm_k * config.radius_update_param_gamma_c) rebuildSM = False interface.rejectStep() # Log iteration information TRFLogger.logIteration() if config.verbose: TRFLogger.printIteration() continue # Switching condition: Eq. (7) in Yoshio/Biegler (2020) if ((obj_val - obj_val_k) >= (config.switch_condition_kappa_theta * pow(feasibility, config.switch_condition_gamma_s)) and (feasibility <= config.minimum_feasibility)): # f-type step TRFLogger.iterrecord.fStep = True trust_radius = min( max(step_norm_k * config.radius_update_param_gamma_e, trust_radius), config.maximum_radius) else: # theta-type step TRFLogger.iterrecord.thetaStep = True filterElement = FilterElement( obj_val_k - config.param_filter_gamma_f * feasibility_k, (1 - config.param_filter_gamma_theta) * feasibility_k) TRFilter.addToFilter(filterElement) # Calculate ratio: Eq. (10) in Yoshio/Biegler (2020) rho_k = ((feasibility - feasibility_k + config.feasibility_termination) / max(feasibility, config.feasibility_termination)) # Ratio tests: Eq. (8) in Yoshio/Biegler (2020) # If rho_k is between eta_1 and eta_2, trust radius stays same if ((rho_k < config.ratio_test_param_eta_1) or (feasibility > config.minimum_feasibility)): trust_radius = max( config.minimum_radius, (config.radius_update_param_gamma_c * step_norm_k)) elif (rho_k >= config.ratio_test_param_eta_2): trust_radius = min( config.maximum_radius, max(trust_radius, (config.radius_update_param_gamma_e * step_norm_k))) TRFLogger.updateIteration(trustRadius=trust_radius) # Accept step and reset for next iteration rebuildSM = True feasibility = feasibility_k obj_val = obj_val_k # Log iteration information TRFLogger.logIteration() if config.verbose: TRFLogger.printIteration() if iteration >= config.maximum_iterations: logger.warning('EXIT: Maximum iterations reached: {}.'.format( config.maximum_iterations)) return interface.model
def test_addToFilter(self): fe = FilterElement(self.objective, self.feasible) self.tmpFilter.addToFilter(fe) self.assertIn(fe, self.tmpFilter.TrustRegionFilter)
def test_FilterElement(self): fe = FilterElement(self.objective, self.feasible) self.assertEqual(fe.objective, self.objective) self.assertEqual(fe.feasible, self.feasible)