B
    d.             	   @   s  d Z ddlZddlZddlZddlZyddlmZ W n  ek
rT   ddlmZ Y nX ddl	m
Z
mZ ddlZddlmZ ddlmZ ddlmZmZ dd	lmZmZ dd
lmZ ddlmZmZmZ dddddddddg	ZegZeegZG dd dZ G dd dZ!G dd de"Z#G dd de#Z$G dd de#e%Z&G dd dej'Z(dd  Z)G d!d de(d"Z*G d#d de(d"Z+G d$d dZ,G d%d de(d"Z-G d&d de*Z.G d'd de*Z/G d(d de(d"Z0d7d)d*Z1d+d, Z2d-d. Z3d/d0 Z4d1d2 Z5d3d4 Z6d5d6 Z7e7  dS )8a  
This module implements classes (called Fitters) which combine optimization
algorithms (typically from `scipy.optimize`) with statistic functions to perform
fitting. Fitters are implemented as callable classes. In addition to the data
to fit, the ``__call__`` method takes an instance of
`~astropy.modeling.core.FittableModel` as input, and returns a copy of the
model with its parameters determined by the optimizer.

Optimization algorithms, called "optimizers" are implemented in
`~astropy.modeling.optimizers` and statistic functions are in
`~astropy.modeling.statistic`. The goal is to provide an easy to extend
framework and allow users to easily create new fitters by combining statistics
with optimizers.

There are two exceptions to the above scheme.
`~astropy.modeling.fitting.LinearLSQFitter` uses Numpy's `~numpy.linalg.lstsq`
function.  `~astropy.modeling.fitting.LevMarLSQFitter` uses
`~scipy.optimize.leastsq` which combines optimization and statistic in one
implementation.
    N)entry_points)reducewraps)Quantity)AstropyUserWarning   )poly_map_domain_combine_equivalency_dict)SLSQPSimplex)leastsquare)DEFAULT_MAXITERDEFAULT_EPSDEFAULT_ACCLinearLSQFitterLevMarLSQFitterFittingWithOutlierRemovalSLSQPLSQFitterSimplexLSQFitterJointFitterFitterModelLinearityErrorModelsErrorc               @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )
Covariancez2Class for covariance matrix calculated by fitter. c             C   s   || _ || _d S )N)
cov_matrixparam_names)selfr   r    r   e/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/astropy/modeling/fitting.py__init__=   s    zCovariance.__init__c       	      C   s   t dd | jD }d}dd| d}xvt| jD ]h\}}||d kr| j| }||dt| |dtt	|d |d  |d	d
 7 }q6|d7 }q6W |
 S )Nc             S   s   g | ]}t |qS r   )len).0xr   r   r   
<listcomp>D   s    z%Covariance.pprint.<locals>.<listcomp>z#parameter variances / covariances 
 z <z| {0}
r       z...)maxr   	enumerater   replacer    formatreprnproundrstrip)	r   	max_lines	round_vallongest_nameret_strfstringirowparamr   r   r   pprintA   s    
*zCovariance.pprintc             C   s   | j dddS )N
      )r0   r1   )r8   )r   r   r   r   __repr__P   s    zCovariance.__repr__c             C   s|   t |dkrtdtdd |D rJ| j|d | j|d  }}n$tdd |D rf|\}}ntd| j| | S )	N   z)Covariance must be indexed by two values.c             s   s   | ]}t |tV  qd S )N)
isinstancestr)r!   itemr   r   r   	<genexpr>W   s    z)Covariance.__getitem__.<locals>.<genexpr>r   r   c             s   s   | ]}t |tV  qd S )N)r=   int)r!   r?   r   r   r   r@   Y   s    zDCovariance can be indexed by two parameter names or integer indices.)r    
ValueErrorallr   index	TypeErrorr   )r   paramsi1i2r   r   r   __getitem__S   s    $
zCovariance.__getitem__N)__name__
__module____qualname____doc__r   r8   r;   rI   r   r   r   r   r   :   s
   r   c               @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )StandardDeviationsz! Class for fitting uncertainties.c             C   s   || _ | || _d S )N)r   
_calc_stdsstds)r   r   r   r   r   r   r   c   s    zStandardDeviations.__init__c             C   s   dd t |D }|S )Nc             S   s"   g | ]}|d krt |ndqS )r   N)r-   sqrt)r!   r"   r   r   r   r#   j   s    z1StandardDeviations._calc_stds.<locals>.<listcomp>)r-   Zdiag)r   r   rP   r   r   r   rO   g   s    zStandardDeviations._calc_stdsc       	      C   s   t dd | jD }d}d}x`t| jD ]R\}}||d krr| j| }|||d|t|  tt||7 }q(|d7 }q(W |	 S )Nc             S   s   g | ]}t |qS r   )r    )r!   r"   r   r   r   r#   n   s    z-StandardDeviations.pprint.<locals>.<listcomp>zstandard deviations
z{0}{1}| {2}
r   r%   z...)
r(   r   r)   rP   r+   r    r>   r-   r.   r/   )	r   r0   r1   r2   r3   r4   r5   Zstdr7   r   r   r   r8   m   s    
zStandardDeviations.pprintc             C   s   | j dddS )Nr9   r:   )r0   r1   )r8   )r   r   r   r   r;   {   s    zStandardDeviations.__repr__c             C   s:   t |tr| j|}nt |tr(|}ntd| j| S )Nz?Standard deviation can be indexed by parameter name or integer.)r=   r>   r   rD   rA   rE   rP   )r   r7   r5   r   r   r   rI   ~   s    

zStandardDeviations.__getitem__N)	rJ   rK   rL   rM   r   rO   r8   r;   rI   r   r   r   r   rN   `   s   rN   c               @   s   e Zd ZdZdS )r   zBase class for model exceptionsN)rJ   rK   rL   rM   r   r   r   r   r      s   c               @   s   e Zd ZdZdS )r   z= Raised when a non-linear model is passed to a linear fitter.N)rJ   rK   rL   rM   r   r   r   r   r      s   c               @   s   e Zd ZdZdS )UnsupportedConstraintErrorzE
    Raised when a fitter does not support a type of constraint.
    N)rJ   rK   rL   rM   r   r   r   r   rR      s   rR   c                   s&   e Zd ZdZe Z fddZ  ZS )_FitterMetazD
    Currently just provides a registry for all Fitter classes.
    c                s6   t  | |||}t|s2|ds2| j| |S )N_)super__new__inspect
isabstract
startswithregistryadd)mclsnamebasesmemberscls)	__class__r   r   rV      s    z_FitterMeta.__new__)rJ   rK   rL   rM   setrZ   rV   __classcell__r   r   )ra   r   rS      s   rS   c                s   t  d fdd	}|S )a&  
    This is a decorator that can be used to add support for dealing with
    quantities to any __call__ method on a fitter which may not support
    quantities itself. This is done by temporarily removing units from all
    parameters then adding them back once the fitting has completed.
    Nc                s  | dd }t|tp(t|tp(t|t}|j}|s:|r|jrt|j||j}	|jd k	rt|tr|j	|j|jd  |	|jd  d}t|tr|d k	r|j	|j|jd  |	|jd  d}|jd |i}
|d k	r||
|j
d < ||
|jd < n||
|j
d < d |
d< |jf |
}d}t|tr2d}|j}n
t|}t|trTd}|j}n
t|}|d k	rt|trd}|j}n
t|}|d kr | |||f|}n | ||||f|}|r|jf |
}|S tdn | |||fd|i|S d S )	Nequivalenciesr   )rd   r   zFTz9This model does not support being fit to data with units.)popr=   r   Z
_has_unitsZ_supports_unit_fittingr	   inputsinput_units_equivalenciesZinput_unitstooutputsZwithout_units_for_datavaluer-   asarrayZwith_units_from_dataNotImplementedError)r   modelr"   yre   kwargsrd   Zdata_has_unitsZmodel_has_unitsrh   Zrename_dataZadd_back_unitsZxdataZydataZzdataZ	model_new)funcr   r   wrapper   sZ    











z$fitter_unit_support.<locals>.wrapper)N)r   )rq   rr   r   )rq   r   fitter_unit_support   s    Yrs   c               @   s>   e Zd ZdZg Zdd Zdd Zedd Ze	j
dd	 Zd
S )r   z
    Base class for all fitters.

    Parameters
    ----------
    optimizer : callable
        A callable implementing an optimization algorithm
    statistic : callable
        Statistic function

    c             C   sl   |d krt d|d kr t dt|r4| | _nt|rF|| _nt dt|rb| | _n|| _d S )NzExpected an optimizer.zExpected a statistic function.z8Expected optimizer to be a callable class or a function.)rB   rW   isclass_opt_method
isfunction_stat_method)r   	optimizer	statisticr   r   r   r     s    




zFitter.__init__c             G   s8   |d }|d }t || | j||f|dd  }|S )a  
        Function to minimize.

        Parameters
        ----------
        fps : list
            parameters returned by the fitter
        args : list
            [model, [other_args], [input coordinates]]
            other_args may include weights or any other quantities specific for
            a statistic

        Notes
        -----
        The list of arguments (args) is set in the `__call__` method.
        Fitters may overwrite this method, e.g. when statistic functions
        require other arguments.

        r   r   )_fitter_to_model_paramsrw   )r   fpsargsrn   measresr   r   r   objective_function*  s
    
zFitter.objective_functionc              G   s   dS )z
        When available, calculate and sets the parameter covariance matrix
        (model.cov_matrix) and standard deviations (model.stds).
        Nr   )r}   r   r   r   _add_fitting_uncertaintiesD  s    z!Fitter._add_fitting_uncertaintiesc             C   s   t ddS )z
        This method performs the actual fitting and modifies the parameter list
        of a model.
        Fitter subclasses should implement this method.
        z(Subclasses should implement this method.N)rm   )r   r   r   r   __call__L  s    zFitter.__call__N)rJ   rK   rL   rM   supported_constraintsr   r   staticmethodr   abcabstractmethodr   r   r   r   r   r   
  s   )	metaclassc               @   s`   e Zd ZdZdgZdZdddZedd Zdd
dZ	edddZ
dddZedddZd	S )r   a^  
    A class performing a linear least square fitting.
    Uses `numpy.linalg.lstsq` to do the fitting.
    Given a model and data, fits the model to the data and changes the
    model's parameters. Keeps a dictionary of auxiliary fitting information.
    Notes
    -----
    Note that currently LinearLSQFitter does not support compound models.
    fixedTFc             C   s   d d d d d| _ || _d S )N)	residualsranksingular_valuesrF   )fit_info_calc_uncertainties)r   calc_uncertaintiesr   r   r   r   h  s
    
zLinearLSQFitter.__init__c             C   s6   | j d | j d krdS tj| | j d k r2dS dS )z+Check if inverse of matrix can be obtained.r   r   FT)shaper-   linalgZmatrix_rank)mr   r   r   _is_invertiblep  s
    zLinearLSQFitter._is_invertibleNc          	      s  t |j|}dpt|d}	| |s*S t j||dkr"tdkrd}
|	rZ|j}
t j	j
||
d}d| |  | g}tdkr g }xttD ]|}d}
|	r|jd|f  }
t j	j
||
d}|dd}t |j| }|d| |  t |d|f | d   qW ntdkrd}
|	rJtd	t dS t j	j
||
dt j	j
||
d }}dt||  | g}n|g }xvttD ]f}||dd}d}
jdkrt |d}|| }|dt||  t || | d  g qW fd
d|D }fddjD  t|dkrXt|d j_t|d  _n(fdd|D _ fdd|D _dS )z
        Calculate and parameter covariance matrix and standard deviations
        and set `cov_matrix` and `stds` attributes.
        FmaskNr   )r   .)model_set_axisr<   z_Calculation of fitting uncertainties for 2D models with masked values not currently supported.
c                s   g | ]} | qS r   r   )r!   r)inv_x_dot_x_primer   r   r#     s    z>LinearLSQFitter._add_fitting_uncertainties.<locals>.<listcomp>c                s,   g | ]$} j | d kr j| d kr|qS )F)r   tied)r!   r"   )rn   r   r   r#     s    r   c                s   g | ]}t | jqS r   )r   r   )r!   cov)rn   r   r   r#     s    c                s   g | ]}t | qS r   )rN   )r!   r   )free_param_namesr   r   r#     s    )r-   dotThasattrr   r   invr    r   maarraycountrangeflattenrollaxisr   appendsumwarningswarnr   r   r   r   r   rN   rP   )r   rn   aZn_coeffr"   ro   re   residsZx_dot_x_primemaskedr   ZxxZRSSjZeval_yyyZeval_zZcovsr   )r   r   rn   r   r   y  sZ    

6"4z*LinearLSQFitter._add_fitting_uncertaintiesc             C   sZ   |d kr"t | j|f| j }nt | j||f| j }| jrJ|| S |d|f S d S )N.)r-   r   	fit_deriv
parameterscol_fit_deriv)rn   Zparam_indicesr"   ro   dr   r   r   _deriv_with_constraints  s    z'LinearLSQFitter._deriv_with_constraintsc             C   s  |dkr\t |dr.|jdkr.| | g|_t |drL|jdkrLddg|_t||j|jS t |dr|jdkr| | g|_t |dr|jdkr| | g|_t |dr|jdkrd	d
g|_t |dr|j	dkrd	d
g|_	t||j|j}t||j|j	}||fS dS )zd
        Maps domain into window for a polynomial model which has these
        attributes.
        Ndomainwindowrz   r   x_domainy_domainx_windowg      g      ?y_window)
r   r   minr(   r   r   r   r   r   r   )r   rn   r"   ro   ZxnewZynewr   r   r   _map_domain_window  s"    


z"LinearLSQFitter._map_domain_windowc          	      s  |j std|jstdt|dr.tdt| j| | d_t	\} j
dkrn|dkrntdt|||tjd	}tj }	|dk	rtj|td
}|	r fddttjD }
tfdd|
D }t|dkr|\}}|dk	r.t|||j|jkrtndjd	\}}tdrF| |}|	rtt| j |d}| j|
|d}ntj|fj }|}|}n|\}}}|dk	rt||||j|jkrtndjd	\}}}tdr | ||\}}|	r2t| j ||d}| j|
||d}ntj||fj }||}tdkrjppd}|jdkrt|||j}|d|jd }n|dkr|j n|}|dk	r8|jdkrt|||j}|d|jd }n,|j|jkr|dkr|j n|}n|! }n|! }|dk	r8|! }j"rLt|j }t|jdkrrtd#t$j%|	rj"rt|j }||&| }|dk	rtdkr|dtj'f }|| }|dk	rb|jdkrD|j|jkr|dtj'f |ddtj'f  }|| }n,||ddtj'f 9 }||ddtj'f  }n||ddtj'f 9 }|| }|| (d}|| }ttj)*|}|dk	r|stt+|rtdd}|rtdks|dk	r|jdkrtj,|jdd |jdd  |j-d
}|jdkr&t|dd}nt.||jdd |j }xt/||j |j D ]f\}}}|rl|j0 nt1d}|| }|| dtj'f }|}tj23|||\}}}}|j |dd< qTW n>|r|j0 nt1d}|| }tj23|| || |\}}}}|| j4d< || j4d< || j4d< ||j|jk r>|ddtj'f n| }|| j4d< t5|!  tdrtdkr|	s|j6krt78dt9 | j:rt|t|kr| ;|| t||||| d_S )a  
        Fit data to this model.

        Parameters
        ----------
        model : `~astropy.modeling.FittableModel`
            model to fit to x, y, z
        x : array
            Input coordinates
        y : array-like
            Input coordinates
        z : array-like, optional
            Input coordinates.
            If the dependent (``y`` or ``z``) co-ordinate values are provided
            as a `numpy.ma.MaskedArray`, any masked points are ignored when
            fitting. Note that model set fitting is significantly slower when
            there are masked points (not just an empty mask), as the matrix
            equation has to be solved for each model separately when their
            co-ordinate grids differ.
        weights : array, optional
            Weights for fitting.
            For data with Gaussian uncertainties, the weights should be
            1/sigma.
        rcond :  float, optional
            Cut-off ratio for small singular values of ``a``.
            Singular values are set to zero if they are smaller than ``rcond``
            times the largest singular value of ``a``.
        equivalencies : list or None, optional, keyword-only
            List of *additional* equivalencies that are should be applied in
            case x, y and/or z have units. Default is None.

        Returns
        -------
        model_copy : `~astropy.modeling.FittableModel`
            a copy of the input model with parameters set by the fitter

        z)Model must be a subclass of FittableModelzIModel is not linear in parameters, linear fit methods should not be used.Zsubmodel_namesz"Model must be simple, not compoundFr<   Nz.Expected x, y and z for a 2 dimensional model.)n_modelsr   )dtypec                s   g | ]}| kr|qS r   r   )r!   idx)fitparam_indicesr   r   r#   +  s    z,LinearLSQFitter.__call__.<locals>.<listcomp>c                s   g | ]}t   j| jqS r   )getattrr   rk   )r!   r   )
model_copyr   r   r#   2  s   r   r   )r"   r   )r"   ro   r   rz   z7{} gives unsupported >2D derivative matrix for this x/y.zFound NaNs in the coefficient matrix, which should not happen and would crash the lapack routine. Maybe check that weights are not null.r   r   r   rF   _orderz"The fit may be poorly conditioned
T)<fittablerB   linearr   r   _validate_constraintsr   copysync_constraints_model_to_fit_paramsn_inputs_convert_inputr    r   anyr   valuesr-   rl   floatr   r   ndimr   r   r   r   sum_of_implicit_terms
asanyarrayr   Zreshaper   r   r   r   r+   typerJ   r   Znewaxisr   r   ZgetmaskisnanZzerosr   Zbroadcast_tozipr   slicer   Zlstsqr   r{   r   r   r   r   r   r   )r   rn   r"   ro   re   weightsZrcondrT   farg	has_fixedZfixparam_indicesZ	fixparamslhsZ	fixderivsr   rhsZ
model_axisZsclr   r   ZlacoefZ	lhs_stackZ	model_lhsZ	model_rhsZmodel_lacoefgoodZt_coefr   r   Zsvalr   )r   r   r   r     s
   (















 
"
(	


(
zLinearLSQFitter.__call__)F)NN)NN)N)NNN)rJ   rK   rL   rM   r   supports_masked_inputr   r   r   r   r   r   rs   r   r   r   r   r   r   Z  s   	
	 
C
c               @   s4   e Zd ZdZdddZdd Zdd Zdd
dZd	S )r   a  
    This class combines an outlier removal technique with a fitting procedure.
    Basically, given a maximum number of iterations ``niter``, outliers are
    removed and fitting is performed for each iteration, until no new outliers
    are found or ``niter`` is reached.

    Parameters
    ----------
    fitter : `Fitter`
        An instance of any Astropy fitter, i.e., LinearLSQFitter,
        LevMarLSQFitter, SLSQPLSQFitter, SimplexLSQFitter, JointFitter. For
        model set fitting, this must understand masked input data (as
        indicated by the fitter class attribute ``supports_masked_input``).
    outlier_func : callable
        A function for outlier removal.
        If this accepts an ``axis`` parameter like the `numpy` functions, the
        appropriate value will be supplied automatically when fitting model
        sets (unless overridden in ``outlier_kwargs``), to find outliers for
        each model separately; otherwise, the same filtering must be performed
        in a loop over models, which is almost an order of magnitude slower.
    niter : int, optional
        Maximum number of iterations.
    outlier_kwargs : dict, optional
        Keyword arguments for outlier_func.

    Attributes
    ----------
    fit_info : dict
        The ``fit_info`` (if any) from the last iteration of the wrapped
        ``fitter`` during the most recent fit. An entry is also added with the
        keyword ``niter`` that records the actual number of fitting iterations
        performed (as opposed to the user-specified maximum).
    r:   c             K   s&   || _ || _|| _|| _dd i| _d S )Nniter)fitteroutlier_funcr   outlier_kwargsr   )r   r   r   r   r   r   r   r   r   :  s
    z"FittingWithOutlierRemoval.__init__c             C   s   d | jjj| jj| j| jS )NzRFitter: {0}
Outlier function: {1}
Num. of iterations: {2}
Outlier func. args.: {3})r+   r   ra   rJ   r   r   r   )r   r   r   r   __str__A  s    
z!FittingWithOutlierRemoval.__str__c             C   s$   d | jj| jjj| jj| j| jS )NzD{0}(fitter: {1}, outlier_func: {2}, niter: {3}, outlier_kwargs: {4}))r+   ra   rJ   r   r   r   r   )r   r   r   r   r;   H  s
    
z"FittingWithOutlierRemoval.__repr__Nc          
      s  t |dkrdn4t| jdr*| jjdk	r@tdt| jj|j|dkrZ|f}|}n||f}|}dk	rdk r|j	7 d| j
krtfdd	t|j	D | j
d< d
}	| j||||fd|i|}
tj|}|jtjjkrd
|_|}|j }d}xtd| jd D ]}|
|dd
i}|	sy| j|| f| j
}W n tk
r   dkrd n`| j
dd d}	tjj|t||dd}|jtjjkrd
|_t|d}t|jd}Y nX |	r:t|d}xNt|||D ]>\}}}| j|| f| j
}|j|jdd< |j|dd< qW tdt ||7 }dkr|j  |dk	rf|  }| j|
f fdd	|D |j  fd|i|}
n| j|
f||fd|i|}
|j }||krP |}qW d|i| _| jt | jdi  |
|jfS )a  
        Parameters
        ----------
        model : `~astropy.modeling.FittableModel`
            An analytic model which will be fit to the provided data.
            This also contains the initial guess for an optimization
            algorithm.
        x : array-like
            Input coordinates.
        y : array-like
            Data measurements (1D case) or input coordinates (2D case).
        z : array-like, optional
            Data measurements (2D case).
        weights : array-like, optional
            Weights to be passed to the fitter.
        kwargs : dict, optional
            Keyword arguments to be passed to the fitter.
        Returns
        -------
        fitted_model : `~astropy.modeling.FittableModel`
            Fitted model after outlier removal.
        mask : `numpy.ndarray`
            Boolean mask array, identifying which points were used in the final
            fitting iteration (False) and which were found to be outliers or
            were masked in the input (True).
        r   Nr   Tz+{} cannot fit model sets with masked valuesr   Zaxisc             3   s   | ]}| kr|V  qd S )Nr   )r!   n)r   r   r   r@     s    z5FittingWithOutlierRemoval.__call__.<locals>.<genexpr>Fr   r   )r   r   zMoutlier_func did not accept axis argument; reverted to slow loop over models.c             3   s   | ]}|  V  qd S )Nr   )r!   c)r   r   r   r@     s    r   r   )!r    r   r   r   rB   r+   r   rJ   r   r   r   tupler   r-   r   Zmasked_arrayr   Znomaskr   r   r   rE   rf   Zresult_typer   r   datar   r   r   r   updater   )r   rn   r"   ro   re   r   rp   Zcoordsr   loopZfitted_modelZfiltered_dataZfiltered_weightsZlast_n_maskedr   Z
model_valsZdata_TZmask_TZmodel_vals_TZrow_dataZrow_maskZrow_mod_valsZmasked_residualsZthis_n_maskedr   )r   r   r   r   P  s    &

 









z"FittingWithOutlierRemoval.__call__)r:   )NN)rJ   rK   rL   rM   r   r   r;   r   r   r   r   r   r     s
   !
c                   sh   e Zd ZdZdddgZd fdd	Zdd	 Zed
d Ze	dde
eedfddZedddZ  ZS )r   a  
    Levenberg-Marquardt algorithm and least squares statistic.

    Attributes
    ----------
    fit_info : dict
        The `scipy.optimize.leastsq` result for the most recent fit (see
        notes).

    Notes
    -----
    The ``fit_info`` dictionary contains the values returned by
    `scipy.optimize.leastsq` for the most recent fit, including the values from
    the ``infodict`` dictionary it returns. See the `scipy.optimize.leastsq`
    documentation for details on the meaning of these values. Note that the
    ``x`` return value is *not* included (as it is instead the parameter values
    of the returned model).
    Additionally, one additional element of ``fit_info`` is computed whenever a
    model is fit, with the key 'param_cov'. The corresponding value is the
    covariance matrix of the parameters as a 2D numpy array.  The order of the
    matrix elements matches the order of the parameters in the fitted model
    (i.e., the same order as ``model.param_names``).

    r   r   boundsFc          
      s.   d d d d d d d d d d	| _ || _t   d S )N)	ZnfevZfvecZfjacZipvtZqtfmessageierrZ	param_jac	param_cov)r   r   rU   r   )r   r   )ra   r   r   r     s    
zLevMarLSQFitter.__init__c             G   sf   |d }|d }t || |d }|dkrDt||dd  | S t|||dd  |  S dS )z
        Function to minimize.

        Parameters
        ----------
        fps : list
            parameters returned by the fitter
        args : list
            [model, [weights], [input coordinates]]

        r   r   rz   Nr<   )r{   r-   ravel)r   r|   r}   rn   r   r~   r   r   r   r   )  s    
z"LevMarLSQFitter.objective_functionc                s0    fdd j D }t|| _t|| _dS )z
        Set ``cov_matrix`` and ``stds`` attributes on model with parameter
        covariance matrix returned by ``optimize.leastsq``.
        c                s,   g | ]$} j | d kr j| d kr|qS )F)r   r   )r!   r"   )rn   r   r   r#   F  s    z>LevMarLSQFitter._add_fitting_uncertainties.<locals>.<listcomp>N)r   r   r   rN   rP   )rn   r   r   r   )rn   r   r   ?  s    z*LevMarLSQFitter._add_fitting_uncertaintiesNc
             C   sf  ddl m}
 t|| j}d|_||ft||| }|jdks@|	rFd}n| j}t|\}}|
j	| j
||||j|||dd	\}}}}}t|| | j| || jd< || jd< || jd	< |d
krtdt t|t|kr$|dk	r$t| j
|f| d }t|t| }|| | | jd< n
d| jd< | jdkr\| jd dk	r\| || jd  d|_|S )a  
        Fit data to this model.

        Parameters
        ----------
        model : `~astropy.modeling.FittableModel`
            model to fit to x, y, z
        x : array
           input coordinates
        y : array
           input coordinates
        z : array, optional
           input coordinates
        weights : array, optional
            Weights for fitting.
            For data with Gaussian uncertainties, the weights should be
            1/sigma.
        maxiter : int
            maximum number of iterations
        acc : float
            Relative error desired in the approximate solution
        epsilon : float
            A suitable step length for the forward-difference
            approximation of the Jacobian (if model.fjac=None). If
            epsfcn is less than the machine precision, it is
            assumed that the relative errors in the functions are
            of the order of the machine precision.
        estimate_jacobian : bool
            If False (default) and if the model has a fit_deriv method,
            it will be used. Otherwise the Jacobian will be estimated.
            If True, the Jacobian will be estimated in any case.
        equivalencies : list or None, optional, keyword-only
            List of *additional* equivalencies that are should be applied in
            case x, y and/or z have units. Default is None.

        Returns
        -------
        model_copy : `~astropy.modeling.FittableModel`
            a copy of the input model with parameters set by the fitter

        r   )optimizeFNT)r}   ZDfunZ	col_derivZmaxfevZepsfcnZxtolZfull_outputcov_xr   r   )r   r<   r:      zLThe fit may be unsuccessful; check fit_info['message'] for more information.r<   r   )scipyr   _validate_modelr   r   r   r   _wrap_derivr   leastsqr   r   r{   r   r   r   r   r   r    r-   r   r   r   )r   rn   r"   ro   re   r   maxiteraccepsilonZestimate_jacobianr   r   r   Zdfuncinit_valuesrT   	fitparamsr   ZdinfoZmessr   Zsum_sqrsZdofr   r   r   r   L  s>    .





zLevMarLSQFitter.__call__c                sT  |dkrd}t  j s*t  j rdt |  |dkr|t j|f j } j	slt
||j }qt
|| }nJtdd  j||f j D } j	st
||j }nt
|| } fdd jD }dd |D }	dd |D }
ttdd |D d	|
}
t|	|
}t|} j	sHt|t| j}n|t| }d
d |D S |dkry0tdd t|t j|f|   D S  tk
r   tdd t|tt j|f|  dd D  S X n^ j	s*dd t
|t j||f|  j jD S dd |t j||f|   D S dS )au  
        Wraps the method calculating the Jacobian of the function to account
        for model constraints.
        `scipy.optimize.leastsq` expects the function derivative to have the
        above signature (parlist, (argtuple)). In order to accommodate model
        constraints, instead of using p directly, we set the parameter list in
        this function.
        Ng      ?c             S   s   g | ]}t |qS r   )r-   r   )r!   rT   r   r   r   r#     s    z/LevMarLSQFitter._wrap_deriv.<locals>.<listcomp>c                s   g | ]}t  |qS r   )r   )r!   r]   )rn   r   r   r#     s    c             S   s   g | ]
}|j qS r   )r   )r!   parr   r   r   r#     s    c             S   s   g | ]
}|j qS r   )r   )r!   r   r   r   r   r#     s    c             S   s   g | ]}|j d k	qS )F)r   )r!   r   r   r   r   r#     s    Tc             S   s   g | ]}t |qS r   )r-   r   )r!   rT   r   r   r   r#     s    c             S   s   g | ]}t |qS r   )r-   r   )r!   rT   r   r   r   r#     s    c             S   s   g | ]}t |qS r   )r-   r   )r!   rT   r   r   r   r#     s    rz   r   c             S   s   g | ]}t |qS r   )r-   r   )r!   rT   r   r   r   r#     s    c             S   s   g | ]}t |qS r   )r-   r   )r!   rT   r   r   r   r#     s    )r   r   r   r   r{   r-   r   r   r   r   r   r   r   listwhere
logical_orZlogical_notrl   ZnonzerorB   ZmoveaxisZ	transpose)rF   rn   r   r"   ro   re   fullZ
full_derivZparsr   r   Zfix_and_tieindZresiduesr   )rn   r   r     sJ    
$


*zLevMarLSQFitter._wrap_deriv)F)N)rJ   rK   rL   rM   r   r   r   r   r   rs   r   r   r   r   r   rc   r   r   )ra   r   r     s   
Sc                   s4   e Zd ZdZejZ fddZedddZ  Z	S )r   a,  
    Sequential Least Squares Programming (SLSQP) optimization algorithm and
    least squares statistic.

    Raises
    ------
    ModelLinearityError
        A linear model is passed to a nonlinear fitter

    Notes
    ------
    See also the `~astropy.modeling.optimizers.SLSQP` optimizer.

    c                s   t  jttd i | _d S )N)rx   ry   )rU   r   r
   r   r   )r   )ra   r   r   r     s    zSLSQPLSQFitter.__init__Nc             K   sf   t || jj}d|_t|||}||f| }t|\}	}
| j| j|	|f|\}| _t|| d|_|S )a  
        Fit data to this model.

        Parameters
        ----------
        model : `~astropy.modeling.FittableModel`
            model to fit to x, y, z
        x : array
            input coordinates
        y : array
            input coordinates
        z : array, optional
            input coordinates
        weights : array, optional
            Weights for fitting.
            For data with Gaussian uncertainties, the weights should be
            1/sigma.
        kwargs : dict
            optional keyword arguments to be passed to the optimizer or the statistic
        verblevel : int
            0-silent
            1-print summary upon completion,
            2-print summary after each iteration
        maxiter : int
            maximum number of iterations
        epsilon : float
            the step size for finite-difference derivative estimates
        acc : float
            Requested accuracy
        equivalencies : list or None, optional, keyword-only
            List of *additional* equivalencies that are should be applied in
            case x, y and/or z have units. Default is None.

        Returns
        -------
        model_copy : `~astropy.modeling.FittableModel`
            a copy of the input model with parameters set by the fitter

        FT)	r   ru   r   r   r   r   r   r   r{   )r   rn   r"   ro   re   r   rp   r   r   r   rT   r   r   r   r   r     s    *
zSLSQPLSQFitter.__call__)NN)
rJ   rK   rL   rM   r
   r   r   rs   r   rc   r   r   )ra   r   r     s
   c                   s4   e Zd ZdZejZ fddZedddZ  Z	S )r   z
    Simplex algorithm and least squares statistic.

    Raises
    ------
    `ModelLinearityError`
        A linear model is passed to a nonlinear fitter

    c                s   t  jttd i | _d S )N)rx   ry   )rU   r   r   r   r   )r   )ra   r   r   r   9  s    zSimplexLSQFitter.__init__Nc             K   sf   t || jj}d|_t|||}||f| }t|\}	}
| j| j|	|f|\}| _t|| d|_|S )a9  
        Fit data to this model.

        Parameters
        ----------
        model : `~astropy.modeling.FittableModel`
            model to fit to x, y, z
        x : array
            input coordinates
        y : array
            input coordinates
        z : array, optional
            input coordinates
        weights : array, optional
            Weights for fitting.
            For data with Gaussian uncertainties, the weights should be
            1/sigma.
        kwargs : dict
            optional keyword arguments to be passed to the optimizer or the statistic
        maxiter : int
            maximum number of iterations
        acc : float
            Relative error in approximate solution
        equivalencies : list or None, optional, keyword-only
            List of *additional* equivalencies that are should be applied in
            case x, y and/or z have units. Default is None.

        Returns
        -------
        model_copy : `~astropy.modeling.FittableModel`
            a copy of the input model with parameters set by the fitter

        FT)	r   ru   r   r   r   r   r   r   r{   )r   rn   r"   ro   re   r   rp   r   r   r   rT   r   r   r   r   r   =  s    $

zSimplexLSQFitter.__call__)NN)
rJ   rK   rL   rM   r   r   r   rs   r   rc   r   r   )ra   r   r   ,  s
   	c               @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )r   aH  
    Fit models which share a parameter.
    For example, fit two gaussians to two data sets but keep
    the FWHM the same.

    Parameters
    ----------
    models : list
        a list of model instances
    jointparameters : list
        a list of joint parameters
    initvals : list
        a list of initial values

    c             C   sP   t || _t || _|| _|   |  | _dd | jD | _t	| j| _
d S )Nc             S   s   g | ]
}|j qS r   )r   )r!   r   r   r   r   r#     s    z(JointFitter.__init__.<locals>.<listcomp>)r   modelsinitvalsjointparams_verify_inputr   r   	modeldimsr-   r   r   )r   r   Zjointparametersr   r   r   r   r     s    


zJointFitter.__init__c             C   sh   g }| | j xR| jD ]H}|j }| j| }|j}x|D ]}|| d }||= q<W | | qW |S )Nr   )extendr   r   r   tolistr   _param_metrics)r   fparamsrn   rF   joint_paramsparam_metrics
param_nameslice_r   r   r   r     s    



z JointFitter._model_to_fit_paramsc             G   s>  t |}g }t |}t| j}|d| }|d|= x| jD ]}| j| }	|d|jd  }
|d|jd = t|jt|	 }|d| }|d|= g }|j}xf|jD ]\}||	kr|		|}|
|| g q|| d }|j|j }|
|d|  |d|= qW |j|
dd f| }|
||
d   q<W t|S )aQ  
        Function to minimize.

        Parameters
        ----------
        fps : list
            the fitted parameters - result of an one iteration of the
            fitting algorithm
        args : dict
            tuple of measured and input coordinates
            args is always passed as a tuple from optimize.leastsq

        Nr   r   rz   )r   r    r   r   r   r   _parametersr  r   rD   r  stopstartevaluater-   r   )r   r|   r}   Z	lstsqargsZfittedr   numjpjointfitparamsrn   r  Zmargsnumfpmfparamsmparamsr  r  rD   r  plenZmodelfitr   r   r   r     s4    




zJointFitter.objective_functionc             C   s   t | jdkr$tdt | j dt | j dk rNtdt | j xJ| j D ]<}t | j| t | jkrZtdt | j| t | jqZW d S )Nr   zExpected >1 models, z	 is givenr<   z1At least two parameters are expected, {} is givenz({} parameter(s) provided but {} expected)r    r   rE   r   keysr+   r   )r   r   r   r   r   r     s    zJointFitter._verify_inputc             G   sZ  ddl m} t|tdd | jkrDtdtdd | jt||j| j| j	|d\| j	dd< }| j	dd }t| j
}|d| }|d|= x| jD ]}| j| }t|jt| }	|d|	 }
|d|	= g }|j}xh|jD ]^}||kr||}||| g q|| d	 }|j|j }||
d|  |
d|= qW t||_qW dS )
zk
        Fit data to these models keeping some of the parameters common to the
        two models.
        r   )r   c             S   s   | d | d S )Nr   r   )r"   ro   r   r   r   <lambda>      z&JointFitter.__call__.<locals>.<lambda>z/Expected {} coordinates in args but {} providedc             S   s   | d | d S )Nr   r   )r"   ro   r   r   r   r    r  )r}   Nr   )r   r   r    r   r   rB   r+   r   r   r   r   r   r   r	  r  r   rD   r  r
  r  r-   r   r   )r   r}   r   rT   r  r  r  rn   r  r  r  r  r  r  rD   r  r  r   r   r   r     s6    





zJointFitter.__call__N)	rJ   rK   rL   rM   r   r   r   r   r   r   r   r   r   r   p  s   2c             C   s*  t j| td} t j|td}|dk	rBt j|td}|j|j }}n|j|j }}|dksb|| jkr|phd|krvtd|| |krtd|dkrt |||j}|jdd }n |jd| |j|d d  }|dkr|| jkrtd| |f}n0| j|j  kr|ksn td	| ||f}|S )
zConvert inputs to float arrays.)r   Nr   r   zmodel_set_axis out of rangezTNumber of data sets (y or z array) is expected to equal the number of parameter setsrz   z"x and y should have the same shapez%x, y and z should have the same shape)r-   r   r   r   r   rB   r   )r"   ro   re   r   r   Z	data_ndimZ
data_shaper   r   r   r   r     s2    	


r   c             C   s  t | \}}t| j }t| j }tdd | j D }| j}|s\|s\|s\|| _dS t|}d}| j}	xt	| j
D ]\}
}|
|krqz|	| d }|	| d }ttj|d}||||  }| j| dkr
| j| \}}|dk	rt||}|dk	r
t||}|||< ||7 }qzW |   |r|xNt	| j
D ]@\}
}| j| r8| j| | }|	| d }|||< |   q8W dS )	zf
    Constructs the full list of model parameters from the fitted and
    constrained parameters.
    c             s   s   | ]}|d kV  qdS ))NNNr   )r!   br   r   r   r@   H  s    z*_fitter_to_model_params.<locals>.<genexpr>Nr   r   r   r   )NN)r   r   r   r   r   r   r   rb   r  r)   r   r   operatormulr-   ZfmaxZfminZ_array_to_parameters)rn   r|   rT   Zfit_param_indicesZhas_tiedr   Z	has_boundr   offsetr  r   r]   r  r   sizer   _min_maxrk   r   r   r   r{   >  sD    
r{   c             C   s   t tt| j}t| j s.t| j rt | j}| j	}xPt t
| jddd D ]4\}}| j| st| j| rX|| d }||= ||= qXW t||fS | j|fS )aO  
    Convert a model instance's parameter array to an array that can be used
    with a fitter that doesn't natively support fixed or tied parameters.
    In particular, it removes fixed/tied parameters from the parameter
    array.
    These may be a subset of the model parameters, if some of them are held
    constant or tied.
    Nrz   r   )r   r   r    r   r   r   r   r   r   r  r)   r-   r   )rn   r   rF   r  r   r]   r  r   r   r   r   }  s    

"
r   c             C   s   d}t |j r(d| kr(t|dt |j rLd| krLt|dt dd |j D rzd| krzt|d	|jrd
| krt|d|jrd| krt|ddS )z@Make sure model constraints are supported by the current fitter.z(Optimizer cannot handle {0} constraints.r   zfixed parameterr   ztied parameterc             s   s   | ]}t |d kV  qdS ))NNN)r   )r!   r  r   r   r   r@     s    z(_validate_constraints.<locals>.<genexpr>r   zbound parametereqconsZequalityineqconsZ
inequalityN)	r   r   r   rR   r+   r   r   r  r  )r   rn   r   r   r   r   r     s     r   c             C   sL   | j std| jr"tdt nt| dkr6tdt||  |  }|S )zT
    Check that model and fitter are compatible and return a copy of the model.
    z%Model does not appear to be fittable.zEModel is linear in parameters; consider using linear fitting methods.r   z7Non-linear fitters can only fit one data set at a time.)	r   rB   r   r   r   r   r    r   r   )rn   r   r   r   r   r   r     s    
r   c             C   s   x| D ]}|j }y| }W nB tk
r^ } z$ttt|j d| d W dd}~X Y qX t	|sttd| d qt
|tr|j}|t |< t| qttd| qW dS )aY  
    This injects entry points into the `astropy.modeling.fitting` namespace.
    This provides a means of inserting a fitting routine without requirement
    of it being merged into astropy's core.

    Parameters
    ----------
    entry_points : list of `~importlib.metadata.EntryPoint`
        entry_points are objects which encapsulate importable objects and
        are defined on the installation of a package.

    Notes
    -----
    An explanation of entry points can be found `here <http://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins>`
    z error occurred in entry point .NzModeling entry point z expected to be a Class.zBModeling entry point {} expected to extend astropy.modeling.Fitter)r]   load	Exceptionr   r   r   r   rJ   rW   rt   
issubclassr   globals__all__r   r+   )r   entry_pointr]   er   r   r   populate_entry_points  s"    
,


r'  c              C   s6   t  } t| dr"t| jdd nt| dg  d S )Nselectzastropy.modeling)group)r   r   r'  r(  get)epr   r   r   _populate_ep  s    
r,  )Nr   r   )8rM   r   rW   r  r   importlib.metadatar   ImportErrorimportlib_metadata	functoolsr   r   numpyr-   Zastropy.unitsr   Zastropy.utils.exceptionsr   utilsr   r	   Z
optimizersr
   r   ry   r   r   r   r   r$  Z
STATISTICSZ
OPTIMIZERSr   rN   r!  r   r   rB   rR   ABCMetarS   rs   r   r   r   r   r   r   r   r   r{   r   r   r   r'  r,  r   r   r   r   <module>   sb   &(dP   @ g cMD 
9?(	