classdef (Hidden) lftdataM < ltipack.AbstractLFT
% Static LFT models.

%   Author(s): P. Gahinet
%   Copyright 1986-2011 The MathWorks, Inc.

   methods
      
      function D = lftdataM(IC,BlockList)
         % Constructs @lftdataM instance
         if nargin==2
            D.IC = IC;
            D.Blocks = BlockList;
         end
      end
      
      function boo = isstatic(D) %#ok<*MANU>
         boo = true;
      end
                     
      function D = uminus(D)
         % Sign change
         [ny,~] = iosize(D);
         D.IC(1:ny,:) = -D.IC(1:ny,:);
      end
      
      function [D,SingularFlag] = inv(D,~)
         % Computes inverse of static LFT model.
         % The inverse model is well-posed iff there are no singularities
         % when replacing each block by its default value. If we shift each 
         % block by this default value, this is the same as saying there 
         % are no singularities when replacing each block by zero, which is 
         % equivalent to M11 being invertible for the shifted LFT.
         % Shift each block by its default value
         D = centerBlocks(D);
         % Form inverse
         IC = D.IC;
         [ny,~,nz,nw] = getSignalSize(D);  % ny=nu
         ICinv = blkdiag(zeros(ny),IC(ny+1:ny+nz,ny+1:ny+nw)) + ...
            [eye(ny) ; IC(ny+1:ny+nz,1:ny)] * ...
            matlab.internal.math.nowarn.mldivide(IC(1:ny,1:ny),[eye(ny),-IC(1:ny,ny+1:ny+nw)]);
         SingularFlag = ~allfinite(ICinv);
         if SingularFlag
            D = createGain(D,NaN(ny));
         else
            D.IC = ICinv;
         end
      end
      
      function [D,SingularFlag] = imp2exp(D,yidx,uidx,~)
         % Implicit to explicit conversion:
         %    A(:,[YIDX UIDX]) * [Y;U] = 0  -> Y = B*U.
         % The index vectors YIDX,UIDX must form a partition of the columns of A.
         D = centerBlocks(D);
         [nOut,nIn,nz,nw] = getSignalSize(D);
         % Solve for y
         nY = numel(yidx);
         iUW = [uidx , nIn+1:nIn+nw];
         IC = D.IC;
         aux = -matlab.internal.math.nowarn.mldivide(IC(1:nY,yidx),IC(1:nY,iUW));
         D.IC = [aux ; IC(nY+1:nOut+nz,iUW) + IC(nY+1:nOut+nz,yidx) * aux];
         SingularFlag = ~allfinite(aux);
      end
      
      function D = iorep(D,s)
         % Replicates static model.
         %   D = IOREP(D,[M N]) replicates and tiles D to produce the M-by-N model D.
         [ny,nu,nz,nw] = getSignalSize(D);
         iy = [repmat(1:ny,[1 s(1)]) ny+1:ny+nz];
         iu = [repmat(1:nu,[1 s(2)]) nu+1:nu+nw];
         D.IC = D.IC(iy,iu);
      end
      
      function A = double(D)
         % Conversion to @double.
         if isempty(D.Blocks)
            A = D.IC;
         else
            A = lft(D.IC,double_(D.Blocks));
         end
      end
      
   end
   
   % UTILITIES
   methods
      
      function D = createGain(~,G)
         % Wraps static gain into ltipack.lftdataM
         D = ltipack.lftdataM(G,ltipack.LFTBlockWrapper.emptyBlockList());
      end
      
      function D = blk2lft(~,B)
         % Wraps LFTBlockWrapper vector into ltipack.lftdataM
         [nw,nz] = iosize(B);
         D = ltipack.lftdataM([zeros(nw,nz) eye(nw);eye(nz) zeros(nz,nw)],B);
      end
      
      function D = utGrowIO(D,ny,nu)
         % Grows I/O size of LFT model.
         [ny0,nu0,nz,nw] = getSignalSize(D);
         if ny>ny0 || nu>nu0
            ICMat = D.IC;
            ICMat(ny+nz,nu+nw) = 0;
            D.IC = ICMat([1:ny0 ny0+nz+1:ny+nz ny0+1:ny0+nz],...
               [1:nu0 nu0+nw+1:nu+nw nu0+1:nu0+nw]);
         end
      end
      
      function D = applyOffset(D,S)
         % Compute D-S where S is a ny-by-nu matrix
         [ny,nu] = size(S);
         D.IC(1:ny,1:nu) = D.IC(1:ny,1:nu)-S;
      end
         
      function D = applyTransform(D,R)
         % Compute LFT(R,D)
         [ny,nu] = iosize(D);
         D.IC = lft(R,D.IC,nu+1:nu+ny,ny+1:ny+nu,1:nu,1:ny);
      end
      
   end
   
   methods(Static)
      
      function D = array(size)
         % Create a lftdataM array of a given size
         D = ltipack.lftdataM.newarray(size);
      end
      
      function D = loadobj(D)
         % Load filter for @lftdataM
      end
      
      function MS = shiftLFT(M,S)
         % Computes MS so that LFT(M,Delta) = LFT(MS,Delta-S).
         [nw,nz] = size(S);
         [nyz,nuw] = size(M);
         % Replicate w,z channels and fold S in
         MS = lft(M([1:nyz nyz-nz+1:nyz],[1:nuw nuw-nw+1:nuw]),S);
      end
      
   end
         
end

