Changeset 2854 for trunk/GSASIImath.py


Ignore:
Timestamp:
Jun 3, 2017 12:23:04 PM (6 years ago)
Author:
vondreele
Message:

implement Hessian SVD refinement option (no Levenberg-Marquardt). Works for final refinements but not good for initial refinements (far from minimum). Warning in Controls status bar

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASIImath.py

    r2853 r2854  
    146146         * 'lamMax':
    147147         * 'psing':
     148         * 'SVD0':
    148149           
    149150    """
     
    162163    nfev = 0
    163164    if Print:
    164         print ' Hessian SVD refinement on %d variables:'%(n)
     165        print ' Hessian Levenburg-Marquardt SVD refinement on %d variables:'%(n)
    165166    Lam = np.zeros((n,n))
    166167    while icycle < maxcyc:
     
    170171        chisq0 = np.sum(M**2)
    171172        Yvec,Amat = Hess(x0,*args)
    172 #        print 'unscaled SVD zeros',pinv(Amat)[1]
    173173        Adiag = np.sqrt(np.diag(Amat))
    174174        psing = np.where(np.abs(Adiag) < 1.e-14,True,False)
    175175        if np.any(psing):                #hard singularity in matrix
    176             return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':psing}]
     176            return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':psing,'SVD0':-1}]
    177177        Anorm = np.outer(Adiag,Adiag)
    178178        Yvec /= Adiag
     
    185185            try:
    186186                Ainv,Nzeros = pinv(Amatlam,xtol)    #do Moore-Penrose inversion (via SVD)
    187 #                Ainv = nl.inv(Amatlam); Nzeros = 0
    188187            except nl.LinAlgError:
    189188                print 'ouch #1 bad SVD inversion; change parameterization'
    190189                psing = list(np.where(np.diag(nl.qr(Amatlam)[1]) < 1.e-14)[0])
    191                 return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':psing}]
     190                return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':psing,'SVD0':-1}]
    192191            Xvec = np.inner(Ainv,Yvec)      #solve
    193192            Xvec /= Adiag
     
    228227#        Bmat = nl.inv(Amatlam); Nzeros = 0
    229228        Bmat = Bmat/Anorm
    230         return [x0,Bmat,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':[], 'Converged': ifConverged, 'DelChi2':deltaChi2}]
     229        return [x0,Bmat,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':[],'SVD0':Nzero,'Converged': ifConverged, 'DelChi2':deltaChi2}]
    231230    except nl.LinAlgError:
    232231        print 'ouch #2 linear algebra error in making v-cov matrix'
     
    234233        if maxcyc:
    235234            psing = list(np.where(np.diag(nl.qr(Amat)[1]) < 1.e-14)[0])
    236         return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':psing}]         
     235        return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':psing,'SVD0':-1}]         
     236           
     237def HessianSVD(func,x0,Hess,args=(),ftol=1.49012e-8,xtol=1.e-6, maxcyc=0,lamda=-3,Print=False):
     238   
     239    """
     240    Minimize the sum of squares of a function (:math:`f`) evaluated on a series of
     241    values (y): :math:`\sum_{y=0}^{N_{obs}} f(y,{args})`   
     242    where :math:`x = arg min(\sum_{y=0}^{N_{obs}} (func(y)^2,axis=0))`
     243
     244    :param function func: callable method or function
     245        should take at least one (possibly length N vector) argument and
     246        returns M floating point numbers.
     247    :param np.ndarray x0: The starting estimate for the minimization of length N
     248    :param function Hess: callable method or function
     249        A required function or method to compute the weighted vector and Hessian for func.
     250        It must be a symmetric NxN array
     251    :param tuple args: Any extra arguments to func are placed in this tuple.
     252    :param float ftol: Relative error desired in the sum of squares.
     253    :param float xtol: Relative tolerance of zeros in the SVD solution in nl.pinv.
     254    :param int maxcyc: The maximum number of cycles of refinement to execute, if -1 refine
     255        until other limits are met (ftol, xtol)
     256    :param bool Print: True for printing results (residuals & times) by cycle
     257
     258    :returns: (x,cov_x,infodict) where
     259
     260      * x : ndarray
     261        The solution (or the result of the last iteration for an unsuccessful
     262        call).
     263      * cov_x : ndarray
     264        Uses the fjac and ipvt optional outputs to construct an
     265        estimate of the jacobian around the solution.  ``None`` if a
     266        singular matrix encountered (indicates very flat curvature in
     267        some direction).  This matrix must be multiplied by the
     268        residual standard deviation to get the covariance of the
     269        parameter estimates -- see curve_fit.
     270      * infodict : dict
     271        a dictionary of optional outputs with the keys:
     272
     273         * 'fvec' : the function evaluated at the output
     274         * 'num cyc':
     275         * 'nfev':
     276         * 'lamMax':0.
     277         * 'psing':
     278         * 'SVD0':
     279           
     280    """
     281               
     282    ifConverged = False
     283    deltaChi2 = -10.
     284    x0 = np.array(x0, ndmin=1)      #might be redundant?
     285    n = len(x0)
     286    if type(args) != type(()):
     287        args = (args,)
     288       
     289    icycle = 0
     290    nfev = 0
     291    if Print:
     292        print ' Hessian SVD refinement on %d variables:'%(n)
     293    while icycle < maxcyc:
     294        time0 = time.time()
     295        M = func(x0,*args)
     296        nfev += 1
     297        chisq0 = np.sum(M**2)
     298        Yvec,Amat = Hess(x0,*args)
     299        Adiag = np.sqrt(np.diag(Amat))
     300        psing = np.where(np.abs(Adiag) < 1.e-14,True,False)
     301        if np.any(psing):                #hard singularity in matrix
     302            return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':0.,'psing':psing,'SVD0':-1}]
     303        Anorm = np.outer(Adiag,Adiag)
     304        Yvec /= Adiag
     305        Amat /= Anorm
     306        if Print:
     307            print 'initial chi^2 %.5g'%(chisq0)
     308        try:
     309            Ainv,Nzeros = pinv(Amat,xtol)    #do Moore-Penrose inversion (via SVD)
     310        except nl.LinAlgError:
     311            print 'ouch #1 bad SVD inversion; change parameterization'
     312            psing = list(np.where(np.diag(nl.qr(Amat)[1]) < 1.e-14)[0])
     313            return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':0.,'psing':psing,'SVD0':-1}]
     314        Xvec = np.inner(Ainv,Yvec)      #solve
     315        Xvec /= Adiag
     316        M2 = func(x0+Xvec,*args)
     317        nfev += 1
     318        chisq1 = np.sum(M2**2)
     319        deltaChi2 = (chisq0-chisq1)/chisq0
     320        if Print:
     321            print ' Cycle: %d, Time: %.2fs, Chi**2: %.5g, Delta: %.3g'%(
     322                icycle,time.time()-time0,chisq1,deltaChi2)
     323        if deltaChi2 < ftol:
     324            ifConverged = True
     325            if Print: print "converged"
     326            break
     327        icycle += 1
     328    M = func(x0,*args)
     329    nfev += 1
     330    Yvec,Amat = Hess(x0,*args)
     331    Adiag = np.sqrt(np.diag(Amat))
     332    Anorm = np.outer(Adiag,Adiag)
     333    Amat = Amat/Anorm       
     334    try:
     335        Bmat,Nzero = pinv(Amat,xtol)    #Moore-Penrose inversion (via SVD) & count of zeros
     336        print 'Found %d SVD zeros'%(Nzero)
     337#        Bmat = nl.inv(Amatlam); Nzeros = 0
     338        Bmat = Bmat/Anorm
     339        return [x0,Bmat,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':0.,'psing':[],
     340            'SVD0':Nzero,'Converged': ifConverged, 'DelChi2':deltaChi2}]
     341    except nl.LinAlgError:
     342        print 'ouch #2 linear algebra error in making v-cov matrix'
     343        psing = []
     344        if maxcyc:
     345            psing = list(np.where(np.diag(nl.qr(Amat)[1]) < 1.e-14)[0])
     346        return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':0.,'psing':psing,'SVD0':-1}]         
    237347           
    238348def getVCov(varyNames,varyList,covMatrix):
Note: See TracChangeset for help on using the changeset viewer.