U
    5dH                     @   sD   d Z ddlZddlZddlmZ dgZdd Zddd	Z	d
d Z
dS )zNon-negative least squares    N   )MAX_MEM_BLOCKnnlsc                 C   sd   |  |} tjd|| dd| }d|j d t|d  }d|j tjd||dd }|| fS )z+Compute the objective and gradient for NNLSzmf,...ft->...mtToptimizer   g      ?   zmf,...mt->...ft)reshapenpeinsumsizesumflatten)xshapeABZdiffvalueZgrad r   6/tmp/pip-unpacked-wheel-8l90aumz/librosa/util/_nnls.py	_nnls_obj   s
    
r   c           	      K   s   |dkr4t jdt j| |dd}t j|dd|d |d| jd  d	g|j }|j}tj	j
t|f|| |f|d
|\}}}||S )a  Solve the constrained problem over a single block

    Parameters
    ----------
    A : np.ndarray [shape=(m, d)]
        The basis matrix
    B : np.ndarray [shape=(m, N)]
        The regression targets
    x_init : np.ndarray [shape=(d, N)]
        An initial guess
    **kwargs
        Additional keyword arguments to `scipy.optimize.fmin_l_bfgs_b`

    Returns
    -------
    x : np.ndarray [shape=(d, N)]
        Non-negative matrix such that Ax ~= B
    Nfm,...mt->...ftTr   r   outmr   )r   N)argsbounds)r	   r
   linalgpinvclip
setdefaultr   r   scipyr   Zfmin_l_bfgs_br   r   )	r   r   x_initkwargsr   r   r   Z	obj_valueZdiagnosticsr   r   r   _nnls_lbfgs_block(   s       r#   c                 K   s  |j dkrtj| |d S tt|jdd | j  }t	|d}|jd |krht
| |f|| jS tjdtj| |dd}tj|dd|d |}td|jd |D ]R}t|| |jd }t
| |d	||f fd
|d	||f i||d	||f< q|S )a  Non-negative least squares.

    Given two matrices A and B, find a non-negative matrix X
    that minimizes the sum squared error::

        err(X) = sum_i,j ((AX)[i,j] - B[i, j])^2

    Parameters
    ----------
    A : np.ndarray [shape=(m, n)]
        The basis matrix
    B : np.ndarray [shape=(..., m, N)]
        The target array.  Additional leading dimensions are supported.
    **kwargs
        Additional keyword arguments to `scipy.optimize.fmin_l_bfgs_b`

    Returns
    -------
    X : np.ndarray [shape=(..., n, N), non-negative]
        A minimizing solution to ``|AX - B|^2``

    See Also
    --------
    scipy.optimize.nnls
    scipy.optimize.fmin_l_bfgs_b

    Examples
    --------
    Approximate a magnitude spectrum from its mel spectrogram

    >>> y, sr = librosa.load(librosa.ex('trumpet'), duration=3)
    >>> S = np.abs(librosa.stft(y, n_fft=2048))
    >>> M = librosa.feature.melspectrogram(S=S, sr=sr, power=1)
    >>> mel_basis = librosa.filters.mel(sr=sr, n_fft=2048, n_mels=M.shape[0])
    >>> S_recover = librosa.util.nnls(mel_basis, M)

    Plot the results

    >>> import matplotlib.pyplot as plt
    >>> fig, ax = plt.subplots(nrows=3, sharex=True, sharey=True)
    >>> librosa.display.specshow(librosa.amplitude_to_db(S, ref=np.max),
    ...                          y_axis='log', x_axis='time', ax=ax[2])
    >>> ax[2].set(title='Original spectrogram (1025 bins)')
    >>> ax[2].label_outer()
    >>> librosa.display.specshow(librosa.amplitude_to_db(M, ref=np.max),
    ...                          y_axis='mel', x_axis='time', ax=ax[0])
    >>> ax[0].set(title='Mel spectrogram (128 bins)')
    >>> ax[0].label_outer()
    >>> img = librosa.display.specshow(librosa.amplitude_to_db(S_recover, ref=np.max(S)),
    ...                          y_axis='log', x_axis='time', ax=ax[1])
    >>> ax[1].set(title='Reconstructed spectrogram (1025 bins)')
    >>> ax[1].label_outer()
    >>> fig.colorbar(img, ax=ax, format="%+2.0f dB")
    r   r   Nr   Tr   r   .r!   )ndimr    r   r   r   r	   prodr   itemsizemaxr#   ZastypeZdtyper
   r   r   r   rangemin)r   r   r"   Z	n_columnsr   r!   Zbl_sZbl_tr   r   r   r   Q   s(    9

 )N)__doc__Znumpyr	   Zscipy.optimizer    utilsr   __all__r   r#   r   r   r   r   r   <module>   s   	
)