Example #1
0
def line_search(f,
                myfprime,
                xk,
                pk,
                gfk,
                old_fval,
                old_old_fval,
                args=(),
                c1=1e-4,
                c2=0.9,
                amax=50):

    fc = 0
    gc = 0
    phi0 = old_fval
    derphi0 = numpy.dot(gfk, pk)
    alpha1 = pymin(1.0, 1.01 * 2 * (phi0 - old_old_fval) / derphi0)
    # trevor: added this test
    alpha1 = pymin(alpha1, amax)

    if isinstance(myfprime, type(())):
        eps = myfprime[1]
        fprime = myfprime[0]
        newargs = (f, eps) + args
        gradient = False
    else:
        fprime = myfprime
        newargs = args
        gradient = True

    xtol = 1e-14
    amin = 1e-8
    isave = numpy.zeros((2, ), numpy.intc)
    dsave = numpy.zeros((13, ), float)
    task = 'START'
    fval = old_fval
    gval = gfk

    while 1:
        stp, fval, derphi, task = minpack2.dcsrch(alpha1, phi0, derphi0, c1,
                                                  c2, xtol, task, amin, amax,
                                                  isave, dsave)
        #print 'minpack2.dcsrch', alpha1, phi0, derphi0, c1, c2, xtol, task, amin, amax,isave,dsave
        #print 'returns', stp,fval,derphi,task

        if task[:2] == 'FG':
            alpha1 = stp
            fval = f(xk + stp * pk, *args)
            fc += 1
            gval = fprime(xk + stp * pk, *newargs)
            if gradient: gc += 1
            else: fc += len(xk) + 1
            phi0 = fval
            derphi0 = numpy.dot(gval, pk)
        else:
            break

    if task[:5] == 'ERROR' or task[1:4] == 'WARN':
        stp = None  # failed
    return stp, fc, gc, fval, old_fval, gval
Example #2
0
    def _lineSearchStep(self, lastStepInfo, curObjVal):
        """
      Determine the next action to take in the line search process
      @ In, lastStepInfo, dict, dictionary of past and present relevant information
      @ In, curObjVal, float, current objective value obtained during line search
      @ Out, stepSize, float, new suggested step size
      @ Out, task, binary string, task of line search
    """
        # determine next task in line search
        stepSize = lastStepInfo['stepSize']
        lineObjDerivative = lastStepInfo['line']['objDerivative']
        task = lastStepInfo['task']
        iSave = lastStepInfo['fortranParams']['iSave']
        dSave = lastStepInfo['fortranParams']['dSave']
        stepSize, _, _, task = minpack2.dcsrch(stepSize,
                                               curObjVal,
                                               lineObjDerivative,
                                               ftol=1e-4,
                                               gtol=0.4,
                                               xtol=1e-14,
                                               task=task,
                                               stpmin=1e-100,
                                               stpmax=1e100,
                                               isave=iSave,
                                               dsave=dSave)

        return stepSize, task
Example #3
0
    def _line_search_minpack(self, maxiter: int, amin: float, amax: float):
        phi0 = self._p['fval']
        old_phi0 = self._p['old_fval']
        derphi0 = self._derphi(0.0)

        if derphi0 != 0.0:
            alpha1 = min(1.0, 2.02 * (phi0 - old_phi0) / derphi0)
        else:
            alpha1 = 1.0

        if alpha1 <= amin:
            alpha1 = 1.0

        phi1 = phi0
        derphi1 = derphi0
        isave = np.zeros((2,), np.intc)
        dsave = np.zeros((13,), float)
        task = b'START'

        for _ in range(maxiter):
            stp, phi1, derphi1, task = dcsrch(alpha1, phi1, derphi1, self._p['c1'],
                                              self._p['c2'], self._p['xtol'],
                                              task, amin, amax, isave, dsave)

            if task[:2] == b'FG':
                alpha1 = stp
                phi1 = self._phi(stp)
                derphi1 = self._derphi(stp)
            else:
                break

        self._p['alpha_k'] = stp
        self._p['fval'] = phi1
        self._p['old_fval'] = phi0
def line_search(f, myfprime, xk, pk, gfk, old_fval, old_old_fval,
                args=(), c1=1e-4, c2=0.9, amax=50):

    fc = 0
    gc = 0
    phi0 = old_fval
    derphi0 = numpy.dot(gfk,pk)
    alpha1 = pymin(1.0,1.01*2*(phi0-old_old_fval)/derphi0)
    # trevor: added this test
    alpha1 = pymin(alpha1,amax)

    if isinstance(myfprime,type(())):
        eps = myfprime[1]
        fprime = myfprime[0]
        newargs = (f,eps) + args
        gradient = False
    else:
        fprime = myfprime
        newargs = args
        gradient = True

    xtol = 1e-14
    amin = 1e-8
    isave = numpy.zeros((2,), numpy.intc)
    dsave = numpy.zeros((13,), float)
    task = 'START'
    fval = old_fval
    gval = gfk

    while 1:
        stp,fval,derphi,task = minpack2.dcsrch(alpha1, phi0, derphi0, c1, c2,
                                               xtol, task, amin, amax,isave,dsave)
        #print 'minpack2.dcsrch', alpha1, phi0, derphi0, c1, c2, xtol, task, amin, amax,isave,dsave
        #print 'returns', stp,fval,derphi,task

        if task[:2] == 'FG':
            alpha1 = stp
            fval = f(xk+stp*pk,*args)
            fc += 1
            gval = fprime(xk+stp*pk,*newargs)
            if gradient: gc += 1
            else: fc += len(xk) + 1
            phi0 = fval
            derphi0 = numpy.dot(gval,pk)
        else:
            break

    if task[:5] == 'ERROR' or task[1:4] == 'WARN':
        stp = None  # failed
    return stp, fc, gc, fval, old_fval, gval
Example #5
0
def scalar_search_wolfe1(phi,
                         derphi,
                         phi0=None,
                         old_phi0=None,
                         derphi0=None,
                         c1=1e-4,
                         c2=0.9,
                         amax=50,
                         amin=1e-8,
                         xtol=1e-14):

    if phi0 is None:
        phi0 = phi(0.)
    if derphi0 is None:
        derphi0 = derphi(0.)

    if old_phi0 is not None and derphi0 != 0:
        alpha1 = min(1.0, 1.01 * 2 * (phi0 - old_phi0) / derphi0)
        if alpha1 < 0:
            alpha1 = 1.0
    else:
        alpha1 = 1.0

    phi1 = phi0
    derphi1 = derphi0
    isave = np.zeros((2, ), np.intc)
    dsave = np.zeros((13, ), float)
    task = b'START'

    maxiter = 100
    for i in xrange(maxiter):
        stp, phi1, derphi1, task = minpack2.dcsrch(alpha1, phi1, derphi1, c1,
                                                   c2, xtol, task, amin, amax,
                                                   isave, dsave)
        if task[:2] == b'FG':
            alpha1 = stp
            phi1 = phi(stp)
            derphi1 = derphi(stp)
        else:
            break
    else:
        # maxiter reached, the line search did not converge
        stp = None

    if task[:5] == b'ERROR' or task[:4] == b'WARN':
        stp = None  # failed

    return stp, phi1, phi0
Example #6
0
def scalar_search_wolfe1(phi, derphi, phi0=None, old_phi0=None, derphi0=None,
                         c1=1e-4, c2=0.9,
                         amax=50, amin=1e-8, xtol=1e-14):

    if phi0 is None:
        phi0 = phi(0.)
    if derphi0 is None:
        derphi0 = derphi(0.)

    if old_phi0 is not None and derphi0 != 0:
        alpha1 = min(1.0, 1.01*2*(phi0 - old_phi0)/derphi0)
        if alpha1 < 0:
            alpha1 = 1.0
    else:
        alpha1 = .01


    phi1 = phi0
    derphi1 = derphi0
    isave = numpy.zeros((2,), numpy.intc)
    dsave = numpy.zeros((13,), float)
    task = b'START'

    maxiter = 15
    for i in xrange(maxiter):
        stp, phi1, derphi1, task = minpack2.dcsrch(alpha1, phi1, derphi1,
                                                   c1, c2, xtol, task,
                                                   amin, amax, isave, dsave)
        #print "alpha1 = ", alpha1 
        
        if task[:2] == b'FG':
            alpha1 = stp
            phi1 = phi(stp)
            derphi1 = derphi(stp)
        else:
            break
    else:
        # maxiter reached, the line search did not converge
        stp = None

    if task[:5] == b'ERROR' or task[:4] == b'WARN':
        stp = None  # failed

    return stp, phi1, phi0
Example #7
0
    def line_search(self,x0,f0,g0,d,above_iter,max_steplength,func,alpha=1e-4,\
                    beta=0.9,xtol_minpack=1e-5,max_iter=30):
        steplength_0 = 1 if max_steplength > 1 else 0.5 * max_steplength
        f_m1 = f0
        dphi = g0.dot(d)
        dphi_m1 = dphi
        idx = 0

        if (above_iter == 0):
            max_steplength = 1.0
            steplength_0 = min(1.0 / np.sqrt(d.dot(d)), 1.0)

        isave = np.zeros((2, ), np.intc)
        dsave = np.zeros((13, ), float)
        task = b'START'

        while idx < max_iter:
            steplength,f0,dphi,task=minpack2.dcsrch(steplength_0,f_m1,dphi_m1,\
                                                    alpha,beta,xtol_minpack,task,\
                                                    0,max_steplength,isave,dsave)
            if task[:2] == b'FG':
                steplength_0 = steplength
                f_m1, g_m1 = func(x0 + steplength * d)
                dphi_m1 = g_m1.dot(d)
                # print(f_m1)
            else:
                break
        else:
            # max_iter reached, the line search did not converge
            steplength = None

        if task[:5] == b'ERROR' or task[:4] == b'WARN':
            if task[:21] != b'WARNING: STP = STPMAX':
                print(task)
                steplength = None  # failed

        return steplength
def scalar_search_wolfe1(phi, derphi, phi0=None, old_phi0=None, derphi0=None,
                         c1=1e-4, c2=0.9,
                         amax=50, amin=1e-8, xtol=1e-14):
    """
    Scalar function search for alpha that satisfies strong Wolfe conditions

    alpha > 0 is assumed to be a descent direction.

    Parameters
    ----------
    phi : callable phi(alpha)
        Function at point `alpha`
    derphi : callable dphi(alpha)
        Derivative `d phi(alpha)/ds`. Returns a scalar.

    phi0 : float, optional
        Value of `f` at 0
    old_phi0 : float, optional
        Value of `f` at the previous point
    derphi0 : float, optional
        Value `derphi` at 0
    c1, c2 : float, optional
        Wolfe parameters
    amax, amin : float, optional
        Maximum and minimum step size
    xtol : float, optional
        Relative tolerance for an acceptable step.

    Returns
    -------
    alpha : float
        Step size, or None if no suitable step was found
    phi : float
        Value of `phi` at the new point `alpha`
    phi0 : float
        Value of `phi` at `alpha=0`

    Notes
    -----
    Uses routine DCSRCH from MINPACK.

    """

    if phi0 is None:
        phi0 = phi(0.)
    if derphi0 is None:
        derphi0 = derphi(0.)

    if old_phi0 is not None and derphi0 != 0:
        alpha1 = min(1.0, 1.01*2*(phi0 - old_phi0)/derphi0)
        if alpha1 < 0:
            alpha1 = 1.0
    else:
        alpha1 = 1.0

    phi1 = phi0
    derphi1 = derphi0
    isave = np.zeros((2,), np.intc)
    dsave = np.zeros((13,), float)
    task = b'START'

    maxiter = 100
    for i in xrange(maxiter):
        stp, phi1, derphi1, task = minpack2.dcsrch(alpha1, phi1, derphi1,
                                                   c1, c2, xtol, task,
                                                   amin, amax, isave, dsave)
        if task[:2] == b'FG':
            alpha1 = stp
            phi1 = phi(stp)
            derphi1 = derphi(stp)
        else:
            break
    else:
        # maxiter reached, the line search did not converge
        stp = None

    if task[:5] == b'ERROR' or task[:4] == b'WARN':
        stp = None  # failed

    return stp, phi1, phi0
Example #9
0
def scalar_search_wolfe1(phi, derphi, phi0=None, old_phi0=None, derphi0=None,
                         c1=1e-4, c2=0.9,
                         amax=50, amin=1e-8, xtol=1e-14):
    """
    Scalar function search for alpha that satisfies strong Wolfe conditions

    alpha > 0 is assumed to be a descent direction.

    Parameters
    ----------
    phi : callable phi(alpha)
        Function at point `alpha`
    derphi : callable dphi(alpha)
        Derivative `d phi(alpha)/ds`. Returns a scalar.

    phi0 : float, optional
        Value of `f` at 0
    old_phi0 : float, optional
        Value of `f` at the previous point
    derphi0 : float, optional
        Value `derphi` at 0
    amax : float, optional
        Maximum step size
    c1, c2 : float, optional
        Wolfe parameters

    Returns
    -------
    alpha : float
        Step size, or None if no suitable step was found
    phi : float
        Value of `phi` at the new point `alpha`
    phi0 : float
        Value of `phi` at `alpha=0`

    Notes
    -----
    Uses routine DCSRCH from MINPACK.

    """

    if phi0 is None:
        phi0 = phi(0.)
    if derphi0 is None:
        derphi0 = derphi(0.)

    if old_phi0 is not None and derphi0 != 0:
        alpha1 = min(1.0, 1.01*2*(phi0 - old_phi0)/derphi0)
        if alpha1 < 0:
            alpha1 = 1.0
    else:
        alpha1 = 1.0

    phi1 = phi0
    derphi1 = derphi0
    isave = np.zeros((2,), np.intc)
    dsave = np.zeros((13,), float)
    task = b'START'

    maxiter = 30
    for i in xrange(maxiter):
        stp, phi1, derphi1, task = minpack2.dcsrch(alpha1, phi1, derphi1,
                                                   c1, c2, xtol, task,
                                                   amin, amax, isave, dsave)
        if task[:2] == b'FG':
            alpha1 = stp
            phi1 = phi(stp)
            derphi1 = derphi(stp)
        else:
            break
    else:
        # maxiter reached, the line search did not converge
        stp = None

    if task[:5] == b'ERROR' or task[:4] == b'WARN':
        stp = None  # failed

    return stp, phi1, phi0
Example #10
0
def scalar_search_wolfe1(phi,
                         derphi,
                         phi0=None,
                         old_phi0=None,
                         derphi0=None,
                         c1=1e-4,
                         c2=0.9,
                         amax=50,
                         amin=1e-8,
                         xtol=1e-14):
    """
    Scalar function search for alpha that satisfies strong Wolfe conditions

    alpha > 0 is assumed to be a descent direction.

    Parameters
    ----------
    phi : callable phi(alpha)
        Function at point `alpha`
    derphi : callable dphi(alpha)
        Derivative `d phi(alpha)/ds`. Returns a scalar.

    phi0 : float, optional
        Value of `f` at 0
    old_phi0 : float, optional
        Value of `f` at the previous point
    derphi0 : float, optional
        Value `derphi` at 0
    amax : float, optional
        Maximum step size
    c1, c2 : float, optional
        Wolfe parameters

    Returns
    -------
    alpha : float
        Step size, or None if no suitable step was found
    phi : float
        Value of `phi` at the new point `alpha`
    phi0 : float
        Value of `phi` at `alpha=0`

    Notes
    -----
    Uses routine DCSRCH from MINPACK.

    """

    if phi0 is None:
        phi0 = phi(0.)
    if derphi0 is None:
        derphi0 = derphi(0.)

    if old_phi0 is not None:
        alpha1 = min(1.0, 1.01 * 2 * (phi0 - old_phi0) / derphi0)
        if alpha1 < 0:
            alpha1 = 1.0
    else:
        alpha1 = 1.0

    phi1 = phi0
    derphi1 = derphi0
    isave = np.zeros((2, ), np.intc)
    dsave = np.zeros((13, ), float)
    task = asbytes('START')

    while 1:
        stp, phi1, derphi1, task = minpack2.dcsrch(alpha1, phi1, derphi1, c1,
                                                   c2, xtol, task, amin, amax,
                                                   isave, dsave)
        if task[:2] == asbytes('FG'):
            alpha1 = stp
            phi1 = phi(stp)
            derphi1 = derphi(stp)
        else:
            break

    if task[:5] == asbytes('ERROR') or task[:4] == asbytes('WARN'):
        stp = None  # failed

    return stp, phi1, phi0
Example #11
0
def find_geodesic_midpoint(start_point, end_point, number_of_inner_points, basis_rotation_matrix,
                           tangent_direction, codimension, metric_server_addresses, mass_matrix, authkey,
                           gtol=1e-5):
    """ This function computes the local geodesic curve joining start_point to end_point using a modified BFGS method.
    The modification arises from taking the implementation of BFGS and re-writing it to minimise the number
    of times the metric function is called.

    Args:
      start_point (numpy.array) :
          The first end point of the curve.
      end_point (numpy.array) :
          The last end point of the curve.
      number_of_inner_points (int) :
          The number of nodes along the curve, less the end points.
      basis_rotation_matrix (numpy.array) :
          The matrix computed as a result of the orthogonal_tangent_basis function.
      tangent_direction (numpy.array) :
          The tangent direction as computed by the SimulationClient.
      codimension (int) :
          The dimension of the problem minus 1. Computed from the atomistic simulation environment.
      metric_server_addresses :
          A list of tuples of the form (str, int) containing the hostnames and port numbers of the SimulationPotential
          instances.
      mass_matrix (numpy.array) :
          A diagonal NumPy array containing the masses of the molecular system as computed in the SimulationClient
          object.
      authkey (str) :
          The password used in order to communicate with the SimulationPotential instances.
      gtol (optional float) :
          The tolerance threshold for the BGFS method.

    Returns:
      numpy.array: The midpoint along the local geodesic curve.

    """

    # Determine the number of variable the BFGS method will be applied to
    number_of_variables = number_of_inner_points * codimension

    # Produce an initial guess for the minimum, in this case it will be that the straight line segment joining
    # start_point to end_point is the initial guess
    x0 = np.zeros(number_of_variables)

    # Allocate memory for the kth iterate
    xk = x0

    # Convert the description of the curve as shifts in the orthonormal hyperspace along the initial line to points in
    # the full space. See LinearAlgebra.shifts_to_curve for more details.
    curve = la.shifts_to_curve(start_point, end_point, xk, number_of_inner_points,
                            basis_rotation_matrix, tangent_direction, codimension)

    # Get the initial metric values along the starting curve.
    metric = get_metric(curve, number_of_inner_points, metric_server_addresses, authkey)

    # If the SimulationPotential couldn't be contacted then return None to close the SimulationClient
    if metric is None:
        return None

    # Obtain the initial gradient of the length functional along the curve
    gfk = GradLength(curve, metric, number_of_inner_points, mass_matrix, basis_rotation_matrix)

    # Create an identity matrix object
    I = np.eye(number_of_variables, dtype=int)

    # Initialise the memory to store the approximate Hessian matrix
    Hk = I

    # Compute the norm of the gradient in the L^{\infty} norm
    gnorm = np.amax(np.abs(gfk))

    # The main body of the BFGS calculation:
    # Repeat the method until the norm of the gradient of the length is sufficiently small.
    while gnorm > gtol:

        alpha1 = 1.0
        pk = -np.dot(Hk, gfk)

        phi0 = Length(curve, metric, number_of_inner_points, mass_matrix)
        phi1 = phi0
        derphi0 = np.dot(gfk, pk)
        derphi1 = derphi0

        isave = np.zeros((2,), np.intc)
        dsave = np.zeros((13,), float)
        task = b'START'

        # Perform the linesearch
        for i in xrange(30):
            stp, phi1, derphi1, task = minpack2.dcsrch(alpha1, phi1, derphi1, 1e-4, 0.9, 1e-14, task, 1e-8, 50,
                                                       isave, dsave)
            if task[:2] == b'FG':
                alpha1 = stp
                # Convert the description of the curve as shifts in the orthonormal hyperspace along the initial line
                # to points in the full space. See LinearAlgebra.shifts_to_curve for more details.
                curve = la.shifts_to_curve(start_point, end_point, xk + stp*pk, number_of_inner_points,
                                        basis_rotation_matrix, tangent_direction, codimension)

                # Get the initial metric values along the current trial.
                metric = get_metric(curve, number_of_inner_points, metric_server_addresses, authkey)

                # If the SimulationPotential couldn't be reached then return None to close SimulationClient
                if metric is None:
                    return None

                phi1 = Length(curve, metric, number_of_inner_points, mass_matrix)
                gfkp1 = GradLength(curve, metric, number_of_inner_points, mass_matrix, basis_rotation_matrix)
                derphi1 = np.dot(gfkp1, pk)
            else:
                break
        else:
            break

        if task[:5] == b'ERROR' or task[:4] == b'WARN':
            break

        alpha_k = stp
        xkp1 = xk + alpha_k * pk
        sk = xkp1 - xk
        xk = xkp1
        yk = gfkp1 - gfk
        gfk = gfkp1
        gnorm = np.amax(np.abs(gfk))
        if gnorm <= gtol:
            break

        rhok = 1.0 / (np.dot(yk, sk))
        if np.isinf(rhok): rhok = 1000.0  # this is patch for numpy

        Hk = np.dot(I - sk[:, np.newaxis] * yk[np.newaxis, :] *
                    rhok, np.dot(Hk, I - yk[:, np.newaxis] * sk[np.newaxis, :] * rhok)) + (rhok * sk[:, np.newaxis]
                                                                                           * sk[np.newaxis, :])

    # Return the midpoint
    return curve[(number_of_inner_points + 1) / 2]
Example #12
0
def line_search(x0, f0, g0, d, above_iter, max_steplength,\
                fct_f, fct_grad,\
                alpha = 1e-4, beta = 0.9,\
                xtol_minpack = 1e-5, max_iter = 30):
    """
        Finds a step that satisfies a sufficient decrease condition and a curvature condition.

        The algorithm is designed to find a step that satisfies the sufficient decrease condition 
        
              f(x0+stp*d) <= f(x0) + alpha*stp*\langle f'(x0),d\rangle,
        
        and the curvature condition
        
              abs(f'(x0+stp*d)) <= beta*abs(\langle f'(x0),d\rangle).
        
        If alpha is less than beta and if, for example, the functionis bounded below, then
        there is always a step which satisfies both conditions. 

    :param x0: starting point 
    :type x0: np.array
    
    :param f0: f(x0) 
    :type f0: float
    
    :param g0: f'(x0), gradient 
    :type g0: np.array
    
    :param d: search direction
    :type d: np.array
    
    :param above_iter: current iteration in optimization process
    :type above_iter: integer
    
    :param max_steplength: maximum steplength allowed 
    :type max_steplength: float 
    
    :param fct_f: callable, function f(x) 
    :type fct_f: function returning float
    
    :param fct_grad: callable, function f'(x) 
    :type fct_grad: function returning np.array
    
    :param alpha, beta: parameters of the decrease and curvature conditions 
    :type alpha, beta: floats
    
    :param xtol_minpack: tolerance used in minpack2.dcsrch
    :type xtol_minpack: float
    
    :param max_iter: number of iteration allowed for finding a steplength
    :type max_iter: integer
    
    :return: optimal steplength meeting both decrease and curvature condition 
    :rtype: float
    
    
    

    .. seealso:: 
        
       [minpack] scipy.optimize.minpack2.dcsrch

       [1] R. H. Byrd, P. Lu, J. Nocedal and C. Zhu, ``A limited
       memory algorithm for bound constrained optimization'',
       SIAM J. Scientific Computing 16 (1995), no. 5, pp. 1190--1208.

       [2] C. Zhu, R.H. Byrd, P. Lu, J. Nocedal, ``L-BFGS-B: FORTRAN
       Subroutines for Large Scale Bound Constrained Optimization''
       Tech. Report, NAM-11, EECS Department, Northwestern University,
       1994.
    """

    steplength_0 = 1 if max_steplength > 1 else 0.5 * max_steplength
    f_m1 = f0
    dphi = g0.dot(d)
    dphi_m1 = dphi
    i = 0

    if (above_iter == 0):
        max_steplength = 1.0
        steplength_0 = min(1.0 / np.sqrt(d.dot(d)), 1.0)

    isave = np.zeros((2, ), np.intc)
    dsave = np.zeros((13, ), float)
    task = b'START'

    while i < max_iter:
        steplength, f0, dphi, task = minpack2.dcsrch(steplength_0, f_m1,
                                                     dphi_m1, alpha, beta,
                                                     xtol_minpack, task, 0,
                                                     max_steplength, isave,
                                                     dsave)
        if task[:2] == b'FG':
            steplength_0 = steplength
            f_m1 = fct_f(x0 + steplength * d)
            dphi_m1 = fct_grad(x0 + steplength * d).dot(d)
        else:
            break
    else:
        # max_iter reached, the line search did not converge
        steplength = None

    if task[:5] == b'ERROR' or task[:4] == b'WARN':
        if task[:21] != b'WARNING: STP = STPMAX':
            print(task)
            steplength = None  # failed

    return steplength
Example #13
0
  def localFinalizeActualSampling(self,jobObject,model,myInput):
    """
      Overwrite only if you need something special at the end of each run....
      This function is used by optimizers that need to collect information from the just ended run
      @ In, jobObject, instance, an instance of a Runner
      @ In, model, Model, instance of a RAVEN model
      @ In, myInput, list, the generating input
      @ Out, None
    """
    #collect first output
    prefix = jobObject.getMetadata()['prefix']
    traj, step, identifier = [int(x) for x in prefix.split('_')]
    self.raiseADebug('Collected sample "{}"'.format(prefix))
    category, number, _, cdId = self._identifierToLabel(identifier)
    done, index = self._checkModelFinish(str(traj), str(step), str(identifier))
    if not done:
      self.raiseAnError(RuntimeError,'Trying to collect "{}" but identifies as not done!'.format(prefix))
    number = number + (cdId * len(self.fullOptVars))
    self.realizations[traj]['collect'][category][number].append(index)
    if len(self.realizations[traj]['collect'][category][number]) == self.realizations[traj]['need']:
      outputs = self._averageCollectedOutputs(self.realizations[traj]['collect'][category][number])
      self.realizations[traj]['denoised'][category][number] = outputs
      if category == 'opt':
        converged = self._finalizeOptimalCandidate(traj,outputs)
      else:
        converged = False
      optDone = bool(len(self.realizations[traj]['denoised']['opt'][0]))
      gradDone = all( len(self.realizations[traj]['denoised']['grad'][i]) for i in range(self.paramDict['pertSingleGrad']))
      if not converged and optDone and gradDone:
        optCandidate = self.normalizeData(self.realizations[traj]['denoised']['opt'][0])
        if self.writeSolnExportOn == 'every':
          self.writeToSolutionExport(traj, optCandidate, self.realizations[traj]['accepted'])
        # whether we wrote to solution export or not, update the counter
        self.counter['solutionUpdate'][traj] += 1
        self.counter['varsUpdate'][traj] += 1

        if self.counter['task'][traj][:5] == b'START':
          ## since accepted, update history
          try:
            self.counter['recentOptHist'][traj][1] = copy.deepcopy(self.counter['recentOptHist'][traj][0])
          except KeyError:
            # this means we don't have an entry for this trajectory yet, so don't copy anything
            pass
          # store realization of most recent developments
          self.counter['recentOptHist'][traj][0] = optCandidate
          # change xk into array with index matching the index map
          xk = dict((var,self.realizations[traj]['denoised']['opt'][0][var]) for var in self.getOptVars())
          self.counter['xk'][traj] = np.asarray(list(xk.values()))
          self.counter['oldGradK'][traj] = self.counter['gfk'][traj]
          gfk = dict((var,self.localEvaluateGradient(traj,gradHist = True)[var][0]) for var in self.getOptVars())
          self.counter['gfk'][traj] = np.asarray(list(gfk.values()))
          if self.useGradHist and self.counter['oldFVal'][traj]:
            self.counter['oldOldFVal'][traj] = self.counter['oldFVal'][traj]
            self.counter['oldFVal'][traj] = self.realizations[traj]['denoised']['opt'][0][self.objVar]
            self.counter['gNorm'][traj] = self.polakRibierePowellStep(traj,self.counter['lastStepSize'][traj], self.counter['gfk'][traj])
          else:
            self.counter['oldFVal'][traj] = self.realizations[traj]['denoised']['opt'][0][self.objVar]
            self.counter['oldOldFVal'][traj] = self.counter['oldFVal'][traj] + np.linalg.norm(self.counter['gfk'][traj]) / 2
            self.counter['pk'][traj] = -(self.counter['gfk'][traj])
            self.counter['gNorm'][traj] = np.amax(np.abs(self.counter['gfk'][traj]))

          # first step
          self.counter['deltaK'][traj] = np.dot(self.counter['gfk'][traj], self.counter['gfk'][traj])
          self.counter['derPhi0'][traj] = np.dot(self.counter['gfk'][traj], self.counter['pk'][traj])
          self.counter['alpha'][traj] = min(1.0, 1.01*2*(self.counter['oldFVal'][traj] - self.counter['oldOldFVal'][traj])/self.counter['derPhi0'][traj])

          phi1 = self.counter['oldFVal'][traj]
          derPhi1 = self.counter['derPhi0'][traj]
        else:
          newGrad = dict((var,self.localEvaluateGradient(traj, gradHist = True)[var][0]) for var in self.getOptVars())
          newGrad = np.asarray(list(newGrad.values()))
          # after step

          phi1 = self.realizations[traj]['denoised']['opt'][0][self.objVar]
          derPhi1 = np.dot(newGrad, self.counter['pk'][traj])

        self.counter['lastStepSize'][traj], self.counter['newFVal'][traj], _, self.counter['task'][traj] = minpack2.dcsrch(self.counter['alpha'][traj], phi1, derPhi1, ftol=1e-4, gtol=0.4,
                                                xtol=1e-14, task = self.counter['task'][traj], stpmin=1e-100,
                                                stpmax=1e100, isave = self.counter['iSave'][traj] , dsave=self.counter['dSave'][traj])
        # return of the line search can be those results
        # If task = 'FG' then evaluate the function and derivative at step and call dcsrch again
        # If task = 'CONV' then the search is successful. Store this point start a new point
        # If task = 'WARN' then the subroutine is not able to satisfy the convergence conditions. Counted as converged and  resubmit the same point for the presistance
        # If task = 'ERROR' then there is an error in the input arguments

        if self.counter['task'][traj][:2] == b'FG':
          pass # No need to do anything because the value have already been updated
        elif self.counter['task'][traj][:11] == b'CONVERGENCE' :
          self.raiseADebug('Local minimal reached, start new line search')
          self.counter['task'][traj] = b'START' # start a new search

        elif self.counter['task'][traj][:7] == b'WARNING' :
          self.raiseAWarning(self.counter['task'][traj][9:].decode().lower())
          self.counter['persistence'][traj] += 1 # counted as one converged point
          if self.counter['persistence'][traj] >= self.convergencePersistence:
            self.raiseAMessage(' ... Trajectory "{}" converged {} times consecutively!'.format(traj,self.counter['persistence'][traj]))
            self.convergeTraj[traj] = True
            self.removeConvergedTrajectory(traj)
          else:
            self.raiseAMessage(' ... converged Traj "{}" {} times, required persistence is {}.'.format(traj,self.counter['persistence'][traj],self.convergencePersistence))
        else:
          self.raiseAWarning('Not able to calculate the forward step')
          self.counter['persistence'][traj] += 1
          if self.counter['persistence'][traj] >= self.convergencePersistence:
            self.raiseAMessage(' ... Trajectory "{}" converged {} times consecutively!'.format(traj,self.counter['persistence'][traj]))
            self.convergeTraj[traj] = True
            self.removeConvergedTrajectory(traj)
          else:
            self.raiseAMessage(' ... converged Traj "{}" {} times, required persistence is {}.'.format(traj,self.counter['persistence'][traj],self.convergencePersistence))
        self.counter['alpha'][traj] = self.counter['lastStepSize'][traj]
        grad = dict((var,self.counter['gfk'][traj][ind]/(self.optVarsInit['upperBound'][var]-self.optVarsInit['lowerBound'][var])) for ind,var in enumerate(self.getOptVars()))
        try:
          self.counter['gradNormHistory'][traj][1] = self.counter['gradNormHistory'][traj][0]
        except IndexError:
          pass # don't have a history on the first pass
        self.counter['gradNormHistory'][traj][0] = grad

        new = self._newOptPointAdd(grad, traj)
        if new is not None:
          # add new gradient points
          self._createPerturbationPoints(traj, new)
        # reset storage
        self._setupNewStorage(traj)