gpe.minimize
============

.. py:module:: gpe.minimize

.. autoapi-nested-parse::

   Robust GPE minimizer



Attributes
----------

.. autoapisummary::

   gpe.minimize._EPS
   gpe.minimize._TINY


Classes
-------

.. autoapisummary::

   gpe.minimize.Minimize
   gpe.minimize.MinimizeState
   gpe.minimize.MinimizeStateFixedPhase


Module Contents
---------------

.. py:data:: _EPS

.. py:data:: _TINY

.. py:class:: Minimize(x=None, x_scale=1.0, f_scale=1.0, plot=False)

   General minimization class.


   .. py:attribute:: x_scale
      :value: 1.0



   .. py:attribute:: f_scale
      :value: 1.0



   .. py:attribute:: plot
      :value: False



   .. py:method:: init()

      Overload this to initialize your state if needed.



   .. py:method:: f_df(x)
      :abstractmethod:


      Return the objective function and it's derivative  as a function of
      the unpacked state `x`.



   .. py:method:: check(x=None)

      Check that the state.get_energy() and state.get_Hy() are correct
      (i.e. that Hy is derivative of E().



   .. py:method:: minimize(plot=False, callback=None, method='L-BFGS-B', polish=False, broyden_alpha=None, broyden_opts=None, f_tol=1e-12, x_tol=1e-07, use_scipy=True, ignore_f=False, _test=False, _debug=False, _log=False, use_cache=True, bounds=None, **kw)

      Return the state with minimized energy.

      If `x_tol < sqrt(eps)`, then we use the canned L-BFGS-B algorithm from
      scipy as the is very robust.  If we need higher precision on `x`, then
      we use a custom L-BFGS algorithm with a modified stopping criterion.

      :param f_tol: Relative stopping tolerance for the energy.
      :type f_tol: float
      :param x_tol: Relative stopping tolerance for the wavefunction.
      :type x_tol: float
      :param polish: If `True`, then build an approximation to the hessian during the
                     minimization phase so that this can be used with Broyden's method to
                     polish the solution to high accuracy after the energy is minimized.
                     This allows us to ensure that the wavefunction is also converged to
                     high accuracy.  (Since the energy is quadratic about the minimum, it
                     is common for the energy to be converged to machine precision eps
                     even though the state is only converged to about sqrt(eps)).

                     Currently does not actually polish the solution - only stores the data in
                     `self.broyden_data`.  See `use_scipy` below.
      :type polish: bool
      :param broyden_alpha: Initial inverse Jacobian approximation is `alpha` times the
                            identity.  If `None`, then this will be estimated by performing a
                            line search in the descent direction.
      :type broyden_alpha: None, float
      :param broyden_opts: Arguments to pass through to `mmfutils.solve.broyden.DyadicSum()`.
      :type broyden_opts: dict()
      :param use_scipy: If `True`, then use the scipy solvers, otherwise, if `x_tol < sqrt(eps)`,
                        then use our custom solver that performs Broyden iterations after.  The issue
                        here is that the minimizer might bail out prematurely because of the `f_tol`
                        criterion before reaching the desired `x_tol` because the minimum is
                        quadratic.  Since we have information about the hessian, we can in principle
                        continue to refine the solution with Broyden iterations to minimize the norm
                        of the residual.

                        This is the idea of the polish option, but one can "trick" scipy into doing
                        this by setting `f_tol=np.nan`.  This will always invalidate the criterion
                        (even `f_tol=0` can fail sometimes when the energy is very flat) and force
                        scipy to continue until `x_tol` is met or the method fails.  Always check
                        your answer if you do this!
      :type use_scipy: bool
      :param _debug: If `True` then return `(x, f, df, locals())`.
      :type _debug: bool

      :returns: * **x** (*array*) -- Solution
                * **f, df** (*functions*) -- Objective function and its gradient in the packed representation.
                * *Developer notes*
                * 1. Do not mutate `state0`.  Use `state` as a working copy if a -- true state is needed.
                * 2. Be careful which version of `state` or `state0` you use as the -- argument to `get_Hy` and `get_energy` since this determines the
                  non-linear portions.  In general one should use `state`, but
                  if one implements a minimization on the norm of `Hy` then for
                  the derivative one must be careful.



   .. py:method:: _minimize(f, df, x0, method, callback, bounds, options)

      Interface to the scipy minimizer.



   .. py:method:: _minimize_L_BFGS(f, df, x0, callback, x_tol=1e-12, safe=True, tries=5, disp=0)

      Custom L-BFGS minimizer.



   .. py:method:: _minimize_norm(df, x0, callback, broyden_alpha=None, x_tol=1e-12, safe=True, tries=5, disp=0)

      Custom Broyden minimizer for df only.

      This looks for solutions to df=0 without regard to them being
      minima of the energy.  This is useful for finding saddle points.



   .. py:method:: check_derivative(f, df, x, rtol=0.0001)


.. py:class:: MinimizeState(state, real=False, fix_N=True, **kw)

   Bases: :py:obj:`Minimize`


   Minimizer for states with the pytimeode.interfaces.IStateForABMEvolver
   interface.


   .. py:attribute:: state


   .. py:attribute:: fix_N
      :value: True



   .. py:attribute:: real
      :value: False



   .. py:attribute:: _active_inds


   .. py:property:: x

      Get current state.  Must allow setting and unsetting.


   .. py:property:: _x_dtype


   .. py:method:: init()

      Overload this to initialize your state if needed.



   .. py:method:: unpack(x, state=None)

      Unpack `x` into `state` including factors of `x_scale`

      Note: Do not scale or otherwise mutate `x`.



   .. py:method:: pack(state)

      This is not symmetric with `unpack` as it does not scale
      the solution by any factors.  (This is because we unpack both
      states and Hpsi which have different scalings.).



   .. py:method:: f_df(x)

      Return the objective function and it's derivative  as a function of
      the unpacked state `x`.



   .. py:method:: g_dg(x)

      Return the objective function minimizing the residual norm.

      INCOMPLETE.



   .. py:method:: minimize(psi_tol=1e-08, E_tol=1e-12, callback=None, _debug=False, **kw)

      Return the state with minimized energy.

      If `x_tol < sqrt(eps)`, then we use the canned L-BFGS-B algorithm from
      scipy as the is very robust.  If we need higher precision on `x`, then
      we use a custom L-BFGS algorithm with a modified stopping criterion.

      :param f_tol: Relative stopping tolerance for the energy.
      :type f_tol: float
      :param x_tol: Relative stopping tolerance for the wavefunction.
      :type x_tol: float
      :param polish: If `True`, then build an approximation to the hessian during the
                     minimization phase so that this can be used with Broyden's method to
                     polish the solution to high accuracy after the energy is minimized.
                     This allows us to ensure that the wavefunction is also converged to
                     high accuracy.  (Since the energy is quadratic about the minimum, it
                     is common for the energy to be converged to machine precision eps
                     even though the state is only converged to about sqrt(eps)).

                     Currently does not actually polish the solution - only stores the data in
                     `self.broyden_data`.  See `use_scipy` below.
      :type polish: bool
      :param broyden_alpha: Initial inverse Jacobian approximation is `alpha` times the
                            identity.  If `None`, then this will be estimated by performing a
                            line search in the descent direction.
      :type broyden_alpha: None, float
      :param broyden_opts: Arguments to pass through to `mmfutils.solve.broyden.DyadicSum()`.
      :type broyden_opts: dict()
      :param use_scipy: If `True`, then use the scipy solvers, otherwise, if `x_tol < sqrt(eps)`,
                        then use our custom solver that performs Broyden iterations after.  The issue
                        here is that the minimizer might bail out prematurely because of the `f_tol`
                        criterion before reaching the desired `x_tol` because the minimum is
                        quadratic.  Since we have information about the hessian, we can in principle
                        continue to refine the solution with Broyden iterations to minimize the norm
                        of the residual.

                        This is the idea of the polish option, but one can "trick" scipy into doing
                        this by setting `f_tol=np.nan`.  This will always invalidate the criterion
                        (even `f_tol=0` can fail sometimes when the energy is very flat) and force
                        scipy to continue until `x_tol` is met or the method fails.  Always check
                        your answer if you do this!
      :type use_scipy: bool
      :param _debug: If `True` then return `(x, f, df, locals())`.
      :type _debug: bool

      :returns: * **x** (*array*) -- Solution
                * **f, df** (*functions*) -- Objective function and its gradient in the packed representation.
                * *Developer notes*
                * 1. Do not mutate `state0`.  Use `state` as a working copy if a -- true state is needed.
                * 2. Be careful which version of `state` or `state0` you use as the -- argument to `get_Hy` and `get_energy` since this determines the
                  non-linear portions.  In general one should use `state`, but
                  if one implements a minimization on the norm of `Hy` then for
                  the derivative one must be careful.



.. py:class:: MinimizeStateFixedPhase(state, phase, fix_N=True, **kw)

   Bases: :py:obj:`MinimizeState`


   Minimizer with fixed phase.


   .. py:attribute:: phase


   .. py:method:: init()

      Overload this to initialize your state if needed.



   .. py:method:: unpack(x, state=None)

      Unpack `x` into `state` including factors of `x_scale`

      Note: Do not scale or otherwise mutate `x`.



   .. py:method:: pack(state)

      This is not symmetric with `unpack` as it does not scale
      the solution by any factors.  (This is because we unpack both
      states and Hpsi which have different scalings.).



   .. py:method:: f_df(x)

      Return the objective function and it's derivative  as a function of
      the unpacked state `x`.



   .. py:method:: minimize(**kw)

      Return the state with minimized energy.

      If `x_tol < sqrt(eps)`, then we use the canned L-BFGS-B algorithm from
      scipy as the is very robust.  If we need higher precision on `x`, then
      we use a custom L-BFGS algorithm with a modified stopping criterion.

      :param f_tol: Relative stopping tolerance for the energy.
      :type f_tol: float
      :param x_tol: Relative stopping tolerance for the wavefunction.
      :type x_tol: float
      :param polish: If `True`, then build an approximation to the hessian during the
                     minimization phase so that this can be used with Broyden's method to
                     polish the solution to high accuracy after the energy is minimized.
                     This allows us to ensure that the wavefunction is also converged to
                     high accuracy.  (Since the energy is quadratic about the minimum, it
                     is common for the energy to be converged to machine precision eps
                     even though the state is only converged to about sqrt(eps)).

                     Currently does not actually polish the solution - only stores the data in
                     `self.broyden_data`.  See `use_scipy` below.
      :type polish: bool
      :param broyden_alpha: Initial inverse Jacobian approximation is `alpha` times the
                            identity.  If `None`, then this will be estimated by performing a
                            line search in the descent direction.
      :type broyden_alpha: None, float
      :param broyden_opts: Arguments to pass through to `mmfutils.solve.broyden.DyadicSum()`.
      :type broyden_opts: dict()
      :param use_scipy: If `True`, then use the scipy solvers, otherwise, if `x_tol < sqrt(eps)`,
                        then use our custom solver that performs Broyden iterations after.  The issue
                        here is that the minimizer might bail out prematurely because of the `f_tol`
                        criterion before reaching the desired `x_tol` because the minimum is
                        quadratic.  Since we have information about the hessian, we can in principle
                        continue to refine the solution with Broyden iterations to minimize the norm
                        of the residual.

                        This is the idea of the polish option, but one can "trick" scipy into doing
                        this by setting `f_tol=np.nan`.  This will always invalidate the criterion
                        (even `f_tol=0` can fail sometimes when the energy is very flat) and force
                        scipy to continue until `x_tol` is met or the method fails.  Always check
                        your answer if you do this!
      :type use_scipy: bool
      :param _debug: If `True` then return `(x, f, df, locals())`.
      :type _debug: bool

      :returns: * **x** (*array*) -- Solution
                * **f, df** (*functions*) -- Objective function and its gradient in the packed representation.
                * *Developer notes*
                * 1. Do not mutate `state0`.  Use `state` as a working copy if a -- true state is needed.
                * 2. Be careful which version of `state` or `state0` you use as the -- argument to `get_Hy` and `get_energy` since this determines the
                  non-linear portions.  In general one should use `state`, but
                  if one implements a minimization on the norm of `Hy` then for
                  the derivative one must be careful.



