function [type] = identifymatrix( varargin ) 
% [type] = identifymatrix( M ) 
% Returns standard properties of matrices.
%
% Input: 
%   M       matrix, or cell array of matrices
%   
% Output: 
%   type    a struct array which holds a distinct set of properties of M.
%               type.nM             number of matrices
%               type.tensordim      the maximal dimension of all matrices (as given by ndimsm)
%               type.tensordim      the maximal dimension of all matrices (as given by ndimsm)
%               type.samesize       checks if all matrices have the same size
%               type.square         checks if all matrices are square-matrices
%
%   If the matrices are square matrices, the following tests are also done
%
%               type.size           size of the matrix
%               type.int            checks if all entries are integers (does check the value, not the type!)
%               type.nonneg         checks if all entries are nonnegative
%               type.pos            checks if all entries are positive
%               type.finite         checks if all entries are finite (excluding inf and nan)
%               type.real           checks if all entries are real
%
%               type.symmetric      checks if all matrices are symmetric (M=M.')
%               type.hermitian      checks if all matrices are hermitian (M=M')
%               type.inv            checks if all matrices are invertible
%               type.possemidef     checks if all matrices are positive semi-definite
%               type.posdef         checks if all matrices are positive definite
%
%                   NOT AVAILABE (SLOW): type.commute        checks if all matrices commute with each other 
%
% E.g.: identifymatrix({[1 2 3; 0 2 1; 0 0 1],[2]})
%
%Wwritten by: tommsch, 2018

%If M is not a cell array make it to one
if(nargin>1); error('Only one argument allowed.'); end;
if(~iscell(varargin{1})); 
    M=varargin(1); 
else; 
    M=varargin{1};
end;

    type.tensordim=max(cellfun(@(x) ndimsm(x),M));
    type.nM=length(M);

    
    if( ~nnz(diff(cell2mat(cellfun(@(x) sizem(x,[],type.tensordim)'  ,M,'UniformOutput',0)),1,2)) );  type.samesize=1;      else; type.samesize=0;        end; 
    if( all(cellfun(@(x) issquare(x)           ,M)) );  type.square=1;      else; type.square=0;        end; 
    
    if( all(cellfun(@(x) allm(iswholenumber(x)),M)) );  type.int=1;         else; type.int=0;           end; 
    if( all(cellfun(@(x) allm(x>=0)            ,M)) );  type.nonneg=1;      else; type.nonneg=0;        end; 
    if( all(cellfun(@(x) allm(x>0)             ,M)) );  type.pos=1;         else; type.pos=0;           end; 
    if( all(cellfun(@(x) allm(isfinite(x))     ,M)) );  type.finite=1;      else; type.finite=0;        end; 
    if( all(cellfun(@(x) allm(isreal(x))       ,M)) );  type.real=1;        else; type.real=0;          end; 
 
 if(type.square)     
     type.size = size(M{1},2);
     epsilon=eps*type.size;
     
     if( all(cellfun(@(x) isAlways(norm(x-x.',1)<eps)     ,M)) ); type.symmetric=1;   else; type.symmetric=0;     end; 
     if( all(cellfun(@(x) isAlways(norm(x-x' ,1)<eps)     ,M)) ); type.hermitian=1;   else; type.hermitian=0;     end; 
     if( all(cellfun(@(x) isAlways(norm(x*x'-eye(type.size),1)<epsilon),M)) )             ; type.unitary=1;   else; type.unitary=0;     end; 
     if( all(cellfun(@(x) rcond(double(x))   >eps       ,M)) ); type.inv=1;         else; type.inv=0;           end; 
     if( all(cellfun(@(x) allm(eig(double(x))>=0)       ,M)) ); type.possemidef=1;  else; type.possemidef=0;    end; 
     if( all(cellfun(@(x) allm(eig(double(x))>=eps)     ,M)) ); type.posdef=1;      else; type.posdef=0;        end; 
     
     %comm=@(A,B) A*B-B*A;
     %val=num2cell(mixvector(1:type.nM,2),1);
     %if( all(cellfun(@(x) norm(comm(M{x(1)},M{x(2)}))<epsilon,val)) );            type.commute=1; else; type.commute=0; end;
     
 end
 

end