# solver¶

The solver module defines solvers for problems of the kind `res = 0` or `∂inertia/∂t + res = 0`, where `res` is a `nutils.evaluable.AsEvaluableArray`. To demonstrate this consider the following setup:

```>>> from nutils import mesh, function, solver
>>> ns = function.Namespace()
>>> domain, ns.x = mesh.rectilinear([4,4])
>>> ns.basis = domain.basis('spline', degree=2)
>>> cons = domain.boundary['left,top'].project(0, onto=ns.basis, geometry=ns.x, ischeme='gauss4')
project > constrained 11/36 dofs, error 0.00e+00/area
>>> ns.u = 'basis_n ?lhs_n'
```

Function `u` represents an element from the discrete space but cannot not evaluated yet as we did not yet establish values for `?lhs`. It can, however, be used to construct a residual functional `res`. Aiming to solve the Poisson problem `u_,kk = f` we define the residual functional ```res = v,k u,k + v f``` and solve for `res == 0` using `solve_linear`:

```>>> res = domain.integral('(basis_n,i u_,i + basis_n) d:x' @ ns, degree=2)
>>> lhs = solver.solve_linear('lhs', residual=res, constrain=cons)
solve > solving 25 dof system to machine precision using arnoldi solver
solve > solver returned with residual ...
```

The coefficients `lhs` represent the solution to the Poisson problem.

In addition to `solve_linear` the solver module defines `newton` and `pseudotime` for solving nonlinear problems, as well as `impliciteuler` for time dependent problems.

nutils.solver.single_or_multiple(f)

add support for legacy string target + array return value

class nutils.solver.withsolve(wrapped)

Bases: `Immutable`

add a .solve method to iterables

solve(self, tol=0.0, maxiter=inf, miniter=0)

execute nonlinear solver, return lhs

Iterates over nonlinear solver until tolerance is reached. Example:

```lhs = newton(target, residual).solve(tol=1e-5)
```
Parameters:
Returns:

Coefficient vector that corresponds to a smaller than `tol` residual.

Return type:

`numpy.ndarray`

solve_withinfo(self, tol, maxiter=inf, miniter=0)

execute nonlinear solver, return lhs and info

Like `solve()`, but return a 2-tuple of the solution and the corresponding info object which holds information about the final residual norm and other generator-dependent information.

class nutils.solver.LineSearch(*args, **kwargs)

Bases: `Immutable`

Line search abstraction for gradient based optimization.

A line search object is a callable that takes four arguments: the current residual and directional derivative, and the candidate residual and directional derivative, with derivatives normalized to unit length; and returns the optimal scaling and a boolean flag that marks whether the candidate should be accepted.

class nutils.solver.NormBased(minscale=0.01, acceptscale=0.6666666666666666, maxscale=2.0)

Bases: `LineSearch`

Line search abstraction for Newton-like iterations, computing relaxation values that correspond to greatest reduction of the residual norm.

Parameters:
• minscale (`float`) – Minimum relaxation scaling per update. Must be strictly greater than zero.

• acceptscale (`float`) – Relaxation scaling that is considered close enough to optimality to to accept the current Newton update. Must lie between minscale and one.

• maxscale (`float`) – Maximum relaxation scaling per update. Must be greater than one, and therefore always coincides with acceptance, determining how fast relaxation values rebound to one if not bounded by optimality.

class nutils.solver.MedianBased(minscale=0.01, acceptscale=0.6666666666666666, maxscale=2.0, quantile=0.5)

Bases: `LineSearch`

Line search abstraction for Newton-like iterations, computing relaxation values such that half (or any other configurable quantile) of the residual vector has its optimal reduction beyond it. Unline the `NormBased` approach this is invariant to constant scaling of the residual items.

Parameters:
• minscale (`float`) – Minimum relaxation scaling per update. Must be strictly greater than zero.

• acceptscale (`float`) – Relaxation scaling that is considered close enough to optimality to to accept the current Newton update. Must lie between minscale and one.

• maxscale (`float`) – Maximum relaxation scaling per update. Must be greater than one, and therefore always coincides with acceptance, determining how fast relaxation values rebound to one if not bounded by optimality.

• quantile (`float`) – Fraction of the residual vector that is aimed to have its optimal reduction at a smaller relaxation value. The default value of one half corresponds to the median. A value close to zero means tighter control, resulting in strong relaxation.

nutils.solver.solve_linear(target, residual, *, constrain=None, lhs0=None, arguments={}, **kwargs)

solve linear problem

Parameters:
Returns:

Array of `target` values for which `residual == 0`

Return type:

`numpy.ndarray`

nutils.solver.newton(target, residual, jacobian=None, lhs0=None, relax0=1.0, constrain=None, linesearch=None, failrelax=1e-06, arguments={}, **kwargs)

iteratively solve nonlinear problem by gradient descent

Generates targets such that residual approaches 0 using Newton procedure with line search based on the residual norm. Suitable to be used inside `solve`.

An optimal relaxation value is computed based on the following cubic assumption:

```|res(lhs + r * dlhs)|^2 = A + B * r + C * r^2 + D * r^3
```

where `A`, `B`, `C` and `D` are determined based on the current residual and tangent, the new residual, and the new tangent. If this value is found to be close to 1 then the newton update is accepted.

Parameters:
Yields:

`numpy.ndarray` – Coefficient vector that approximates residual==0 with increasing accuracy

nutils.solver.minimize(target, energy, lhs0=None, constrain=None, rampup=0.5, rampdown=-1.0, failrelax=-10.0, arguments={}, **kwargs)

iteratively minimize nonlinear functional by gradient descent

Generates targets such that residual approaches 0 using Newton procedure with line search based on the energy. Suitable to be used inside `solve`.

An optimal relaxation value is computed based on the following assumption:

```energy(lhs + r * dlhs) = A + B * r + C * r^2 + D * r^3 + E * r^4 + F * r^5
```

where `A`, `B`, `C`, `D`, `E` and `F` are determined based on the current and new energy, residual and tangent. If this value is found to be close to 1 then the newton update is accepted.

Parameters:
Yields:

`numpy.ndarray` – Coefficient vector that approximates residual==0 with increasing accuracy

nutils.solver.pseudotime(target, residual, inertia, timestep, lhs0=None, constrain=None, arguments={}, **kwargs)

iteratively solve nonlinear problem by pseudo time stepping

Generates targets such that residual approaches 0 using hybrid of Newton and time stepping. Requires an inertia term and initial timestep. Suitable to be used inside `solve`.

Parameters:
Yields:

`numpy.ndarray` with dtype `float` – Tuple of coefficient vector and residual norm

nutils.solver.thetamethod(target, residual, inertia, timestep, theta, lhs0=None, target0=None, constrain=None, newtontol=1e-10, arguments={}, newtonargs={}, timetarget='_thetamethod_time', time0=0.0, historysuffix='0')

solve time dependent problem using the theta method

Parameters:
Yields:

`numpy.ndarray` – Coefficient vector for all timesteps after the initial condition.

nutils.solver.impliciteuler(target, residual, inertia, timestep, *, theta=1, lhs0=None, target0=None, constrain=None, newtontol=1e-10, arguments={}, newtonargs={}, timetarget='_thetamethod_time', time0=0.0, historysuffix='0')

solve time dependent problem using the theta method

Parameters:
Yields:

`numpy.ndarray` – Coefficient vector for all timesteps after the initial condition.

nutils.solver.cranknicolson(target, residual, inertia, timestep, *, theta=0.5, lhs0=None, target0=None, constrain=None, newtontol=1e-10, arguments={}, newtonargs={}, timetarget='_thetamethod_time', time0=0.0, historysuffix='0')

solve time dependent problem using the theta method

Parameters:
Yields:

`numpy.ndarray` – Coefficient vector for all timesteps after the initial condition.

nutils.solver.optimize(target, functional, *, tol=0.0, arguments={}, droptol=None, constrain=None, lhs0=None, relax0=1.0, linesearch=None, failrelax=1e-06, **kwargs)

find the minimizer of a given functional

Parameters:
Yields:

`numpy.ndarray` – Coefficient vector corresponding to the functional optimum