www.gusucode.com > qit_matlab_0.10.0工具箱源码程序 > qit/@state/state.m

    classdef state < lmap
% STATE  Class for quantum states.
%
%  Describes a discrete composite quantum system consisting of subsystems
%  whose dimensions are given in the vector dim (big-endian ordering).
%  Can handle both pure and mixed states.

%  State class instances are special cases of lmaps. They have exactly two indices.
%  TODO If the dimension of the first  index is 1, it is a bra.
%  If the dimension of the second index is 1, it is a ket.
%  If neither of the above is true, both indices must have equal dimensions and the
%  object represents a state operator.

% Ville Bergholm 2008-2012

  methods
    function out = state(s, dim)
    % constructor
    %  x = state(s [, dim]);
    %  x = state(y);                % copy constructor
    %  x = state(y, [2 2]);         % copy constructor, reinterpret system as two qubits
    %  x = state('00101');          % standard basis ket |00101> in a five-qubit system
    %  x = state('02', [2 3]);      % standard basis ket |02> in a qubit+qutrit system
    %  x = state(k, [2 3]);         % standard basis ket |k> in a qubit+qutrit system, k must be an integer scalar
    %  x = state(rand(4,1));        % ket, dim = 4
    %  x = state(rand(4,1), [2 2]); % ket, two qubits
    %  x = state(rand(4));          % state operator, dim = 4
    %  x = state(rand_positive(6), [3 2]); % state operator, qutrit+qubit
    %  x = state('GHZ', [2 2 2]);   % named states (in this case the three-qubit GHZ state)
    %
    %  The currently supported named states are
    %   GHZ (Greenberger-Horne-Zeilinger),
    %   W,
    %   Bell1, Bell2, Bell3, Bell4 

    if (nargin == 0)
      error('No arguments given.');

    elseif (nargin > 2)
      error('Too many arguments.');

    elseif (isa(s, 'state'))
      % copy constructor
      if (nargin == 1)
        dim = s.dim;  % copy also dimensions
      end
      s = s.data;

    elseif (isa(s, 'lmap'))
      % state from lmap (TODO kind of a hack really, we should not need this)
      if (nargin == 1)
        dim = s.dim;  % copy also dimensions
        dim = dim{1}; % dim{2} should be the same for this operation to make sense
      end
      s = s.data;

    elseif (ischar(s))
      % string
      if (isletter(s(1)))
        % named state
        if (nargin == 1)
          dim = [2 2 2];
        end

        name = lower(s);
        n = length(dim);
        s = zeros(prod(dim), 1);
        switch name
          case {'bell1', 'bell2', 'bell3', 'bell4'}
            Q_Bell = [0 0 1 1i; 1 1i 0 0; -1 1i 0 0; 0 0 1 -1i] / sqrt(2);
            dim = [2 2];
            s = Q_Bell(:, name(5)-'0');
            
          case 'ghz'
            s(1) = 1; s(end) = 1;

          case 'w'
            ind = 1;
            for k=n:-1:1
              s(ind*(dim(k) - 1) + 1) = 1; % MATLAB indexing starts at 1
              ind = ind*dim(k);
            end

          otherwise
            error('Unknown named state ''%s''.', name)
        end
        s = s/norm(s); % normalize
      
      else
        % number string defining a standard basis ket
        if (nargin == 1)
          n = length(s); % number of units
          dim = 2*ones(1, n); % assume units are qubits
        end

        % calculate the linear index
        n = length(dim);
        s = s - '0';
        if (any(s >= dim))
          error('Invalid basis ket.')
        end
        muls = fliplr(circshift(cumprod(fliplr(dim)), [0 1]));
        muls(end) = 1;
        ind = muls*s.';
        s = zeros(prod(dim), 1);
        s(ind+1) = 1; % MATLAB indexing starts at 1
      end

    elseif (isnumeric(s))
      if (isscalar(s))
        % integer represented using the computational standard basis
        if (nargin == 1)
          error('Need system dimension.')
        end

        ind = s;
        temp = prod(dim); % total number of states
        if (ind >= temp)
          error('Invalid basis ket.')
        end
        s = zeros(temp, 1);
        s(ind+1) = 1; % MATLAB indexing starts at 1

      else
        % state vector or matrix
        sss = size(s);
        if (length(sss) > 2)
          error('State must be given as a state vector or a state operator.')
        end
        if (sss(1) == 1)
          s = s.'; % row vector into column vector
        elseif (sss(2) > 1 && sss(1) ~= sss(2))
          error('State operator matrix must be square.')
        end
      end

      if (nargin == 1)
        dim = size(s, 1); % no dim given, infer from s
      end
    end

    % state vector or operator?
    if (size(s, 2) ~= 1)
      dim = {dim, dim};
    else
      dim = {dim, 1};
    end

    % call the lmap constructor
    out = out@lmap(s, dim);
    end

    function x = subsref(s, index)
    % SUBSREF  Direct access to the data members.

        switch index(1).type
        case '.'
          switch index(1).subs
            case 'data'
              x = s.data;
            case 'dim'
              % NOTE this is the only reason we overload subsref in the first place.
              x = s.dim{1}; % since for a state the indices must be identical or singletons
            otherwise
              % MATLAB is the worst language
              x = builtin('subsref', s, index);
              return
          end
          % let MATLAB take it from here
          if length(index) > 1
              x = subsref(x, index(2:end));
          end

        otherwise
          error('State class cannot be indexed with that operator.')
      end
    end

    function n = subsystems(s)
    % SUBSYSTEMS  Returns the number of subsystems in the state.
      n = length(s.dim{1});
    end
    
    function d = dims(s)
    % DIMS  Returns the dimension vector of the state.
      d = s.dim{1}; % dims of the other index must be equal (or 1)
    end

    function ret = is_compatible(s, t)
    % IS_COMPATIBLE  True iff s and t have the same dimensions.
      ret = isequal(dims(s), dims(t));
      if ~ret
          error('The states have different dimensions.')
      end
    end

    function ret = trace(s)
    % TRACE  Returns the trace of the state operator.
    %
    %  For a normalized state this equals 1.
      if is_ket(s)
        ret = norm(s.data)^2;
      else
        ret = trace(s.data);
      end
    end
    
    function s = normalize(s)
    % NORMALIZE  Normalize the state.
    %  q = normalize(s)
    %
    %  Returns the state s normalized.
      if is_ket(s)
        s.data = s.data / norm(s.data);
      else
        s.data = s.data / trace(s.data);
      end
    end
    
    function sys = clean_selection(s, sys)
    % CLEAN_SELECTION  Internal helper, makes a subsystem set unique and sorted.
      sys = intersect(1:length(s.dim{1}), sys);
    end

    function check(s)
    % CHECK  Checks the validity of the state.

      global qit;

      ok = true;
      if abs(trace(s) - 1) > qit.tol
          disp('State not properly normalized.')
          ok = false;
      end
      if ~is_ket(s)
        if norm(s.data - s.data') > qit.tol
            disp('State operator not Hermitian.')
            ok = false;
        end
        if min(real(eig(s.data))) < -qit.tol
            disp('State operator not semipositive.')
            ok = false;
        end
      end
      if ~ok
          error('Not a valid state.')
      end
    end
  end
end