Ejemplo n.º 1
0
  def solve(self, x0, y, *args):
    """Solve the inverse problem F(x)=y.  The initial estimate is x=x0.
    Any extra arguments are passed to :func:`initialize`.
    """
    (x,y) = self.initialize(x0,y,*args)

    # self.discrepancy_history=[]

    forward_problem = self.forwardProblem()
    cg_reset = x.size()
    if (self.params.cg_reset != 0): cg_reset = self.params.cg_reset

    # Initial functional evalutation
    if self.params.verbose: msg('initial evaluation')
    Fx = forward_problem.evalFandLinearize(x)

    residual = y.copy()
    residual.axpy(-1, Fx)

    Jx = 0.5*forward_problem.rangeIP(residual,residual)

    TStarR = forward_problem.TStar(residual)
    TStarRLast = TStarR.copy()

    # Compute our first guess for the descent direction.  
    d = TStarR.copy();
    Jp = -forward_problem.domainIP(TStarR,d)

    if self.params.verbose: msg('initial J %g Jp %g', Jx, Jp)

    # We need to give an initial guess for the stepsize in the linesearch routine
    # t0 = Jx/(1-Jp);
    t0 = Jx/(self.params.deriv_eps-Jp)

    # An analog of matlab's realmin
    realmin = np.finfo(np.double).tiny
    
    # The class that performs our linesearches.
    line_search = linesearchHZ.LinesearchHZ(params=self.params.linesearch)
    line_searchee = ForwardProblemLineSearchAdaptor(forward_problem)

    # Keep track of multiple line search failures.
    prevLineSearchFailed = False

    try:
      # Main loop
      count = 0
      while True:
        # self.discrepancy_history.append(sqrt(2*Jx))

        if count > self.params.ITER_MAX:
          raise IterationCountFailure(self.params.ITER_MAX)
        count += 1

        self.iterationHook(count,x,Fx,y,d,residual,TStarR)

        if self.stopConditionMet(count,x,Fx,y,residual):
          msg('done at iteration %d', count)
          break

        # Phi = lambda t: self.evalPhiAndPhiPrime(forward_problem,x,d,y,t)
        Phi = lambda t: line_searchee.eval(x,d,y,t)
        line_search.search(Phi,Jx,Jp,t0)
        if line_search.error():
          if prevLineSearchFailed:
            raise NumericalFailure('linesearch failed twice in a row: %s' % line_search.errMsg);
          else:
            msg('linesearch failed: %s, switching to steepest descent', line_search.errMsg);
            d = TStarR;
            t = 1/(self.params.deriv_eps-Jp);
            prevLineSearchFailed = True;
            continue      

        prevLineSearchFailed = False;

        t = line_search.value.t;
        x.axpy(t,d)
        TStarRLast.set(TStarR)

        Fx = forward_problem.evalFandLinearize(x,out=Fx,guess=Fx)
        residual.set(y)
        residual -= Fx

        self.xUpdateHook(count,x,Fx,y,residual)

        TStarR = forward_problem.TStar(residual,out=TStarR)

        Jx = 0.5*forward_problem.rangeIP(residual,residual)

        if self.params.steepest_descent:
          beta = 0
        else:
          # Polak-Ribiere
          beta = forward_problem.domainIP(TStarR,TStarR-TStarRLast)/forward_problem.domainIP(TStarRLast,TStarRLast)

          # If we have done more iterations than we have points, reset the conjugate gradient method.
          if count > cg_reset:
            beta = 0

        d *= beta
        d += TStarR

        JpLast = Jp
        Jp =  -forward_problem.domainIP(TStarR,d)
        if Jp >=0:
          if self.params.verbose:
            msg('found an uphill direction; resetting!');
          d.set(TStarR)
          Jp = -forward_problem.domainIP(TStarR,d);
          t0 = Jx/(self.params.deriv_eps-Jp);
        else:
          t0 =  t* min(10, JpLast/(Jp - realmin));
    except Exception as e:
      # Store the current x and y values in case they are interesting to the caller, then
      # re-raise the exception.
      import traceback
      traceback.print_exc()
      self.finalState = self.finalize(x,Fx)
      raise e

    return self.finalize(x, Fx)
Ejemplo n.º 2
0
    def solve(self, x0, y, *args):
        """Solve the inverse problem F(x)=y.  The initial estimate is x=x0.
    Any extra arguments are passed to :func:`initialize`.
    """
        (x, y) = self.initialize(x0, y, *args)

        # self.discrepancy_history=[]

        forward_problem = self.forwardProblem()
        cg_reset = x.size()
        if (self.params.cg_reset != 0): cg_reset = self.params.cg_reset

        # Initial functional evalutation
        if self.params.verbose: msg('initial evaluation')
        Fx = forward_problem.evalFandLinearize(x)

        residual = y.copy()
        residual.axpy(-1, Fx)

        Jx = 0.5 * forward_problem.rangeIP(residual, residual)

        TStarR = forward_problem.TStar(residual)
        TStarRLast = TStarR.copy()

        # Compute our first guess for the descent direction.
        d = TStarR.copy()
        Jp = -forward_problem.domainIP(TStarR, d)

        if self.params.verbose: msg('initial J %g Jp %g', Jx, Jp)

        # We need to give an initial guess for the stepsize in the linesearch routine
        # t0 = Jx/(1-Jp);
        t0 = Jx / (self.params.deriv_eps - Jp)

        # An analog of matlab's realmin
        realmin = np.finfo(np.double).tiny

        # The class that performs our linesearches.
        line_search = linesearchHZ.LinesearchHZ(params=self.params.linesearch)
        line_searchee = ForwardProblemLineSearchAdaptor(forward_problem)

        # Keep track of multiple line search failures.
        prevLineSearchFailed = False

        try:
            # Main loop
            count = 0
            while True:
                # self.discrepancy_history.append(sqrt(2*Jx))

                if count > self.params.ITER_MAX:
                    raise IterationCountFailure(self.params.ITER_MAX)
                count += 1

                self.iterationHook(count, x, Fx, y, d, residual, TStarR)

                if self.stopConditionMet(count, x, Fx, y, residual):
                    msg('done at iteration %d', count)
                    break

                # Phi = lambda t: self.evalPhiAndPhiPrime(forward_problem,x,d,y,t)
                Phi = lambda t: line_searchee.eval(x, d, y, t)
                line_search.search(Phi, Jx, Jp, t0)
                if line_search.error():
                    if prevLineSearchFailed:
                        raise NumericalFailure(
                            'linesearch failed twice in a row: %s' %
                            line_search.errMsg)
                    else:
                        msg(
                            'linesearch failed: %s, switching to steepest descent',
                            line_search.errMsg)
                        d = TStarR
                        t = 1 / (self.params.deriv_eps - Jp)
                        prevLineSearchFailed = True
                        continue

                prevLineSearchFailed = False

                t = line_search.value.t
                x.axpy(t, d)
                TStarRLast.set(TStarR)

                Fx = forward_problem.evalFandLinearize(x, out=Fx, guess=Fx)
                residual.set(y)
                residual -= Fx

                self.xUpdateHook(count, x, Fx, y, residual)

                TStarR = forward_problem.TStar(residual, out=TStarR)

                Jx = 0.5 * forward_problem.rangeIP(residual, residual)

                if self.params.steepest_descent:
                    beta = 0
                else:
                    # Polak-Ribiere
                    beta = forward_problem.domainIP(
                        TStarR,
                        TStarR - TStarRLast) / forward_problem.domainIP(
                            TStarRLast, TStarRLast)

                    # If we have done more iterations than we have points, reset the conjugate gradient method.
                    if count > cg_reset:
                        beta = 0

                d *= beta
                d += TStarR

                JpLast = Jp
                Jp = -forward_problem.domainIP(TStarR, d)
                if Jp >= 0:
                    if self.params.verbose:
                        msg('found an uphill direction; resetting!')
                    d.set(TStarR)
                    Jp = -forward_problem.domainIP(TStarR, d)
                    t0 = Jx / (self.params.deriv_eps - Jp)
                else:
                    t0 = t * min(10, JpLast / (Jp - realmin))
        except Exception as e:
            # Store the current x and y values in case they are interesting to the caller, then
            # re-raise the exception.
            import traceback
            traceback.print_exc()
            self.finalState = self.finalize(x, Fx)
            raise e

        return self.finalize(x, Fx)
Ejemplo n.º 3
0
  def solve(self, x0, y, *args):
    """Main routine to solve the inverse problem F(x)=y.  Initial guess is x=x0.
    Extra arguments are passed to :func:`initialize`."""
    (x,y,targetDiscrepancy) = self.initialize(x0,y,*args)

    self.discrepancy_history=[]

    forward_problem = self.forwardProblem()
    params = self.params
    
    cg_reset = x.size()
    if (self.params.cg_reset != 0): cg_reset = self.params.cg_reset

    # Initial functional evalutation
    Fx = forward_problem.evalFandLinearize(x)

    # Prepare some storage
    Td = None

    residual = y.copy()
    residual.axpy(-1, Fx)

    discrepancy = self.discrepancy(x,y,residual);
    
    # The class that performs our linesearches.
    line_search = linesearchHZ.LinesearchHZ(params=self.params.linesearch)
    line_searchee = ForwardProblemLineSearchAdaptor(forward_problem)

    # Main loop
    count = 0
    theta = params.thetaMax;
    # try:
    for kkkkk in range(1):
      while True:
        self.discrepancy_history.append(discrepancy)

        if count > self.params.ITER_MAX:
          raise IterationCountFailure(self.params.ITER_MAX)
        count += 1

        if theta < self.params.thetaMin:
          raise NumericalFailure('Reached smallest trust region size.')

        # Error to correct:
        discrepancyLin = (1-theta)*discrepancy + theta*targetDiscrepancy
        msg('(%d) discrepancy: current %g linear goal:%g goal: %g\n---', count, discrepancy, discrepancyLin, targetDiscrepancy)

        if discrepancy <= self.params.mu*targetDiscrepancy:
          msg('done at iteration %d', count)
          break

        # try:
        d = self.linearInverseSolve(x,y,residual,discrepancyLin)
        # except Exception as e:
        #   theta *= self.params.kappaTrust
        #   msg('Exception during linear inverse solve:\n%s\nShriking theta to %g.',str(e),theta)
        #   continue

        # forward_problem.evalFandLinearize(x,out=Fx)
        # residual[:] = y
        # residual -= Fx
        Td = forward_problem.T(d,out=Td)
        Jp = -forward_problem.rangeIP(Td,residual)

        if Jp >= 0:
          theta *= self.params.kappaTrust
          msg('Model problem found an uphill direction.  Shrinking theta to %g.',theta)
          continue

          # % Sometimes in the initial stages, the linearization asks for an adjustment many orders of magnitude
          # % larger than the size of the coefficient gamma.  This is due to the very shallow derivatives
          # % in the coefficent function (and hence large derivatives in its inverse).  We've been 
          # % guaranteed that dh is pointing downhill, so scale it so that its size is on the order 
          # % of the size of the current gamma and try it out.  If this doesn't do a good job, we'll end
          # % up reducing theta later.
          # if (params.forceGammaPositive)

        self.temper_d(x,d,y,residual)

        self.iterationHook(count,x,Fx,y,d,residual,Td)

        # Do a linesearch in the determined direction.
        Phi = lambda t: line_searchee.eval(x,d,y,t)
        Jx = 0.5*forward_problem.rangeIP(residual,residual)
        line_search.search(Phi,Jx,Jp,1)
        if line_search.error():
          msg('Linesearch failed: %s. Shrinking theta.', line_search.errMsg);        
          theta *= self.params.kappaTrust
          continue

        discrepancyPrev = discrepancy
        t = line_search.value.t
        x.axpy(t,d)

        forward_problem.evalFandLinearize(x,out=Fx,guess=Fx)
        residual.set(y)
        residual -= Fx
        discrepancy = self.discrepancy(x,y,residual);

        self.xUpdateHook(count,x,Fx,y,residual)
        
        # Check to see if we did a good job reducing the misfit (compared to the amount that we asked
        # the linearized problem to correct).
        rho = (discrepancy-discrepancyPrev)/(discrepancyLin-discrepancyPrev)
      
        # assert(rho>0)

        # Determine if the trust region requires any adjustment.
        if rho > self.params.rhoLow:
          # We have a good fit.
          if rho > self.params.rhoHigh:
            if theta < self.params.thetaMax:
              theta = min(theta/self.params.kappaTrust, self.params.thetaMax);
              msg('Very good decrease (rho=%g).  New theta %g', rho, theta);
            else:
              msg('Very good decrease (rho=%g).  Keeping theta %g', rho, theta);
          else:
            msg('Reasonable decrease (rho=%g). Keeping theta %g',rho, theta);
        else:
          # We have a lousy fit.  Try asking for less correction.
          theta = theta * params.kappaTrust;
          msg('Poor decrease (rho=%g) from %g to %g;', rho, discrepancyPrev, discrepancy)
          msg('wanted %g.  New theta %g', discrepancyLin, theta);
    # except Exception as e:
    #   # Store the current x and y values in case they are interesting to the caller, then
    #   # re-raise the exception.
    #   self.finalState = self.finalize(x,Fx)
    #   raise e
      
    return self.finalize(x, Fx)
Ejemplo n.º 4
0
    def solve(self, x0, y, *args):
        """Main routine to solve the inverse problem F(x)=y.  Initial guess is x=x0.
    Extra arguments are passed to :func:`initialize`."""
        (x, y, targetDiscrepancy) = self.initialize(x0, y, *args)

        self.discrepancy_history = []

        forward_problem = self.forwardProblem()
        params = self.params

        cg_reset = x.size()
        if (self.params.cg_reset != 0): cg_reset = self.params.cg_reset

        # Initial functional evalutation
        Fx = forward_problem.evalFandLinearize(x)

        # Prepare some storage
        Td = None

        residual = y.copy()
        residual.axpy(-1, Fx)

        discrepancy = self.discrepancy(x, y, residual)

        # The class that performs our linesearches.
        line_search = linesearchHZ.LinesearchHZ(params=self.params.linesearch)
        line_searchee = ForwardProblemLineSearchAdaptor(forward_problem)

        # Main loop
        count = 0
        theta = params.thetaMax
        # try:
        for kkkkk in range(1):
            while True:
                self.discrepancy_history.append(discrepancy)

                if count > self.params.ITER_MAX:
                    raise IterationCountFailure(self.params.ITER_MAX)
                count += 1

                if theta < self.params.thetaMin:
                    raise NumericalFailure(
                        'Reached smallest trust region size.')

                # Error to correct:
                discrepancyLin = (
                    1 - theta) * discrepancy + theta * targetDiscrepancy
                msg(
                    '(%d) discrepancy: current %g linear goal:%g goal: %g\n---',
                    count, discrepancy, discrepancyLin, targetDiscrepancy)

                if discrepancy <= self.params.mu * targetDiscrepancy:
                    msg('done at iteration %d', count)
                    break

                # try:
                d = self.linearInverseSolve(x, y, residual, discrepancyLin)
                # except Exception as e:
                #   theta *= self.params.kappaTrust
                #   msg('Exception during linear inverse solve:\n%s\nShriking theta to %g.',str(e),theta)
                #   continue

                # forward_problem.evalFandLinearize(x,out=Fx)
                # residual[:] = y
                # residual -= Fx
                Td = forward_problem.T(d, out=Td)
                Jp = -forward_problem.rangeIP(Td, residual)

                if Jp >= 0:
                    theta *= self.params.kappaTrust
                    msg(
                        'Model problem found an uphill direction.  Shrinking theta to %g.',
                        theta)
                    continue

                    # % Sometimes in the initial stages, the linearization asks for an adjustment many orders of magnitude
                    # % larger than the size of the coefficient gamma.  This is due to the very shallow derivatives
                    # % in the coefficent function (and hence large derivatives in its inverse).  We've been
                    # % guaranteed that dh is pointing downhill, so scale it so that its size is on the order
                    # % of the size of the current gamma and try it out.  If this doesn't do a good job, we'll end
                    # % up reducing theta later.
                    # if (params.forceGammaPositive)

                self.temper_d(x, d, y, residual)

                self.iterationHook(count, x, Fx, y, d, residual, Td)

                # Do a linesearch in the determined direction.
                Phi = lambda t: line_searchee.eval(x, d, y, t)
                Jx = 0.5 * forward_problem.rangeIP(residual, residual)
                line_search.search(Phi, Jx, Jp, 1)
                if line_search.error():
                    msg('Linesearch failed: %s. Shrinking theta.',
                        line_search.errMsg)
                    theta *= self.params.kappaTrust
                    continue

                discrepancyPrev = discrepancy
                t = line_search.value.t
                x.axpy(t, d)

                forward_problem.evalFandLinearize(x, out=Fx, guess=Fx)
                residual.set(y)
                residual -= Fx
                discrepancy = self.discrepancy(x, y, residual)

                self.xUpdateHook(count, x, Fx, y, residual)

                # Check to see if we did a good job reducing the misfit (compared to the amount that we asked
                # the linearized problem to correct).
                rho = (discrepancy - discrepancyPrev) / (discrepancyLin -
                                                         discrepancyPrev)

                # assert(rho>0)

                # Determine if the trust region requires any adjustment.
                if rho > self.params.rhoLow:
                    # We have a good fit.
                    if rho > self.params.rhoHigh:
                        if theta < self.params.thetaMax:
                            theta = min(theta / self.params.kappaTrust,
                                        self.params.thetaMax)
                            msg('Very good decrease (rho=%g).  New theta %g',
                                rho, theta)
                        else:
                            msg(
                                'Very good decrease (rho=%g).  Keeping theta %g',
                                rho, theta)
                    else:
                        msg('Reasonable decrease (rho=%g). Keeping theta %g',
                            rho, theta)
                else:
                    # We have a lousy fit.  Try asking for less correction.
                    theta = theta * params.kappaTrust
                    msg('Poor decrease (rho=%g) from %g to %g;', rho,
                        discrepancyPrev, discrepancy)
                    msg('wanted %g.  New theta %g', discrepancyLin, theta)
        # except Exception as e:
        #   # Store the current x and y values in case they are interesting to the caller, then
        #   # re-raise the exception.
        #   self.finalState = self.finalize(x,Fx)
        #   raise e

        return self.finalize(x, Fx)