B
    q\                 @   s  d Z ddlZddlZddlZddlZddlmZmZ ddlZ	ddl
mZmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ ydd
lmZ dZW n ek
r   dZY nX dddddddgZegZeegZddlmZmZm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 Z.d5d'd(Z/d)d* Z0d+d, Z1d-d. Z2d/d0 Z3d1d2 Z4ere4ed3dd4 dS )6a  
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)reducewraps   )poly_map_domain_combine_equivalency_dict)Quantity)AstropyUserWarning)SLSQPSimplex)leastsquare)iter_entry_pointsTFLinearLSQFitterLevMarLSQFitterFittingWithOutlierRemovalSLSQPLSQFitterSimplexLSQFitterJointFitterFitter)DEFAULT_MAXITERDEFAULT_EPSDEFAULT_ACCc               @   s   e Zd ZdZdS )ModelsErrorzBase class for model exceptionsN)__name__
__module____qualname____doc__ r   r   7lib/python3.7/site-packages/astropy/modeling/fitting.pyr   =   s   r   c               @   s   e Zd ZdZdS )ModelLinearityErrorz= Raised when a non-linear model is passed to a linear fitter.N)r   r   r   r   r   r   r   r   r   A   s   r   c               @   s   e Zd ZdZdS )UnsupportedConstraintErrorzE
    Raised when a fitter does not support a type of constraint.
    N)r   r   r   r   r   r   r   r   r   E   s   r   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__inspectZ
isabstract
startswithregistryadd)mclsnamebasesmemberscls)	__class__r   r   r#   R   s    z_FitterMeta.__new__)r   r   r   r   setr&   r#   __classcell__r   r   )r-   r   r    K   s   r    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rtt|j||j}	|jd k	rt|tr~|j	|jd |	d d}t|tr|d k	r|j	|jd |	d d}|j
|||d}d}
t|trd}
|j}n
t|}t|trd}
|j}n
t|}|d k	r(t|trd}
|j}n
t|}|d krF | |||f|}n | ||||f|}|
rp|j|||d}|S tdn | |||fd	|i|S d S )
Nequivalenciesx)r0   y)r1   r2   zFTz8This model does not support being fit to data with unitsr3   )pop
isinstancer   Z
_has_unitsZ_supports_unit_fittingr   Zinputsinput_units_equivalenciesZinput_unitstoZwithout_units_for_datavaluenpasarrayZwith_units_from_dataNotImplementedError)selfmodelr1   r2   r3   kwargsr0   Zdata_has_unitsZmodel_has_unitsr6   Zadd_back_unitsZxdataZydataZzdataZ	model_new)funcr   r   wrapperb   sJ    













z$fitter_unit_support.<locals>.wrapper)N)r   )r?   r@   r   )r?   r   fitter_unit_support[   s    QrA   c               @   s.   e Zd ZdZdd Z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.)
ValueErrorr$   isclass_opt_methodZ
isfunction_stat_method)r<   	optimizer	statisticr   r   r   __init__   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_paramsrE   )r<   fpsargsr=   measZresr   r   r   objective_function   s
    
zFitter.objective_functionc             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)r;   )r<   r   r   r   __call__   s    	zFitter.__call__N)	r   r   r   r   rH   rN   abcabstractmethodrO   r   r   r   r   r      s   
)	metaclassc               @   sH   e Zd ZdZdgZdZ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.
    fixedTc             C   s   d d d d d| _ d S )N)	residualsranksingular_valuesparams)fit_info)r<   r   r   r   rH     s    zLinearLSQFitter.__init__Nc             C   sZ   |d kr"t | j|f| j }nt | j||f| j }| jrJ|| S |d|f S d S )N.)r9   array	fit_deriv
parameterscol_fit_deriv)r=   Zparam_indicesr1   r2   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windowrI   r   x_domainy_domainx_windowg      g      ?y_window)
hasattrr_   minmaxr`   r   ra   rb   rc   rd   )r<   r=   r1   r2   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| | t\} j	dkrh|dkrhtdt
|||tjd}tj }	|	rƇ fd	d
ttjD }
tfdd
|
D }t|dkr<|\}}tdr| |}|	r| j |d}| j|
|d}nj|fj }|}|}n|\}}}tdrd| ||\}}|	r| j ||d}| j|
||d}nj||fj }||}tdkrjpd}|jdkrt|||j}|d|jd }n|dkr
|jn|}n| }jr,t|j}|jdkrLtd t!j"|	rtjrft|j}||#| }|dk	rtdkr|dtj$f }|| }|dk	r,tj|t%d}t|t|krtd|jdkr||ddtj$f 9 }||ddtj$f  }n||ddtj$f 9 }|| }|dkrLt|t&|j'j( }|| )d}|| }ttj*+|}tdks|s|r|j, nt-d}tj./|| || |\}}}}ntj0|jdd |jdd  |j'd}xdt1|j|jD ]R\}}|j, }|| }|| dtj$f }tj./|||\}}}}|j|dd< qW || j2d< || j2d< || j2d< |j| j}|| j2d< tdr|j3krt45dt6 t7|  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 and keyword-only argument
            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 compound   Nz.Expected x, y and z for a 2 dimensional model.)n_modelsmodel_set_axisc                s   g | ]}| kr|qS r   r   ).0idx)fitparam_indicesr   r   
<listcomp>{  s    z,LinearLSQFitter.__call__.<locals>.<listcomp>c                s   g | ]}t   j| jqS r   )getattrparam_namesr8   )rl   rm   )
model_copyr   r   ro     s   r_   )r1   ra   )r1   r2   r   r   rI   z8{0} gives unsupported >2D derivative matrix for this x/y.)dtypez)x and weights should have the same lengthrT   rU   rV   rW   _orderz"The fit may be poorly conditioned
)8fittablerB   linearr   re   _validate_constraintssupported_constraintscopy_model_to_fit_paramsn_inputs_convert_inputlenrk   anyrS   valuesrangerq   r9   r:   rh   r^   rZ   r[   sum_of_implicit_termsndimrollaxisZreshapeshapeTZflattenr\   formattyper   dotZnewaxisfloatZfinfors   ZepssummaZgetmaskmasksliceZlinalgZlstsqZzerosziprX   rt   warningswarnr   rJ   )r<   r=   r1   r2   r3   weightsZrcondr!   farg	has_fixedZfixparam_indicesZ	fixparamsZlhsZ	fixderivsr   ZrhsZ
model_axisZsclZmaskedgoodZlacoefZresidsrU   ZsvalZ	model_rhsZmodel_lacoefZ	model_lhsZt_coefr   )rn   rr   r   rO   :  s    '










(	



zLinearLSQFitter.__call__)NN)N)NNN)r   r   r   r   rx   supports_masked_inputrH   staticmethodr^   rh   rA   rO   r   r   r   r   r      s   
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 number of iterations ``niter``, outliers are removed
    and fitting is performed for each iteration.

    Parameters
    ----------
    fitter : An Astropy 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 : function
        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)
        Number of iterations.
    outlier_kwargs : dict (optional)
        Keyword arguments for outlier_func.
       c             K   s   || _ || _|| _|| _d S )N)fitteroutlier_funcniteroutlier_kwargs)r<   r   r   r   r   r   r   r   rH   C  s    z"FittingWithOutlierRemoval.__init__c             C   s   d | jj| jj| j| jS )NzRFitter: {0}
Outlier function: {1}
Num. of iterations: {2}
Outlier func. args.: {3})r   Zfitter__class__r   r   r   r   )r<   r   r   r   __str__I  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   r-   r   r   r   r   r   )r<   r   r   r   __repr__P  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
|_|}xt| jD ]}|
|dd
i}|	sy| j|| f| j
}W n tk
r   dkrP 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	rR|  }| j|
f fdd	|D |j  fd|i|}
q| j|
f||fd|i|}
qW |
|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,{0} cannot fit model sets with masked valuesr   Zaxisc             3   s   | ]}| kr|V  qd S )Nr   )rl   n)rk   r   r   	<genexpr>  s    z5FittingWithOutlierRemoval.__call__.<locals>.<genexpr>Fr   rk   )rs   ry   zMoutlier_func did not accept axis argument; reverted to slow loop over models.c             3   s   | ]}|  V  qd S )Nr   )rl   c)r   r   r   r     s    )r}   re   r   r   rB   r   r   r   rk   r   r   tupler   r9   r   Zmasked_arrayr   Znomaskr   r   	TypeErrorr4   Zresult_typer   r   datar   r   r   )r<   r=   r1   r2   r3   r   r>   Zcoordsr   ZloopZfitted_modelZfiltered_dataZfiltered_weightsr   Z
model_valsZdata_TZmask_TZmodel_vals_TZrow_dataZrow_maskZrow_mod_valsZmasked_residualsr   )r   rk   r   rO   X  s    '

 




z"FittingWithOutlierRemoval.__call__)r   )NN)r   r   r   r   rH   r   r   rO   r   r   r   r   r   )  s
   
c                   sZ   e Zd ZdZdddgZ fddZ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``).
    rS   tiedboundsc          
      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)rX   r"   rH   )r<   )r-   r   r   rH     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   rI   Nri   )rJ   r9   ravel)r<   rK   rL   r=   r   rM   r   r   r   rN   (  s    
z"LevMarLSQFitter.objective_functionNFc
             C   s,  ddl m}
 t|| j}||ft||| }|jdks:|	r@d}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< |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 and keyword-only argument
            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   )optimizeNT)rL   ZDfunZ	col_derivZmaxfevZepsfcnZxtolZfull_outputcov_xr   r   )r   ri   r      zLThe fit may be unsuccessful; check fit_info['message'] for more information.ri   r   )scipyr   _validate_modelrx   r|   rZ   _wrap_derivrz   leastsqrN   r\   rJ   rX   updater   r   r   r}   r9   r   )r<   r=   r1   r2   r3   r   maxiterZaccepsilonZestimate_jacobianr   rr   r   ZdfuncZinit_valuesr!   	fitparamsr   ZdinfoZmessr   Zsum_sqrsZdofr   r   r   rO   =  s2    -





zLevMarLSQFitter.__call__c                s  |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rdd t
|t j|f|   D S  j	sdd t
|t j||f|  j jD S dd |t j||f|   D S dS )av  
        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   )r9   r   )rl   r!   r   r   r   ro     s    z/LevMarLSQFitter._wrap_deriv.<locals>.<listcomp>c                s   g | ]}t  |qS r   )rp   )rl   r)   )r=   r   r   ro     s    c             S   s   g | ]
}|j qS r   )rS   )rl   parr   r   r   ro     s    c             S   s   g | ]
}|j qS r   )r   )rl   r   r   r   r   ro     s    c             S   s   g | ]}|j d k	qS )F)r   )rl   r   r   r   r   ro     s    Tc             S   s   g | ]}t |qS r   )r9   r   )rl   r!   r   r   r   ro     s    c             S   s   g | ]}t |qS r   )r9   r   )rl   r!   r   r   r   ro     s    c             S   s   g | ]}t |qS r   )r9   r   )rl   r!   r   r   r   ro     s    c             S   s   g | ]}t |qS r   )r9   r   )rl   r!   r   r   r   ro     s    )r~   rS   r   r   rJ   r9   rY   rZ   r[   r\   r   r   rq   listwhereZ
logical_orZlogical_notr:   Znonzero)rW   r=   r   r1   r2   r3   ZfullZ
full_derivZparsrS   r   Zfix_and_tieZindZresiduesr   )r=   r   r     s<    
$


**zLevMarLSQFitter._wrap_deriv)N)r   r   r   r   rx   rH   rN   rA   r   r   r   rO   r   r   r/   r   r   )r-   r   r     s   
Lc                   s4   e Zd ZdZejZ fddZedddZ  Z	S )r   z
    SLSQP optimization 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)rF   rG   )r"   rH   r	   r   rX   )r<   )r-   r   r   rH     s    zSLSQPLSQFitter.__init__Nc             K   sZ   t || jj}t|||}||f| }t|\}	}
| j| j|	|f|\}| _t|| |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 and keyword-only argument
            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   rD   rx   r|   rz   rN   rX   rJ   )r<   r=   r1   r2   r3   r   r>   rr   r   p0r!   r   r   r   r   rO     s    *
zSLSQPLSQFitter.__call__)NN)
r   r   r   r   r	   rx   rH   rA   rO   r/   r   r   )r-   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)rF   rG   )r"   rH   r
   r   rX   )r<   )r-   r   r   rH     s    zSimplexLSQFitter.__init__Nc             K   sZ   t || jj}t|||}||f| }t|\}	}
| j| j|	|f|\}| _t|| |S )aG  
        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 and keyword-only argument
            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   rD   rx   r|   rz   rN   rX   rJ   )r<   r=   r1   r2   r3   r   r>   rr   r   r   r!   r   r   r   r   rO     s    $

zSimplexLSQFitter.__call__)NN)
r   r   r   r   r
   rx   rH   rA   rO   r/   r   r   )r-   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{   )rl   mr   r   r   ro   g  s    z(JointFitter.__init__.<locals>.<listcomp>)r   modelsinitvalsjointparams_verify_inputrz   r   	modeldimsr9   r   r   )r<   r   Zjointparametersr   r   r   r   rH   _  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<   fparamsr=   rW   joint_paramsparam_metrics
param_nameslice_r   r   r   rz   k  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 )aP  
        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   rI   )r   r}   r   r   r   r{   _parametersr   rq   indexr   stopstartZevaluater9   r   )r<   rK   rL   Z	lstsqargsZfittedr   numjpjointfitparamsr=   r   Zmargsnumfpmfparamsmparamsr   r   r   r   plenZmodelfitr   r   r   rN   x  s4    




zJointFitter.objective_functionc             C   s   t | jdkr"tdt | jt | j dk rLtdt | j xJ| j D ]<}t | j| t | jkrXtdt | j| t | jqXW d S )Nr   zExpected >1 models, {} is givenri   z1At least two parameters are expected, {} is givenz({} parameter(s) provided but {} expected)r}   r   r   r   r   keysr   )r<   jr   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   )r1   r2   r   r   r   <lambda>  s    z&JointFitter.__call__.<locals>.<lambda>z/Expected {} coordinates in args but {} providedc             S   s   | d | d S )Nr   r   )r1   r2   r   r   r   r     s    )rL   Nr   )r   r   r}   r   r   rB   r   r   rN   r   r   r   r   r   r   rq   r   r   r   r   r9   rY   r[   )r<   rL   r   r!   r   r   r   r=   r   r   r   r   r   r   r   r   r   r   r   r   rO     s6    





zJointFitter.__call__N)	r   r   r   r   rH   rz   rN   r   rO   r   r   r   r   r   N  s   1c             C   s   t j| td} t j|td}|dk	r2t j|td}|dkr|dkrj|j| |krXtdt |||j}nB|jd| |j|d d  }| j|j  kr|ksn td|dkr| |f}n
| ||f}|S )zConvert inputs to float arrays.)rs   Nr   zONumber of data sets (y array is expected to equal the number of parameter sets)z%x, y and z should have the same shape)r9   Z
asanyarrayr   r   rB   r   r   )r1   r2   r3   rj   rk   Zz_shaper   r   r   r   r|     s"    
 

r|   c             C   sn  t | \}}t| j }t| j }tdd | j D }|sV|sV|sV|| _dS t|}d}| j}xt	| j
D ]\}	}
|	|krqt||
 d }||
 d }ttj|d}||||  }| j|
 dkr| j|
 \}}|dk	rt||}|dk	rt||}|| j|< ||7 }qtW |rjxHt	| j
D ]:\}	}
| j|
 r,| j|
 | }||
 d }|| j|< q,W 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   )rl   br   r   r   r     s    z*_fitter_to_model_params.<locals>.<genexpr>Nr   r   r   r   )NN)rz   r~   r   r   rS   r   r[   r.   r   	enumeraterq   r   operatormulr9   ZfmaxZfmin)r=   rK   r!   Zfit_param_indicesZhas_tiedr   Z	has_boundoffsetr   rm   r)   r   r   sizer   Z_minZ_maxr8   r   r   r   rJ     s>    

rJ   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 dS )aP  
    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.
    NrI   r   )r   r   r}   rq   r~   rS   r   r   r[   r   r   r9   rY   )r=   rn   rW   r   rm   r)   r   r   r   r   rz   J  s    
"
rz   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.rS   zfixed parameterr   ztied parameterc             s   s   | ]}t |d kV  qdS ))NNN)r   )rl   r   r   r   r   r   q  s    z(_validate_constraints.<locals>.<genexpr>r   zbound parametereqconsZequalityineqconsZ
inequalityN)	r~   rS   r   r   r   r   r   r   r   )rx   r=   r   r   r   r   rw   c  s     rw   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.)	ru   rB   rv   r   r   r   r}   rw   ry   )r=   rx   rr   r   r   r   r   }  s    
r   c             C   s   x| D ]}|j }y| }W n@ tk
r\ } z"ttdjt|j|d W dd}~X Y qX t	
|s~ttd| qt|tr|j}|t |< t| qttd| qW dS )a}  
    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 : a list of `~pkg_resources.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,{type} error occurred in entry point {name}.)r   r)   Nz0Modeling entry point {0} expected to be a Class.zCModeling entry point {0} expected to extend astropy.modeling.Fitter)r)   load	Exceptionr   r   r   r   r   r   r$   rC   
issubclassr   globals__all__append)Zentry_pointsZentry_pointr)   er   r   r   populate_entry_points  s$    

&


r   zastropy.modeling)groupr)   )Nr   r   )5r   rP   r$   r   r   	functoolsr   r   Znumpyr9   Zutilsr   r   Zastropy.unitsr   Zastropy.utils.exceptionsr   Z
optimizersr	   r
   rG   r   Zpkg_resourcesr   ZHAS_PKGImportErrorr   Z
STATISTICSZ
OPTIMIZERSr   r   r   r   r   r   rB   r   ABCMetar    rA   r   r   r   r   r   r   r   r|   rJ   rz   rw   r   r   r   r   r   r   <module>   s\   
\F  . T IGC 
07,