
    -ji-T                    F   S SK Jr  S SKJr  S SKJr  S SKrS SKrS SKJ	r	  S SKJ
r
  S SKJr  S SKJr  S S	KJr  S S
KJr  S SKJr  S SKJr  S SKJr  S SKJr  S SKJr  \(       aJ  S SKJr  S SKJr  S SKrS SKJs  Jr   S SK!Js  J"r"  S SK#Js  J$r$  S SK%Js  J&r&  S SK'Js  J(r)  S SK*J+r+  S SKJ,r,  O6S SK-J.r.  \." S5      r\." S5      r)\." S5      r"\." S5      r$\." S5      r \." S5      r&S SK/r/\/R`                  " \15      r2Sr3S!S jr4\	" S5       " S S\5      5       r5      S"S  jr6g)#    )annotations)Any)TYPE_CHECKINGN)experimental_class)warn_experimental_argument)_CONSTRAINTS_KEY)&_INDEPENDENT_SAMPLING_WARNING_TEMPLATE) _process_constraints_after_trial)BaseSampler)LazyRandomState)StudyDirection)_is_pareto_front)FrozenTrial)
TrialState)Callable)Sequence)BaseDistribution)Study)_LazyImporttorchzoptuna._gp.search_spacezoptuna._gp.gpzoptuna._gp.optim_mixedzoptuna._gp.acqfzoptuna._gp.priorg|=c                    [         R                  " U 5      n[        R                  " USS9n[        R                  " USS9nX-
  [        R
                  " [        U5      -  nXBU4$ )Nr   axis)gpwarn_and_convert_infnpmeanstdmaximumEPS)valuesclipped_valuesmeansstdsstandardized_valuess        U/home/james-whalen/.local/lib/python3.13/site-packages/optuna/samplers/_gp/sampler.py_standardize_valuesr'   5   sV    ,,V4NGGN+E66.q)D)1RZZT5JJt++    z3.6.0c                     \ rS rSrSrSSSSSSS.             SS jjrSS	 jrSS
 jr      SS jr      SS jr	        SS jr
      SS jr        SS jr          SS jrSS jr          SS jrSrg)	GPSampler=   a  Sampler using Gaussian process-based Bayesian optimization.

This sampler fits a Gaussian process (GP) to the objective function and optimizes
the acquisition function to suggest the next parameters.

The current implementation uses Matern kernel with nu=2.5 (twice differentiable) with automatic
relevance determination (ARD) for the length scale of each parameter.
The hyperparameters of the kernel are obtained by maximizing the marginal log-likelihood of the
hyperparameters given the past trials.
To prevent overfitting, Gamma prior is introduced for kernel scale and noise variance and
a hand-crafted prior is introduced for inverse squared lengthscales.

As an acquisition function, we use:

- log expected improvement (logEI) for single-objective optimization,
- log expected hypervolume improvement (logEHVI) for Multi-objective optimization, and
- the summation of logEI and the logarithm of the feasible probability with the independent
  assumption of each constraint for (black-box inequality) constrained optimization.

For further information about these acquisition functions, please refer to the following
papers:

- `Unexpected Improvements to Expected Improvement for Bayesian Optimization
  <https://arxiv.org/abs/2310.20708>`__
- `Differentiable Expected Hypervolume Improvement for Parallel Multi-Objective Bayesian
  Optimization <https://arxiv.org/abs/2006.05078>`__
- `Bayesian Optimization with Inequality Constraints
  <https://proceedings.mlr.press/v32/gardner14.pdf>`__

Please also check our articles:

- `[Optuna v4.5] Gaussian Process-Based Sampler (GPSampler) Can Now Perform Constrained
  Multi-Objective Optimization <https://medium.com/optuna/optuna-v4-5-81e78d8e077a>`__
- `[Optuna v4.2] Gaussian Process-Based Sampler (GPSampler) Can Now Handle Inequality
  Constraints
  <https://medium.com/optuna/optuna-v4-2-gaussian-process-based-sampler-can-now-handle-inequality-constraints-a4f68e8ee810>`__
- `Introducing Optuna's Native GPSampler
  <https://medium.com/optuna/introducing-optunas-native-gpsampler-0aa9aa3b4840>`__

The optimization of the acquisition function is performed via:

1. Collect the best param from the past trials,
2. Collect ``n_preliminary_samples`` points using Quasi-Monte Carlo (QMC) sampling,
3. Choose the best point from the collected points,
4. Choose ``n_local_search - 2`` points from the collected points using the roulette
   selection,
5. Perform a local search for each chosen point as an initial point, and
6. Return the point with the best acquisition function value as the next parameter.

Decoupled optimizer update with a batched evaluation is employed to perform a batch of local
searches simultaneously, specifically speeding up Step 5 above.

The following paper details the methodology:

- `Batch Acquisition Function Evaluations and Decouple Optimizer Updates for Faster Bayesian
  Optimization <https://arxiv.org/abs/2511.13625>`__

Note that the procedures for non single-objective optimization setups are slightly different
from the single-objective version described above, but we omit the descriptions for the others
for brevity.

The local search iteratively optimizes the acquisition function by repeating:

1. Gradient ascent using l-BFGS-B for continuous parameters, and
2. Line search or exhaustive search for each discrete parameter independently.

The local search is terminated if the routine stops updating the best parameter set or the
maximum number of iterations is reached.

We use line search instead of rounding the results from the continuous optimization since EI
typically yields a high value between one grid and its adjacent grid.

.. note::
    This sampler requires ``scipy`` and ``torch``.
    You can install these dependencies with ``pip install scipy torch``.

Args:
    seed:
        Random seed to initialize internal random number generator.
        Defaults to :obj:`None` (a seed is picked randomly).
    independent_sampler:
        Sampler used for initial sampling (for the first ``n_startup_trials`` trials)
        and for conditional parameters. Defaults to :obj:`None`
        (a random sampler with the same ``seed`` is used).
    n_startup_trials:
        Number of initial trials. Defaults to 10.
    deterministic_objective:
        Whether the objective function is deterministic or not.
        If :obj:`True`, the sampler will fix the noise variance of the surrogate model to
        the minimum value (slightly above 0 to ensure numerical stability).
        Defaults to :obj:`False`. Currently, all the objectives will be assume to be
        deterministic if :obj:`True`.
    constraints_func:
        An optional function that computes the objective constraints. It must take a
        :class:`~optuna.trial.FrozenTrial` and return the constraints. The return value must
        be a sequence of :obj:`float` s. A value strictly larger than 0 means that a
        constraints is violated. A value equal to or smaller than 0 is considered feasible.
        If ``constraints_func`` returns more than one value for a trial, that trial is
        considered feasible if and only if all values are equal to 0 or smaller.

        The ``constraints_func`` will be evaluated after each successful trial.
        The function won't be called when trials fail or are pruned, but this behavior is
        subject to change in future releases.
    warn_independent_sampling:
        If this is :obj:`True`, a warning message is emitted when
        the value of a parameter is sampled by using an independent sampler,
        meaning that no GP model is used in the sampling.
        Note that the parameters of the first trial in a study are always sampled
        via an independent sampler, so no warning messages are emitted in this case.
N
   FT)seedindependent_samplern_startup_trialsdeterministic_objectiveconstraints_funcwarn_independent_samplingc                  [        U5      U l        U=(       d    [        R                  R	                  US9U l        [        R                  R                  5       U l        X0l	        [        R                  U l        [        R                  U l        S U l        S U l        X@l        XPl        X`l        Ub  [)        S5        SU l        SU l        SU l        g )N)r-   r1   i   r,   g-C6?)r   _rngoptunasamplersRandomSampler_independent_samplersearch_spaceIntersectionSearchSpace_intersection_search_space_n_startup_trialspriordefault_log_prior
_log_priorDEFAULT_MINIMUM_NOISE_VAR_minimum_noise_gprs_cache_list_constraints_gprs_cache_list_deterministic_constraints_func_warn_independent_samplingr   _n_preliminary_samples_n_local_search_tol)selfr-   r.   r/   r0   r1   r2   s          r&   __init__GPSampler.__init__   s     $D)	$7$c6??;X;X^b;X;c!*0*=*=*U*U*W'!1DID[D[%*%D%D >BIM)5!1*C''&'9: ,0#!	r(   c                    [         R                  " UUR                  U R                  R                  R
                  U R                  R
                  SS9n[        R                  U5        g )Nz2dynamic search space is not supported by GPSampler)
param_nametrial_numberindependent_sampler_namesampler_namefallback_reason)r	   formatnumberr8   	__class____name___loggerwarning)rJ   trialrN   msgs       r&   _log_independent_sampling#GPSampler._log_independent_sampling   sO    4;;!%)%>%>%H%H%Q%Q00P
 	r(   c                    U R                   R                  R                  5         U R                  R	                  5         g N)r4   rngr-   r8   
reseed_rng)rJ   s    r&   r`   GPSampler.reseed_rng   s(    		!!,,.r(   c                    0 nU R                   R                  U5      R                  5        H   u  pEUR                  5       (       a  M  XSU'   M"     U$ r^   )r;   	calculateitemssingle)rJ   studyrY   r9   namedistributions         r&   infer_relative_search_space%GPSampler.infer_relative_search_space   sS     "&"A"A"K"KE"R"X"X"ZD""$$!- #[
 r(   c           	         Ub  [        UR                  5      S:X  d   e[        R                  " UUU R                  U R
                  U R                  U R                  R                  S9u  p4U$ )N   )!warmstart_normalized_params_arrayn_preliminary_samplesn_local_searchtolr_   )	lenshapeoptim_mixedoptimize_acqf_mixedrG   rH   rI   r4   r_   )rJ   acqfbest_paramsnormalized_params	_acqf_vals        r&   _optimize_acqfGPSampler._optimize_acqf   sh     "c+*;*;&<&AAA'2'F'F.9"&"="=//				(
$ ! r(   c                >   [        U* 5      u  pEnU R                  b7  [        U R                  S   R                  5      UR                  :w  a  S U l        UR                  n/ n/ n	U* [        R                  " [        U5      -  R                  5       n	[        UR                  5       Hl  u  pU R
                  b  U R
                  U
   OS n[        R                  " UUUU R                  U R                   UU R"                  S9nUR%                  U5        Mn     Xl        X4$ )Nr   XYis_categorical	log_priorminimum_noise	gpr_cacher0   )r'   rB   rq   inverse_squared_lengthscalesdimrC   r   r   r   r    tolist	enumerateTr   fit_kernel_paramsr?   rA   rD   append)rJ   constraint_valsinternal_search_spacerw   standardized_constraint_valsr#   r$   r   constraints_gprsconstraints_threshold_listivalscachegprs                 r&   _get_constraints_acqf_args$GPSampler._get_constraints_acqf_args   s$    5HHX4Y1$T!!-D))!,IIJ$(() 15D-.==%'"',frzz#t/D&D%L%L%N" !=!?!?@GA 44@ 11!4 
 &&#-//"11(,(;(;C ##C( A" -=);;r(   c                    U[        U* SS9   n[        U5      n[        U R                  S-  U5      nU R                  R
                  R                  XESS9nX6   $ )NF)assume_unique_lexsortedrl   )sizereplace)r   rq   minrH   r4   r_   choice)rJ   rw   standardized_score_valspareto_paramsn_pareto_solsr   chosen_indicess          r&   $_get_best_params_for_multi_objective.GPSampler._get_best_params_for_multi_objective!  sf    
 *55uU
 M*4''1,m<--mPU-V,,r(   c                
	   U0 :X  a  0 $ [         R                  4nUR                  SUSS9n[        U5      U R                  :  a  0 $ [
        R                  " U5      nUR                  U5      n[        R                  " UR                   Vs/ s H  o[        R                  :X  a  SOSPM     sn5      n	[        U	[        R                  " U Vs/ s H  o"R                  PM     sn5      -  5      u  n
  nU R                  b7  [        U R                  S   R                   5      UR"                  :w  a  S U l        / nU
R$                  S   nUR&                  n[)        U5       Ho  nU R                  b  U R                  U   OS nUR+                  [,        R.                  " UU
S S 2U4   UU R0                  U R2                  UU R4                  S95        Mq     Xl        U R6                  c  US	:X  aj  [        U5      S	:X  d   e[8        R:                  " US   UU
S S 2S4   R=                  5       S
9nU[        R>                  " U
5      [        R@                  4   nGO[8        RB                  " UU[D        RF                  " U
5      SU RH                  RJ                  RM                  S5      S9nU RO                  Xz5      nGOUS	:X  a  [        U5      S	:X  d   e[Q        X5      u  nn[        RR                  " UU
S S 2S4   [        RT                  * 5      nU RW                  UXg5      u  nn[        R>                  " U5      nUU   n[8        RX                  " US   UUUUS9nUR$                  S S UR$                  :X  d   e[        RZ                  " U5      (       a  S OUU[        R@                  4   nO[Q        X5      u  nnU RW                  UXg5      u  nn[]        U5      (       + n[8        R^                  " UUU(       d  [D        RF                  " U
U   5      OS SU RH                  RJ                  RM                  S5      UUS9nU(       d  U RO                  UU   U
U   5      OS nU Ra                  UU5      nURc                  U5      $ s  snf s  snf )NFTdeepcopystates	use_cacheg      g      ?r   r|      )r   r9   	threshold   i   @)gpr_listr9   Y_trainn_qmc_samplesqmc_seed)r   r9   r   constraints_gpr_listr   )r   r9   
Y_feasibler   r   r   r   )2r   COMPLETE_get_trialsrq   r<   gp_search_spaceSearchSpaceget_normalized_paramsr   array
directionsr   MINIMIZEr'   r!   rB   r   r   rr   r   ranger   r   r   r?   rA   rD   rE   acqf_moduleLogEImaxargmaxnewaxisLogEHVIr   
from_numpyr4   r_   randintr   $_get_constraint_vals_and_feasibilitywhereinfr   ConstrainedLogEIisneginfanyConstrainedLogEHVIry   get_unnormalized_param)rJ   rf   rY   r9   r   trialsr   rw   d_signr   _	gprs_listn_objectivesr   r   r   ru   rv   r   is_feasibley_with_neginfconstr_gpr_listconstr_threshold_listi_optbest_feasible_yis_all_infeasiblenormalized_params                               r&   sample_relativeGPSampler.sample_relative/  sq    2I%%'""E&D"Qv;///I / ; ;L I1GGOQVQaQabQaA~'>'>">$CGQabc(;BHH?ull?@@)
%A
 !!-D))!,IIJ$(() %)D!	.44R8.==|$A040E0E0QD))!,W[E$$'-ad3#1"oo"&"5"5#,0,?,?
 % !* !!)q 9~***"((!!!65ad;??A
 0		:Q0RTVT^T^0^_"**&!6!,,-DE"%!YY]]227; #GG% q 9~***/STY/b, "6MaQRd6SVXV\V\U\ ] :>9X9X#%::6!6 		-0"/"6"33!!!6-)8/D )..s3}7J7JJJJKK88D>OPUWYWaWaPa>b  0TTY/b,9=9X9X#%::6!6 ),K(8$8!"55&!6  1 (()@)MN!"%!YY]]227;)8/D$ -	 ==)+6/<
    ..t[A$;;<LMMY c?s   !Q;R c                    U R                   (       aL  [        R                  4nUR                  SUSS9n[	        U5      U R
                  :  a  U R                  X#5        U R                  R                  XX45      $ )NFTr   )	rF   r   r   r   rq   r<   r[   r8   sample_independent)rJ   rf   rY   rN   param_distributionr   complete_trialss          r&   r   GPSampler.sample_independent  sr     ** ))+F#//vY]/^O?#t'='==..uA((;;*
 	
r(   c                :    U R                   R                  X5        g r^   )r8   before_trial)rJ   rf   rY   s      r&   r   GPSampler.before_trial  s    !!..u<r(   c                    U R                   b  [        U R                   XU5        U R                  R                  XX45        g r^   )rE   r
   r8   after_trial)rJ   rf   rY   stater!   s        r&   r   GPSampler.after_trial  s9     !!-,T-C-CUSXY!!--eEJr(   )rE   rC   rD   rB   r8   r;   r?   rA   rH   rG   r<   r4   rI   rF   )r-   z
int | Noner.   zBaseSampler | Noner/   intr0   boolr1   z/Callable[[FrozenTrial], Sequence[float]] | Noner2   r   returnNone)rY   r   rN   strr   r   )r   r   )rf   r   rY   r   r   dict[str, BaseDistribution])ru   zacqf_module.BaseAcquisitionFuncrv   znp.ndarray | Noner   
np.ndarray)r   r   r   zgp_search_space.SearchSpacerw   r   r   z(tuple[list[gp.GPRegressor], list[float]])rw   r   r   r   r   r   )rf   r   rY   r   r9   r   r   zdict[str, Any])
rf   r   rY   r   rN   r   r   r   r   r   )rf   r   rY   r   r   r   )
rf   r   rY   r   r   r   r!   zSequence[float] | Noner   r   )rV   
__module____qualname____firstlineno____doc__rK   r[   r`   ri   ry   r   r   r   r   r   r   __static_attributes__ r(   r&   r*   r*   =   s   md  26 "(-LP*.  0	
  "& J $( 
B/		#.		$	!3!BS!	!"&<#&<  ;&< &	&<
 
2&<P-%- ",- 
	-{N{N#.{N>Y{N	{Nz

 
 	

 -
 

 =	K	K 	K 		K
 '	K 
	Kr(   r*   c                  ^ U Vs/ s H<  nU R                   R                  UR                  5      R                  [        S5      PM>     snm[        U4S jT 5       5      (       a  [        S5      e[        R                  " T5      n[        UR                  5      S:X  d   S5       e[        R                  " US:*  SS9n[        U[        R                  5      (       a   S	5       eX44$ s  snf )
Nr   c              3  X   >#    U  H  n[        TS    5      [        U5      :g  v   M!     g7f)r   N)rq   ).0c_constraint_valss     r&   	<genexpr>7_get_constraint_vals_and_feasibility.<locals>.<genexpr>  s'     
H7G!3"#s1v-7Gs   '*z:The number of constraints must be the same for all trials.rl   z#constraint_vals must be a 2d array.r   r   r   z#MyPy Redefinition for NumPy v2.2.0.)_storageget_trial_system_attrs	_trial_idgetr   r   
ValueErrorr   r   rq   rr   all
isinstancebool_)rf   r   rY   r   r   r   s        @r&   r   r     s    
 E 	--eoo>BBCSUWX 
H7G
HHHUVVhh/0O$$%*Q,QQ*&&A-A6K+rxx00W2WW0''s   AC()r!   r   r   z)tuple[np.ndarray, np.ndarray, np.ndarray])rf   r   r   zlist[FrozenTrial]r   ztuple[np.ndarray, np.ndarray])7
__future__r   typingr   r   numpyr   r5   optuna._experimentalr   r   optuna.samplers._baser   r	   r
   r   "optuna.samplers._lazy_random_stater   optuna.studyr   optuna.study._multi_objectiver   optuna.trialr   r   collections.abcr   r   r   optuna._gp.acqf_gpru   r   optuna._gp.gpr   optuna._gp.optim_mixedrs   optuna._gp.priorr=   optuna._gp.search_spacer9   r   optuna.distributionsr   r   optuna._importsr   logging	getLoggerrV   rW   r    r'   r*   r   r   r(   r&   <module>r     s   "      3 ; 2 H B - > ' : $ # (())00$$555"+ E!";<O	_	%B67K/0K*+E  

H
%, GJK JK JKZ((+("(r(   