a
    J5d                     @   s   d dl mZ d dlmZmZmZ d dlZd dlm	Z	 d dl
mZ d dlmZ dejeee  eeeee eeeef d
ddZejee eeedddZee edddZeeeedddZdS )    )default_timer)ListOptionalTupleN)neighborhood_gen)setup)compute_permutation_distancetwo_opt?F)distance_matrixx0perturbation_schemealphamax_processing_timelog_fileverbosereturnc                 C   sh  t | |\}}t| |||}	|p$tj}|r8t|ddd}
t|}|}d| }d}t }d}|dk r`|s`d}t|D ]}t | |krd}|rt||
d	 |rt| d
} qJt	||}t
| |}t|||	r|| }}|d7 }d}d|	 d| d|d  d| d| d| d| }|r,t||
d	 |r:t| ||krv qJqv|	|9 }	||dk7 }qZ||fS )u%  Solve a TSP problem using a Simulated Annealing
    The approach used here is the one proposed in [1].

    Parameters
    ----------
    distance_matrix
        Distance matrix of shape (n x n) with the (i, j) entry indicating the
        distance from node i to j

    x0
        Initial permutation. If not provided, it starts with a random path

    perturbation_scheme {"ps1", "ps2", "ps3", "ps4", "ps5", "ps6", ["two_opt"]}
        Mechanism used to generate new solutions. Defaults to "two_opt"

    alpha
        Reduction factor (``alpha`` < 1) used to reduce the temperature. As a
        rule of thumb, 0.99 takes longer but may return better solutions, whike
        0.9 is faster but may not be as good. A good approach is to use 0.9
        (as default) and if required run the returned solution with a local
        search.

    max_processing_time {None}
        Maximum processing time in seconds. If not provided, the method stops
        only when there were 3 temperature cycles with no improvement.

    log_file
        If not `None`, creates a log file with details about the whole
        execution

    verbose
        If true, prints algorithm status every iteration

    Returns
    -------
    A permutation of nodes from 0 to n - 1 that produces the least total
    distance obtained (not necessarily optimal).

    The total distance the returned permutation produces.

    References
    ----------
    [1] Dréo, Johann, et al. Metaheuristics for hard optimization: methods and
    case studies. Springer Science & Business Media, 2006.
    wzutf-8)encoding
   r   F   z/WARNING: Stopping early due to time constraints)fileT   zTemperature z. Current value: z k: /z k_accepted: z k_noimprovements: )r   _initial_temperaturenpinfopenlenr   rangeprint_perturbationr   _acceptance_rule)r   r   r   r   r   r   r   xfxtempZlog_file_handlernZk_inner_minZk_inner_maxZk_noimprovementsZticZ
stop_earlyZ
k_acceptedkZwarning_msgxnfnmsg r+   e/var/www/html/django/DPS/env/lib/python3.9/site-packages/python_tsp/heuristics/simulated_annealing.pysolve_tsp_simulated_annealing   sb    7



r-   )r   r#   r$   r   r   c           
      C   sX   g }t dD ]&}t||}t| |}|||  qtt|}d}	| t|	 S )u  Compute initial temperature
    Instead of relying on problem-dependent parameters, this function estimates
    the temperature using the suggestion in [1].

    Notes
    -----
    Here are the steps followed:
        1. Generate 100 disturbances at random from T0, and evaluate the mean
        objective value differences dfx_mean = mean(fn - fx);
        2. Choose tau0 = 0.5 as assumed quality of initial solution (assuming
        a bad one), and deduce T0 from exp(-fx_mean/T0) = tau0, that is,
        T0 = -fx_mean/ln(tau0)

    References
    ----------
    [1] Dréo, Johann, et al. Metaheuristics for hard optimization: methods and
    case studies. Springer Science & Business Media, 2006.
    d   g      ?)r   r!   r   appendr   absmeanlog)
r   r#   r$   r   Zdfx_list_r(   r)   Zdfx_meanZtau0r+   r+   r,   r   w   s    

r   r#   r   c                 C   s   t t| | S )a
  Generate a random neighbor of a current solution ``x``
    In this case, we can use the generators created in the `local_search`
    module, and pick the first solution. Since the neighborhood is randomized,
    it is the same as creating a random perturbation.
    )nextr   r4   r+   r+   r,   r!      s    r!   )r$   r)   r%   r   c                 C   s6   ||  }|dk p4|dko4t j t ||   | kS )zMetropolis acceptance ruler   )r   randomZrandexp)r$   r)   r%   Zdfxr+   r+   r,   r"      s    $r"   )Nr	   r
   NNF)Ztimeitr   typingr   r   r   numpyr   Z*python_tsp.heuristics.perturbation_schemesr   Z"python_tsp.heuristics.local_searchr   Zpython_tsp.utilsr   Zndarrayintstrfloatboolr-   r   r!   r"   r+   r+   r+   r,   <module>   s:         

m'	