def test_log_create(self): from sfepy.base.log import Log log = Log([['x^3']], plot_kwargs=[{ 'color': 'b', 'ls': '', 'marker': 'o' }], yscales=['linear'], xlabels=['x'], ylabels=['a cubic function'], is_plot=False, aggregate=0, sleep=0.0, log_filename=self.log_filename, formats=[['{:.5e}']]) for x in nm.linspace(0, 1, 11): log(x**3, x=[x]) if nm.allclose(x, 0.5): log.plot_vlines([0], color='g', linewidth=2) log(finished=True) return True
def main(): cwd = os.path.split(os.path.join(os.getcwd(), __file__))[0] log = Log((['sin(x) + i sin(x**2)', 'cos(x)'], ['exp(x)']), yscales=['linear', 'log'], xlabels=['angle', None], ylabels=[None, 'a function'], aggregate=1000, sleep=0.05, log_filename=os.path.join(cwd, 'live_plot.log')) log2 = Log([['x^3']], yscales=['linear'], xlabels=['x'], ylabels=['a cubic function'], aggregate=1000, sleep=0.05, log_filename=os.path.join(cwd, 'live_plot2.log'), formats=[['{:.5e}']]) added = 0 for x in nm.linspace(0, 4.0 * nm.pi, 200): output('x: ', x) if x < (2.0 * nm.pi): log(nm.sin(x) + 1j * nm.sin(x**2), nm.cos(x), nm.exp(x), x=[x, None]) else: if added: log(nm.sin(x) + 1j * nm.sin(x**2), nm.cos(x), nm.exp(x), x**2, x=[x, None, x]) else: log.plot_vlines(color='r', linewidth=2) log.add_group(['x^2'], yscale='linear', xlabel='new x', ylabel='square', formats=['%+g']) added += 1 if (added == 20) or (added == 50): log.plot_vlines([2], color='g', linewidth=2) log2(x * x * x, x=[x]) print(log) print(log2) pause() log(finished=True) log2(finished=True)
def main(): cwd = os.path.split(os.path.join(os.getcwd(), __file__))[0] log = Log( (["sin(x)", "cos(x)"], ["exp(x)"]), yscales=["linear", "log"], xlabels=["angle", None], ylabels=[None, "a function"], log_filename=os.path.join(cwd, "live_plot.log"), ) log2 = Log( [["x^3"]], yscales=["linear"], xlabels=["x"], ylabels=["a cubic function"], log_filename=os.path.join(cwd, "live_plot2.log"), ) added = 0 for x in nm.linspace(0, 4.0 * nm.pi, 200): output("x: ", x) if x < (2.0 * nm.pi): log(nm.sin(x), nm.cos(x), nm.exp(x), x=[x, None]) else: if added: log(nm.sin(x), nm.cos(x), nm.exp(x), x ** 2, x=[x, None, x]) else: log.plot_vlines(color="r", linewidth=2) log.add_group(["x^2"], "linear", "new x", "square", formats=["%+g"]) added += 1 if (added == 20) or (added == 50): log.plot_vlines([2], color="g", linewidth=2) log2(x * x * x, x=[x]) print log print log2 pause() log(finished=True) log2(finished=True)
def main(): cwd = os.path.split(os.path.join(os.getcwd(), __file__))[0] log = Log((['sin(x) + i sin(x**2)', 'cos(x)'], ['exp(x)']), yscales=['linear', 'log'], xlabels=['angle', None], ylabels=[None, 'a function'], log_filename=os.path.join(cwd, 'live_plot.log')) log2 = Log([['x^3']], yscales=['linear'], xlabels=['x'], ylabels=['a cubic function'], aggregate=50, sleep=0.05, log_filename=os.path.join(cwd, 'live_plot2.log'), formats=[['{:.5e}']]) added = 0 for x in nm.linspace(0, 4.0 * nm.pi, 200): output('x: ', x) if x < (2.0 * nm.pi): log(nm.sin(x)+1j*nm.sin(x**2), nm.cos(x), nm.exp(x), x=[x, None]) else: if added: log(nm.sin(x)+1j*nm.sin(x**2), nm.cos(x), nm.exp(x), x**2, x=[x, None, x]) else: log.plot_vlines(color='r', linewidth=2) log.add_group(['x^2'], yscale='linear', xlabel='new x', ylabel='square', formats=['%+g']) added += 1 if (added == 20) or (added == 50): log.plot_vlines([2], color='g', linewidth=2) log2(x*x*x, x=[x]) print(log) print(log2) pause() log(finished=True) log2(finished=True)
class Oseen( NonlinearSolver ): name = 'nls.oseen' @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values. Example configuration, all items:: solver_1 = { 'name' : 'oseen', 'kind' : 'nls.oseen', 'needs_problem_instance' : True, 'stabil_mat' : 'stabil', 'adimensionalize' : False, 'check_navier_stokes_rezidual' : False, 'i_max' : 10, 'eps_a' : 1e-8, 'eps_r' : 1.0, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'is_plot' : False, 'log' : {'text' : 'oseen_log.txt', 'plot' : 'oseen_log.png'}, } """ get = make_get_conf(conf, kwargs) common = NonlinearSolver.process_conf(conf) # Compulsory. needs_problem_instance = get('needs_problem_instance', True) if not needs_problem_instance: msg = 'set solver option "needs_problem_instance" to True!' raise ValueError(msg) stabil_mat = get('stabil_mat', None, 'missing "stabil_mat" in options!') # With defaults. adimensionalize = get('adimensionalize', False) if adimensionalize: raise NotImplementedError check = get('check_navier_stokes_rezidual', False) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) return Struct(needs_problem_instance=needs_problem_instance, stabil_mat=stabil_mat, adimensionalize=adimensionalize, check_navier_stokes_rezidual=check, i_max=get('i_max', 1), eps_a=get('eps_a', 1e-10), eps_r=get('eps_r', 1.0), macheps=get('macheps', nm.finfo(nm.float64).eps), lin_red=get('lin_red', 1.0), lin_precision=get('lin_precision', None), is_plot=get('is_plot', False), log=log, is_any_log=is_any_log) + common def __init__( self, conf, **kwargs ): NonlinearSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None def __call__( self, vec_x0, conf = None, fun = None, fun_grad = None, lin_solver = None, status = None, problem = None ): """ Oseen solver is problem-specific - it requires a Problem instance. """ import sfepy.base.plotutils as plu conf = get_default( conf, self.conf ) fun = get_default( fun, self.fun ) fun_grad = get_default( fun_grad, self.fun_grad ) lin_solver = get_default( lin_solver, self.lin_solver ) status = get_default( status, self.status ) problem = get_default( problem, self.problem ) if problem is None: msg = 'set solver option "needs_problem_instance" to True!' raise ValueError(msg) time_stats = {} stabil = problem.get_materials()[conf.stabil_mat] ns, ii = stabil.function.function.get_maps() variables = problem.get_variables() update_var = variables.set_data_from_state make_full_vec = variables.make_full_vec print 'problem size:' print ' velocity: %s' % ii['us'] print ' pressure: %s' % ii['ps'] vec_x = vec_x0.copy() vec_x_prev = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err0 = -1.0 it = 0 while 1: vec_x_prev_f = make_full_vec( vec_x_prev ) update_var( ns['b'], vec_x_prev_f, ns['u'] ) vec_b = vec_x_prev_f[ii['u']] b_norm = nla.norm( vec_b, nm.inf ) print '|b|_max: %.12e' % b_norm vec_x_f = make_full_vec( vec_x ) vec_u = vec_x_f[ii['u']] u_norm = nla.norm( vec_u, nm.inf ) print '|u|_max: %.2e' % u_norm stabil.function.set_extra_args(b_norm=b_norm) stabil.time_update(None, problem.equations, mode='force', problem=problem) max_pars = stabil.reduce_on_datas( lambda a, b: max( a, b.max() ) ) print 'stabilization parameters:' print ' gamma: %.12e' % max_pars[ns['gamma']] print ' max( delta ): %.12e' % max_pars[ns['delta']] print ' max( tau ): %.12e' % max_pars[ns['tau']] if (not are_close( b_norm, 1.0 )) and conf.adimensionalize: adimensionalize = True else: adimensionalize = False tt = time.clock() try: vec_r = fun( vec_x ) except ValueError: ok = False else: ok = True time_stats['rezidual'] = time.clock() - tt if ok: err = nla.norm( vec_r ) if it == 0: err0 = err; else: err += nla.norm( vec_dx ) else: # Failure. output( 'rezidual computation failed for iter %d!' % it ) raise RuntimeError( 'giving up...' ) if self.log is not None: self.log(err, it, max_pars[ns['gamma']], max_pars[ns['delta']], max_pars[ns['tau']]) condition = conv_test( conf, it, err, err0 ) if condition >= 0: break if adimensionalize: output( 'adimensionalizing' ) ## mat.viscosity = viscosity / b_norm ## vec_r[indx_us] /= b_norm tt = time.clock() try: mtx_a = fun_grad( vec_x ) except ValueError: ok = False else: ok = True time_stats['matrix'] = time.clock() - tt if not ok: raise RuntimeError( 'giving up...' ) tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, mtx=mtx_a) time_stats['solve'] = time.clock() - tt vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm( vec_e ) if lerr > (conf.eps_a * conf.lin_red): output( 'linear system not solved! (err = %e)' % lerr ) if adimensionalize: output( 'restoring pressure...' ) ## vec_dx[indx_ps] *= b_norm dx_norm = nla.norm( vec_dx ) output( '||dx||: %.2e' % dx_norm ) for kv in time_stats.iteritems(): output( '%10s: %7.2f [s]' % kv ) vec_x_prev = vec_x.copy() vec_x -= vec_dx if conf.is_plot: plu.plt.ion() plu.plt.gcf().clear() plu.plt.subplot( 2, 2, 1 ) plu.plt.plot( vec_x_prev ) plu.plt.ylabel( r'$x_{i-1}$' ) plu.plt.subplot( 2, 2, 2 ) plu.plt.plot( vec_r ) plu.plt.ylabel( r'$r$' ) plu.plt.subplot( 2, 2, 4 ) plu.plt.plot( vec_dx ) plu.plt.ylabel( r'$\_delta x$' ) plu.plt.subplot( 2, 2, 3 ) plu.plt.plot( vec_x ) plu.plt.ylabel( r'$x_i$' ) plu.plt.draw() plu.plt.ioff() pause() it += 1 if conf.check_navier_stokes_rezidual: t1 = '+ dw_div_grad.%s.%s( %s.viscosity, %s, %s )' \ % (ns['i2'], ns['omega'], ns['fluid'], ns['v'], ns['u']) ## t2 = '+ dw_lin_convect.%s( %s, %s, %s )' % (ns['omega'], ## ns['v'], b_name, ns['u']) t2 = '+ dw_convect.%s.%s( %s, %s )' % (ns['i2'], ns['omega'], ns['v'], ns['u']) t3 = '- dw_stokes.%s.%s( %s, %s )' % (ns['i1'], ns['omega'], ns['v'], ns['p']) t4 = 'dw_stokes.%s.%s( %s, %s )' % (ns['i1'], ns['omega'], ns['u'], ns['q']) equations = { 'balance' : ' '.join( (t1, t2, t3) ), 'incompressibility' : t4, } problem.set_equations( equations ) try: vec_rns0 = fun( vec_x0 ) vec_rns = fun( vec_x ) except ValueError: ok = False else: ok = True if not ok: print 'Navier-Stokes rezidual computation failed!' err_ns = err_ns0 = None else: err_ns0 = nla.norm( vec_rns0 ) err_ns = nla.norm( vec_rns ) print 'Navier-Stokes rezidual0: %.8e' % err_ns0 print 'Navier-Stokes rezidual : %.8e' % err_ns print 'b - u: %.8e' % nla.norm( vec_b - vec_u ) print condition ## print vec_rns - vec_rns1 plu.plt.ion() plu.plt.gcf().clear() plu.plt.plot( vec_rns ) ## plu.plt.gcf().clear() ## plu.plt.plot( vec_rns1 ) plu.plt.draw() plu.plt.ioff() pause() else: err_ns = None if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['err_ns'] = err_ns status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
class Newton(NonlinearSolver): r""" Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. """ name = 'nls.newton' __metaclass__ = SolverMeta _parameters = [ ('i_max', 'int', 1, False, 'The maximum number of iterations.'), ('eps_a', 'float', 1e-10, False, 'The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`.'), ('eps_r', 'float', 1.0, False, """The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`."""), ('eps_mode', "'and' or 'or'", 'and', False, """The logical operator to use for combining the absolute and relative tolerances."""), ('macheps', 'float', nm.finfo(nm.float64).eps, False, 'The float considered to be machine "zero".'), ('lin_red', 'float', 1.0, False, """The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed."""), ('lin_precision', 'float or None', None, False, """If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers."""), ('ls_on', 'float', 0.99999, False, """Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`."""), ('ls_red', '0.0 < float < 1.0', 0.1, False, 'The step reduction factor in case of correct residual assembling.'), ('ls_red_warp', '0.0 < float < 1.0', 0.001, False, """The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations)."""), ('ls_min', '0.0 < float < 1.0', 1e-5, False, 'The minimum step reduction factor.'), ('give_up_warp', 'bool', False, False, 'If True, abort on the "warp violation" error.'), ('check', '0, 1 or 2', 0, False, """If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns."""), ('delta', 'float', 1e-6, False, r"""If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`."""), ('log', 'dict or None', None, False, """If not None, log the convergence according to the configuration in the following form: ``{'text' : 'log.txt', 'plot' : 'log.pdf'}``. Each of the dict items can be None."""), ('is_linear', 'bool', False, False, 'If True, the problem is considered to be linear.'), ] def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, iter_hook=None, status=None): """ Nonlinear system solver call. Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. Parameters ---------- vec_x0 : array The initial guess vector :math:`x_0`. conf : Struct instance, optional The solver configuration parameters, fun : function, optional The function :math:`f(x)` whose zero is sought - the residual. fun_grad : function, optional The gradient of :math:`f(x)` - the tangent matrix. lin_solver : LinearSolver instance, optional The linear solver for each nonlinear iteration. iter_hook : function, optional User-supplied function to call before each iteration. status : dict-like, optional The user-supplied object to hold convergence statistics. Notes ----- * The optional parameters except `iter_hook` and `status` need to be given either here or upon `Newton` construction. * Setting `conf.is_linear == True` means a pre-assembled and possibly pre-solved matrix. This is mostly useful for linear time-dependent problems. """ conf = get_default(conf, self.conf) fun = get_default(fun, self.fun) fun_grad = get_default(fun_grad, self.fun_grad) lin_solver = get_default(lin_solver, self.lin_solver) iter_hook = get_default(iter_hook, self.iter_hook) status = get_default(status, self.status) ls_eps_a, ls_eps_r = lin_solver.get_tolerance() eps_a = get_default(ls_eps_a, 1.0) eps_r = get_default(ls_eps_r, 1.0) lin_red = conf.eps_a * conf.lin_red time_stats = {} vec_x = vec_x0.copy() vec_x_last = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err = err0 = -1.0 err_last = -1.0 it = 0 while 1: if iter_hook is not None: iter_hook(self, vec_x, it, err, err0) ls = 1.0 vec_dx0 = vec_dx; while 1: tt = time.clock() try: vec_r = fun(vec_x) except ValueError: if (it == 0) or (ls < conf.ls_min): output('giving up!') raise else: ok = False else: ok = True time_stats['rezidual'] = time.clock() - tt if ok: try: err = nla.norm(vec_r) except: output('infs or nans in the residual:', vec_r) output(nm.isfinite(vec_r).all()) debug() if self.log is not None: self.log(err, it) if it == 0: err0 = err; break if err < (err_last * conf.ls_on): break red = conf.ls_red; output('linesearch: iter %d, (%.5e < %.5e) (new ls: %e)' % (it, err, err_last * conf.ls_on, red * ls)) else: # Failure. if conf.give_up_warp: output('giving up!') break red = conf.ls_red_warp; output('rezidual computation failed for iter %d' ' (new ls: %e)!' % (it, red * ls)) if ls < conf.ls_min: output('linesearch failed, continuing anyway') break ls *= red; vec_dx = ls * vec_dx0; vec_x = vec_x_last.copy() - vec_dx # End residual loop. if self.log is not None: self.log.plot_vlines([1], color='g', linewidth=0.5) err_last = err; vec_x_last = vec_x.copy() condition = conv_test(conf, it, err, err0) if condition >= 0: break if (not ok) and conf.give_up_warp: condition = 2 break tt = time.clock() if not conf.is_linear: mtx_a = fun_grad(vec_x) else: mtx_a = fun_grad('linear') time_stats['matrix'] = time.clock() - tt if conf.check: tt = time.clock() wt = check_tangent_matrix(conf, vec_x, fun, fun_grad) time_stats['check'] = time.clock() - tt - wt if conf.lin_precision is not None: if ls_eps_a is not None: eps_a = max(err * conf.lin_precision, ls_eps_a) elif ls_eps_r is not None: eps_r = max(conf.lin_precision, ls_eps_r) lin_red = max(eps_a, err * eps_r) if conf.verbose: output('solving linear system...') tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, eps_a=eps_a, eps_r=eps_r, mtx=mtx_a) time_stats['solve'] = time.clock() - tt if conf.verbose: output('...done') for kv in time_stats.iteritems(): output('%10s: %7.2f [s]' % kv) vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm(vec_e) if lerr > lin_red: output('warning: linear system solution precision is lower') output('then the value set in solver options! (err = %e < %e)' % (lerr, lin_red)) vec_x -= vec_dx it += 1 if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['n_iter'] = it status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
class Newton(NonlinearSolver): r""" Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. """ name = 'nls.newton' __metaclass__ = SolverMeta _parameters = [ ('i_max', 'int', 1, False, 'The maximum number of iterations.'), ('eps_a', 'float', 1e-10, False, 'The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`.'), ('eps_r', 'float', 1.0, False, """The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`."""), ('eps_mode', "'and' or 'or'", 'and', False, """The logical operator to use for combining the absolute and relative tolerances."""), ('macheps', 'float', nm.finfo(nm.float64).eps, False, 'The float considered to be machine "zero".'), ('lin_red', 'float', 1.0, False, """The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed."""), ('lin_precision', 'float or None', None, False, """If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers."""), ('ls_on', 'float', 0.99999, False, """Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`."""), ('ls_red', '0.0 < float < 1.0', 0.1, False, 'The step reduction factor in case of correct residual assembling.'), ('ls_red_warp', '0.0 < float < 1.0', 0.001, False, """The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations)."""), ('ls_min', '0.0 < float < 1.0', 1e-5, False, 'The minimum step reduction factor.'), ('give_up_warp', 'bool', False, False, 'If True, abort on the "warp violation" error.'), ('check', '0, 1 or 2', 0, False, """If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns."""), ('delta', 'float', 1e-6, False, r"""If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`."""), ('log', 'dict or None', None, False, """If not None, log the convergence according to the configuration in the following form: ``{'text' : 'log.txt', 'plot' : 'log.pdf'}``. Each of the dict items can be None."""), ('is_linear', 'bool', False, False, 'If True, the problem is considered to be linear.'), ] def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, iter_hook=None, status=None): """ Nonlinear system solver call. Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. Parameters ---------- vec_x0 : array The initial guess vector :math:`x_0`. conf : Struct instance, optional The solver configuration parameters, fun : function, optional The function :math:`f(x)` whose zero is sought - the residual. fun_grad : function, optional The gradient of :math:`f(x)` - the tangent matrix. lin_solver : LinearSolver instance, optional The linear solver for each nonlinear iteration. iter_hook : function, optional User-supplied function to call before each iteration. status : dict-like, optional The user-supplied object to hold convergence statistics. Notes ----- * The optional parameters except `iter_hook` and `status` need to be given either here or upon `Newton` construction. * Setting `conf.is_linear == True` means a pre-assembled and possibly pre-solved matrix. This is mostly useful for linear time-dependent problems. """ conf = get_default(conf, self.conf) fun = get_default(fun, self.fun) fun_grad = get_default(fun_grad, self.fun_grad) lin_solver = get_default(lin_solver, self.lin_solver) iter_hook = get_default(iter_hook, self.iter_hook) status = get_default(status, self.status) ls_eps_a, ls_eps_r = lin_solver.get_tolerance() eps_a = get_default(ls_eps_a, 1.0) eps_r = get_default(ls_eps_r, 1.0) lin_red = conf.eps_a * conf.lin_red time_stats_keys = ['residual', 'matrix', 'solve'] time_stats = {key: 0.0 for key in time_stats_keys} vec_x = vec_x0.copy() vec_x_last = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err = err0 = -1.0 err_last = -1.0 it = 0 ls_status = {} ls_n_iter = 0 while 1: if iter_hook is not None: iter_hook(self, vec_x, it, err, err0) ls = 1.0 vec_dx0 = vec_dx while 1: tt = time.clock() try: vec_r = fun(vec_x) except ValueError: if (it == 0) or (ls < conf.ls_min): output('giving up!') raise else: ok = False else: ok = True time_stats['residual'] = time.clock() - tt if ok: try: err = nla.norm(vec_r) except: output('infs or nans in the residual:', vec_r) output(nm.isfinite(vec_r).all()) debug() if self.log is not None: self.log(err, it) if it == 0: err0 = err break if err < (err_last * conf.ls_on): break red = conf.ls_red output('linesearch: iter %d, (%.5e < %.5e) (new ls: %e)' % (it, err, err_last * conf.ls_on, red * ls)) else: # Failure. if conf.give_up_warp: output('giving up!') break red = conf.ls_red_warp output('residual computation failed for iter %d' ' (new ls: %e)!' % (it, red * ls)) if ls < conf.ls_min: output('linesearch failed, continuing anyway') break ls *= red vec_dx = ls * vec_dx0 vec_x = vec_x_last.copy() - vec_dx # End residual loop. if self.log is not None: self.log.plot_vlines([1], color='g', linewidth=0.5) err_last = err vec_x_last = vec_x.copy() condition = conv_test(conf, it, err, err0) if condition >= 0: break if (not ok) and conf.give_up_warp: condition = 2 break tt = time.clock() if not conf.is_linear: mtx_a = fun_grad(vec_x) else: mtx_a = fun_grad('linear') time_stats['matrix'] = time.clock() - tt if conf.check: tt = time.clock() wt = check_tangent_matrix(conf, vec_x, fun, fun_grad) time_stats['check'] = time.clock() - tt - wt if conf.lin_precision is not None: if ls_eps_a is not None: eps_a = max(err * conf.lin_precision, ls_eps_a) elif ls_eps_r is not None: eps_r = max(conf.lin_precision, ls_eps_r) lin_red = max(eps_a, err * eps_r) if conf.verbose: output('solving linear system...') tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, eps_a=eps_a, eps_r=eps_r, mtx=mtx_a, status=ls_status) ls_n_iter += ls_status['n_iter'] time_stats['solve'] = time.clock() - tt if conf.verbose: output('...done') for key in time_stats_keys: output('%10s: %7.2f [s]' % (key, time_stats[key])) vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm(vec_e) if lerr > lin_red: output('warning: linear system solution precision is lower') output( 'then the value set in solver options! (err = %e < %e)' % (lerr, lin_red)) vec_x -= vec_dx it += 1 if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['n_iter'] = it status['ls_n_iter'] = ls_n_iter if ls_n_iter >= 0 else -1 status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
class FMinSteepestDescent( OptimizationSolver ): name = 'opt.fmin_sd' def process_conf( conf ): """ Missing items are set to default values. Example configuration, all items:: solver_0 = { 'name' : 'fmin_sd', 'kind' : 'opt.fmin_sd', 'i_max' : 10, 'eps_rd' : 1e-5, # Relative delta of objective function 'eps_of' : 1e-4, 'eps_ofg' : 1e-8, 'norm' : nm.Inf, 'ls' : True, # Linesearch. 'ls_method' : 'backtracking', # 'backtracking' or 'full' 'ls0' : 0.25, 'ls_red' : 0.5, 'ls_red_warp' : 0.1, 'ls_on' : 0.99999, 'ls_min' : 1e-5, 'check' : 0, 'delta' : 1e-6, 'output' : None, # 'itc' 'log' : {'text' : 'output/log.txt', 'plot' : 'output/log.png'}, 'yscales' : ['linear', 'log', 'log', 'linear'], } """ get = conf.get_default_attr i_max = get( 'i_max', 10 ) eps_rd = get( 'eps_rd', 1e-5 ) eps_of = get( 'eps_of', 1e-4 ) eps_ofg = get( 'eps_ofg', 1e-8 ) norm = get( 'norm', nm.Inf ) ls = get( 'ls', True ) ls_method = get( 'ls_method', 'backtracking' ) ls0 = get( 'ls0', 0.25 ) ls_red = get( 'ls_red', 0.5 ) ls_red_warp = get( 'ls_red_warp', 0.1 ) ls_on = get( 'ls_on', 0.99999 ) ls_min = get( 'ls_min', 1e-5 ) check = get( 'check', 0 ) delta = get( 'delta', 1e-6) output = get( 'output', None ) yscales = get( 'yscales', ['linear', 'log', 'log', 'linear'] ) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) common = OptimizationSolver.process_conf( conf ) return Struct( **locals() ) + common process_conf = staticmethod( process_conf ) ## # 17.10.2007, c def __init__( self, conf, **kwargs ): OptimizationSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None ## # 19.04.2006, c # 20.04.2006 # 21.04.2006 # 26.04.2006 # 06.06.2006 # 07.06.2006 # 04.09.2006 # 21.03.2007 # 17.10.2007, from fmin_sd() def __call__( self, x0, conf = None, obj_fun = None, obj_fun_grad = None, status = None, obj_args = None ): # def fmin_sd( conf, x0, fn_of, fn_ofg, args = () ): conf = get_default( conf, self.conf ) obj_fun = get_default( obj_fun, self.obj_fun ) obj_fun_grad = get_default( obj_fun_grad, self.obj_fun_grad ) status = get_default( status, self.status ) obj_args = get_default( obj_args, self.obj_args ) if conf.output: globals()['output'] = conf.output output( 'entering optimization loop...' ) nc_of, tt_of, fn_of = wrap_function( obj_fun, obj_args ) nc_ofg, tt_ofg, fn_ofg = wrap_function( obj_fun_grad, obj_args ) time_stats = {'of' : tt_of, 'ofg': tt_ofg, 'check' : []} ofg = None it = 0 xit = x0.copy() while 1: of = fn_of( xit ) if it == 0: of0 = ofit0 = of_prev = of of_prev_prev = of + 5000.0 if ofg is None: ofg = fn_ofg( xit ) if conf.check: tt = time.clock() check_gradient( xit, ofg, fn_of, conf.delta, conf.check ) time_stats['check'].append( time.clock() - tt ) ofg_norm = nla.norm( ofg, conf.norm ) ret = conv_test( conf, it, of, ofit0, ofg_norm ) if ret >= 0: break ofit0 = of ## # Backtrack (on errors). alpha = conf.ls0 can_ls = True while 1: xit2 = xit - alpha * ofg aux = fn_of( xit2 ) if self.log is not None: self.log(of, ofg_norm, alpha, it) if aux is None: alpha *= conf.ls_red_warp can_ls = False output( 'warp: reducing step (%f)' % alpha ) elif conf.ls and conf.ls_method == 'backtracking': if aux < of * conf.ls_on: break alpha *= conf.ls_red output( 'backtracking: reducing step (%f)' % alpha ) else: of_prev_prev = of_prev of_prev = aux break if alpha < conf.ls_min: if aux is None: raise RuntimeError, 'giving up...' output( 'linesearch failed, continuing anyway' ) break # These values are modified by the line search, even if it fails of_prev_bak = of_prev of_prev_prev_bak = of_prev_prev if conf.ls and can_ls and conf.ls_method == 'full': output( 'full linesearch...' ) alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ linesearch.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev,of_prev_prev, c2=0.4) if alpha is None: # line search failed -- use different one. alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ sopt.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev_bak, of_prev_prev_bak) if alpha is None or alpha == 0: # This line search also failed to find a better solution. ret = 3 break output( ' -> alpha: %.8e' % alpha ) else: if conf.ls_method == 'full': output( 'full linesearch off (%s and %s)' % (conf.ls, can_ls) ) ofg1 = None if self.log is not None: self.log.plot_vlines(color='g', linewidth=0.5) xit = xit - alpha * ofg if ofg1 is None: ofg = None else: ofg = ofg1.copy() for key, val in time_stats.iteritems(): if len( val ): output( '%10s: %7.2f [s]' % (key, val[-1]) ) it = it + 1 output( 'status: %d' % ret ) output( 'initial value: %.8e' % of0 ) output( 'current value: %.8e' % of ) output( 'iterations: %d' % it ) output( 'function evaluations: %d in %.2f [s]' \ % (nc_of[0], nm.sum( time_stats['of'] ) ) ) output( 'gradient evaluations: %d in %.2f [s]' \ % (nc_ofg[0], nm.sum( time_stats['ofg'] ) ) ) if self.log is not None: self.log(of, ofg_norm, alpha, it) if conf.log.plot is not None: self.log(save_figure=conf.log.plot, finished=True) else: self.log(finished=True) if status is not None: status['log'] = self.log status['status'] = status status['of0'] = of0 status['of'] = of status['it'] = it status['nc_of'] = nc_of[0] status['nc_ofg'] = nc_ofg[0] status['time_stats'] = time_stats return xit
class Oseen(NonlinearSolver): name = 'nls.oseen' @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values. Example configuration, all items:: solver_1 = { 'name' : 'oseen', 'kind' : 'nls.oseen', 'needs_problem_instance' : True, 'stabil_mat' : 'stabil', 'adimensionalize' : False, 'check_navier_stokes_rezidual' : False, 'i_max' : 10, 'eps_a' : 1e-8, 'eps_r' : 1.0, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'log' : {'text' : 'oseen_log.txt', 'plot' : 'oseen_log.png'}, } """ get = make_get_conf(conf, kwargs) common = NonlinearSolver.process_conf(conf) # Compulsory. needs_problem_instance = get('needs_problem_instance', True) if not needs_problem_instance: msg = 'set solver option "needs_problem_instance" to True!' raise ValueError(msg) stabil_mat = get('stabil_mat', None, 'missing "stabil_mat" in options!') # With defaults. adimensionalize = get('adimensionalize', False) if adimensionalize: raise NotImplementedError check = get('check_navier_stokes_rezidual', False) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) return Struct(needs_problem_instance=needs_problem_instance, stabil_mat=stabil_mat, adimensionalize=adimensionalize, check_navier_stokes_rezidual=check, i_max=get('i_max', 1), eps_a=get('eps_a', 1e-10), eps_r=get('eps_r', 1.0), macheps=get('macheps', nm.finfo(nm.float64).eps), lin_red=get('lin_red', 1.0), lin_precision=get('lin_precision', None), log=log, is_any_log=is_any_log) + common def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, status=None, problem=None): """ Oseen solver is problem-specific - it requires a Problem instance. """ conf = get_default(conf, self.conf) fun = get_default(fun, self.fun) fun_grad = get_default(fun_grad, self.fun_grad) lin_solver = get_default(lin_solver, self.lin_solver) status = get_default(status, self.status) problem = get_default(problem, self.problem) if problem is None: msg = 'set solver option "needs_problem_instance" to True!' raise ValueError(msg) time_stats = {} stabil = problem.get_materials()[conf.stabil_mat] ns, ii = stabil.function.function.get_maps() variables = problem.get_variables() update_var = variables.set_data_from_state make_full_vec = variables.make_full_vec print 'problem size:' print ' velocity: %s' % ii['us'] print ' pressure: %s' % ii['ps'] vec_x = vec_x0.copy() vec_x_prev = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err0 = -1.0 it = 0 while 1: vec_x_prev_f = make_full_vec(vec_x_prev) update_var(ns['b'], vec_x_prev_f, ns['u']) vec_b = vec_x_prev_f[ii['u']] b_norm = nla.norm(vec_b, nm.inf) print '|b|_max: %.12e' % b_norm vec_x_f = make_full_vec(vec_x) vec_u = vec_x_f[ii['u']] u_norm = nla.norm(vec_u, nm.inf) print '|u|_max: %.2e' % u_norm stabil.function.set_extra_args(b_norm=b_norm) stabil.time_update(None, problem.equations, mode='force', problem=problem) max_pars = stabil.reduce_on_datas(lambda a, b: max(a, b.max())) print 'stabilization parameters:' print ' gamma: %.12e' % max_pars[ns['gamma']] print ' max( delta ): %.12e' % max_pars[ns['delta']] print ' max( tau ): %.12e' % max_pars[ns['tau']] if (not are_close(b_norm, 1.0)) and conf.adimensionalize: adimensionalize = True else: adimensionalize = False tt = time.clock() try: vec_r = fun(vec_x) except ValueError: ok = False else: ok = True time_stats['rezidual'] = time.clock() - tt if ok: err = nla.norm(vec_r) if it == 0: err0 = err else: err += nla.norm(vec_dx) else: # Failure. output('rezidual computation failed for iter %d!' % it) raise RuntimeError('giving up...') if self.log is not None: self.log(err, it, max_pars[ns['gamma']], max_pars[ns['delta']], max_pars[ns['tau']]) condition = conv_test(conf, it, err, err0) if condition >= 0: break if adimensionalize: output('adimensionalizing') ## mat.viscosity = viscosity / b_norm ## vec_r[indx_us] /= b_norm tt = time.clock() try: mtx_a = fun_grad(vec_x) except ValueError: ok = False else: ok = True time_stats['matrix'] = time.clock() - tt if not ok: raise RuntimeError('giving up...') tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, mtx=mtx_a) time_stats['solve'] = time.clock() - tt vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm(vec_e) if lerr > (conf.eps_a * conf.lin_red): output('linear system not solved! (err = %e)' % lerr) if adimensionalize: output('restoring pressure...') ## vec_dx[indx_ps] *= b_norm dx_norm = nla.norm(vec_dx) output('||dx||: %.2e' % dx_norm) for kv in time_stats.iteritems(): output('%10s: %7.2f [s]' % kv) vec_x_prev = vec_x.copy() vec_x -= vec_dx it += 1 if conf.check_navier_stokes_rezidual: t1 = '+ dw_div_grad.%s.%s( %s.viscosity, %s, %s )' \ % (ns['i2'], ns['omega'], ns['fluid'], ns['v'], ns['u']) ## t2 = '+ dw_lin_convect.%s( %s, %s, %s )' % (ns['omega'], ## ns['v'], b_name, ns['u']) t2 = '+ dw_convect.%s.%s( %s, %s )' % (ns['i2'], ns['omega'], ns['v'], ns['u']) t3 = '- dw_stokes.%s.%s( %s, %s )' % (ns['i1'], ns['omega'], ns['v'], ns['p']) t4 = 'dw_stokes.%s.%s( %s, %s )' % (ns['i1'], ns['omega'], ns['u'], ns['q']) equations = { 'balance': ' '.join((t1, t2, t3)), 'incompressibility': t4, } problem.set_equations(equations) try: vec_rns0 = fun(vec_x0) vec_rns = fun(vec_x) except ValueError: ok = False else: ok = True if not ok: print 'Navier-Stokes rezidual computation failed!' err_ns = err_ns0 = None else: err_ns0 = nla.norm(vec_rns0) err_ns = nla.norm(vec_rns) print 'Navier-Stokes rezidual0: %.8e' % err_ns0 print 'Navier-Stokes rezidual : %.8e' % err_ns print 'b - u: %.8e' % nla.norm(vec_b - vec_u) print condition else: err_ns = None if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['err_ns'] = err_ns status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
class Newton( NonlinearSolver ): name = 'nls.newton' def process_conf( conf ): """ Missing items are set to default values for a linear problem. Example configuration, all items:: solver_1 = { 'name' : 'newton', 'kind' : 'nls.newton', 'i_max' : 2, 'eps_a' : 1e-8, 'eps_r' : 1e-2, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'ls_red' : 0.1, 'ls_red_warp' : 0.001, 'ls_on' : 0.99999, 'ls_min' : 1e-5, 'check' : 0, 'delta' : 1e-6, 'is_plot' : False, 'log' : None, # 'nonlinear' or 'linear' (ignore i_max) 'problem' : 'nonlinear', } """ get = conf.get_default_attr i_max = get( 'i_max', 1 ) eps_a = get( 'eps_a', 1e-10 ) eps_r = get( 'eps_r', 1.0 ) macheps = get( 'macheps', nm.finfo( nm.float64 ).eps ) lin_red = get( 'lin_red', 1.0 ) ls_red = get( 'ls_red', 0.1 ) ls_red_warp = get( 'ls_red_warp', 0.001 ) ls_on = get( 'ls_on', 0.99999 ) ls_min = get( 'ls_min', 1e-5 ) check = get( 'check', 0 ) delta = get( 'delta', 1e-6) is_plot = get( 'is_plot', False ) problem = get( 'problem', 'nonlinear' ) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) common = NonlinearSolver.process_conf( conf ) return Struct( **locals() ) + common process_conf = staticmethod( process_conf ) def __init__(self, conf, **kwargs): NonlinearSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None ## # c: 02.12.2005, r: 04.04.2008 # 10.10.2007, from newton() def __call__( self, vec_x0, conf = None, fun = None, fun_grad = None, lin_solver = None, status = None ): """setting conf.problem == 'linear' means 1 iteration and no rezidual check! """ import sfepy.base.plotutils as plu conf = get_default( conf, self.conf ) fun = get_default( fun, self.fun ) fun_grad = get_default( fun_grad, self.fun_grad ) lin_solver = get_default( lin_solver, self.lin_solver ) status = get_default( status, self.status ) time_stats = {} vec_x = vec_x0.copy() vec_x_last = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err0 = -1.0 err_last = -1.0 it = 0 while 1: ls = 1.0 vec_dx0 = vec_dx; while 1: tt = time.clock() try: vec_r = fun( vec_x ) except ValueError: if (it == 0) or (ls < conf.ls_min): output('giving up!') raise else: ok = True time_stats['rezidual'] = time.clock() - tt if ok: try: err = nla.norm( vec_r ) except: output( 'infs or nans in the residual:', vec_r ) output( nm.isfinite( vec_r ).all() ) debug() if self.log is not None: self.log(err, it) if it == 0: err0 = err; break if err < (err_last * conf.ls_on): break red = conf.ls_red; output( 'linesearch: iter %d, (%.5e < %.5e) (new ls: %e)'\ % (it, err, err_last * conf.ls_on, red * ls) ) else: # Failure. red = conf.ls_red_warp; output( 'rezidual computation failed for iter %d' ' (new ls: %e)!' % (it, red * ls) ) if ls < conf.ls_min: output( 'linesearch failed, continuing anyway' ) break ls *= red; vec_dx = ls * vec_dx0; vec_x = vec_x_last.copy() - vec_dx # End residual loop. if self.log is not None: self.log.plot_vlines([1], color='g', linewidth=0.5) err_last = err; vec_x_last = vec_x.copy() condition = conv_test( conf, it, err, err0 ) if condition >= 0: break tt = time.clock() if conf.problem == 'nonlinear': mtx_a = fun_grad(vec_x) else: mtx_a = fun_grad( 'linear' ) time_stats['matrix'] = time.clock() - tt if conf.check: tt = time.clock() wt = check_tangent_matrix( conf, vec_x, fun, fun_grad ) time_stats['check'] = time.clock() - tt - wt tt = time.clock() vec_dx = lin_solver( vec_r, mtx = mtx_a ) time_stats['solve'] = time.clock() - tt for kv in time_stats.iteritems(): output( '%10s: %7.2f [s]' % kv ) vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm( vec_e ) if lerr > (conf.eps_a * conf.lin_red): output( 'linear system not solved! (err = %e)' % lerr ) vec_x -= vec_dx if conf.is_plot: plu.pylab.ion() plu.pylab.gcf().clear() plu.pylab.subplot( 2, 2, 1 ) plu.pylab.plot( vec_x_last ) plu.pylab.ylabel( r'$x_{i-1}$' ) plu.pylab.subplot( 2, 2, 2 ) plu.pylab.plot( vec_r ) plu.pylab.ylabel( r'$r$' ) plu.pylab.subplot( 2, 2, 4 ) plu.pylab.plot( vec_dx ) plu.pylab.ylabel( r'$\_delta x$' ) plu.pylab.subplot( 2, 2, 3 ) plu.pylab.plot( vec_x ) plu.pylab.ylabel( r'$x_i$' ) plu.pylab.draw() plu.pylab.ioff() pause() it += 1 if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
class FMinSteepestDescent(OptimizationSolver): """ Steepest descent optimization solver. """ name = 'opt.fmin_sd' __metaclass__ = SolverMeta _parameters = [ ('i_max', 'int', 10, False, 'The maximum number of iterations.'), ('eps_rd', 'float', 1e-5, False, 'The relative delta of the objective function.'), ('eps_of', 'float', 1e-4, False, 'The tolerance for the objective function.'), ('eps_ofg', 'float', 1e-8, False, 'The tolerance for the objective function gradient.'), ('norm', 'numpy norm', nm.Inf, False, 'The norm to be used.'), ('ls', 'bool', True, False, 'If True, use a line-search.'), ('ls_method', "{'backtracking', 'full'}", 'backtracking', False, 'The line-search method.'), ('ls_on', 'float', 0.99999, False, """Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`."""), ('ls0', '0.0 < float < 1.0', 1.0, False, 'The initial step.'), ('ls_red', '0.0 < float < 1.0', 0.5, False, 'The step reduction factor in case of correct residual assembling.'), ('ls_red_warp', '0.0 < float < 1.0', 0.1, False, """The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations)."""), ('ls_min', '0.0 < float < 1.0', 1e-5, False, 'The minimum step reduction factor.'), ('check', '0, 1 or 2', 0, False, """If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns."""), ('delta', 'float', 1e-6, False, r"""If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`."""), ('output', 'function', None, False, """If given, use it instead of :func:`output() <sfepy.base.base.output()>` function."""), ('yscales', 'list of str', ['linear', 'log', 'log', 'linear'], False, 'The list of four convergence log subplot scales.'), ('log', 'dict or None', None, False, """If not None, log the convergence according to the configuration in the following form: ``{'text' : 'log.txt', 'plot' : 'log.pdf'}``. Each of the dict items can be None."""), ] def __init__(self, conf, **kwargs): OptimizationSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) if conf.is_any_log: self.log = Log( [[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None def __call__(self, x0, conf=None, obj_fun=None, obj_fun_grad=None, status=None, obj_args=None): conf = get_default(conf, self.conf) obj_fun = get_default(obj_fun, self.obj_fun) obj_fun_grad = get_default(obj_fun_grad, self.obj_fun_grad) status = get_default(status, self.status) obj_args = get_default(obj_args, self.obj_args) if conf.output: globals()['output'] = conf.output output('entering optimization loop...') nc_of, tt_of, fn_of = wrap_function(obj_fun, obj_args) nc_ofg, tt_ofg, fn_ofg = wrap_function(obj_fun_grad, obj_args) time_stats = {'of': tt_of, 'ofg': tt_ofg, 'check': []} ofg = None it = 0 xit = x0.copy() while 1: of = fn_of(xit) if it == 0: of0 = ofit0 = of_prev = of of_prev_prev = of + 5000.0 if ofg is None: ofg = fn_ofg(xit) if conf.check: tt = time.clock() check_gradient(xit, ofg, fn_of, conf.delta, conf.check) time_stats['check'].append(time.clock() - tt) ofg_norm = nla.norm(ofg, conf.norm) ret = conv_test(conf, it, of, ofit0, ofg_norm) if ret >= 0: break ofit0 = of ## # Backtrack (on errors). alpha = conf.ls0 can_ls = True while 1: xit2 = xit - alpha * ofg aux = fn_of(xit2) if self.log is not None: self.log(of, ofg_norm, alpha, it) if aux is None: alpha *= conf.ls_red_warp can_ls = False output('warp: reducing step (%f)' % alpha) elif conf.ls and conf.ls_method == 'backtracking': if aux < of * conf.ls_on: break alpha *= conf.ls_red output('backtracking: reducing step (%f)' % alpha) else: of_prev_prev = of_prev of_prev = aux break if alpha < conf.ls_min: if aux is None: raise RuntimeError, 'giving up...' output('linesearch failed, continuing anyway') break # These values are modified by the line search, even if it fails of_prev_bak = of_prev of_prev_prev_bak = of_prev_prev if conf.ls and can_ls and conf.ls_method == 'full': output('full linesearch...') alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ linesearch.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev,of_prev_prev, c2=0.4) if alpha is None: # line search failed -- use different one. alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ sopt.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev_bak, of_prev_prev_bak) if alpha is None or alpha == 0: # This line search also failed to find a better # solution. ret = 3 break output(' -> alpha: %.8e' % alpha) else: if conf.ls_method == 'full': output('full linesearch off (%s and %s)' % (conf.ls, can_ls)) ofg1 = None if self.log is not None: self.log.plot_vlines(color='g', linewidth=0.5) xit = xit - alpha * ofg if ofg1 is None: ofg = None else: ofg = ofg1.copy() for key, val in time_stats.iteritems(): if len(val): output('%10s: %7.2f [s]' % (key, val[-1])) it = it + 1 output('status: %d' % ret) output('initial value: %.8e' % of0) output('current value: %.8e' % of) output('iterations: %d' % it) output('function evaluations: %d in %.2f [s]' % (nc_of[0], nm.sum(time_stats['of']))) output('gradient evaluations: %d in %.2f [s]' % (nc_ofg[0], nm.sum(time_stats['ofg']))) if self.log is not None: self.log(of, ofg_norm, alpha, it) if conf.log.plot is not None: self.log(save_figure=conf.log.plot, finished=True) else: self.log(finished=True) if status is not None: status['log'] = self.log status['status'] = status status['of0'] = of0 status['of'] = of status['it'] = it status['nc_of'] = nc_of[0] status['nc_ofg'] = nc_ofg[0] status['time_stats'] = time_stats return xit
class Newton(NonlinearSolver): name = "nls.newton" @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values for a linear problem. Example configuration, all items:: solver_1 = { 'name' : 'newton', 'kind' : 'nls.newton', 'i_max' : 2, 'eps_a' : 1e-8, 'eps_r' : 1e-2, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'lin_precision' : None, 'ls_red' : 0.1, 'ls_red_warp' : 0.001, 'ls_on' : 0.99999, 'ls_min' : 1e-5, 'give_up_warp' : False, 'check' : 0, 'delta' : 1e-6, 'is_plot' : False, 'log' : None, # 'nonlinear' or 'linear' (ignore i_max) 'problem' : 'nonlinear', } """ get = make_get_conf(conf, kwargs) common = NonlinearSolver.process_conf(conf) log = get_logging_conf(conf) log = Struct(name="log_conf", **log) is_any_log = (log.text is not None) or (log.plot is not None) return ( Struct( i_max=get("i_max", 1), eps_a=get("eps_a", 1e-10), eps_r=get("eps_r", 1.0), macheps=get("macheps", nm.finfo(nm.float64).eps), lin_red=get("lin_red", 1.0), lin_precision=get("lin_precision", None), ls_red=get("ls_red", 0.1), ls_red_warp=get("ls_red_warp", 0.001), ls_on=get("ls_on", 0.99999), ls_min=get("ls_min", 1e-5), give_up_warp=get("give_up_warp", False), check=get("check", 0), delta=get("delta", 1e-6), is_plot=get("is_plot", False), problem=get("problem", "nonlinear"), log=log, is_any_log=is_any_log, ) + common ) def __init__(self, conf, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log( [[r"$||r||$"], ["iteration"]], xlabels=["", "all iterations"], ylabels=[r"$||r||$", "iteration"], yscales=["log", "linear"], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[["%.8e"], ["%d"]], ) else: self.log = None def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, iter_hook=None, status=None): """ Nonlinear system solver call. Solves :math:`f(x) = 0` by the Newton method with backtracking linesearch. Parameters ---------- vec_x0 : array The initial guess vector :math:`x_0`. conf : Struct instance, optional The solver configuration parameters, fun : function, optional The function :math:`f(x)` whose zero is sought - the residual. fun_grad : function, optional The gradient of :math:`f(x)` - the tangent matrix. lin_solver : LinearSolver instance, optional The linear solver for each nonlinear iteration. iter_hook : function, optional User-supplied function to call before each iteration. status : dict-like, optional The user-supplied object to hold convergence statistics. Notes ----- * The optional parameters except `iter_hook` and `status` need to be given either here or upon `Newton` construction. * Setting `conf.problem == 'linear'` means 1 iteration and no rezidual check! """ import sfepy.base.plotutils as plu conf = get_default(conf, self.conf) fun = get_default(fun, self.fun) fun_grad = get_default(fun_grad, self.fun_grad) lin_solver = get_default(lin_solver, self.lin_solver) iter_hook = get_default(iter_hook, self.iter_hook) status = get_default(status, self.status) ls_eps_a, ls_eps_r = lin_solver.get_tolerance() eps_a = get_default(ls_eps_a, 1.0) eps_r = get_default(ls_eps_r, 1.0) lin_red = conf.eps_a * conf.lin_red time_stats = {} vec_x = vec_x0.copy() vec_x_last = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color="r", linewidth=1.0) err = err0 = -1.0 err_last = -1.0 it = 0 while 1: if iter_hook is not None: iter_hook(self, vec_x, it, err, err0) ls = 1.0 vec_dx0 = vec_dx while 1: tt = time.clock() try: vec_r = fun(vec_x) except ValueError: if (it == 0) or (ls < conf.ls_min): output("giving up!") raise else: ok = False else: ok = True time_stats["rezidual"] = time.clock() - tt if ok: try: err = nla.norm(vec_r) except: output("infs or nans in the residual:", vec_r) output(nm.isfinite(vec_r).all()) debug() if self.log is not None: self.log(err, it) if it == 0: err0 = err break if err < (err_last * conf.ls_on): break red = conf.ls_red output( "linesearch: iter %d, (%.5e < %.5e) (new ls: %e)" % (it, err, err_last * conf.ls_on, red * ls) ) else: # Failure. if conf.give_up_warp: output("giving up!") break red = conf.ls_red_warp output("rezidual computation failed for iter %d" " (new ls: %e)!" % (it, red * ls)) if ls < conf.ls_min: output("linesearch failed, continuing anyway") break ls *= red vec_dx = ls * vec_dx0 vec_x = vec_x_last.copy() - vec_dx # End residual loop. if self.log is not None: self.log.plot_vlines([1], color="g", linewidth=0.5) err_last = err vec_x_last = vec_x.copy() condition = conv_test(conf, it, err, err0) if condition >= 0: break if (not ok) and conf.give_up_warp: condition = 2 break tt = time.clock() if conf.problem == "nonlinear": mtx_a = fun_grad(vec_x) else: mtx_a = fun_grad("linear") time_stats["matrix"] = time.clock() - tt if conf.check: tt = time.clock() wt = check_tangent_matrix(conf, vec_x, fun, fun_grad) time_stats["check"] = time.clock() - tt - wt if conf.lin_precision is not None: if ls_eps_a is not None: eps_a = max(err * conf.lin_precision, ls_eps_a) elif ls_eps_r is not None: eps_r = max(conf.lin_precision, ls_eps_r) lin_red = max(eps_a, err * eps_r) if conf.verbose: output("solving linear system...") tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, eps_a=eps_a, eps_r=eps_r, mtx=mtx_a) time_stats["solve"] = time.clock() - tt if conf.verbose: output("...done") for kv in time_stats.iteritems(): output("%10s: %7.2f [s]" % kv) vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm(vec_e) if lerr > lin_red: output("linear system not solved! (err = %e < %e)" % (lerr, lin_red)) vec_x -= vec_dx if conf.is_plot: plu.plt.ion() plu.plt.gcf().clear() plu.plt.subplot(2, 2, 1) plu.plt.plot(vec_x_last) plu.plt.ylabel(r"$x_{i-1}$") plu.plt.subplot(2, 2, 2) plu.plt.plot(vec_r) plu.plt.ylabel(r"$r$") plu.plt.subplot(2, 2, 4) plu.plt.plot(vec_dx) plu.plt.ylabel(r"$\_delta x$") plu.plt.subplot(2, 2, 3) plu.plt.plot(vec_x) plu.plt.ylabel(r"$x_i$") plu.plt.draw() plu.plt.ioff() pause() it += 1 if status is not None: status["time_stats"] = time_stats status["err0"] = err0 status["err"] = err status["n_iter"] = it status["condition"] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
class Oseen(NonlinearSolver): """ The Oseen solver for Navier-Stokes equations. """ name = 'nls.oseen' __metaclass__ = SolverMeta _parameters = [ ('stabil_mat', 'str', None, True, 'The name of stabilization material.'), ('adimensionalize', 'bool', False, False, 'If True, adimensionalize the problem (not implemented!).'), ('check_navier_stokes_rezidual', 'bool', False, False, 'If True, check the Navier-Stokes rezidual after the nonlinear loop.'), ('i_max', 'int', 1, False, 'The maximum number of iterations.'), ('eps_a', 'float', 1e-10, False, 'The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`.'), ('eps_r', 'float', 1.0, False, """The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`."""), ('macheps', 'float', nm.finfo(nm.float64).eps, False, 'The float considered to be machine "zero".'), ('lin_red', 'float', 1.0, False, """The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed."""), ('lin_precision', 'float or None', None, False, """If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers."""), ] def __init__(self, conf, problem, **kwargs): NonlinearSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) conf.problem = problem conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, status=None, problem=None): """ Oseen solver is problem-specific - it requires a Problem instance. """ conf = get_default(conf, self.conf) fun = get_default(fun, self.fun) fun_grad = get_default(fun_grad, self.fun_grad) lin_solver = get_default(lin_solver, self.lin_solver) status = get_default(status, self.status) problem = get_default(problem, conf.problem, '`problem` parameter needs to be set!') time_stats = {} stabil = problem.get_materials()[conf.stabil_mat] ns, ii = stabil.function.function.get_maps() variables = problem.get_variables() update_var = variables.set_data_from_state make_full_vec = variables.make_full_vec output('problem size:') output(' velocity: %s' % ii['us']) output(' pressure: %s' % ii['ps']) vec_x = vec_x0.copy() vec_x_prev = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err0 = -1.0 it = 0 while 1: vec_x_prev_f = make_full_vec(vec_x_prev) update_var(ns['b'], vec_x_prev_f, ns['u']) vec_b = vec_x_prev_f[ii['u']] b_norm = nla.norm(vec_b, nm.inf) output('|b|_max: %.12e' % b_norm) vec_x_f = make_full_vec(vec_x) vec_u = vec_x_f[ii['u']] u_norm = nla.norm(vec_u, nm.inf) output('|u|_max: %.2e' % u_norm) stabil.function.set_extra_args(b_norm=b_norm) stabil.time_update(None, problem.equations, mode='force', problem=problem) max_pars = stabil.reduce_on_datas(lambda a, b: max(a, b.max())) output('stabilization parameters:') output(' gamma: %.12e' % max_pars[ns['gamma']]) output(' max(delta): %.12e' % max_pars[ns['delta']]) output(' max(tau): %.12e' % max_pars[ns['tau']]) if (not are_close(b_norm, 1.0)) and conf.adimensionalize: adimensionalize = True else: adimensionalize = False tt = time.clock() try: vec_r = fun(vec_x) except ValueError: ok = False else: ok = True time_stats['rezidual'] = time.clock() - tt if ok: err = nla.norm(vec_r) if it == 0: err0 = err; else: err += nla.norm(vec_dx) else: # Failure. output('rezidual computation failed for iter %d!' % it) raise RuntimeError('giving up...') if self.log is not None: self.log(err, it, max_pars[ns['gamma']], max_pars[ns['delta']], max_pars[ns['tau']]) condition = conv_test(conf, it, err, err0) if condition >= 0: break if adimensionalize: output('adimensionalizing') ## mat.viscosity = viscosity / b_norm ## vec_r[indx_us] /= b_norm tt = time.clock() try: mtx_a = fun_grad(vec_x) except ValueError: ok = False else: ok = True time_stats['matrix'] = time.clock() - tt if not ok: raise RuntimeError('giving up...') tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, mtx=mtx_a) time_stats['solve'] = time.clock() - tt vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm(vec_e) if lerr > (conf.eps_a * conf.lin_red): output('linear system not solved! (err = %e)' % lerr) if adimensionalize: output('restoring pressure...') ## vec_dx[indx_ps] *= b_norm dx_norm = nla.norm(vec_dx) output('||dx||: %.2e' % dx_norm) for kv in six.iteritems(time_stats): output('%10s: %7.2f [s]' % kv) vec_x_prev = vec_x.copy() vec_x -= vec_dx it += 1 if conf.check_navier_stokes_rezidual: t1 = '+ dw_div_grad.%s.%s(%s.viscosity, %s, %s)' \ % (ns['i2'], ns['omega'], ns['fluid'], ns['v'], ns['u']) # t2 = '+ dw_lin_convect.%s(%s, %s, %s)' % (ns['omega'], # ns['v'], b_name, ns['u']) t2 = '+ dw_convect.%s.%s(%s, %s)' % (ns['i2'], ns['omega'], ns['v'], ns['u']) t3 = '- dw_stokes.%s.%s(%s, %s)' % (ns['i1'], ns['omega'], ns['v'], ns['p']) t4 = 'dw_stokes.%s.%s(%s, %s)' % (ns['i1'], ns['omega'], ns['u'], ns['q']) equations = { 'balance' : ' '.join((t1, t2, t3)), 'incompressibility' : t4, } problem.set_equations(equations) try: vec_rns0 = fun(vec_x0) vec_rns = fun(vec_x) except ValueError: ok = False else: ok = True if not ok: output('Navier-Stokes rezidual computation failed!') err_ns = err_ns0 = None else: err_ns0 = nla.norm(vec_rns0) err_ns = nla.norm(vec_rns) output('Navier-Stokes rezidual0: %.8e' % err_ns0) output('Navier-Stokes rezidual : %.8e' % err_ns) output('b - u: %.8e' % nla.norm(vec_b - vec_u)) output(condition) else: err_ns = None if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['err_ns'] = err_ns status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
class FMinSteepestDescent(OptimizationSolver): """ Steepest descent optimization solver. """ name = 'opt.fmin_sd' __metaclass__ = SolverMeta _parameters = [ ('i_max', 'int', 10, False, 'The maximum number of iterations.'), ('eps_rd', 'float', 1e-5, False, 'The relative delta of the objective function.'), ('eps_of', 'float', 1e-4, False, 'The tolerance for the objective function.'), ('eps_ofg', 'float', 1e-8, False, 'The tolerance for the objective function gradient.'), ('norm', 'numpy norm', nm.Inf, False, 'The norm to be used.'), ('ls', 'bool', True, False, 'If True, use a line-search.'), ('ls_method', "{'backtracking', 'full'}", 'backtracking', False, 'The line-search method.'), ('ls_on', 'float', 0.99999, False, """Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`."""), ('ls0', '0.0 < float < 1.0', 1.0, False, 'The initial step.'), ('ls_red', '0.0 < float < 1.0', 0.5, False, 'The step reduction factor in case of correct residual assembling.'), ('ls_red_warp', '0.0 < float < 1.0', 0.1, False, """The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations)."""), ('ls_min', '0.0 < float < 1.0', 1e-5, False, 'The minimum step reduction factor.'), ('check', '0, 1 or 2', 0, False, """If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns."""), ('delta', 'float', 1e-6, False, r"""If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`."""), ('output', 'function', None, False, """If given, use it instead of :func:`output() <sfepy.base.base.output()>` function."""), ('yscales', 'list of str', ['linear', 'log', 'log', 'linear'], False, 'The list of four convergence log subplot scales.'), ('log', 'dict or None', None, False, """If not None, log the convergence according to the configuration in the following form: ``{'text' : 'log.txt', 'plot' : 'log.pdf'}``. Each of the dict items can be None."""), ] def __init__(self, conf, **kwargs): OptimizationSolver.__init__(self, conf, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) if conf.is_any_log: self.log = Log([[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None def __call__(self, x0, conf=None, obj_fun=None, obj_fun_grad=None, status=None, obj_args=None): conf = get_default(conf, self.conf) obj_fun = get_default(obj_fun, self.obj_fun) obj_fun_grad = get_default(obj_fun_grad, self.obj_fun_grad) status = get_default(status, self.status) obj_args = get_default(obj_args, self.obj_args) if conf.output: globals()['output'] = conf.output output('entering optimization loop...') nc_of, tt_of, fn_of = wrap_function(obj_fun, obj_args) nc_ofg, tt_ofg, fn_ofg = wrap_function(obj_fun_grad, obj_args) time_stats = {'of' : tt_of, 'ofg': tt_ofg, 'check' : []} ofg = None it = 0 xit = x0.copy() while 1: of = fn_of(xit) if it == 0: of0 = ofit0 = of_prev = of of_prev_prev = of + 5000.0 if ofg is None: ofg = fn_ofg(xit) if conf.check: tt = time.clock() check_gradient(xit, ofg, fn_of, conf.delta, conf.check) time_stats['check'].append(time.clock() - tt) ofg_norm = nla.norm(ofg, conf.norm) ret = conv_test(conf, it, of, ofit0, ofg_norm) if ret >= 0: break ofit0 = of ## # Backtrack (on errors). alpha = conf.ls0 can_ls = True while 1: xit2 = xit - alpha * ofg aux = fn_of(xit2) if self.log is not None: self.log(of, ofg_norm, alpha, it) if aux is None: alpha *= conf.ls_red_warp can_ls = False output('warp: reducing step (%f)' % alpha) elif conf.ls and conf.ls_method == 'backtracking': if aux < of * conf.ls_on: break alpha *= conf.ls_red output('backtracking: reducing step (%f)' % alpha) else: of_prev_prev = of_prev of_prev = aux break if alpha < conf.ls_min: if aux is None: raise RuntimeError, 'giving up...' output('linesearch failed, continuing anyway') break # These values are modified by the line search, even if it fails of_prev_bak = of_prev of_prev_prev_bak = of_prev_prev if conf.ls and can_ls and conf.ls_method == 'full': output('full linesearch...') alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ linesearch.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev,of_prev_prev, c2=0.4) if alpha is None: # line search failed -- use different one. alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ sopt.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev_bak, of_prev_prev_bak) if alpha is None or alpha == 0: # This line search also failed to find a better # solution. ret = 3 break output(' -> alpha: %.8e' % alpha) else: if conf.ls_method == 'full': output('full linesearch off (%s and %s)' % (conf.ls, can_ls)) ofg1 = None if self.log is not None: self.log.plot_vlines(color='g', linewidth=0.5) xit = xit - alpha * ofg if ofg1 is None: ofg = None else: ofg = ofg1.copy() for key, val in time_stats.iteritems(): if len(val): output('%10s: %7.2f [s]' % (key, val[-1])) it = it + 1 output('status: %d' % ret) output('initial value: %.8e' % of0) output('current value: %.8e' % of) output('iterations: %d' % it) output('function evaluations: %d in %.2f [s]' % (nc_of[0], nm.sum(time_stats['of']))) output('gradient evaluations: %d in %.2f [s]' % (nc_ofg[0], nm.sum(time_stats['ofg']))) if self.log is not None: self.log(of, ofg_norm, alpha, it) if conf.log.plot is not None: self.log(save_figure=conf.log.plot, finished=True) else: self.log(finished=True) if status is not None: status['log'] = self.log status['status'] = status status['of0'] = of0 status['of'] = of status['it'] = it status['nc_of'] = nc_of[0] status['nc_ofg'] = nc_ofg[0] status['time_stats'] = time_stats return xit
class Oseen(NonlinearSolver): """ The Oseen solver for Navier-Stokes equations. """ name = 'nls.oseen' _parameters = [ ('stabil_mat', 'str', None, True, 'The name of stabilization material.'), ('adimensionalize', 'bool', False, False, 'If True, adimensionalize the problem (not implemented!).'), ('check_navier_stokes_residual', 'bool', False, False, 'If True, check the Navier-Stokes residual after the nonlinear loop.' ), ('i_max', 'int', 1, False, 'The maximum number of iterations.'), ('eps_a', 'float', 1e-10, False, 'The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`.'), ('eps_r', 'float', 1.0, False, """The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`."""), ('macheps', 'float', nm.finfo(nm.float64).eps, False, 'The float considered to be machine "zero".'), ('lin_red', 'float', 1.0, False, """The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed."""), ('lin_precision', 'float or None', None, False, """If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers."""), ] def __init__(self, conf, context=None, **kwargs): NonlinearSolver.__init__(self, conf, context=context, **kwargs) conf = self.conf log = get_logging_conf(conf) conf.log = log = Struct(name='log_conf', **log) conf.is_any_log = (log.text is not None) or (log.plot is not None) conf.problem = context conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration'], [r'$\gamma$', r'$\max(\delta)$', r'$\max(\tau)$']], xlabels=['', '', 'all iterations'], ylabels=[r'$||r||$', 'iteration', 'stabilization'], yscales=['log', 'linear', 'log'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d'], ['%.8e', '%.8e', '%.8e']]) else: self.log = None def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, status=None, problem=None): """ Oseen solver is problem-specific - it requires a Problem instance. """ conf = get_default(conf, self.conf) fun = get_default(fun, self.fun) fun_grad = get_default(fun_grad, self.fun_grad) lin_solver = get_default(lin_solver, self.lin_solver) status = get_default(status, self.status) problem = get_default(problem, conf.problem, '`problem` parameter needs to be set!') timer = Timer() time_stats = {} stabil = problem.get_materials()[conf.stabil_mat] ns, ii = stabil.function.function.get_maps() variables = problem.get_variables() update_var = variables.set_from_state make_full_vec = variables.make_full_vec output('problem size:') output(' velocity: %s' % ii['us']) output(' pressure: %s' % ii['ps']) vec_x = vec_x0.copy() vec_x_prev = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err0 = -1.0 it = 0 while 1: vec_x_prev_f = make_full_vec(vec_x_prev) update_var(ns['b'], vec_x_prev_f, ns['u']) vec_b = vec_x_prev_f[ii['u']] b_norm = nla.norm(vec_b, nm.inf) output('|b|_max: %.12e' % b_norm) vec_x_f = make_full_vec(vec_x) vec_u = vec_x_f[ii['u']] u_norm = nla.norm(vec_u, nm.inf) output('|u|_max: %.2e' % u_norm) stabil.function.set_extra_args(b_norm=b_norm) stabil.time_update(None, problem.equations, mode='force', problem=problem) max_pars = stabil.reduce_on_datas(lambda a, b: max(a, b.max())) output('stabilization parameters:') output(' gamma: %.12e' % max_pars[ns['gamma']]) output(' max(delta): %.12e' % max_pars[ns['delta']]) output(' max(tau): %.12e' % max_pars[ns['tau']]) if (not are_close(b_norm, 1.0)) and conf.adimensionalize: adimensionalize = True else: adimensionalize = False timer.start() try: vec_r = fun(vec_x) except ValueError: ok = False else: ok = True time_stats['residual'] = timer.stop() if ok: err = nla.norm(vec_r) if it == 0: err0 = err else: err += nla.norm(vec_dx) else: # Failure. output('residual computation failed for iter %d!' % it) raise RuntimeError('giving up...') if self.log is not None: self.log(err, it, max_pars[ns['gamma']], max_pars[ns['delta']], max_pars[ns['tau']]) condition = conv_test(conf, it, err, err0) if condition >= 0: break if adimensionalize: output('adimensionalizing') ## mat.viscosity = viscosity / b_norm ## vec_r[indx_us] /= b_norm timer.start() try: mtx_a = fun_grad(vec_x) except ValueError: ok = False else: ok = True time_stats['matrix'] = timer.stop() if not ok: raise RuntimeError('giving up...') timer.start() vec_dx = lin_solver(vec_r, x0=vec_x, mtx=mtx_a) time_stats['solve'] = timer.stop() vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm(vec_e) if lerr > (conf.eps_a * conf.lin_red): output('linear system not solved! (err = %e)' % lerr) if adimensionalize: output('restoring pressure...') ## vec_dx[indx_ps] *= b_norm dx_norm = nla.norm(vec_dx) output('||dx||: %.2e' % dx_norm) for kv in six.iteritems(time_stats): output('%10s: %7.2f [s]' % kv) vec_x_prev = vec_x.copy() vec_x -= vec_dx it += 1 if conf.check_navier_stokes_residual: t1 = '+ dw_div_grad.%s.%s(%s.viscosity, %s, %s)' \ % (ns['i2'], ns['omega'], ns['fluid'], ns['v'], ns['u']) # t2 = '+ dw_lin_convect.%s(%s, %s, %s)' % (ns['omega'], # ns['v'], b_name, ns['u']) t2 = '+ dw_convect.%s.%s(%s, %s)' % (ns['i2'], ns['omega'], ns['v'], ns['u']) t3 = '- dw_stokes.%s.%s(%s, %s)' % (ns['i1'], ns['omega'], ns['v'], ns['p']) t4 = 'dw_stokes.%s.%s(%s, %s)' % (ns['i1'], ns['omega'], ns['u'], ns['q']) equations = { 'balance': ' '.join((t1, t2, t3)), 'incompressibility': t4, } problem.set_equations(equations) try: vec_rns0 = fun(vec_x0) vec_rns = fun(vec_x) except ValueError: ok = False else: ok = True if not ok: output('Navier-Stokes residual computation failed!') err_ns = err_ns0 = None else: err_ns0 = nla.norm(vec_rns0) err_ns = nla.norm(vec_rns) output('Navier-Stokes residual0: %.8e' % err_ns0) output('Navier-Stokes residual : %.8e' % err_ns) output('b - u: %.8e' % nla.norm(vec_b - vec_u)) output(condition) else: err_ns = None if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['err_ns'] = err_ns status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
class Newton(NonlinearSolver): r""" Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. For common configuration parameters, see :class:`Solver <sfepy.solvers.solvers.Solver>`. Parameters ---------- i_max : int The maximum number of iterations. eps_a : float The absolute tolerance for the residual, i.e. :math:`||f(x^i)||`. eps_r : float The relative tolerance for the residual, i.e. :math:`||f(x^i)|| / ||f(x^0)||`. macheps : float The float considered to be machine "zero". lin_red : float The linear system solution error should be smaller than (`eps_a` * `lin_red`), otherwise a warning is printed. lin_precision : float or None If not None, the linear system solution tolerances are set in each nonlinear iteration relative to the current residual norm by the `lin_precision` factor. Ignored for direct linear solvers. ls_on : float Start the backtracking line-search by reducing the step, if :math:`||f(x^i)|| / ||f(x^{i-1})||` is larger than `ls_on`. ls_red : 0.0 < float < 1.0 The step reduction factor in case of correct residual assembling. ls_red_warp : 0.0 < float < 1.0 The step reduction factor in case of failed residual assembling (e.g. the "warp violation" error caused by a negative volume element resulting from too large deformations). ls_min : 0.0 < float < 1.0 The minimum step reduction factor. give_up_warp : bool If True, abort on the "warp violation" error. check : 0, 1 or 2 If >= 1, check the tangent matrix using finite differences. If 2, plot the resulting sparsity patterns. delta : float If `check >= 1`, the finite difference matrix is taken as :math:`A_{ij} = \frac{f_i(x_j + \delta) - f_i(x_j - \delta)}{2 \delta}`. is_plot : False If True, plot the solution and residual in each step. log : dict or None If not None, log the convergence according to the configuration in the following form:: {'text' : 'log.txt', 'plot' : 'log.pdf'} Each of the dict items can be None. problem : 'nonlinear' or 'linear' Specifies if the problem is linear or non-linear. """ name = 'nls.newton' @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values for a linear problem. Example configuration, all items:: solver_1 = { 'name' : 'newton', 'kind' : 'nls.newton', 'i_max' : 2, 'eps_a' : 1e-8, 'eps_r' : 1e-2, 'macheps' : 1e-16, 'lin_red' : 1e-2, # Linear system error < (eps_a * lin_red). 'lin_precision' : None, 'ls_on' : 0.99999, 'ls_red' : 0.1, 'ls_red_warp' : 0.001, 'ls_min' : 1e-5, 'give_up_warp' : False, 'check' : 0, 'delta' : 1e-6, 'is_plot' : False, 'log' : None, # 'nonlinear' or 'linear' (ignore i_max) 'problem' : 'nonlinear', } """ get = make_get_conf(conf, kwargs) common = NonlinearSolver.process_conf(conf) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) return Struct(i_max=get('i_max', 1), eps_a=get('eps_a', 1e-10), eps_r=get('eps_r', 1.0), macheps=get('macheps', nm.finfo(nm.float64).eps), lin_red=get('lin_red', 1.0), lin_precision=get('lin_precision', None), ls_red=get('ls_red', 0.1), ls_red_warp=get('ls_red_warp', 0.001), ls_on=get('ls_on', 0.99999), ls_min=get('ls_min', 1e-5), give_up_warp=get('give_up_warp', False), check=get('check', 0), delta=get('delta', 1e-6), is_plot=get('is_plot', False), problem=get('problem', 'nonlinear'), log=log, is_any_log=is_any_log) + common def __init__(self, conf, **kwargs): NonlinearSolver.__init__( self, conf, **kwargs ) conf = self.conf if conf.is_any_log: self.log = Log([[r'$||r||$'], ['iteration']], xlabels=['', 'all iterations'], ylabels=[r'$||r||$', 'iteration'], yscales=['log', 'linear'], is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%d']]) else: self.log = None def __call__(self, vec_x0, conf=None, fun=None, fun_grad=None, lin_solver=None, iter_hook=None, status=None): """ Nonlinear system solver call. Solves a nonlinear system :math:`f(x) = 0` using the Newton method with backtracking line-search, starting with an initial guess :math:`x^0`. Parameters ---------- vec_x0 : array The initial guess vector :math:`x_0`. conf : Struct instance, optional The solver configuration parameters, fun : function, optional The function :math:`f(x)` whose zero is sought - the residual. fun_grad : function, optional The gradient of :math:`f(x)` - the tangent matrix. lin_solver : LinearSolver instance, optional The linear solver for each nonlinear iteration. iter_hook : function, optional User-supplied function to call before each iteration. status : dict-like, optional The user-supplied object to hold convergence statistics. Notes ----- * The optional parameters except `iter_hook` and `status` need to be given either here or upon `Newton` construction. * Setting `conf.problem == 'linear'` means a pre-assembled and possibly pre-solved matrix. This is mostly useful for linear time-dependent problems. """ import sfepy.base.plotutils as plu conf = get_default( conf, self.conf ) fun = get_default( fun, self.fun ) fun_grad = get_default( fun_grad, self.fun_grad ) lin_solver = get_default( lin_solver, self.lin_solver ) iter_hook = get_default(iter_hook, self.iter_hook) status = get_default( status, self.status ) ls_eps_a, ls_eps_r = lin_solver.get_tolerance() eps_a = get_default(ls_eps_a, 1.0) eps_r = get_default(ls_eps_r, 1.0) lin_red = conf.eps_a * conf.lin_red time_stats = {} vec_x = vec_x0.copy() vec_x_last = vec_x0.copy() vec_dx = None if self.log is not None: self.log.plot_vlines(color='r', linewidth=1.0) err = err0 = -1.0 err_last = -1.0 it = 0 while 1: if iter_hook is not None: iter_hook(self, vec_x, it, err, err0) ls = 1.0 vec_dx0 = vec_dx; while 1: tt = time.clock() try: vec_r = fun( vec_x ) except ValueError: if (it == 0) or (ls < conf.ls_min): output('giving up!') raise else: ok = False else: ok = True time_stats['rezidual'] = time.clock() - tt if ok: try: err = nla.norm( vec_r ) except: output( 'infs or nans in the residual:', vec_r ) output( nm.isfinite( vec_r ).all() ) debug() if self.log is not None: self.log(err, it) if it == 0: err0 = err; break if err < (err_last * conf.ls_on): break red = conf.ls_red; output( 'linesearch: iter %d, (%.5e < %.5e) (new ls: %e)'\ % (it, err, err_last * conf.ls_on, red * ls) ) else: # Failure. if conf.give_up_warp: output('giving up!') break red = conf.ls_red_warp; output( 'rezidual computation failed for iter %d' ' (new ls: %e)!' % (it, red * ls) ) if ls < conf.ls_min: output( 'linesearch failed, continuing anyway' ) break ls *= red; vec_dx = ls * vec_dx0; vec_x = vec_x_last.copy() - vec_dx # End residual loop. if self.log is not None: self.log.plot_vlines([1], color='g', linewidth=0.5) err_last = err; vec_x_last = vec_x.copy() condition = conv_test( conf, it, err, err0 ) if condition >= 0: break if (not ok) and conf.give_up_warp: condition = 2 break tt = time.clock() if conf.problem == 'nonlinear': mtx_a = fun_grad(vec_x) else: mtx_a = fun_grad( 'linear' ) time_stats['matrix'] = time.clock() - tt if conf.check: tt = time.clock() wt = check_tangent_matrix( conf, vec_x, fun, fun_grad ) time_stats['check'] = time.clock() - tt - wt if conf.lin_precision is not None: if ls_eps_a is not None: eps_a = max(err * conf.lin_precision, ls_eps_a) elif ls_eps_r is not None: eps_r = max(conf.lin_precision, ls_eps_r) lin_red = max(eps_a, err * eps_r) if conf.verbose: output('solving linear system...') tt = time.clock() vec_dx = lin_solver(vec_r, x0=vec_x, eps_a=eps_a, eps_r=eps_r, mtx=mtx_a) time_stats['solve'] = time.clock() - tt if conf.verbose: output('...done') for kv in time_stats.iteritems(): output( '%10s: %7.2f [s]' % kv ) vec_e = mtx_a * vec_dx - vec_r lerr = nla.norm( vec_e ) if lerr > lin_red: output('linear system not solved! (err = %e < %e)' % (lerr, lin_red)) vec_x -= vec_dx if conf.is_plot: plu.plt.ion() plu.plt.gcf().clear() plu.plt.subplot( 2, 2, 1 ) plu.plt.plot( vec_x_last ) plu.plt.ylabel( r'$x_{i-1}$' ) plu.plt.subplot( 2, 2, 2 ) plu.plt.plot( vec_r ) plu.plt.ylabel( r'$r$' ) plu.plt.subplot( 2, 2, 4 ) plu.plt.plot( vec_dx ) plu.plt.ylabel( r'$\_delta x$' ) plu.plt.subplot( 2, 2, 3 ) plu.plt.plot( vec_x ) plu.plt.ylabel( r'$x_i$' ) plu.plt.draw() plu.plt.ioff() pause() it += 1 if status is not None: status['time_stats'] = time_stats status['err0'] = err0 status['err'] = err status['n_iter'] = it status['condition'] = condition if conf.log.plot is not None: if self.log is not None: self.log(save_figure=conf.log.plot) return vec_x
class FMinSteepestDescent(OptimizationSolver): name = 'opt.fmin_sd' @staticmethod def process_conf(conf, kwargs): """ Missing items are set to default values. Example configuration, all items:: solver_0 = { 'name' : 'fmin_sd', 'kind' : 'opt.fmin_sd', 'i_max' : 10, 'eps_rd' : 1e-5, # Relative delta of objective function 'eps_of' : 1e-4, 'eps_ofg' : 1e-8, 'norm' : nm.Inf, 'ls' : True, # Linesearch. 'ls_method' : 'backtracking', # 'backtracking' or 'full' 'ls0' : 0.25, 'ls_red' : 0.5, 'ls_red_warp' : 0.1, 'ls_on' : 0.99999, 'ls_min' : 1e-5, 'check' : 0, 'delta' : 1e-6, 'output' : None, # 'itc' 'log' : {'text' : 'output/log.txt', 'plot' : 'output/log.png'}, 'yscales' : ['linear', 'log', 'log', 'linear'], } """ get = make_get_conf(conf, kwargs) common = OptimizationSolver.process_conf(conf) log = get_logging_conf(conf) log = Struct(name='log_conf', **log) is_any_log = (log.text is not None) or (log.plot is not None) return Struct(i_max=get('i_max', 10), eps_rd=get('eps_rd', 1e-5), eps_of=get('eps_of', 1e-4), eps_ofg=get('eps_ofg', 1e-8), norm=get('norm', nm.Inf), ls=get('ls', True), ls_method=get('ls_method', 'backtracking'), ls0=get('ls0', 0.25), ls_red=get('ls_red', 0.5), ls_red_warp=get('ls_red_warp', 0.1), ls_on=get('ls_on', 0.99999), ls_min=get('ls_min', 1e-5), check=get('check', 0), delta=get('delta', 1e-6), output=get('output', None), yscales=get('yscales', ['linear', 'log', 'log', 'linear']), log=log, is_any_log=is_any_log) + common ## # 17.10.2007, c def __init__(self, conf, **kwargs): OptimizationSolver.__init__(self, conf, **kwargs) conf = self.conf if conf.is_any_log: self.log = Log( [[r'$||\Psi||$'], [r'$||\nabla \Psi||$'], [r'$\alpha$'], ['iteration']], xlabels=['', '', 'all iterations', 'all iterations'], yscales=conf.yscales, is_plot=conf.log.plot is not None, log_filename=conf.log.text, formats=[['%.8e'], ['%.3e'], ['%.3e'], ['%d']]) else: self.log = None ## # 19.04.2006, c # 20.04.2006 # 21.04.2006 # 26.04.2006 # 06.06.2006 # 07.06.2006 # 04.09.2006 # 21.03.2007 # 17.10.2007, from fmin_sd() def __call__(self, x0, conf=None, obj_fun=None, obj_fun_grad=None, status=None, obj_args=None): # def fmin_sd( conf, x0, fn_of, fn_ofg, args = () ): conf = get_default(conf, self.conf) obj_fun = get_default(obj_fun, self.obj_fun) obj_fun_grad = get_default(obj_fun_grad, self.obj_fun_grad) status = get_default(status, self.status) obj_args = get_default(obj_args, self.obj_args) if conf.output: globals()['output'] = conf.output output('entering optimization loop...') nc_of, tt_of, fn_of = wrap_function(obj_fun, obj_args) nc_ofg, tt_ofg, fn_ofg = wrap_function(obj_fun_grad, obj_args) time_stats = {'of': tt_of, 'ofg': tt_ofg, 'check': []} ofg = None it = 0 xit = x0.copy() while 1: of = fn_of(xit) if it == 0: of0 = ofit0 = of_prev = of of_prev_prev = of + 5000.0 if ofg is None: ofg = fn_ofg(xit) if conf.check: tt = time.clock() check_gradient(xit, ofg, fn_of, conf.delta, conf.check) time_stats['check'].append(time.clock() - tt) ofg_norm = nla.norm(ofg, conf.norm) ret = conv_test(conf, it, of, ofit0, ofg_norm) if ret >= 0: break ofit0 = of ## # Backtrack (on errors). alpha = conf.ls0 can_ls = True while 1: xit2 = xit - alpha * ofg aux = fn_of(xit2) if self.log is not None: self.log(of, ofg_norm, alpha, it) if aux is None: alpha *= conf.ls_red_warp can_ls = False output('warp: reducing step (%f)' % alpha) elif conf.ls and conf.ls_method == 'backtracking': if aux < of * conf.ls_on: break alpha *= conf.ls_red output('backtracking: reducing step (%f)' % alpha) else: of_prev_prev = of_prev of_prev = aux break if alpha < conf.ls_min: if aux is None: raise RuntimeError, 'giving up...' output('linesearch failed, continuing anyway') break # These values are modified by the line search, even if it fails of_prev_bak = of_prev of_prev_prev_bak = of_prev_prev if conf.ls and can_ls and conf.ls_method == 'full': output('full linesearch...') alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ linesearch.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev,of_prev_prev, c2=0.4) if alpha is None: # line search failed -- use different one. alpha, fc, gc, of_prev, of_prev_prev, ofg1 = \ sopt.line_search(fn_of,fn_ofg,xit, -ofg,ofg,of_prev_bak, of_prev_prev_bak) if alpha is None or alpha == 0: # This line search also failed to find a better solution. ret = 3 break output(' -> alpha: %.8e' % alpha) else: if conf.ls_method == 'full': output('full linesearch off (%s and %s)' % (conf.ls, can_ls)) ofg1 = None if self.log is not None: self.log.plot_vlines(color='g', linewidth=0.5) xit = xit - alpha * ofg if ofg1 is None: ofg = None else: ofg = ofg1.copy() for key, val in time_stats.iteritems(): if len(val): output('%10s: %7.2f [s]' % (key, val[-1])) it = it + 1 output('status: %d' % ret) output('initial value: %.8e' % of0) output('current value: %.8e' % of) output('iterations: %d' % it) output( 'function evaluations: %d in %.2f [s]' \ % (nc_of[0], nm.sum( time_stats['of'] ) ) ) output( 'gradient evaluations: %d in %.2f [s]' \ % (nc_ofg[0], nm.sum( time_stats['ofg'] ) ) ) if self.log is not None: self.log(of, ofg_norm, alpha, it) if conf.log.plot is not None: self.log(save_figure=conf.log.plot, finished=True) else: self.log(finished=True) if status is not None: status['log'] = self.log status['status'] = status status['of0'] = of0 status['of'] = of status['it'] = it status['nc_of'] = nc_of[0] status['nc_ofg'] = nc_ofg[0] status['time_stats'] = time_stats return xit