No BSD License  

Highlights from
LYAPACK

from LYAPACK by Volker Mehrmann
LYAPACK toolbox provides solutions for certain large scale problems related to Lyapunov equations.

...
function [oa1, flag_r, oa3, oa4, oa5, oa6, oa7, oa8] = ...
         lp_lrnm( zk, ia2, ia3, ia4, ia5, ia6, ia7, ia8, ia9, ia10, ...
         ia11, ia12, ia13, ia14, ia15, ia16, ia17, ia18, ia19, ia20, ...
         ia21, ia22 )
%
%  Low rank Cholesky factor Newton method (explicit version LRCF-NM and  
%  implicit version LRCF-NM-I) for the solution of the continuous-time
%  algebraic Riccati equation (CARE)
%
%    0 = C'*Q*C + A'*X + X*A - X*B*inv(R)*B'*X =: R(X)
%
%  or the corresponding linear-quadratic optimal control problem (LQOCP)
%
%          oo
%    1/2 * int y'*Q*y + u'*R*u dt
%          t=0     
%
%  subject to
%    .
%    x = A*x + B*u,  x(0) = x_0
%
%    y = C*x .
%
%  Here, Q = Q0*Q0' and R = R0*R0'.
%
%  The output is either the matrix Z, for which the low rank Cholesky 
%  factor product Z*Z' provides an approximation to the stabilizing
%  solution X of the CARE, or the matrix K_out that approximates the
%  feedback K, for which u = -K'*x describes the solution of the LQOCP.
%
%  Whether the CARE or the LQOCP is solved depends on the choice of the 
%  input parameter zk: For zk = 'Z', Z is computed by LRCF-NM; for 
%  zk = 'K', K_out is computed by LRCF-NM-I.
%
%  Calling sequences:
%
%     zk = 'Z':
%       [Z, flag_r, res_r, flp_r, flag_l, its_l, res_l, flp_l] = ...
%       lp_lrnm( zk, rc, name, B, C, Q0, R0, K_in, max_it_r, ... 
%       min_res_r, with_rs_r, min_ck_r, with_ks_r, info_r, kp, km, ... 
%       l0, max_it_l, min_res_l, with_rs_l, min_in_l, info_l ) 
%
%     zk = 'K'
%       [K_out, flag_r, flp_r, flag_l, its_l, flp_l] = ...
%       lp_lrnm( zk, name, B, C, Q0, R0, K_in, max_it_r, min_ck_r, ...
%       with_ks_r, info_r, kp, km, l0, max_it_l, min_in_l, info_l ) 
%
%  Input:
%
%    zk        (= 'Z' or 'K') determines whether Z or K_out should be
%              computed;
%    rc        (= 'R' or 'C') determines whether the low rank factor Z
%              must be real ('R') or if complex factors are allowed ('C');
%              Sometimes rc = 'R' results in some additional computation. 
%              If zk = 'K', rc is ignored;
%    name      basis name of the m-file which generates matrix 
%              operations with A, e.g., 'as';
%    B         matrix B (n-x-m matrix, where  m << n !);
%    C         matrix C (q-x-n matrix, where  q << n !);
%    Q0        Cholesky factor of Q. Q0 should have full rank and q rows;
%    R0        Cholesky factor of R. R0 must be a nonsingular m-x-m
%              matrix;
%    K_in      stabilizing initial feedback (n-x-m matrix); if K_in = 0,
%              set K_in = [];
%    max_it_r  stopping criterion for (outer) Newton iteration: maximal 
%              number of iteration steps. Set to +Inf to avoid this 
%              criterion;
%    min_res_r stopping criterion for (outer) Newton iteration: The 
%              iteration is stopped when 
%
%                 ||R(Z*Z')||_F < min_res_r * ||C'*Q0*Q0'*C||_F.
%
%              Set min_res_r = 0 to avoid this criterion. Note: If 
%              min_res_r<=0 and with_rs_r='N', the (often expensive) 
%              calculation of the norm of the residual R(Z*Z') is avoided, 
%              but, of course, res_r is not provided on exit.
%    with_rs_r (= 'S' or 'N') stopping criterion for (outer) Newton iteration:
%              if with_rs_r = 'S', the iteration is stopped, when the 
%              routine detects a stagnation of the CARE residual norms, 
%              which is most likely the case, when roundoff errors rather 
%              than the approximation error start to dominante the residual 
%              norm. This implies that the residual norms are computed (which
%              can be expensive). This criterion works quite well in practice,
%              but is not absolutely sure. Use with_rs_r = 'S' if you
%              want to compute the CARE solution as accurate as possible
%              (for a given machine precision). If with_rs_r = 'N', this 
%              criterion is not used;
%    min_ck_r  stopping criterion for (outer) Newton iteration: The Newton
%              iteration is stopped at iteration step i, when
%         
%                ||K_i - K_(i-1)||_F < min_ck_r * ||K_i||_F,
%
%              i.e., when "relative changes in the feedback matrix"
%              K_i become sufficiently small. This, is an inexpensive, 
%              heuristical, and not absolutely safe stopping criterion. If 
%              min_ck_r <= 0, this criterion is not used;
%    with_ks_r (= 'L' or 'N') stopping criterion for (outer) Newton iteration:
%              if with_ks_r = 'L', the iteration is stopped, when the 
%              routine detects a stagnation of the relative changes in the 
%              feedback matrix K, i.e., when the quantities
%
%                ||K_i - K_(i-1)||_F / ||K_i||_F,
%
%              stagnate (most likely because of roundoff errors). This,
%              is an inexpensive, heuristical, and not absolutely safe
%              stopping criterion.  If with_ks_r = 'N', this criterion is 
%              not used;
%    info_r    (= 0, 1, 2, or 3) the desired "amount" of information on the 
%              outer Newton iteration. Default value is 3 ( = "maximal 
%              information");
%    kp,
%    km,
%    l0        these parameter control the algorithm which computes ADI
%              shift parameters. See also 'lp_para' and 'lp_lradi';
%
%    max_it_l, 
%    min_res_l, 
%    with_rs_l, 
%    min_in_l, 
%    info_l    These parameters steer the inner LRCF-ADI iterations. For their
%              descriptions, see 'lp_lradi' (max_it_l corresponds to max_it
%              there, etc).
%
%  Output:
%
%    Z         Z*Z' is a low rank approximation of X;
%              (Note that Z can be complex if rc = 'C'!)
%    K_out     an approximation to the stabilizing feedback K, that describes
%              the solution of the LQOCP;
%    flag_r    the criterion which had stopped the (outer) Newton iteration:
%               = 'I': max_it_r,
%               = 'R': min_res_r,
%               = 'S': with_rs_r,
%               = 'K': min_ck_r,
%               = 'L': with_ks_r;
%    res_r     the normalized CARE residual norms attained in the course of
%              the iterations (res_r(i+1) is the norm after the i-th 
%              iteration step;
%    flp_r     flop count. flp_r(i+1) containes the number of flops needed
%              to perform the first i steps of the (outer) Newton iteration. 
%              It does not include the cost for computing the residual norm 
%              (which is sometimes more expensive than the actual iteration)!
%    flag_l    a vector with length equal to number of Newton steps. It
%              contains the flags, that show which criteria have stopped
%              the (inner) LRCF-ADI iterations. See also 'lp_lradi'; 
%    its_l     a vector with length equal to number of Newton steps. It
%              contains the number of iteration steps taken in the (inner)
%              LRCF-ADI iterations;
%    res_l     a matrix with column number equal to number of Newton steps. 
%              Its i-th column contains the residual history for the
%              LRCF-ADI iteration in the i-th Newton step. See output
%              argument res in 'lp_lradi'. Entries exactly equal to zero
%              must be considered as "void". If the stopping criteria w.r.t.
%              the LRCF-ADI iteration are chosen such that no Lyapunov
%              residuals are computed, [] is returned;
%    flp_l     a matrix with column number equal to number of Newton steps. 
%              Its i-th column contains the flops history for the
%              LRCF-ADI iteration in the i-th Newton step. See output
%              argument flp in 'lp_lradi'. Entries exactly equal to zero
%              must be considered as "void";
%
%  User-supplied functions called by this function:
%
%    '[name]_m', '[name]_l', '[name]_s_i', '[name]_s', '[name]_s_d'    
%
%  Remark:
%
%    Note on the choice of zk: In the case when only Z*Z'*K_in and not Z*Z' is
%    sought, zk = 'K' can save much memory in some situations. But the amount
%    of computation is mostly not less than in the first mode, which should be 
%    considered as the standard mode. zk = 'Z' mode has several advantages:
%    there are more stopping criteria available, the computation of the 
%    residual norm is possible. In contrast, there is no secure way to
%    verify that the computed matrix K_out indeed approximates the exact 
%    matrix K in the second mode. In general, one should also use the first 
%    mode when the LQOCP is to be solved.
%
%  Reference:
%
%  [1] P. Benner, J. Li, and T. Penzl
%      Numerical solution of large Lyapunov equations, Riccati equations,
%      and linear-quadratic optimal control problems.
%      Submitted for publication.
%
%  [2] T. Penzl.
%      LYAPACK (Users' Guide - Version 1.0).
%      1999.
%
%
%   LYAPACK 1.0 (Thilo Penzl, October 1999)

% Input data not completely checked!

na = nargin;

% Constant that is used to detect "stagnation" in the residual norm
% of the Riccati equation as well as in the matrix K.
min_rs_r = 0.1;

if na==0, error('Wrong number of input arguments.'); end

if zk~='Z' & zk~='K', error('zk must be either ''Z'' or ''K''.'); end
compute_K = zk=='K';

if compute_K, 
  if na~=17, error('Wrong number of input arguments.'); end
  name = ia2; 
  B = ia3;
  C = ia4; 
  Q0 = ia5; 
  R0 = ia6; 
  Kf = ia7; 
  max_it_r = ia8;
  min_ck_r = ia9; 
  with_ks_r = ia10;
  info_r = ia11;
  kp = ia12;
  km = ia13; 
  l0 = ia14; 
  max_it_l = ia15;
  min_in_l = ia16; 
  info_l = ia17;
  with_norm = 0;
  K_in_is_real = ~any(any(imag(Kf)));
else
  if na~=22, error('Wrong number of input arguments.'); end
  rc = ia2; 
  if rc~='R' & rc~='C', error('rc must be either ''R'' or ''C''.'); end
  name = ia3; 
  B = ia4; 
  C = ia5; 
  Q0 = ia6; 
  R0 = ia7; 
  Kf = ia8;
  max_it_r = ia9; 
  min_res_r = ia10; 
  with_rs_r = ia11;
  if with_rs_r~='N' & with_rs_r~='S', error('with_rs_r must be either ''S'' or ''N''.'); end
  min_ck_r = ia12;
  with_ks_r = ia13;
  info_r = ia14;
  kp = ia15;
  km = ia16;
  l0 = ia17;
  max_it_l = ia18;
  min_res_l = ia19;
  with_rs_l = ia20;
  min_in_l = ia21;
  info_l = ia22;
  with_norm = min_res_r>0 | with_rs_r;
  make_real = rc=='R';
end
if with_ks_r~='N' & with_ks_r~='L', error('with_ks_r must be either ''L'' or ''N''.'); end

with_k_crit = min_ck_r>0 | with_ks_r=='L';   
                         % (true if stopping criteria based on K are used)

C0 = Q0'*C;
R = R0*R0';
BRi = B/R;                   

eval(lp_e( 'n = ',name,'_m;' ));                    % Get system order.
m = size(B,2);

flag_r = 'I';
flp_r = 0;
fl = 0;
flag_l = [];
its_l = [];
flp_l = [];

if with_norm
  res_r_0 = lp_rcnrm( name, B, C0, R, [] );  
  res_r = 1;
end
res_l = [];

b0 = randn(n,1);         % Arnoldi start vector for lp_para.

for i = 1:max_it_r

  fl0 = flops;
  if length(Kf)
    TM =  [C0; R0'*Kf']; 
    Bf = B;
  else
    TM =  C0;
    Bf = [];
  end    

  p = lp_para(name,Bf,Kf,l0,kp,km,b0);

  eval(lp_e( name,'_s_i(p);' ));

  fl = fl+flops-fl0;

  if with_k_crit,
    if length(Kf)
      Kf_old = Kf;
    else 
      Kf_old = zeros(n,m); 
    end
  end

  if info_l >= 3 & ~compute_K
    if  (with_rs_l=='S' | min_res_l>0), figure(2); end
  end
  m = size(TM,1);
  if compute_K                           
    [Kf,flag0,flp0] = lp_lradi('C','K','C',name,Bf,Kf,TM,p,BRi,max_it_l,...
      min_in_l, info_l);  
  else
    [Z,flag0,res0,flp0] = lp_lradi('C','Z','C',name,Bf,Kf,TM,p,max_it_l,... 
      min_res_l,with_rs_l,min_in_l,info_l);  
  end
  its_l = [its_l; length(flp0)-1];

  if info_l>=2,
    disp(' ');
    disp('Results for LRCF-ADI iteration in current Newton step:')
    disp(['Termination flag:  ',flag0]);
    disp(sprintf('Number of LRCF-ADI iterations: %d',size(flp0,1)-1))
  end
  fl = fl+flp0(length(flp0));

  flag_l = [ flag_l; flag0 ];
  flp_l(1:length(flp0),size(flp_l,2)+1) = flp0;
  flp_r = [ flp_r; fl ];

  if info_r >= 2
    disp(' ');
    disp('------------------------------------------------------------')
    disp(sprintf('Newton (LRCF-NM or LRCF-NM-I) step: %d',i));
  end  

  if with_norm

    res_l(1:length(res0),size(res_l,2)+1) = res0;

    resnrm = lp_rcnrm( name, B, C0, R, Z );
    akt_res = resnrm/res_r_0;
    res_r = [ res_r; akt_res ];

    if info_r >= 2
      disp(sprintf('norm. Riccati residual =    %e',akt_res));
      disp(' ');
    end  

    if info_r >= 3
      figure(1)
      semilogy((0:length(res_r)-1)',res_r,'r-');
      ylabel('Normalized residual norm');                   
      xlabel('Iteration steps');
      title('LRCF-Newton iteration');
      pause(0.01);
    end
%                                % Stopping criteria w.r.t. residual norm 
    if akt_res <= min_res_r
      flag_r = 'R';
      break;
    end  

    if i>2 & with_rs_r=='S'
      if log(res_r(i))-log(res_r(i+1)) < min_rs_r*(log(res_r(2))-...
        log(res_r(i+1)))/(i-1) & 0 < res_r(2)-res_r(i+1),
        flag_r = 'S';
        break;
      end
    end 

  end

  % Feedback for the next Newton step

  if ~compute_K 
    if i==max_it_r, break; end       % (need not compute Kf any more) 
    fl0 = flops;
    Kf = Z*(Z'*BRi);              
    fl = fl+flops-fl0;
  end 

  if with_k_crit                   % Stopping criterion w.r.t. Kf
    t1 = norm(Kf-Kf_old,'fro');
    t2 = norm(Kf,'fro');
    if i>=2, rc_K_old = rc_K; end
    rc_K = t1/t2;
    if info_r>=2 & i>=2
      disp(sprintf('rel. change in feedback matrix = %e',rc_K));
    end  
    if t1<min_ck_r*t2              % Smallness of changes in K
      flag_r = 'K';
      break;
    end    
    if i>=2 & with_ks_r=='L'       % Stagnation of changes in K or
                                   % rel. changes in K VERY small
      if (rc_K<1 & abs(log(rc_K)-log(rc_K_old))<-min_rs_r*log(rc_K)/i)...
        | rc_K<eps
        flag_r = 'L';
        break;
      end
    end 
  end
 
end


if compute_K
  if norm(imag(Kf),'fro') > 1e-10*norm(real(Kf),'fro') 
    disp('WARNING in ''lp_lrnm'': K_out is not real!');
  else
    Kf = real(Kf);
  end
  oa1 = Kf;
  oa3 = flp_r;
  oa4 = flag_l;
  oa5 = its_l;
  oa6 = flp_l;
  oa7 = [];
  oa8 = [];
else
  if make_real                   % Make the Cholesky factor of the
                                 % last Newton iterate real by the
                                 % technique, which is used in lp_lradi. 

    i_max = round(size(Z,2)/m);  % Number of LRCF-ADI steps
                                 % in last Newton step   
    i_p = 1;                     % Pointer to i-th entry in p(:)
    is_compl = imag(p(1))~=0;    % is_compl = (current parameter is complex.)
    is_first = 1;                % is_first = (current parameter is the first
                                 % of a pair, PROVIDED THAT is_compl.)
    l = length(p);
    fl = flops;
    for i = 2:i_max
      p_old = p(i_p);
      i_p = i_p+1; if i_p>l, i_p = 1; end   % update current parameter index
      if is_compl & is_first
        is_first = 0;
      else
        is_compl = imag(p(i_p))~=0;  
        is_first = 1;
      end                                 
      if is_compl & ~is_first    % Make group of 2*m columns real.  
        for j = (i-1)*m+1:i*m  
          [U1,S1,V1] = svd([real(Z(:,j-m)),real(Z(:,j)),imag(Z(:,j-m)),...
                    imag(Z(:,j))],0);
          [U2,S2,V2] = svd(V1(1:2,1:2)'*V1(1:2,1:2)...
                       +V1(3:4,1:2)'*V1(3:4,1:2));
          TMP = U1(:,1:2)*S1(1:2,1:2)*U2*diag(sqrt(diag(S2)));
          Z(:,j-m) = TMP(:,1);
          Z(:,j) = TMP(:,2);
        end
      end
    end
    flp_r(end) = flp_r(end)+flops-fl; 
  end
  oa1 = Z;
  if with_norm
    oa3 = res_r;
  else
    oa3 = [];
  end
  oa4 = flp_r;
  oa5 = flag_l;
  oa6 = its_l;
  oa7 = res_l;
  oa8 = flp_l;
end

Contact us at files@mathworks.com