Example #1
0
def stereo_NMF(SXR,
               SXL,
               numberOfAccompanimentSpectralShapes,
               WM0=None,
               HM0=None,
               numberOfIterations=50,
               updateRulePower=1.0,
               verbose=False,
               displayEvolution=False):

    eps = 10**(-20)

    if displayEvolution:
        import matplotlib.pyplot as plt
        from matplotlib.pyplot import imshow as imageM
        plt.ion()
        print "Is the display interactive? ", plt.isinteractive()

    R = numberOfAccompanimentSpectralShapes
    omega = updateRulePower

    F, N = SXR.shape
    if (F, N) != SXL.shape:
        print "The input STFT matrices do not have the same dimension.\n"
        print "Please check what happened..."
        raise ValueError("Dimension of STFT matrices must be the same.")

    if HM0 is None:
        HM0 = np.abs(randn(R, N))
    else:
        if np.array(HM0).shape[0] == R and np.array(HM0).shape[1] == N:
            HM0 = np.array(HM0)
        else:
            print "Wrong dimensions for given HM0, \n"
            print "random initialization used instead"
            HM0 = np.abs(randn(R, N))
    HM = np.copy(HM0)

    if WM0 is None:
        WM0 = np.abs(randn(F, R))
    else:
        if np.array(WM0).shape[0] == F and np.array(WM0).shape[1] == R:
            WM0 = np.array(WM0)
        else:
            print "Wrong dimensions for given WM0, \n"
            print "random initialization used instead"
            WM0 = np.abs(randn(F, R))
    WM = np.copy(WM0)

    betaR = np.diag(np.random.rand(R))
    betaL = np.eye(R) - betaR

    hatSXR = np.maximum(np.dot(np.dot(WM, betaR**2), HM), eps)
    hatSXL = np.maximum(np.dot(np.dot(WM, betaL**2), HM), eps)

    # temporary matrices
    tempNumFbyN = np.zeros([F, N])
    tempDenFbyN = np.zeros([F, N])

    recoError = np.zeros([numberOfIterations * 3 + 1])
    recoError[0] = ISDistortion(SXR, hatSXR) + ISDistortion(SXL, hatSXL)
    if verbose:
        print "Reconstruction error at beginning: ", recoError[0]
    counterError = 1
    if displayEvolution:
        h1 = plt.figure(1)

    for n in np.arange(numberOfIterations):
        # order of re-estimation: HF0, HPHI, HM, HGAMMA, WM
        if verbose:
            print "iteration ", n, " over ", numberOfIterations

        if displayEvolution:
            h1.clf()
            imageM(db(hatSXR))
            plt.clim([np.amax(db(hatSXR)) - 100, np.amax(db(hatSXR))])
            plt.draw()

        # updating HM
        HM = HM * \
             ((np.dot(np.dot((betaR**2), WM.T), SXR /
                      np.maximum(hatSXR ** 2, eps)) +
               np.dot(np.dot((betaL**2), WM.T), SXL /
                      np.maximum(hatSXL ** 2, eps))
               ) /
              np.maximum(np.dot(np.dot((betaR**2), WM.T), 1 /
                                np.maximum(hatSXR, eps)) +
                         np.dot(np.dot((betaL**2), WM.T), 1 /
                                np.maximum(hatSXL, eps)),
                         eps)) ** omega

        hatSXR = np.maximum(np.dot(np.dot(WM, betaR**2), HM), eps)
        hatSXL = np.maximum(np.dot(np.dot(WM, betaL**2), HM), eps)

        recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                  + ISDistortion(SXL, hatSXL)

        if verbose:
            print "Reconstruction error difference after HM    : ",\
                  recoError[counterError] - recoError[counterError - 1]
        counterError += 1

        # updating WM
        WM = WM * \
             ((np.dot(SXR / np.maximum(hatSXR ** 2, eps),
                      np.dot(HM.T, betaR ** 2)) +
               np.dot(SXL / np.maximum(hatSXL ** 2, eps),
                      np.dot(HM.T, betaL ** 2))
               ) /
              (np.dot(1 / np.maximum(hatSXR, eps),
                      np.dot(HM.T, betaR ** 2)) +
               np.dot(1 / np.maximum(hatSXL, eps),
                      np.dot(HM.T, betaL ** 2))
               )) ** omega

        sumWM = np.sum(WM, axis=0)
        WM[:, sumWM > 0] = (WM[:, sumWM > 0] /
                            np.outer(np.ones(F), sumWM[sumWM > 0]))
        HM = HM * np.outer(sumWM, np.ones(N))

        hatSXR = np.maximum(np.dot(np.dot(WM, betaR**2), HM), eps)
        hatSXL = np.maximum(np.dot(np.dot(WM, betaL**2), HM), eps)

        recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                  + ISDistortion(SXL, hatSXL)

        if verbose:
            print "Reconstruction error difference after WM    : ",
            print recoError[counterError] - recoError[counterError - 1]

        counterError += 1

        # updating betaR and betaL
        betaR = np.diag(
            np.diag(
                np.maximum(
                    betaR *
                    ((np.dot(np.dot(WM.T, SXR / np.maximum(hatSXR**2, eps)),
                             HM.T)) /
                     (np.dot(np.dot(WM.T, 1 / np.maximum(hatSXR, eps)), HM.T)))
                    **(omega * .1), eps)))
        betaL = np.diag(
            np.diag(
                np.maximum(
                    betaL *
                    ((np.dot(np.dot(WM.T, SXL / np.maximum(hatSXL**2, eps)),
                             HM.T)) /
                     (np.dot(np.dot(WM.T, 1 / np.maximum(hatSXL, eps)), HM.T)))
                    **(omega * .1), eps)))
        betaR = betaR / np.maximum(betaR + betaL, eps)
        betaL = np.copy(np.eye(R) - betaR)

        hatSXR = np.maximum(np.dot(np.dot(WM, betaR**2), HM), eps)
        hatSXL = np.maximum(np.dot(np.dot(WM, betaL**2), HM), eps)

        recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                  + ISDistortion(SXL, hatSXL)

        if verbose:
            print "Reconstruction error difference after BETA  : ",
            print recoError[counterError] - recoError[counterError - 1]

        counterError += 1

    return betaR, betaL, HM, WM
Example #2
0
def Stereo_SIMM(  # the data to be fitted to:
        SXR,
        SXL,
        # the basis matrices for the spectral combs
        WF0,
        # and for the elementary filters:
        WGAMMA,
        # number of desired filters, accompaniment spectra:
        numberOfFilters=4,
        numberOfAccompanimentSpectralShapes=10,
        # if any, initial amplitude matrices for
        HGAMMA0=None,
        HPHI0=None,
        HF00=None,
        WM0=None,
        HM0=None,
        # Some more optional arguments, to control the "convergence"
        # of the algo
        numberOfIterations=1000,
        updateRulePower=1.0,
        stepNotes=4,
        lambdaHF0=0.00,
        alphaHF0=0.99,
        displayEvolution=False,
        verbose=True,
        updateHGAMMA=True,
        computeError=False):
    """
    HGAMMA, HPHI, HF0, HM, WM, recoError =
        SIMM(SXR, SXL, WF0, WGAMMA, numberOfFilters=4,
             numberOfAccompanimentSpectralShapes=10, HGAMMA0=None, HPHI0=None,
             HF00=None, WM0=None, HM0=None, numberOfIterations=1000,
             updateRulePower=1.0, stepNotes=4, 
             lambdaHF0=0.00, alphaHF0=0.99, displayEvolution=False,
             verbose=True)

    Implementation of the Smooth-filters Instantaneous Mixture Model
    (SIMM). This model can be used to estimate the main melody of a
    song, and separate the lead voice from the accompaniment, provided
    that the basis WF0 is constituted of elements associated to
    particular pitches.

    Inputs:
        SX
            the F x N power spectrogram to be approximated.
            F is the number of frequency bins, while N is the number of
            analysis frames
        WF0
            the F x NF0 basis matrix containing the NF0 source elements
        WGAMMA
            the F x P basis matrix of P smooth elementary filters
        numberOfFilters
            the number of filters K to be considered
        numberOfAccompanimentSpectralShapes
            the number of spectral shapes R for the accompaniment
        HGAMMA0
            the P x K decomposition matrix of WPHI on WGAMMA
        HPHI0
            the K x N amplitude matrix of the filter part of the lead
            instrument
        HF00
            the NF0 x N amplitude matrix for the source part of the lead
            instrument
        WM0
            the F x R the matrix for spectral shapes of the
            accompaniment
        HM0
            the R x N amplitude matrix associated with each of the R
            accompaniment spectral shapes
        numberOfIterations
            the number of iterations for the estimatino algorithm
        updateRulePower
            the power to which the multiplicative gradient is elevated to
        stepNotes
            the number of elements in WF0 per semitone. stepNotes=4 means
            that there are 48 elements per octave in WF0.
        lambdaHF0
            Lagrangian multiplier for the octave control
        alphaHF0
            parameter that controls how much influence a lower octave
            can have on the upper octave's amplitude.

    Outputs:
        HGAMMA
            the estimated P x K decomposition matrix of WPHI on WGAMMA
        HPHI
            the estimated K x N amplitude matrix of the filter part 
        HF0
            the estimated NF0 x N amplitude matrix for the source part
        HM
            the estimated R x N amplitude matrix for the accompaniment
        WM
            the estimate F x R spectral shapes for the accompaniment
        recoError
            the successive values of the Itakura Saito divergence
            between the power spectrogram and the spectrogram
            computed thanks to the updated estimations of the matrices.

    Please also refer to the following article for more details about
    the algorithm within this function, as well as the meaning of the
    different matrices that are involved:
        J.-L. Durrieu, G. Richard, B. David and C. Fevotte
        Source/Filter Model for Unsupervised Main Melody
        Extraction From Polyphonic Audio Signals
        IEEE Transactions on Audio, Speech and Language Processing
        Vol. 18, No. 3, March 2010
    """
    eps = 10**(-20)

    if displayEvolution:
        import matplotlib.pyplot as plt
        from matplotlib.pyplot import imshow as imageM
        plt.ion()
        print "Is the display interactive? ", plt.isinteractive()

    # renamed for convenience:
    K = numberOfFilters
    R = numberOfAccompanimentSpectralShapes
    omega = updateRulePower

    F, N = SXR.shape
    if (F, N) != SXL.shape:
        print "The input STFT matrices do not have the same dimension.\n"
        print "Please check what happened..."
        raise ValueError("Dimension of STFT matrices must be the same.")

    Fwf0, NF0 = WF0.shape
    Fwgamma, P = WGAMMA.shape

    # Checking the sizes of the matrices
    if Fwf0 != F:
        return False  # A REVOIR!!!
    if HGAMMA0 is None:
        HGAMMA0 = np.abs(randn(P, K))
    else:
        if not (isinstance(HGAMMA0, np.ndarray)):  # default behaviour
            HGAMMA0 = np.array(HGAMMA0, copy=True, order='C')
        Phgamma0, Khgamma0 = HGAMMA0.shape
        if Phgamma0 != P or Khgamma0 != K:
            print "Wrong dimensions for given HGAMMA0, \n"
            print "random initialization used instead"
            HGAMMA0 = np.abs(randn(P, K))

    HGAMMA = np.array(HGAMMA0, copy=True, order='C')

    if HPHI0 is None:  # default behaviour
        HPHI = np.abs(randn(K, N))
    else:
        Khphi0, Nhphi0 = np.array(HPHI0).shape
        if Khphi0 != K or Nhphi0 != N:
            print "Wrong dimensions for given HPHI0, \n"
            print "random initialization used instead"
            HPHI = np.abs(randn(K, N))
        else:
            HPHI = np.array(HPHI0, copy=True, order='C')

    if HF00 is None:
        HF00 = np.abs(randn(NF0, N))
    else:
        if np.array(HF00).shape[0] == NF0 and np.array(HF00).shape[1] == N:
            HF00 = np.array(HF00, copy=True, order='C')
        else:
            print "Wrong dimensions for given HF00, \n"
            print "random initialization used instead"
            HF00 = np.abs(randn(NF0, N))
    HF0 = np.array(HF00, copy=True, order='C')

    if HM0 is None:
        HM0 = np.abs(randn(R, N))
    else:
        if np.array(HM0).shape[0] == R and np.array(HM0).shape[1] == N:
            HM0 = np.array(HM0, copy=True, order='C')
        else:
            print "Wrong dimensions for given HM0, \n"
            print "random initialization used instead"
            HM0 = np.abs(randn(R, N))
    HM = np.array(HM0, copy=True, order='C')

    if WM0 is None:
        WM0 = np.abs(randn(F, R))
    else:
        if np.array(WM0).shape[0] == F and np.array(WM0).shape[1] == R:
            WM0 = np.array(WM0, copy=True, order='C')
        else:
            print "Wrong dimensions for given WM0, \n"
            print "random initialization used instead"
            WM0 = np.abs(randn(F, R))
    WM = np.array(WM0, copy=True, order='C')

    alphaR = 0.5
    alphaL = 0.5
    betaR = np.random.rand(R)
    betaL = 1 - betaR

    # Iterations to estimate the SIMM parameters:
    WPHI = np.dot(WGAMMA, HGAMMA)
    SF0 = np.dot(WF0, HF0)
    SPHI = np.dot(WPHI, HPHI)
    hatSXL = SF0 * SPHI
    hatSXR = (alphaR**2) * hatSXL
    hatSXR += np.dot((WM * (betaR**2)), HM)
    hatSXL *= (alphaL**2)
    hatSXL += np.dot((WM * (betaL**2)), HM)

    # temporary matrices
    tempNumFbyN = np.zeros([F, N])
    tempDenFbyN = np.zeros([F, N])
    tempComFbyN = np.zeros([F, N])

    # Array containing the reconstruction error after the update of each
    # of the parameter matrices:
    recoError = np.zeros([numberOfIterations * 5 * 2 + NF0 * 2 + 1])
    if computeError:
        recoError[0] = ISDistortion(SXR, hatSXR) + ISDistortion(SXL, hatSXL)
        if verbose:
            print "Reconstruction error at beginning: ", recoError[0]
    counterError = 1
    if displayEvolution:
        h1 = plt.figure(1)

    WF0T = np.ascontiguousarray(WF0.T)

    # Main loop for multiplicative updating rules:
    for n in np.arange(numberOfIterations):
        # order of re-estimation: HF0, HPHI, HM, HGAMMA, WM
        if verbose:
            print "iteration ", n, " over ", numberOfIterations
        if displayEvolution:
            h1.clf()
            imageM(db(HF0))
            plt.clim([np.amax(db(HF0)) - 100,
                      np.amax(db(HF0))])
            plt.draw()

        # updating HF0:
        tempComFbyN = (alphaR**2) * SPHI / np.maximum(hatSXR, eps)
        tempDenFbyN = (alphaL**2) * SPHI / np.maximum(hatSXL, eps)
        tempNumFbyN = tempComFbyN * SXR / np.maximum(
            hatSXR, eps) + tempDenFbyN * SXL / np.maximum(hatSXL, eps)
        #tempNumFbyN = ((alphaR**2) * SPHI * SXR) / np.maximum(hatSXR ** 2, eps)\
        #              + ((alphaL**2) * SPHI * SXL) / np.maximum(hatSXL ** 2, eps)
        tempDenFbyN += tempComFbyN
        #tempDenFbyN = (alphaR**2) * SPHI / np.maximum(hatSXR, eps)\
        #              + (alphaL**2) * SPHI / np.maximum(hatSXL, eps)

        ##if verbose>10: #DEBUG
        ##    print "tempNumFbyN.flags",tempNumFbyN.flags
        ##    print "tempDenFbyN.flags",tempDenFbyN.flags

        # This to enable octave control
        ## HF0[np.arange(12 * stepNotes, NF0), :] \
        ##    = HF0[np.arange(12 * stepNotes, NF0), :] \
        ##      * (np.dot(WF0[:, np.arange(12 * stepNotes,
        ##                                 NF0)].T, tempNumFbyN) \
        ##         / np.maximum(
        ##     np.dot(WF0[:, np.arange(12 * stepNotes, NF0)].T,
        ##            tempDenFbyN) \
        ##     + lambdaHF0 * (- (alphaHF0 - 1.0) \
        ##                    / np.maximum(HF0[
        ##     np.arange(12 * stepNotes, NF0), :], eps) \
        ##                    + HF0[
        ##     np.arange(NF0 - 12 * stepNotes), :]),
        ##     eps)) ** omega
        ##
        ## HF0[np.arange(12 * stepNotes), :] \
        ##    = HF0[np.arange(12 * stepNotes), :] \
        ##      * (np.dot(WF0[:, np.arange(12 * stepNotes)].T,
        ##               tempNumFbyN) /
        ##        np.maximum(
        ##         np.dot(WF0[:, np.arange(12 * stepNotes)].T,
        ##                tempDenFbyN), eps)) ** omega

        # normal update rules:
        HF0 *= (np.dot(WF0T, tempNumFbyN) /
                np.maximum(np.dot(WF0T, tempDenFbyN), eps))**omega
        ##if verbose>10: #DEBUG
        ##    print "HF0.flags", HF0.flags

        SF0 = np.dot(WF0, HF0, out=SF0)

        hatSXL = SF0 * SPHI
        hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
        hatSXR += (alphaR**2) * hatSXL
        hatSXL *= (alphaL**2)
        hatSXL += np.dot((WM * (betaL**2)), HM)

        hatSXR = np.maximum(hatSXR, eps)
        hatSXL = np.maximum(hatSXL, eps)

        if computeError:
            recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                      + ISDistortion(SXL, hatSXL)

            if verbose:
                print "Reconstruction error difference after HF0   : ",
                print recoError[counterError] - recoError[counterError - 1]
        counterError += 1

        # updating HPHI
        if updateHGAMMA or True:
            tempComFbyN = (alphaR**2) * SF0 / np.maximum(hatSXR, eps)
            tempDenFbyN = (alphaL**2) * SF0 / np.maximum(hatSXL, eps)
            tempNumFbyN = tempComFbyN * SXR
            tempNumFbyN /= np.maximum(hatSXR, eps)
            tempNumFbyN += tempDenFbyN * SXL / np.maximum(hatSXL, eps)
            tempDenFbyN += tempComFbyN
            #tempNumFbyN = ((alphaR**2) * SF0 * SXR) / np.maximum(hatSXR ** 2, eps)\
            #              + ((alphaL**2) * SF0 * SXL) / np.maximum(hatSXL ** 2, eps)
            #tempDenFbyN = (alphaR**2) * SF0 / np.maximum(hatSXR, eps)\
            #              + (alphaL**2) * SF0 / np.maximum(hatSXL, eps)
            HPHI *= (np.dot(WPHI.T, tempNumFbyN) /
                     np.maximum(np.dot(WPHI.T, tempDenFbyN), eps))**omega
            sumHPHI = np.sum(HPHI, axis=0)
            HPHI[:, sumHPHI > 0] = HPHI[:, sumHPHI > 0] / np.outer(
                np.ones(K), sumHPHI[sumHPHI > 0])
            HF0 *= np.outer(np.ones(NF0), sumHPHI)

            SF0 = np.dot(WF0, HF0, out=SF0)
            SPHI = np.dot(WPHI, HPHI, out=SPHI)

            hatSXL = SF0 * SPHI
            hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
            hatSXR += (alphaR**2) * hatSXL
            hatSXL *= (alphaL**2)
            hatSXL += np.dot((WM * (betaL**2)), HM)

            hatSXR = np.maximum(hatSXR, eps)
            hatSXL = np.maximum(hatSXL, eps)

            ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
            ##                    np.dot(WM*(betaR**2),HM),
            ##                    eps)
            ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
            ##                    np.dot(WM*(betaL**2),HM),
            ##                    eps)

            if computeError:
                recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                          + ISDistortion(SXL, hatSXL)

                if verbose:
                    print "Reconstruction error difference after HPHI  : ",
                    print recoError[counterError] - recoError[counterError - 1]

            counterError += 1

        # updating HM
        # tempNumFbyN = SXR / np.maximum(hatSXR ** 2, eps)\
        #               + SXL / np.maximum(hatSXL ** 2, eps)
        # tempDenFbyN = 1 / np.maximum(hatSXR, eps)\
        #               + 1 / np.maximum(hatSXL, eps)
        # HM = np.maximum(HM * (np.dot(WM.T, tempNumFbyN) /
        #      np.maximum(np.dot(WM.T, tempDenFbyN), eps)) ** omega, eps)

        HM *= ((np.dot(
            (WM * (betaR**2)).T, SXR / np.maximum(hatSXR**2, eps)) + np.dot(
                (WM * (betaL**2)).T, SXL / np.maximum(hatSXL**2, eps))) /
               np.maximum(
                   np.dot(
                       (WM *
                        (betaR**2)).T, 1 / np.maximum(hatSXR, eps)) + np.dot(
                            (WM * (betaL**2)).T, 1 / np.maximum(hatSXL, eps)),
                   eps))**omega

        hatSXL = SF0 * SPHI
        hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
        hatSXR += (alphaR**2) * hatSXL
        hatSXL *= (alphaL**2)
        hatSXL += np.dot((WM * (betaL**2)), HM)

        hatSXR = np.maximum(hatSXR, eps)
        hatSXL = np.maximum(hatSXL, eps)

        ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
        ##                    np.dot(WM*(betaR**2), HM), eps)
        ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
        ##                    np.dot(WM*(betaL**2), HM), eps)

        ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
        ##                           + ISDistortion(SXL, hatSXL)
        ##
        ## if verbose:
        ##     print "Reconstruction error difference after HM    : ",
        ##     print recoError[counterError] - recoError[counterError - 1]
        counterError += 1

        # updating HGAMMA
        if updateHGAMMA:
            tempComFbyN = (alphaR**2) * SF0 / np.maximum(hatSXR, eps)
            tempDenFbyN = (alphaL**2) * SF0 / np.maximum(hatSXL, eps)
            tempNumFbyN = tempComFbyN * SXR
            tempNumFbyN /= np.maximum(hatSXR, eps)
            tempNumFbyN += tempDenFbyN * SXL / np.maximum(hatSXL, eps)
            tempDenFbyN += tempComFbyN

            ##tempNumFbyN = ((alphaR ** 2) * SF0 * SXR) / np.maximum(hatSXR ** 2, eps)\
            ##              + ((alphaL ** 2) * SF0 * SXL) / np.maximum(hatSXL ** 2, eps)
            ##tempDenFbyN = (alphaR ** 2) * SF0 / np.maximum(hatSXR, eps) \
            ##              + (alphaL ** 2) * SF0 / np.maximum(hatSXL, eps)

            HGAMMA *= (
                np.dot(WGAMMA.T, np.dot(tempNumFbyN, HPHI.T)) / np.maximum(
                    np.dot(WGAMMA.T, np.dot(tempDenFbyN, HPHI.T)), eps))**omega

            sumHGAMMA = np.sum(HGAMMA, axis=0)
            HGAMMA[:, sumHGAMMA > 0] /= sumHGAMMA[sumHGAMMA > 0]
            HPHI *= np.outer(sumHGAMMA, np.ones(N))
            sumHPHI = np.sum(HPHI, axis=0)
            HPHI[:, sumHPHI > 0] /= sumHPHI[sumHPHI > 0]
            HF0 *= sumHPHI

            WPHI = np.dot(WGAMMA, HGAMMA, out=WPHI)
            SF0 = np.dot(WF0, HF0, out=SF0)
            SPHI = np.dot(WPHI, HPHI, out=SPHI)

            hatSXL = SF0 * SPHI
            hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
            hatSXR += (alphaR**2) * hatSXL
            hatSXL *= (alphaL**2)
            hatSXL += np.dot((WM * (betaL**2)), HM)

            hatSXR = np.maximum(hatSXR, eps)
            hatSXL = np.maximum(hatSXL, eps)

            ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
            ##                    np.dot(WM*(betaR**2),HM), eps)
            ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
            ##                    np.dot(WM*(betaL**2),HM), eps)

            ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
            ##                           + ISDistortion(SXL, hatSXL)
            ##
            ## if verbose:
            ##     print "Reconstruction error difference after HGAMMA: ",
            ##     print recoError[counterError] - recoError[counterError - 1]
            ##
            counterError += 1

        # updating WM, after a certain number of iterations (here, after 1 iteration)
        if n > -1:  # this test can be used such that WM is updated only
            # after a certain number of iterations
            ##           tempNumFbyN = SX / np.maximum(hatSX ** 2, eps)
            ##            tempDenFbyN = 1 / np.maximum(hatSX, eps)
            ##            WM = np.maximum(WM * (np.dot(tempNumFbyN, HM.T) /
            ##                                  np.maximum(np.dot(tempDenFbyN, HM.T),
            ##                                             eps)) ** omega, eps)
            WM = WM * \
                 ((np.dot(SXR / np.maximum(hatSXR ** 2, eps),
                          HM.T * (betaR ** 2)) +
                   np.dot(SXL / np.maximum(hatSXL ** 2, eps),
                          HM.T * (betaL ** 2))
                   ) /
                  (np.dot(1 / np.maximum(hatSXR, eps),
                          HM.T * (betaR ** 2)) +
                   np.dot(1 / np.maximum(hatSXL, eps),
                          HM.T * (betaL ** 2))
                   )) ** omega

            sumWM = np.sum(WM, axis=0)
            WM[:, sumWM > 0] /= sumWM[sumWM > 0]
            HM *= np.vstack(sumWM)

            hatSXL = SF0 * SPHI
            hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
            hatSXR += (alphaR**2) * hatSXL
            hatSXL *= (alphaL**2)
            hatSXL += np.dot((WM * (betaL**2)), HM)

            hatSXR = np.maximum(hatSXR, eps)
            hatSXL = np.maximum(hatSXL, eps)

            ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
            ##                    np.dot(WM * (betaR**2), HM), eps)
            ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
            ##                    np.dot(WM * (betaL**2), HM), eps)

            ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
            ##                       + ISDistortion(SXL, hatSXL)
            ##
            ## if verbose:
            ##     print "Reconstruction error difference after WM    : ",
            ##     print recoError[counterError] - recoError[counterError - 1]
            counterError += 1

        # updating alphaR and alphaL:
        tempDenFbyN = SF0 * SPHI / np.maximum(hatSXR, eps)
        tempNumFbyN = tempDenFbyN * SXR / np.maximum(hatSXR, eps)
        ## tempDenFbyN = SF0 * SPHI / np.maximum(hatSXR, eps)
        alphaR = np.maximum(
            alphaR * (np.sum(tempNumFbyN) / np.sum(tempDenFbyN))**(omega * .1),
            eps)
        tempDenFbyN = SF0 * SPHI / np.maximum(hatSXL, eps)
        tempNumFbyN = tempDenFbyN * SXL / np.maximum(hatSXL, eps)
        alphaL = np.maximum(
            alphaL * (np.sum(tempNumFbyN) / np.sum(tempDenFbyN))**(omega * .1),
            eps)
        alphaR = alphaR / np.maximum(alphaR + alphaL, .001)
        alphaL = np.copy(1 - alphaR)

        hatSXL = SF0 * SPHI
        hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
        hatSXR += (alphaR**2) * hatSXL
        hatSXL *= (alphaL**2)
        hatSXL += np.dot((WM * (betaL**2)), HM)

        hatSXR = np.maximum(hatSXR, eps)
        hatSXL = np.maximum(hatSXL, eps)

        ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
        ##                    np.dot(WM * (betaR**2), HM), eps)
        ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
        ##                    np.dot(WM * (betaL**2), HM), eps)

        ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
        ##                           + ISDistortion(SXL, hatSXL)
        ##
        ## if verbose:
        ##     print "Reconstruction error difference after ALPHA : ",
        ##     print recoError[counterError] - recoError[counterError - 1]
        counterError += 1

        # updating betaR and betaL
        betaR *= np.diag(
            ((np.dot(np.dot(WM.T, SXR / np.maximum(hatSXR**2, eps)), HM.T)) /
             (np.dot(np.dot(WM.T, 1 / np.maximum(hatSXR, eps)), HM.T)))**(
                 omega * .1))
        betaL *= np.diag(
            ((np.dot(np.dot(WM.T, SXL / np.maximum(hatSXL**2, eps)), HM.T)) /
             (np.dot(np.dot(WM.T, 1 / np.maximum(hatSXL, eps)), HM.T)))**(
                 omega * .1))
        betaR = betaR / np.maximum(betaR + betaL, eps)
        # betaL = np.copy(np.eye(R) - betaR)
        betaL = 1 - betaR

        hatSXL = SF0 * SPHI
        hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
        hatSXR += (alphaR**2) * hatSXL
        hatSXL *= (alphaL**2)
        hatSXL += np.dot((WM * (betaL**2)), HM)

        hatSXR = np.maximum(hatSXR, eps)
        hatSXL = np.maximum(hatSXL, eps)

        ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
        ##                    np.dot(WM * (betaR**2),HM), eps)
        ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
        ##                    np.dot(WM * (betaL**2),HM), eps)

        ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
        ##                           + ISDistortion(SXL, hatSXL)
        ##
        ## if verbose:
        ##     print "Reconstruction error difference after BETA  : ",
        ##     print recoError[counterError] - recoError[counterError - 1]
        counterError += 1

    return alphaR, alphaL, HGAMMA, HPHI, HF0, np.diag(betaR), np.diag(
        betaL), HM, WM, recoError
Example #3
0
def stereo_NMF(SXR, SXL,
               numberOfAccompanimentSpectralShapes,
               WM0=None, HM0=None,
               numberOfIterations=50, updateRulePower=1.0,
               verbose=False, displayEvolution=False):
    
    eps = 10 ** (-20)
    
    if displayEvolution:
        import matplotlib.pyplot as plt
        from matplotlib.pyplot import imshow as imageM
        plt.ion()
        print "Is the display interactive? ", plt.isinteractive()
    
    R = numberOfAccompanimentSpectralShapes
    omega = updateRulePower
    
    F, N = SXR.shape
    if (F, N) != SXL.shape:
        print "The input STFT matrices do not have the same dimension.\n"
        print "Please check what happened..."
        raise ValueError("Dimension of STFT matrices must be the same.")
    
    if HM0 is None:
        HM0 = np.abs(randn(R, N))
    else:
        if np.array(HM0).shape[0] == R and np.array(HM0).shape[1] == N:
            HM0 = np.array(HM0)
        else:
            print "Wrong dimensions for given HM0, \n"
            print "random initialization used instead"
            HM0 = np.abs(randn(R, N))
    HM = np.copy(HM0)
    
    if WM0 is None:
        WM0 = np.abs(randn(F, R))
    else:
        if np.array(WM0).shape[0] == F and np.array(WM0).shape[1] == R:
            WM0 = np.array(WM0)
        else:
            print "Wrong dimensions for given WM0, \n"
            print "random initialization used instead"
            WM0 = np.abs(randn(F, R))
    WM = np.copy(WM0)
    
    betaR = np.diag(np.random.rand(R))
    betaL = np.eye(R) - betaR
    
    hatSXR = np.maximum(np.dot(np.dot(WM, betaR**2), HM), eps)
    hatSXL = np.maximum(np.dot(np.dot(WM, betaL**2), HM), eps)
    
    # temporary matrices
    tempNumFbyN = np.zeros([F, N])
    tempDenFbyN = np.zeros([F, N])
    
    recoError = np.zeros([numberOfIterations * 3 + 1])
    recoError[0] = ISDistortion(SXR, hatSXR) + ISDistortion(SXL, hatSXL)
    if verbose:
        print "Reconstruction error at beginning: ", recoError[0]
    counterError = 1
    if displayEvolution:
        h1 = plt.figure(1)
        
        
    for n in np.arange(numberOfIterations):
        # order of re-estimation: HF0, HPHI, HM, HGAMMA, WM
        if verbose:
            print "iteration ", n, " over ", numberOfIterations
            
        if displayEvolution:
            h1.clf()
            imageM(db(hatSXR))
            plt.clim([np.amax(db(hatSXR))-100, np.amax(db(hatSXR))])
            plt.draw()
        
        # updating HM
        HM = HM * \
             ((np.dot(np.dot((betaR**2), WM.T), SXR /
                      np.maximum(hatSXR ** 2, eps)) +
               np.dot(np.dot((betaL**2), WM.T), SXL /
                      np.maximum(hatSXL ** 2, eps))
               ) /
              np.maximum(np.dot(np.dot((betaR**2), WM.T), 1 /
                                np.maximum(hatSXR, eps)) +
                         np.dot(np.dot((betaL**2), WM.T), 1 /
                                np.maximum(hatSXL, eps)),
                         eps)) ** omega
        
        hatSXR = np.maximum(np.dot(np.dot(WM, betaR**2),HM), eps)
        hatSXL = np.maximum(np.dot(np.dot(WM, betaL**2),HM), eps)
        
        recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                  + ISDistortion(SXL, hatSXL)
        
        if verbose:
            print "Reconstruction error difference after HM    : ",\
                  recoError[counterError] - recoError[counterError - 1]
        counterError += 1
        
        # updating WM
        WM = WM * \
             ((np.dot(SXR / np.maximum(hatSXR ** 2, eps),
                      np.dot(HM.T, betaR ** 2)) +
               np.dot(SXL / np.maximum(hatSXL ** 2, eps),
                      np.dot(HM.T, betaL ** 2))
               ) /
              (np.dot(1 / np.maximum(hatSXR, eps),
                      np.dot(HM.T, betaR ** 2)) +
               np.dot(1 / np.maximum(hatSXL, eps),
                      np.dot(HM.T, betaL ** 2))
               )) ** omega
        
        sumWM = np.sum(WM, axis=0)
        WM[:, sumWM>0] = (WM[:, sumWM>0] /
                          np.outer(np.ones(F),sumWM[sumWM>0]))
        HM = HM * np.outer(sumWM, np.ones(N))
        
        hatSXR = np.maximum(np.dot(np.dot(WM, betaR**2), HM), eps)
        hatSXL = np.maximum(np.dot(np.dot(WM, betaL**2), HM), eps)
        
        recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                  + ISDistortion(SXL, hatSXL)
        
        if verbose:
            print "Reconstruction error difference after WM    : ",
            print recoError[counterError] - recoError[counterError - 1]
            
        counterError += 1
        
        # updating betaR and betaL
        betaR = np.diag(np.diag(np.maximum(betaR *
                        ((np.dot(np.dot(WM.T, SXR / np.maximum(hatSXR ** 2,
                                                               eps)),
                                 HM.T)) /
                         (np.dot(np.dot(WM.T, 1 / np.maximum(hatSXR,
                                                             eps)),
                                 HM.T))) ** (omega*.1), eps)))
        betaL = np.diag(np.diag(np.maximum(betaL *
                        ((np.dot(np.dot(WM.T, SXL / np.maximum(hatSXL ** 2,
                                                               eps)),
                                 HM.T)) /
                         (np.dot(np.dot(WM.T, 1 / np.maximum(hatSXL,
                                                             eps)),
                                 HM.T))) ** (omega*.1), eps)))
        betaR = betaR / np.maximum(betaR + betaL, eps)
        betaL = np.copy(np.eye(R) - betaR)
        
        hatSXR = np.maximum(np.dot(np.dot(WM, betaR**2), HM), eps)
        hatSXL = np.maximum(np.dot(np.dot(WM, betaL**2), HM), eps)
        
        recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                  + ISDistortion(SXL, hatSXL)
        
        if verbose:
            print "Reconstruction error difference after BETA  : ",
            print recoError[counterError] - recoError[counterError - 1]
        
        counterError += 1
        
    return betaR, betaL, HM, WM
 
 # draw figure plus formant annotated
 FHzmax = 4000.0
 nFmax = np.int32(np.ceil(FHzmax/Fs*NFT))
 ytickslab = np.array([1000, 2000, 3000, 4000])
 ytickspos = np.int32(np.ceil(ytickslab/Fs*NFT))
 fontsize = 16
 figheight=4.5
 figwidth=9.0
 
 displayEvolution = False #True
 
 if displayEvolution:
     plt.figure(1)#, figsize=[figwidth, figheight])
     plt.clf()
     imageM(db(specFromLpc))
     plt.hold(True)
     
 trueFormant = {}
 for n in range(3):
     trueFormant[n] = bigdat[filenb,5+n+3*np.arange(8)]
     if displayEvolution:
         plt.plot(timeStampsInFrame,
                  trueFormant[n]/np.double(fs)*NFT,
                  'ok')
 
 if displayEvolution:
     plt.plot(freqLpc.T/np.double(fs)*NFT, )
     plt.axis('tight')
     plt.draw()
     
Example #5
0
def Stereo_SIMM(# the data to be fitted to:
         SXR, SXL,
         # the basis matrices for the spectral combs
         WF0,
         # and for the elementary filters:
         WGAMMA,
         # number of desired filters, accompaniment spectra:
         numberOfFilters=4, numberOfAccompanimentSpectralShapes=10,
         # if any, initial amplitude matrices for 
         HGAMMA0=None, HPHI0=None,
         HF00=None,
         WM0=None, HM0=None,
         # Some more optional arguments, to control the "convergence"
         # of the algo
         numberOfIterations=1000, updateRulePower=1.0,
         stepNotes=4, 
         lambdaHF0=0.00,alphaHF0=0.99,
         displayEvolution=False, verbose=True,
         updateHGAMMA=True,
         computeError=False):
    """
    HGAMMA, HPHI, HF0, HM, WM, recoError =
        SIMM(SXR, SXL, WF0, WGAMMA, numberOfFilters=4,
             numberOfAccompanimentSpectralShapes=10, HGAMMA0=None, HPHI0=None,
             HF00=None, WM0=None, HM0=None, numberOfIterations=1000,
             updateRulePower=1.0, stepNotes=4, 
             lambdaHF0=0.00, alphaHF0=0.99, displayEvolution=False,
             verbose=True)

    Implementation of the Smooth-filters Instantaneous Mixture Model
    (SIMM). This model can be used to estimate the main melody of a
    song, and separate the lead voice from the accompaniment, provided
    that the basis WF0 is constituted of elements associated to
    particular pitches.

    Inputs:
        SX
            the F x N power spectrogram to be approximated.
            F is the number of frequency bins, while N is the number of
            analysis frames
        WF0
            the F x NF0 basis matrix containing the NF0 source elements
        WGAMMA
            the F x P basis matrix of P smooth elementary filters
        numberOfFilters
            the number of filters K to be considered
        numberOfAccompanimentSpectralShapes
            the number of spectral shapes R for the accompaniment
        HGAMMA0
            the P x K decomposition matrix of WPHI on WGAMMA
        HPHI0
            the K x N amplitude matrix of the filter part of the lead
            instrument
        HF00
            the NF0 x N amplitude matrix for the source part of the lead
            instrument
        WM0
            the F x R the matrix for spectral shapes of the
            accompaniment
        HM0
            the R x N amplitude matrix associated with each of the R
            accompaniment spectral shapes
        numberOfIterations
            the number of iterations for the estimatino algorithm
        updateRulePower
            the power to which the multiplicative gradient is elevated to
        stepNotes
            the number of elements in WF0 per semitone. stepNotes=4 means
            that there are 48 elements per octave in WF0.
        lambdaHF0
            Lagrangian multiplier for the octave control
        alphaHF0
            parameter that controls how much influence a lower octave
            can have on the upper octave's amplitude.

    Outputs:
        HGAMMA
            the estimated P x K decomposition matrix of WPHI on WGAMMA
        HPHI
            the estimated K x N amplitude matrix of the filter part 
        HF0
            the estimated NF0 x N amplitude matrix for the source part
        HM
            the estimated R x N amplitude matrix for the accompaniment
        WM
            the estimate F x R spectral shapes for the accompaniment
        recoError
            the successive values of the Itakura Saito divergence
            between the power spectrogram and the spectrogram
            computed thanks to the updated estimations of the matrices.

    Please also refer to the following article for more details about
    the algorithm within this function, as well as the meaning of the
    different matrices that are involved:
        J.-L. Durrieu, G. Richard, B. David and C. Fevotte
        Source/Filter Model for Unsupervised Main Melody
        Extraction From Polyphonic Audio Signals
        IEEE Transactions on Audio, Speech and Language Processing
        Vol. 18, No. 3, March 2010
    """
    eps = 10 ** (-20)

    if displayEvolution:
        import matplotlib.pyplot as plt
        from matplotlib.pyplot import imshow as imageM
        plt.ion()
        print "Is the display interactive? ", plt.isinteractive()

    # renamed for convenience:
    K = numberOfFilters
    R = numberOfAccompanimentSpectralShapes
    omega = updateRulePower
    
    F, N = SXR.shape
    if (F, N) != SXL.shape:
        print "The input STFT matrices do not have the same dimension.\n"
        print "Please check what happened..."
        raise ValueError("Dimension of STFT matrices must be the same.")
        
    Fwf0, NF0 = WF0.shape
    Fwgamma, P = WGAMMA.shape
    
    # Checking the sizes of the matrices
    if Fwf0 != F:
        return False # A REVOIR!!!
    if HGAMMA0 is None:
        HGAMMA0 = np.abs(randn(P, K))
    else:
        if not(isinstance(HGAMMA0,np.ndarray)): # default behaviour
            HGAMMA0 = np.array(HGAMMA0, copy=True, order='C')
        Phgamma0, Khgamma0 = HGAMMA0.shape
        if Phgamma0 != P or Khgamma0 != K:
            print "Wrong dimensions for given HGAMMA0, \n"
            print "random initialization used instead"
            HGAMMA0 = np.abs(randn(P, K))

    HGAMMA = np.array(HGAMMA0, copy=True, order='C')
    
    if HPHI0 is None: # default behaviour
        HPHI = np.abs(randn(K, N))
    else:
        Khphi0, Nhphi0 = np.array(HPHI0).shape
        if Khphi0 != K or Nhphi0 != N:
            print "Wrong dimensions for given HPHI0, \n"
            print "random initialization used instead"
            HPHI = np.abs(randn(K, N))
        else:
            HPHI = np.array(HPHI0, copy=True, order='C')

    if HF00 is None:
        HF00 = np.abs(randn(NF0, N))
    else:
        if np.array(HF00).shape[0] == NF0 and np.array(HF00).shape[1] == N:
            HF00 = np.array(HF00, copy=True, order='C')
        else:
            print "Wrong dimensions for given HF00, \n"
            print "random initialization used instead"
            HF00 = np.abs(randn(NF0, N))
    HF0 = np.array(HF00, copy=True, order='C')

    if HM0 is None:
        HM0 = np.abs(randn(R, N))
    else:
        if np.array(HM0).shape[0] == R and np.array(HM0).shape[1] == N:
            HM0 = np.array(HM0, copy=True, order='C')
        else:
            print "Wrong dimensions for given HM0, \n"
            print "random initialization used instead"
            HM0 = np.abs(randn(R, N))
    HM = np.array(HM0, copy=True, order='C')
    
    if WM0 is None:
        WM0 = np.abs(randn(F, R))
    else:
        if np.array(WM0).shape[0] == F and np.array(WM0).shape[1] == R:
            WM0 = np.array(WM0, copy=True, order='C')
        else:
            print "Wrong dimensions for given WM0, \n"
            print "random initialization used instead"
            WM0 = np.abs(randn(F, R))
    WM = np.array(WM0, copy=True, order='C')
    
    alphaR = 0.5
    alphaL = 0.5
    betaR = np.random.rand(R)
    betaL = 1 - betaR
    
    # Iterations to estimate the SIMM parameters:
    WPHI = np.dot(WGAMMA, HGAMMA)
    SF0 = np.dot(WF0, HF0)
    SPHI = np.dot(WPHI, HPHI)
    hatSXL = SF0 * SPHI
    hatSXR = (alphaR**2) * hatSXL
    hatSXR += np.dot((WM * (betaR**2)), HM)
    hatSXL *= (alphaL**2)
    hatSXL += np.dot((WM * (betaL**2)), HM)
    
    # temporary matrices
    tempNumFbyN = np.zeros([F, N])
    tempDenFbyN = np.zeros([F, N])
    tempComFbyN = np.zeros([F, N])
    
    # Array containing the reconstruction error after the update of each 
    # of the parameter matrices:
    recoError = np.zeros([numberOfIterations * 5 * 2 + NF0 * 2 + 1])
    if computeError:
        recoError[0] = ISDistortion(SXR, hatSXR) + ISDistortion(SXL, hatSXL)
        if verbose:
            print "Reconstruction error at beginning: ", recoError[0]
    counterError = 1
    if displayEvolution:
        h1 = plt.figure(1)
        
    WF0T = np.ascontiguousarray(WF0.T)
        
    # Main loop for multiplicative updating rules:
    for n in np.arange(numberOfIterations):
        # order of re-estimation: HF0, HPHI, HM, HGAMMA, WM
        if verbose:
            print "iteration ", n, " over ", numberOfIterations
        if displayEvolution:
            h1.clf()
            imageM(db(HF0))
            plt.clim([np.amax(db(HF0))-100, np.amax(db(HF0))]);plt.draw()
            
        # updating HF0:
        tempComFbyN = (alphaR**2) * SPHI / np.maximum(hatSXR, eps)
        tempDenFbyN = (alphaL**2) * SPHI / np.maximum(hatSXL, eps)
        tempNumFbyN = tempComFbyN * SXR / np.maximum(hatSXR, eps) + tempDenFbyN * SXL / np.maximum(hatSXL, eps)
        #tempNumFbyN = ((alphaR**2) * SPHI * SXR) / np.maximum(hatSXR ** 2, eps)\
        #              + ((alphaL**2) * SPHI * SXL) / np.maximum(hatSXL ** 2, eps)
        tempDenFbyN += tempComFbyN
        #tempDenFbyN = (alphaR**2) * SPHI / np.maximum(hatSXR, eps)\
        #              + (alphaL**2) * SPHI / np.maximum(hatSXL, eps)
        
        ##if verbose>10: #DEBUG
        ##    print "tempNumFbyN.flags",tempNumFbyN.flags
        ##    print "tempDenFbyN.flags",tempDenFbyN.flags
        
        # This to enable octave control
        ## HF0[np.arange(12 * stepNotes, NF0), :] \
        ##    = HF0[np.arange(12 * stepNotes, NF0), :] \
        ##      * (np.dot(WF0[:, np.arange(12 * stepNotes,
        ##                                 NF0)].T, tempNumFbyN) \
        ##         / np.maximum(
        ##     np.dot(WF0[:, np.arange(12 * stepNotes, NF0)].T,
        ##            tempDenFbyN) \
        ##     + lambdaHF0 * (- (alphaHF0 - 1.0) \
        ##                    / np.maximum(HF0[
        ##     np.arange(12 * stepNotes, NF0), :], eps) \
        ##                    + HF0[
        ##     np.arange(NF0 - 12 * stepNotes), :]),
        ##     eps)) ** omega
        ## 
        ## HF0[np.arange(12 * stepNotes), :] \
        ##    = HF0[np.arange(12 * stepNotes), :] \
        ##      * (np.dot(WF0[:, np.arange(12 * stepNotes)].T,
        ##               tempNumFbyN) /
        ##        np.maximum(
        ##         np.dot(WF0[:, np.arange(12 * stepNotes)].T,
        ##                tempDenFbyN), eps)) ** omega
        
        # normal update rules:
        HF0 *= (np.dot(WF0T, tempNumFbyN) /
                np.maximum(np.dot(WF0T, tempDenFbyN), eps)) ** omega
        ##if verbose>10: #DEBUG
        ##    print "HF0.flags", HF0.flags
        
        SF0 = np.dot(WF0, HF0, out=SF0)
        
        hatSXL = SF0 * SPHI
        hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
        hatSXR += (alphaR**2) * hatSXL
        hatSXL *= (alphaL**2)
        hatSXL += np.dot((WM * (betaL**2)), HM)
        
        hatSXR = np.maximum(hatSXR, eps)
        hatSXL = np.maximum(hatSXL, eps)
        
        if computeError:
            recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                      + ISDistortion(SXL, hatSXL)
            
            if verbose:
                print "Reconstruction error difference after HF0   : ",
                print recoError[counterError] - recoError[counterError - 1]
        counterError += 1
    
        # updating HPHI
        if updateHGAMMA or True:
            tempComFbyN = (alphaR**2) * SF0 / np.maximum(hatSXR, eps)
            tempDenFbyN = (alphaL**2) * SF0 / np.maximum(hatSXL, eps)
            tempNumFbyN = tempComFbyN * SXR
            tempNumFbyN /= np.maximum(hatSXR, eps)
            tempNumFbyN += tempDenFbyN * SXL / np.maximum(hatSXL, eps)
            tempDenFbyN += tempComFbyN
            #tempNumFbyN = ((alphaR**2) * SF0 * SXR) / np.maximum(hatSXR ** 2, eps)\
            #              + ((alphaL**2) * SF0 * SXL) / np.maximum(hatSXL ** 2, eps)
            #tempDenFbyN = (alphaR**2) * SF0 / np.maximum(hatSXR, eps)\
            #              + (alphaL**2) * SF0 / np.maximum(hatSXL, eps)
            HPHI *= (np.dot(WPHI.T, tempNumFbyN) / np.maximum(np.dot(WPHI.T, tempDenFbyN), eps)) ** omega
            sumHPHI = np.sum(HPHI, axis=0)
            HPHI[:, sumHPHI>0] = HPHI[:, sumHPHI>0] / np.outer(np.ones(K), sumHPHI[sumHPHI>0])
            HF0 *= np.outer(np.ones(NF0), sumHPHI)
            
            SF0 = np.dot(WF0, HF0, out=SF0)
            SPHI = np.dot(WPHI, HPHI, out=SPHI)
            
            hatSXL = SF0 * SPHI
            hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
            hatSXR += (alphaR**2) * hatSXL
            hatSXL *= (alphaL**2)
            hatSXL += np.dot((WM * (betaL**2)), HM)
            
            hatSXR = np.maximum(hatSXR, eps)
            hatSXL = np.maximum(hatSXL, eps)
            
            ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
            ##                    np.dot(WM*(betaR**2),HM),
            ##                    eps)
            ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
            ##                    np.dot(WM*(betaL**2),HM),
            ##                    eps)
            
            if computeError:
                recoError[counterError] = ISDistortion(SXR, hatSXR) \
                                          + ISDistortion(SXL, hatSXL)
                
                if verbose:
                    print "Reconstruction error difference after HPHI  : ",
                    print recoError[counterError] - recoError[counterError - 1]
                 
            counterError += 1
        
        
        # updating HM
        # tempNumFbyN = SXR / np.maximum(hatSXR ** 2, eps)\
        #               + SXL / np.maximum(hatSXL ** 2, eps)
        # tempDenFbyN = 1 / np.maximum(hatSXR, eps)\
        #               + 1 / np.maximum(hatSXL, eps)
        # HM = np.maximum(HM * (np.dot(WM.T, tempNumFbyN) /
        #      np.maximum(np.dot(WM.T, tempDenFbyN), eps)) ** omega, eps)
        
        HM *= (
            (
            np.dot((WM * (betaR**2)).T,
                   SXR /np.maximum(hatSXR ** 2, eps))
            + np.dot((WM*(betaL**2)).T,
                     SXL /np.maximum(hatSXL ** 2, eps))
            ) /
            np.maximum(np.dot((WM*(betaR**2)).T,
                              1 / np.maximum(hatSXR, eps))
                       + np.dot((WM*(betaL**2)).T,
                                1 /np.maximum(hatSXL, eps)), eps)
            ) ** omega
        
        hatSXL = SF0 * SPHI
        hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
        hatSXR += (alphaR**2) * hatSXL
        hatSXL *= (alphaL**2)
        hatSXL += np.dot((WM * (betaL**2)), HM)
        
        hatSXR = np.maximum(hatSXR, eps)
        hatSXL = np.maximum(hatSXL, eps)
        
        ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
        ##                    np.dot(WM*(betaR**2), HM), eps)
        ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
        ##                    np.dot(WM*(betaL**2), HM), eps)
        
        ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
        ##                           + ISDistortion(SXL, hatSXL)
        ## 
        ## if verbose:
        ##     print "Reconstruction error difference after HM    : ",
        ##     print recoError[counterError] - recoError[counterError - 1]
        counterError += 1  

        # updating HGAMMA
        if updateHGAMMA:
            tempComFbyN = (alphaR**2) * SF0 / np.maximum(hatSXR, eps)
            tempDenFbyN = (alphaL**2) * SF0 / np.maximum(hatSXL, eps)
            tempNumFbyN = tempComFbyN * SXR
            tempNumFbyN /= np.maximum(hatSXR, eps)
            tempNumFbyN += tempDenFbyN * SXL / np.maximum(hatSXL, eps)
            tempDenFbyN += tempComFbyN
            
            ##tempNumFbyN = ((alphaR ** 2) * SF0 * SXR) / np.maximum(hatSXR ** 2, eps)\
            ##              + ((alphaL ** 2) * SF0 * SXL) / np.maximum(hatSXL ** 2, eps)
            ##tempDenFbyN = (alphaR ** 2) * SF0 / np.maximum(hatSXR, eps) \
            ##              + (alphaL ** 2) * SF0 / np.maximum(hatSXL, eps)
            
            HGAMMA *= (np.dot(WGAMMA.T, np.dot(tempNumFbyN, HPHI.T)) / np.maximum(np.dot(WGAMMA.T, np.dot(tempDenFbyN, HPHI.T)), eps)) ** omega
            
            sumHGAMMA = np.sum(HGAMMA, axis=0)
            HGAMMA[:, sumHGAMMA>0] /= sumHGAMMA[sumHGAMMA>0]
            HPHI *= np.outer(sumHGAMMA, np.ones(N))
            sumHPHI = np.sum(HPHI, axis=0)
            HPHI[:, sumHPHI>0] /= sumHPHI[sumHPHI>0]
            HF0 *= sumHPHI
            
            WPHI = np.dot(WGAMMA, HGAMMA, out=WPHI)
            SF0 = np.dot(WF0, HF0, out=SF0)
            SPHI = np.dot(WPHI, HPHI, out=SPHI)
            
            hatSXL = SF0 * SPHI
            hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
            hatSXR += (alphaR**2) * hatSXL
            hatSXL *= (alphaL**2)
            hatSXL += np.dot((WM * (betaL**2)), HM)
            
            hatSXR = np.maximum(hatSXR, eps)
            hatSXL = np.maximum(hatSXL, eps)
            
            ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
            ##                    np.dot(WM*(betaR**2),HM), eps)
            ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
            ##                    np.dot(WM*(betaL**2),HM), eps)
            
            ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
            ##                           + ISDistortion(SXL, hatSXL)
            ## 
            ## if verbose:
            ##     print "Reconstruction error difference after HGAMMA: ",
            ##     print recoError[counterError] - recoError[counterError - 1]
            ## 
            counterError += 1
        
        # updating WM, after a certain number of iterations (here, after 1 iteration)
        if n > -1: # this test can be used such that WM is updated only
                  # after a certain number of iterations
##           tempNumFbyN = SX / np.maximum(hatSX ** 2, eps)
##            tempDenFbyN = 1 / np.maximum(hatSX, eps)
##            WM = np.maximum(WM * (np.dot(tempNumFbyN, HM.T) /
##                                  np.maximum(np.dot(tempDenFbyN, HM.T),
##                                             eps)) ** omega, eps)
            WM = WM * \
                 ((np.dot(SXR / np.maximum(hatSXR ** 2, eps),
                          HM.T * (betaR ** 2)) +
                   np.dot(SXL / np.maximum(hatSXL ** 2, eps),
                          HM.T * (betaL ** 2))
                   ) /
                  (np.dot(1 / np.maximum(hatSXR, eps),
                          HM.T * (betaR ** 2)) +
                   np.dot(1 / np.maximum(hatSXL, eps),
                          HM.T * (betaL ** 2))
                   )) ** omega
            
            sumWM = np.sum(WM, axis=0)
            WM[:, sumWM>0] /= sumWM[sumWM>0]
            HM *= np.vstack(sumWM)
            
            hatSXL = SF0 * SPHI
            hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
            hatSXR += (alphaR**2) * hatSXL
            hatSXL *= (alphaL**2)
            hatSXL += np.dot((WM * (betaL**2)), HM)
            
            hatSXR = np.maximum(hatSXR, eps)
            hatSXL = np.maximum(hatSXL, eps)
            
            ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
            ##                    np.dot(WM * (betaR**2), HM), eps)
            ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
            ##                    np.dot(WM * (betaL**2), HM), eps)
            
            ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
            ##                       + ISDistortion(SXL, hatSXL)
            ## 
            ## if verbose:
            ##     print "Reconstruction error difference after WM    : ",
            ##     print recoError[counterError] - recoError[counterError - 1]
            counterError += 1
            
        # updating alphaR and alphaL:
        tempDenFbyN = SF0 * SPHI / np.maximum(hatSXR, eps)
        tempNumFbyN = tempDenFbyN * SXR / np.maximum(hatSXR, eps)
        ## tempDenFbyN = SF0 * SPHI / np.maximum(hatSXR, eps)
        alphaR = np.maximum(alphaR *
                            (np.sum(tempNumFbyN) /
                            np.sum(tempDenFbyN)) ** (omega*.1), eps)
        tempDenFbyN = SF0 * SPHI / np.maximum(hatSXL, eps)
        tempNumFbyN = tempDenFbyN * SXL / np.maximum(hatSXL, eps)
        alphaL = np.maximum(alphaL *
                            (np.sum(tempNumFbyN) /
                            np.sum(tempDenFbyN)) ** (omega*.1), eps)
        alphaR = alphaR / np.maximum(alphaR + alphaL, .001)
        alphaL = np.copy(1 - alphaR)
        
        hatSXL = SF0 * SPHI
        hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
        hatSXR += (alphaR**2) * hatSXL
        hatSXL *= (alphaL**2)
        hatSXL += np.dot((WM * (betaL**2)), HM)
        
        hatSXR = np.maximum(hatSXR, eps)
        hatSXL = np.maximum(hatSXL, eps)
        
        ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
        ##                    np.dot(WM * (betaR**2), HM), eps)
        ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
        ##                    np.dot(WM * (betaL**2), HM), eps)
        
        ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
        ##                           + ISDistortion(SXL, hatSXL)
        ## 
        ## if verbose:
        ##     print "Reconstruction error difference after ALPHA : ",
        ##     print recoError[counterError] - recoError[counterError - 1]
        counterError += 1
        
        # updating betaR and betaL
        betaR *= np.diag(
            ((np.dot(np.dot(WM.T, SXR / np.maximum(hatSXR ** 2, eps)), HM.T)) /
             (np.dot(np.dot(WM.T, 1 / np.maximum(hatSXR, eps)), HM.T)))
            ** (omega*.1))
        betaL *= np.diag(
            ((np.dot(np.dot(WM.T, SXL / np.maximum(hatSXL ** 2, eps)), HM.T)) /
             (np.dot(np.dot(WM.T, 1 / np.maximum(hatSXL, eps)), HM.T)))
            ** (omega*.1))
        betaR = betaR / np.maximum(betaR + betaL, eps)
        # betaL = np.copy(np.eye(R) - betaR)
        betaL = 1 - betaR
        
        hatSXL = SF0 * SPHI
        hatSXR = np.dot((WM * (betaR**2)), HM, out=hatSXR)
        hatSXR += (alphaR**2) * hatSXL
        hatSXL *= (alphaL**2)
        hatSXL += np.dot((WM * (betaL**2)), HM)
        
        hatSXR = np.maximum(hatSXR, eps)
        hatSXL = np.maximum(hatSXL, eps)
        
        ##hatSXR = np.maximum((alphaR**2) * SF0 * SPHI + \
        ##                    np.dot(WM * (betaR**2),HM), eps)
        ##hatSXL = np.maximum((alphaL**2) * SF0 * SPHI + \
        ##                    np.dot(WM * (betaL**2),HM), eps)
        
        ## recoError[counterError] = ISDistortion(SXR, hatSXR) \
        ##                           + ISDistortion(SXL, hatSXL)
        ## 
        ## if verbose:
        ##     print "Reconstruction error difference after BETA  : ",
        ##     print recoError[counterError] - recoError[counterError - 1]
        counterError += 1
        
    return alphaR, alphaL, HGAMMA, HPHI, HF0, np.diag(betaR), np.diag(betaL), HM, WM, recoError