function U = sylvesterschur(A,B,C)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% function U = sylvesterschur(A,B,C)
% Given nxn input matrices A, B, and C, this function solves
% the equation
%       AU + UB = C
% for the nxn matrix U.
%
% The algorithm is to compute a Schur decomposition of A' and of B
% as
%    A = W L W',       B = Y R Y'
% where L is lower triangular, R is upper triangular, and W and Y
% are unitary.
%
% Then we transform the problem to
%    L Us + Us R = Chat
% where Chat = W' C Y.  This can be solved by substitution.
% 
% Finally, we compute U = W Us Y'.
%
% This algorithm is due to Bartels and Stewart.
%
% Its disadvantage is that the Schur decomposition is complex if the
% matrix has any complex eigenvalues, so the returned matrix U may
% have small imaginary part even if all of the input matrices are real.
%
% The solution fails to exist if L(i,i) + R(j,j) = 0 for some value
% of i and j.  If such a value is nearly zero, the function returns
% an error message with U=0.
% sylvesterschurr.m  Dianne O'Leary 08/2005
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Step 1: compute a Schur decomposition of A' and of B.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

   [n,m]=size(C);
   [W,R] = schur(A','complex');
   L = R';
   [Y,R] = schur(B,'complex');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The problem is transformed to L Us + Us R = Chat where Chat = W' C Y.  
% Step 2: Solve the transformed problem by substitution, producing an 
% error message if the divisor becomes too small.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

   Us = zeros(n,n);
   Chat = W'*C*Y;
   a = max(abs([diag(R);diag(L)]));
   for i=1:n,
     for j=1:n,
       if (abs(L(i,i)+R(j,j))) > 1000*eps*a
         Us(i,j) = (Chat(i,j)-L(i,1:i-1) *Us(1:i-1,j)...
                             -Us(i,1:j-1)*R(1:j-1,j))/(L(i,i)+R(j,j));
       else
         disp(sprintf('Problem very ill-conditioned or no solution exists.'))
         U = zeros(n,n);
         return
       end
     end
   end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Step 3: compute U = W Us Y'.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

   U = W*Us*Y';

