% maxsep   Maximum for multi-qudit separable states. 
%   maxsep(op) gives the maximum of op for separable multi-qubit 
%   states. maxsep(op,d) makes it possible to handle qudits
%   with dimension d. Uses simple numerical search.
%   maxsep(op,d,par) makes it possible to set parameters.
%   par is a three-element vector. Defaults value
%   [10000 20000 0.005 ]. First element: Number of
%   random trials in the first phase. Second element:
%   Number of random trials in the second phase.
%   Third element: Constant determining accuracy.
%   Slower than maxsymsep.

function m=maxsep(op,varargin)

% Parameters for the simulation
Delta=0.005;
Nit1=10000;
Nit2=20000;

if isempty(varargin),
   d=2;
elseif length(varargin)==1,
   d=varargin{1};  
elseif length(varargin)==2,
   d=varargin{1};  
   par=varargin{2};
   Nit1=par(1);
   Nit2=par(2);
   Delta=par(3);
else
        error('Wrong number of input arguments.');
end %if

[sx,sy]=size(op);
N=floor(log(sx)/log(d)+0.5);

rmax=-Inf;

fa=zeros(d,N);
famax=fa;
for n=1:Nit1
     %%if mod(n,100)==0,  randn('state',sum(100*clock));  end %if
     f=randn(d,1)+i*randn(d,1);
     fa(:,1)=f;
     for n=1:N-1
        f2=randn(d,1)+i*randn(d,1);
  	 fa(:,n+1)=f2;
        f=kron(f,f2);
     end %for
     r=real(trace(op*f*f')/(f'*f));
     if r>rmax,
         rmax=r;
	 famax=fa;
     end %if
end %for


fa0=famax;
r0=rmax;

% Second phase of the search
for n=1:Nit2
     %%if mod(n,100)==0,  randn('state',sum(100*clock));  end %if
     f=randn(d,1)+i*randn(d,1);
     f=fa0(:,1)+Delta*f;
     fa(:,1)=f;
     for n=1:N-1
        f2=randn(d,1)+i*randn(d,1);
	f2=fa0(:,n+1)+Delta*f2;
	fa(:,n+1)=f2;
        f=kron(f,f2);
     end %for
     r=real(trace(op*f*f')/(f'*f));
     if r>r0,
         r0=r;
         fa0=fa;        
     end %if
end %for
 
m=r0;