%  This function takes a problem in SeDuMi MATLAB format and writes it out 
%  in SDPA sparse format.  
%
%  Usage:
%
%  ret=writesdpa(fname,A,b,c,K,pars)
%
%      fname           Name of SDPpack file, in quotes
%      A,b,c,K         Problem in SeDuMi form
%      pars            Optional parameters.
%                      pars.printlevel=0           No printed output  
%                      pars.prinlevel=1 (default)  Some printed output.
%                      pars.check=0 (default)      Do not check problem data
%                                                  for symmetry.
%                      pars.check=1                Check problem data for
%                                                  symmetry.       
%      
%      ret             ret=0 on success, ret=1 on failure.
%
%  Notes:
%
%     Problems with complex data are not allowed.    
%
%     Quadratic cone and rotated cone constraints are not supported.  
%
%     Nonsymmetric A.s and C.s matrices are symmetrized with A=(A+A')/2
%     a warning is given when this happens.
%
%     Free variables are not supported.
%
%     Floating point numbers are written out with 18 decimal digits for
%     accuracy.
%
%  Please contact the author (Brian Borchers, borchers@nmt.edu) with any
%  questions or bug reports.
%
%  Third Version:  8/22/04.  Fixed bug that caused the routine to
%                            crash under MATLAB 7.0.
%
%  Second Version: 7/14/04.  Modified to vastly speed up operations on sparse
%                 matrices.  On some problems, this version is 100 times 
%                 faster! 
%
%  First Version: 7/14/03.  Modified from old writesdp.m which wrote problems
%                 in SDPPack format.
%
function ret=writesdpa(fname,A,b,c,K,pars)
%
% First, check to see whether or not we should be quiet.
%
if (nargin > 5),
  if (isfield(pars,'printlevel')),
    if (pars.printlevel == 0)
      quiet=1;
    else
      quiet=0;
    end;
  else
    quiet=0;
  end;
  if (~isfield(pars,'check')),
    pars.check=0;
  end;
else
  pars.printlevel=1;
  quiet=0;
  pars.check=0;
end;
%
%  First, check for complex numbers in A, b, or c.
%
if (isreal(A) ~= 1),
  if (quiet == 0),
    fprintf('A is not real!\n');
  end;
  ret=1;
  return;
end;
if (isreal(b) ~= 1),
  if (quiet == 0),
    fprintf('b is not real!\n');
  end;
  ret=1;
  return;
end;
if (isreal(c) ~= 1),
  if (quiet == 0),
    fprintf('c is not real!\n');
  end;
  ret=1;
  return;
end;
%
%  Check for any quadratic cone constraints.
%
if (isfield(K,'q')),
  if ((~isempty(K.q)) & (K.q ~= 0)),
    if (quiet == 0),
      fprintf('quadratic cone constraints are not supported.\n');
    end;
    ret=1;
    return;
  end;
end; 
%
%  Check for any rotated cone constraints.
%
if (isfield(K,'r')),
  if ((~isempty(K.r)) & (K.r ~= 0)),
    if (quiet == 0),
      fprintf('rotated cone constraints are not supported.\n');
    end;
    ret=1;
    return;
  end;
end; 
%
% Check for any free variables.
%
if (isfield(K,'f')),
  if ((~isempty(K.f)) & (K.f ~= 0)),
    if (quiet == 0),
      fprintf('Free variables are not supported.\n');
    end;
    ret=1;
    return;
  end;
end; 
%
%  Find the number of constraints.
%
m=length(b);
%
%  Deal with the following special case.  If A is transposed, transpose
%  it again so that it is of the right size.
%
[Am,An]=size(A);
if (Am ~= m),
  if (An == m),
    if (quiet==0),  
      fprintf('Transposing A to match b \n');
    end;
    AT=A;
    A=A';
%
% Also swap Am and An so that they're correct.
%
    temp=Am;
    Am=An;
    An=temp;
  else
%
% In this case, A is just plain the wrong size.
%
    if (quiet==0),
      fprintf('A is not of the correct size to match b \n');
    end;
    ret=1;
    return;
  end;
else
%
% No need to transpose A, but we'll need AT.
%
  AT=A';
end;
%
%  Deal with the following special case:  if c==0, then c should really
%  be a zero vector of the appropriate size.
%
if (c == 0),
  if (quiet==0),
    fprintf('Expanding c to the appropriate size\n');
  end;
  c=sparse(An,1);
end;
%
% If c is empty, then act as if it was zero.
%
if (isempty(c)),
  if (quiet==0),
    fprintf('Expanding empty c to zeros of the appropriate size\n');
  end;
  c=sparse(An,1);
end;
%
% If c is a row vector, make it a column vector.
%
[cm,cn]=size(c);
if (cn > cm),
  c=c';
end;
%
%  Get the size data.
%
%
% First, the size of the LP block.
%
if (isfield(K,'l')),
  nlin=K.l;
  sizelin=nlin;
  if (isempty(sizelin)),
    sizelin=0;
    nlin=0;
  end;
  if (K.l == 0),
    nlin=0;
    sizelin=0;
  end;
else
  nlin=0;
  sizelin=0;
end;
%
% Get the sizes of the SDP blocks.
%
if (isfield(K,'s')),
  nsdpblocks=length(K.s);
  sizesdp=sum((K.s).^2);
  if (isempty(sizesdp)),
    sizesdp=0;
    nsdpblocks=0;
  end;
  if (K.s == 0),
    nsdpblocks=0;
    sizesdp=0;
  end;
else
  sizesdp=0;
  nsdpblocks=0;
end;
%
% Figure out the number of blocks.
%
nblocks=nsdpblocks;
if (nlin>0),
  nblocks=nblocks+1;
end;
%
%  print out some size information
%
if (quiet==0),
  fprintf('Number of constraints: %d \n',m);
  fprintf('Number of SDP blocks: %d \n',nsdpblocks);
  fprintf('Number of LP vars: %d \n',nlin);
end;
%
%  Open up the file for writing.
%
fid=fopen(fname,'w');
if (fid==-1),
  if (quiet==0),
    fprintf('Could not open file for output!');
  end;
  ret=1;
  return;
end;
%
%  Print out m, the number of constraints.
%
fprintf(fid,'%d \n',m);
%
% Next, the number of blocks.
%
fprintf(fid,'%d \n',nblocks);
%
% Print out the block structure.
%
if (K.s > 0),
  fprintf(fid,'%d ',K.s);
end;
if (nlin > 0),
  fprintf(fid,'%d ',-nlin);
end;
fprintf(fid,'\n');
%
%  Next, b, with all on one line.
%
fprintf(fid,'%.18e  ',full(b));
fprintf(fid,'\n');
%
% First, the C matrix.
%
%
%  First, calculate where in c things start.
%
base=sizelin+1;
%
%  Next, work through the SDP blocks.
%
for i=1:nsdpblocks,
%
% Get the current block of C.
%
  I=find(c);
  II=find(I>=base);
  I=I(II);
  II=find(I<=base+K.s(i)^2-1);
  I=I(II);
  II=I-(base-1)*ones(size(I));
  work=sparse(II,ones(size(II)),c(I),K.s(i)^2,1);
  work=reshape(work,K.s(i),K.s(i));

%
% If pars.check is set, then check this block for symmetry.
%
  if (pars.check==1),
    if (work ~= work'),
      if (quiet==0),
        fprintf('Non symmetric C.s matrix!\n');
      end;
      work=(work+work')/2;
    end;
  end;

% 
% Write out the C.s matrix. 
%
  work=triu(work);
  [II,JJ,V]=find(work);
  cnt=length(II);
  if (cnt ~= 0),
    fprintf(fid,'%d %d %d %d %.18e\n',[zeros(size(II)) i*ones(size(II)) II JJ -V]');
  end;

%
%  Next, update to the next base.
%
  base=base+K.s(i)^2;
end;
%
% Print out the coefficients for the linear block of C.
%
for i=1:nlin,
  if (c(i) ~= 0.0),
    fprintf(fid,'%d %d %d %d %.18e\n',[0 nsdpblocks+1 i i -c(i)]);
  end;
end;

%
%  Now, loop through the constraints, one at a time.
%
for cn=1:m,
%
%  Print out the SDP part of constraint cn.
%
  base=sizelin+1;
  rowcn=AT(:,cn);
  for i=1:nsdpblocks,
    I=find(rowcn);
    II=find(I>=base);
    I=I(II);
    II=find(I<=(base+K.s(i)^2-1));
    I=I(II);
    II=I-(base-1)*ones(size(I));
    work=sparse(II,ones(size(II)),rowcn(I),K.s(i)^2,1);

    work=reshape(work,K.s(i),K.s(i));

    if (pars.check==1),
      if (work ~= work'),
        if (quiet==0),
          fprintf('Non symmetric A.s matrix! \n');
        end;
        work=(work+work')/2;
      end;
    end;
%
% Ignore the lower left triangle.
%
    work=triu(work);
%
% Get the nonzero entries.
%
    [II,JJ,V]=find(work);
    cnt=length(II);
    if (cnt ~= 0),
      fprintf(fid,'%d %d %d %d %.18e\n',[cn*ones(size(II)) i*ones(size(II)) II JJ V]');
    end;
%
%  Next, update to the next base.
%
    base=base+K.s(i)^2;
  end;
%
% Finally, the linear part.
%
  I=find(rowcn);
  II=find(I<=nlin);
  I=I(II);
  workrow=sparse(I,ones(size(I)),rowcn(I),nlin,1);
  [II,JJ,V]=find(workrow);
  if (length(II) > 0),
    fprintf(fid,'%d %d %d %d %.18e\n',[cn*ones(length(II),1) (nsdpblocks+1)*ones(length(II),1) II II V]');
  end;
end;
%
% Close the file.
%
fclose(fid);
%
% Return success
%
ret=0;
return;
