Program Listing for File project.m

Return to documentation for file (+Indigo/@RungeKutta/project.m)

%> Project the system solution \f$ \mathbf{x} \f$ on the invariants
%> \f$ \mathbf{h} (\mathbf{x}, \mathbf{v}, t) = \mathbf{0} \f$. The
%> constrained minimization problem to be solved is:
%>
%> \f[
%> \textrm{minimize} \quad
%> \dfrac{1}{2}\left(\mathbf{x} - \widetilde{\mathbf{x}}\right)^2 \quad
%> \textrm{subject to} \quad \mathbf{h}(\mathbf{x}, \mathbf{v}, t) =
%> \mathbf{0}.
%> \f]
%>
%> **Solution Algorithm**
%>
%> Given the Lagrangian of the minimization problem of the form:
%>
%> \f[
%> \mathcal{L}(\mathbf{x}, \boldsymbol{\lambda}) =
%> \frac{1}{2}\left(\mathbf{x} - \widetilde{\mathbf{x}}\right)^2 +
%> \boldsymbol{\lambda} \cdot \mathbf{h}(\mathbf{x}, \mathbf{v}, t).
%> \f]
%>
%> The solution of the problem is obtained by solving the following:
%>
%> \f[
%> \left\{\begin{array}{l}
%> \mathbf{x} + \mathbf{Jh}_\mathbf{x}^T \boldsymbol{\lambda} =
%> \widetilde{\mathbf{x}} \\[0.5em]
%> \mathbf{h}(\mathbf{x}, \mathbf{v}, t) = \mathbf{0}
%> \end{array}\right.
%> \f]
%>
%> Using the Taylor expansion of the Lagrangian:
%>
%> \f[
%> \mathbf{h}(\mathbf{x}, \mathbf{v}, t) + \mathbf{Jh}_\mathbf{x} \delta\mathbf{x} +
%> \mathcal{O}\left(\left\| \delta\mathbf{x} \right\|^2\right) = \mathbf{0}
%> \f]
%>
%> define the iterative method as:
%>
%> \f[
%> \mathbf{x} = \widetilde{\mathbf{x}} + \delta\mathbf{x}.
%> \f]
%>
%> Notice that \f$ \delta\mathbf{x} \f$ is the solution of the linear system:
%>
%> \f[
%> \begin{bmatrix}
%> \mathbf{I}             & \mathbf{Jh}_\mathbf{x}^T \\[0.5em]
%> \mathbf{Jh}_\mathbf{x} & \mathbf{0}
%> \end{bmatrix}
%> \begin{bmatrix}
%> \delta\mathbf{x} \\[0.5em]
%> \boldsymbol{\lambda}
%> \end{bmatrix}
%> =
%> \begin{bmatrix}
%> \widetilde{\mathbf{x}} - \mathbf{x} \\[0.5em]
%> -\mathbf{h}(\mathbf{x}, \mathbf{v}, t)
%> \end{bmatrix}
%> \f]
%>
%> where \f$ \mathbf{Jh}_\mathbf{x} \f$ is the Jacobian of the invariants/
%> with respect to the states \f$ \mathbf{x} \f$.
%>
%> \param x_t The initial guess for the states \f$ \widetilde{\mathbf{x}} \f$.
%> \param t   The time \f$ t \f$ at which the states are evaluated.
%> \param x_b [optional] Boolean vector to project the corresponding states
%>            to be projected (default: all states are projected).
%>
%> \return The solution of the projection problem \f$ \mathbf{x} \f$.
%
function x = project( this, x_t, t, varargin )

  CMD = 'Indigo.RungeKutta.project(...): ';

  % Get the number of states, equations and invariants
  num_eqns = this.m_sys.get_num_eqns();
  num_invs = this.m_sys.get_num_invs();

  assert(length(x_t) == num_eqns, ...
    [CMD, 'the number of states does not match the number of equations.']);

  % Check the input
  if (nargin == 3)
    projected_x = true(num_eqns, 1);
  elseif (nargin == 4)
    projected_x = varargin{1}{1};
    assert(length(projected_x) == num_eqns, ...
      [CMD, 'the number of the projectes states does not match the ', ...
      'number of equations.']);
  else
    error([CMD, 'invalid number of input arguments.']);
  end
  num_projected_x = sum(projected_x);

  % Check if there are any constraints
  x = x_t;
  if (num_invs > 0)
    for k = 1:this.m_max_projection_iter

      % Standard projection method
      %     [A]         {x}    =        {b}
      % / I  Jh_x^T \ /   dx   \   / x_t - x_k \
      % |           | |        | = |           |
      % \ Jh_x    0 / \ lambda /   \    -h     /

      % Evaluate the veils, invariants vector and their Jacobian
      v    = this.m_sys.v(x, t);
      y    = this.m_sys.y(x, v, t);
      h    = this.m_sys.h(x, y, v, t);
      Jv_x = this.m_sys.Jv_x(x, v, t);
      Jh_x = this.m_sys.Jh_x(x, y, v, t);
      Jh_y = this.m_sys.Jh_y(x, y, v, t);
      Jh_v = this.m_sys.Jh_v(x, y, v, t);
      Jy_x = this.m_sys.Jy_x(x, y, v, t);
      Jh_x = Jh_x + Jh_y * Jy_x + Jh_v * Jv_x;

      % Select only the projected invariants
      h    = h(this.m_projected_invs);
      Jh_x = Jh_x(this.m_projected_invs, projected_x);

      % Check if the solution is found
      if (norm(h, inf) < this.m_projection_low_tolerance)
        break;
      end

      % Compute the solution of the linear system
      A = [eye(num_projected_x), Jh_x.'; ...
           Jh_x, zeros(sum(this.m_projected_invs))];
      b = [x_t(projected_x) - x(projected_x); -h];
      if (rcond(A) > this.m_projection_rcond_tolerance)
        sol = A\b;
      else
        [sol, ~] = lsqr(A, b, this.m_projection_low_tolerance, 500);
      end

      % Update the solution
      dx = sol(1:num_projected_x);
      x(projected_x) = x(projected_x) + dx;

      % Check if the solution is found
      if (k == this.m_max_projection_iter)
        warning([CMD, 'maximum number of iterations reached.']);
      end
    end
  end
end