simopt.solvers.astrodf ====================== .. py:module:: simopt.solvers.astrodf .. autoapi-nested-parse:: ASTRO-DF Solver. The ASTRO-DF solver progressively builds local models (quadratic with diagonal Hessian) using interpolation on a set of points on the coordinate bases of the best (incumbent) solution. Solving the local models within a trust region (closed ball around the incumbent solution) at each iteration suggests a candidate solution for the next iteration. If the candidate solution is worse than the best interpolation point, it is replaced with the latter (a.k.a. direct search). The solver then decides whether to accept the candidate solution and expand the trust-region or reject it and shrink the trust-region based on a success ratio test. The sample size at each visited point is determined adaptively and based on closeness to optimality. A detailed description of the solver can be found `here `__. This version does not require a delta_max, instead it estimates the maximum step size using get_random_solution(). Parameter tuning on delta_max is therefore not needed and removed from this version as well. - Delta_max is so longer a factor, instead the maximum step size is estimated using get_random_solution(). - Parameter tuning on delta_max is therefore not needed and removed from this version as well. - No upper bound on sample size may be better - testing - It seems for SAN we always use pattern search - why? because the problem is convex and model may be misleading at the beginning - Added sufficient reduction for the pattern search Module Contents --------------- .. py:class:: ASTRODFConfig Bases: :py:obj:`simopt.base.SolverConfig` Configuration for ASTRO-DF solver. .. py:attribute:: eta_1 :type: Annotated[float, Field(default=0.1, gt=0, description='threshold for a successful iteration')] .. py:attribute:: eta_2 :type: Annotated[float, Field(default=0.8, description='threshold for a very successful iteration')] .. py:attribute:: gamma_1 :type: Annotated[float, Field(default=2.5, gt=1, description='trust-region radius increase rate after successful iteration')] .. py:attribute:: gamma_2 :type: Annotated[float, Field(default=0.5, gt=0, lt=1, description='trust-region radius decrease rate after failed iteration')] .. py:attribute:: lambda_min :type: Annotated[int, Field(default=5, gt=2, description='minimum sample size')] .. py:attribute:: easy_solve :type: Annotated[bool, Field(default=True, description='solve the subproblem approximately with Cauchy point')] .. py:attribute:: reuse_points :type: Annotated[bool, Field(default=True, description='reuse the previously visited points')] .. py:attribute:: ps_sufficient_reduction :type: Annotated[float, Field(default=0.1, ge=0, description='use pattern search if with sufficient reduction, 0 always allows it, large value never does')] .. py:attribute:: use_gradients :type: Annotated[bool, Field(default=True, description='if direct gradient observations are available, use them')] .. py:class:: ASTRODF(name: str = '', fixed_factors: dict | None = None) Bases: :py:obj:`simopt.base.Solver` The ASTRO-DF solver. Initialize a solver object. :param name: Name of the solver. Defaults to an empty string. :type name: str, optional :param fixed_factors: Dictionary of user-specified solver factors. Defaults to None. :type fixed_factors: dict | None, optional .. py:attribute:: name :type: str :value: 'ASTRODF' .. py:attribute:: config_class :type: ClassVar[type[simopt.base.SolverConfig]] Configuration class for the solver. .. py:attribute:: class_name_abbr :type: ClassVar[str] :value: 'ASTRODF' Short name of the solver class. .. py:attribute:: class_name :type: ClassVar[str] :value: 'ASTRO-DF' Long name of the solver class. .. py:attribute:: objective_type :type: ClassVar[simopt.base.ObjectiveType] Description of objective types. .. py:attribute:: constraint_type :type: ClassVar[simopt.base.ConstraintType] Description of constraint types. .. py:attribute:: variable_type :type: ClassVar[simopt.base.VariableType] Description of variable types. .. py:attribute:: gradient_needed :type: ClassVar[bool] :value: False True if gradient of objective function is needed, otherwise False. .. py:property:: iteration_count :type: int Get the current iteration count. .. py:property:: delta_k :type: float Get the current delta_k value. .. py:property:: delta_max :type: float Get the current delta_max value. .. py:property:: incumbent_x :type: tuple[float, Ellipsis] Get the incumbent solution. .. py:property:: incumbent_solution :type: simopt.base.Solution Get the incumbent solution. .. py:property:: h_k :type: numpy.ndarray Get the Hessian approximation. .. py:method:: get_coordinate_vector(size: int, v_no: int) -> numpy.ndarray Generate the coordinate vector corresponding to the variable number v_no. .. py:method:: get_rotated_basis(first_basis: numpy.ndarray, rotate_index: numpy.ndarray) -> numpy.ndarray Generate the basis (rotated coordinate). The first vector comes from the visited design points (origin basis) .. py:method:: evaluate_model(x_k: numpy.ndarray, q: numpy.ndarray) -> float Evaluate a local quadratic model using linear interpolation and a diagonal Hessian. :param x_k: The point at which to evaluate the model (decision variables). :type x_k: np.ndarray :param q: Coefficient vector defining the local quadratic model. :type q: np.ndarray :returns: The evaluated model value as a NumPy array. :rtype: np.ndarray .. py:method:: get_stopping_time(pilot_run: int, sig2: float, delta: float, kappa: float) -> int Compute the sample size using adaptive stopping based on the optimality gap. :param pilot_run: Number of initial samples used in the pilot run. :type pilot_run: int :param sig2: Estimated variance of the solution. :type sig2: float :param delta: Optimality gap threshold. :type delta: float :param kappa: Constant in the stopping time denominator. If 0, it defaults to 1. :type kappa: float :returns: The computed sample size, rounded up to the nearest integer. :rtype: int .. py:method:: select_interpolation_points(delta_k: float, f_index: int) -> tuple[list, list] Select interpolation points for the local model. :param delta_k: The current trust-region radius. :type delta_k: float :param f_index: The index of the farthest design point. :type f_index: int :returns: A tuple containing: - var_y (list): The interpolation points. - var_z (list): The reused design point. :rtype: tuple[list, list] .. py:method:: perform_adaptive_sampling(solution: simopt.base.Solution, pilot_run: int, delta_k: float, compute_kappa: bool = False) -> None Perform adaptive sampling on a solution until the stopping condition is met. :param solution: The solution object being sampled. :type solution: Solution :param pilot_run: The number of initial pilot runs. :type pilot_run: int :param delta_k: The current trust-region radius. :type delta_k: float :param compute_kappa: Whether or not to compute kappa dynamically (needed in the first iteration). :type compute_kappa: bool .. py:method:: construct_model() -> tuple[list[float], list, numpy.ndarray, numpy.ndarray, numpy.ndarray, list[simopt.base.Solution]] Construct the local model for the current iteration. Construct the "qualified" local model for each iteration k with the center point x_k reconstruct with new points in a shrunk trust-region if the model fails the criticality condition the criticality condition keeps the model gradient norm and the trust-region size in lock-step .. py:method:: get_model_coefficients(y_var: list, fval: list, problem: simopt.base.Problem) -> tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray] Compute model coefficients using 2d+1 design points and function values. This method fits a quadratic model with a diagonal Hessian by evaluating `2 * dim + 1` points centered at the solution. :param y_var: List of sampled decision vectors (design points). :type y_var: list :param fval: Corresponding function values for each design point. :type fval: list :param problem: Problem instance providing dimension and structure. :type problem: Problem :returns: A tuple containing: - q (np.ndarray): Coefficients of the fitted local quadratic model. - y_mean (np.ndarray): Mean of the y_var design points. - fval_mean (np.ndarray): Mean of the function values. :rtype: tuple[np.ndarray, np.ndarray, np.ndarray] .. py:method:: get_coordinate_basis_interpolation_points(x_k: tuple[int | float, Ellipsis], delta: float, problem: simopt.base.Problem) -> list[list[list[int | float]]] Compute the interpolation points (2d+1) using the coordinate basis. .. py:method:: get_rotated_basis_interpolation_points(x_k: numpy.ndarray, delta: float, problem: simopt.base.Problem, rotate_matrix: numpy.ndarray, reused_x: numpy.ndarray) -> list[list[numpy.ndarray]] Compute the interpolation points (2d+1) using the rotated coordinate basis. One design point is reused, which is the farthest point from the center point. .. py:method:: update_hessian(candidate_solution: simopt.base.Solution, grad: numpy.ndarray, s: numpy.ndarray) -> None Performs Hessian update if gradients are enabled. .. py:method:: iterate() -> None Run one iteration of the ASTRO-DF algorithm. Build and solve a local model, update the current incumbent and trust-region radius, and save the data .. py:method:: solve(problem: simopt.base.Problem) -> None Run a single macroreplication of a solver on a problem. :param problem: Simulation-optimization problem to solve. :type problem: Problem :returns: - list [Solution]: List of solutions recommended throughout the budget. - list [int]: List of intermediate budgets when recommended solutions change. :rtype: tuple .. py:function:: clamp_with_epsilon(val: float, lower_bound: float, upper_bound: float, epsilon: float = 0.01) -> float Clamp a value within bounds while avoiding exact boundary values. Adds a small epsilon to the lower bound or subtracts it from the upper bound if `val` lies outside the specified range. :param val: The value to clamp. :type val: float :param lower_bound: Minimum acceptable value. :type lower_bound: float :param upper_bound: Maximum acceptable value. :type upper_bound: float :param epsilon: Small margin to avoid returning exact boundary values. Defaults to 0.01. :type epsilon: float, optional :returns: The adjusted value, guaranteed to lie strictly within the bounds. :rtype: float