
    (^i%                        d dl mZ d dlmZ d dlZd dlZd dlZd dlm	Z	 d dl
mZ d dlmZ d dlmZ erd dlmZ d dlmZ nd d	lmZ  ed
      Z e	d       G d de             Zy)    )annotations)TYPE_CHECKINGN)experimental_class)
BasePruner)StudyDirection)FrozenTrial)Literal)_LazyImportzscipy.statsz3.6.0c                  2    e Zd ZdZddd	 	 	 	 	 ddZd	dZy)
WilcoxonPrunera  Pruner based on the `Wilcoxon signed-rank test <https://en.wikipedia.org/w/index.php?title=Wilcoxon_signed-rank_test&oldid=1195011212>`__.

    This pruner performs the Wilcoxon signed-rank test between the current trial and the current best trial,
    and stops whenever the pruner is sure up to a given p-value that the current trial is worse than the best one.

    This pruner is effective for optimizing the mean/median of some (costly-to-evaluate) performance scores over a set of problem instances.
    Example applications include the optimization of:

    * the mean performance of a heuristic method (simulated annealing, genetic algorithm, SAT solver, etc.) on a set of problem instances,
    * the k-fold cross-validation score of a machine learning model, and
    * the accuracy of outputs of a large language model (LLM) on a set of questions.

    There can be "easy" or "hard" instances (the pruner handles correspondence of the instances between different trials).
    In each trial, it is recommended to shuffle the evaluation order, so that the optimization doesn't overfit to the instances in the beginning.

    When you use this pruner, you must call ``Trial.report(value, step)`` method for each step (instance id) with
    the evaluated value. The instance id may not be in ascending order.
    This is different from other pruners in that the reported value need not converge
    to the real value. To use pruners such as :class:`~optuna.pruners.SuccessiveHalvingPruner`
    in the same setting, you must provide e.g., the historical average of the evaluated values.

    .. seealso::
        Please refer to :meth:`~optuna.trial.Trial.report`.

    Example:

        .. testcode::

            import optuna
            import numpy as np


            # We minimize the mean evaluation loss over all the problem instances.
            def evaluate(param, instance):
                # A toy loss function for demonstrative purpose.
                return (param - instance) ** 2


            problem_instances = np.linspace(-1, 1, 100)


            def objective(trial):
                # Sample a parameter.
                param = trial.suggest_float("param", -1, 1)

                # Evaluate performance of the parameter.
                results = []

                # For best results, shuffle the evaluation order in each trial.
                instance_ids = np.random.permutation(len(problem_instances))
                for instance_id in instance_ids:
                    loss = evaluate(param, problem_instances[instance_id])
                    results.append(loss)

                    # Report loss together with the instance id.
                    # CAVEAT: You need to pass the same id for the same instance,
                    # otherwise WilcoxonPruner cannot correctly pair the losses across trials and
                    # the pruning performance will degrade.
                    trial.report(loss, instance_id)

                    if trial.should_prune():
                        # Return the current predicted value instead of raising `TrialPruned`.
                        # This is a workaround to tell the Optuna about the evaluation
                        # results in pruned trials. (See the note below.)
                        return sum(results) / len(results)

                return sum(results) / len(results)


            study = optuna.create_study(pruner=optuna.pruners.WilcoxonPruner(p_threshold=0.1))
            study.optimize(objective, n_trials=100)



    .. note::
        This pruner cannot handle ``infinity`` or ``nan`` values.
        Trials containing those values are never pruned.

    .. note::
        If :func:`~optuna.trial.FrozenTrial.should_prune` returns :obj:`True`, you can return an
        estimation of the final value (e.g., the average of all evaluated
        values) instead of ``raise optuna.TrialPruned()``.
        This is a workaround for the problem that currently there is no way
        to tell Optuna the predicted objective value for trials raising
        :class:`optuna.TrialPruned`.

    Args:
        p_threshold:
            The p-value threshold for pruning. This value should be between 0 and 1.
            A trial will be pruned whenever the pruner is sure up to the given p-value
            that the current trial is worse than the best trial.
            The larger this value is, the more aggressive pruning will be performed.
            Defaults to 0.1.

            .. note::
                This pruner repeatedly performs statistical tests between the
                current trial and the current best trial with increasing samples.
                The false-positive rate of such a sequential test is different from
                performing the test only once. To get the nominal false-positive rate,
                please specify the Pocock-corrected p-value.

        n_startup_steps:
            The number of steps before which no trials are pruned.
            Pruning starts only after you have ``n_startup_steps`` steps of
            available observations for comparison between the current trial
            and the best trial.
            Defaults to 2. Note that the trial is not pruned at the first and second steps even if
            the `n_startup_steps` is set to 0 or 1 due to the lack of enough data for comparison.
    g?   )p_thresholdn_startup_stepsc                   |dk  rt        d| d      d|cxk  rdk  sn t        d| d      || _        || _        y )Nr   z,n_startup_steps must be nonnegative but got .g        g      ?z,p_threshold must be between 0 and 1 but got )
ValueError_n_startup_steps_p_threshold)selfr   r   s      Y/var/www/html/hubwallet-dev/venv/lib/python3.12/site-packages/optuna/pruners/_wilcoxon.py__init__zWilcoxonPruner.__init__   sV     QKOK\\]^__k(S(KK=XYZ[[ /'    c                   t        |j                        dk(  ryt        j                  t	        |j                  j                                     j                  \  }}t        j                  t        j                  |             r$t        j                  d|j                   d       y	 |j                  }t        |j                        dk(  rt        j                  d       yt        j                  t	        |j                  j                                     j                  \  }}t        j                  t        j                  |             r$t        j                  d|j                   d       yt        j                  ||d	      \  }}	}
t        |	      t        |      k  rt        j                  d
       ||	   ||
   z
  }t        |      t        d| j                         k  ry|j"                  t$        j&                  k(  r2d}t)        |      t        |      z  t)        |      t        |      z  k  }n1d}t)        |      t        |      z  t)        |      t        |      z  k\  }t+        j,                  ||d      j.                  }|| j0                  k  r|ryt3        || j0                  k        S # t        $ r Y yw xY w)Nr   Fz4The intermediate values of the current trial (trial zB) contain infinity/NaNs. WilcoxonPruner will not prune this trial.zThe best trial has no intermediate values so WilcoxonPruner cannot prune trials. If you have added the best trial with Study.add_trial, please consider setting intermediate_values argument.z1The intermediate values of the best trial (trial zI) contain infinity/NaNs. WilcoxonPruner will not prune the current trial.T)return_indiceszxWilcoxonPruner finds steps existing in the current trial but does not exist in the best trial. Those values are ignored.r   lessgreaterzsplit)alternativezero_method)lenintermediate_valuesnparraylistitemsTanyisfinitewarningswarnnumber
best_trialr   intersect1dmaxr   	directionr   MAXIMIZEsumsswilcoxonpvaluer   bool)r   studytrialstepsstep_valuesr,   
best_stepsbest_step_values_idx1idx2diff_valuesaltaverage_is_bestps                  r   prunezWilcoxonPruner.prune   s   u(()Q.XXd5+D+D+J+J+L&MNPP{662;;{++,MMFu||n US T 	))J z--.!3MM0
 ')xxZ5S5S5Y5Y5[0\']'_'_$
$662;;/001MMCJDUDUCV WZ [ ujN4t9s;'' MM, "$'*:4*@@{c!T%:%:;; ??n555C!"23c:J6KKsPK P! !O C!"23c:J6KKsPK P! !O
 KK(KRRt   _
  A)))**w  		s   +J7 7	KKN)r   floatr   intreturnNone)r6   z'optuna.study.Study'r7   r   rF   r5   )__name__
__module____qualname____doc__r   rC    r   r   r   r      s:    lb ! 	( ( 	(
 
(J+r   r   )
__future__r   typingr   r)   numpyr"   optunaoptuna._experimentalr   optuna.prunersr   optuna.study._study_directionr   optuna.trialr   r	   scipy.statsstatsr2   optuna._importsr
   r   rL   r   r   <module>rX      s[    "      3 % 8 $ +	]	#B GG+Z G+ G+r   