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)
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)
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)
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)