/*
 * Read in a problem in SDPpack SQLP format, and convert it to SDPA sparse
 * format.  
 *
 * Usage:
 *
 *   sqlptosdpa <input problem> <output problem>
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

/*
  Declarations needed to handle indexing into Fortran arrays.

*/

/*
  First, to convert fortran i,j indices into a C vector index.
*/

#define ijtok(iiii,jjjj,lda) ((jjjj-1)*lda+iiii-1)

/*
  Next, to convert C vector index into Fortran i,j indices.
*/

#define ktoi(k,lda) ((k % lda)+1)
#define ktoj(k,lda) ((k/lda)+1)

int main(argc,argv)
     int argc;
     char *argv[];
{
  FILE *fid;
  int orig_constraints;
  int *sdp_block_sizes;
  int sdp_blocks;
  int q_blocks;
  int *q_block_sizes=NULL;
  int l_vars;
  int l_blocks=0;
  int q_vars;
  int block_size;
  int i;
  int j=0;
  int k;
  int kk;
  int p;
  int base;
  int block_type;
  int num_entries;
  double foo;
  int indexi;
  int indexj;
  int ret;
  int *entry_counts;
  int cs_entries=0;
  int aq_entries=0;
  int al_entries=0;
  int extra_constraints=0;

  double *b;
  int *AQi;
  int *AQj;
  double *AQ;

  int *CSi;
  int *CSj;
  double *CS;
  int *CSblock;

  double *CL;
  int *ALi;
  int *ALj;
  double *AL;

  double *CQ;

  typedef double *dptr;

  typedef int *iptr;

  dptr *AS;
  iptr *ASi;
  iptr *ASj;
  iptr *ASblock;

  int *thisASi;
  int *thisASj;
  double *thisAS;
  int *thisASblock;

  int *which_q_block=NULL;
  int *q_block_offset=NULL;

  /*
   * Check that we have enough arguments.
   */

  if (argc != 3)
    {
      printf("Usage: \n");
      printf("\n");
      printf("sqlptosdpa <input problem> <output problem> \n");
      exit(1);
    };

  /*
   * Determine the size of the problem.
   * Return:
   *    orig_constraints
   *    sdp_blocks
   *    sdp_block_sizes
   *    q_blocks
   *    q_block_sizes
   *    l_vars
   *    cs_entries.               (Entries in C.S matrix.)
   *    entry_counts (1..m)       (Entries in the A.S matrices.)
   *    aq_entries                (Entries in the A.Q matrix)
   *    al_entries                (Entries in the A.L matrix)
   */

  /*
   * Open up the SQLP file for reading.
   */

  fid=fopen(argv[1],"r");

  if (fid == (FILE *) NULL)
    {
      printf("Couldn't open SQLP problem file for reading! \n");
      exit(1);
    };

  /*
   *  Read in the count of constraints.
   */
  
  fscanf(fid,"%d",&orig_constraints);

  /*
   *  Allocate storage for an array that lists how many entries are in
   *  each A.S array.  
   */

  entry_counts=(int *) malloc((orig_constraints+1)*sizeof(int));
 
  for (i=1; i<=orig_constraints; i++)
    entry_counts[i]=0;

  /*
   *  Next, read in the constraint rhs's.  
   */

  for (i=1; i<=orig_constraints; i++)
    {
      ret=fscanf(fid,"%lf",&foo);
      if (ret != 1)
	{
	  printf("Incorrect SDPpack file. \n");
	  exit(1);
	};
    };

  /*
   * Read in the number of sdp blocks.
   */

  ret=fscanf(fid,"%d",&sdp_blocks);
  if (ret != 1)
    {
      printf("Incorrect SDPpack file. \n");
      exit(1);
    };

  sdp_block_sizes=(int *) malloc((sdp_blocks+1)*sizeof(int));

  if (sdp_blocks != 0)
    {
      
      /*
       * Next, read in the SDP block sizes.  
       */
      for (i=1; i<=sdp_blocks; i++)
	{
	  ret=fscanf(fid,"%d",&block_size);
	  if (ret != 1)
	    {
	      printf("Incorrect SDPpack file. \n");
	      exit(1);
	    };
	  sdp_block_sizes[i]=block_size;
	};

      /*
       *  Next, read over C.S
       */ 
      
      for (k=1; k<=sdp_blocks; k++)
	{
	  ret=fscanf(fid,"%d",&block_type);
	  if (ret != 1)
	    {
	      printf("Incorrect SDPpack file. \n");
	      exit(1);
	    };
	  
	  if (block_type == 0)
	    {
	      /*
	       *  Read in a dense block.
	       */
	      block_size=sdp_block_sizes[k];
	      for (i=1; i<=(block_size*(block_size+1))/2; i++)
		{
		  fscanf(fid,"%lf",&foo);
		};
	      cs_entries=cs_entries+(block_size*(block_size+1))/2;
	      
	    }
	  else
	    {
	      if (block_type == 1)
		{
		  /*
		   *  Read in a sparse block.
		   */
		  
		  ret=fscanf(fid,"%d",&num_entries);
		  for (i=1; i<=num_entries; i++)
		    {
		      fscanf(fid,"%d",&indexi);
		      fscanf(fid,"%d",&indexj);
		      fscanf(fid,"%lf",&foo);
		      cs_entries++;
		    };
		}
	      else
		{
		  printf("Incorrect SDPpack file. \n");
		  printf("Bad Block Type. \n");
		  exit(1);
		};
	    };
	  
	}; /* End of loop through blocks of Cs */

      /*
       * Now, read through the A.S constraint matrices.
       */

      for (kk=1; kk<= orig_constraints; kk++)
	{

	  for (k=1; k<=sdp_blocks; k++)
	    {
	      ret=fscanf(fid,"%d",&block_type);
	      if (ret != 1)
		{
		  printf("Incorrect SDPpack file. \n");
		  exit(1);
		};
	      
	      if (block_type == 0)
		{
		  /*
		   *  Read in a dense block.
		   */
		  block_size=sdp_block_sizes[k];
		  for (i=1; i<=(block_size*(block_size+1))/2; i++)
		    {
		      fscanf(fid,"%lf",&foo);
		    };
		  entry_counts[kk] += (block_size*(block_size+1))/2;
		  
		}
	      else
		{
		  if (block_type == 1)
		    {
		      /*
		       *  Read in a sparse block.
		       */
		      
		      ret=fscanf(fid,"%d",&num_entries);
		      for (i=1; i<=num_entries; i++)
			{
			  fscanf(fid,"%d",&indexi);
			  fscanf(fid,"%d",&indexj);
			  fscanf(fid,"%lf",&foo);
			  entry_counts[kk]++;
			};
		    }
		  else
		    {
		      printf("Incorrect SDPpack file. \n");
		      printf("Bad Block Type. \n");
		      exit(1);
		    };
		};
	      
	    }; /* End of loop through blocks of AS */

	}; /* End of loop through m constraints. */

    }
  else
    {
      /*
       * Nothing in SDP part of the problem.
       */
    };

  /*
   * Next, read the QC part of the problem.  
   */

  ret=fscanf(fid,"%d",&q_blocks);
  if (ret != 1)
    {
      printf("Incorrect SDPpack file. \n");
      printf("Bad Block Count. \n");
      return(1);
    };

  if (q_blocks != 0)
    {
      /*
       *  We've got some QC blocks.
       */

      q_block_sizes=(int *) malloc((q_blocks+1)*sizeof(int));
      if (q_block_sizes == NULL)
	{
	  printf("Storage Allocation Failed. \n");
	  exit(1);
	};
      /*
       * Read in the block sizes.
       */

      q_vars=0;
      for (i=1; i<=q_blocks; i++)
	{
	  ret=fscanf(fid,"%d",&block_size);
	  if (ret != 1)
	    {
	      printf("Incorrect SDPpack file. \n");
	      printf("Bad QC Block Size. \n");
	      return(1);
	    };
	  q_block_sizes[i]=block_size;
	  q_vars=q_vars+block_size;
	  extra_constraints=extra_constraints+block_size-1;
	  if (block_size > 2)
	    {
	      extra_constraints += ((block_size-2)*(block_size-1))/2;
	    };
	};

      /*
       *  Compute arrays which_q_block, and q_block_offset.  
       */

      which_q_block=(int *)malloc((q_vars+1)*sizeof(int));
      q_block_offset=(int *)malloc((q_vars+1)*sizeof(int));

      p=1;
      for (i=1; i<=q_blocks; i++)
	{
	  for (j=1; j<=q_block_sizes[i]; j++)
	    {
	      which_q_block[p]=i;
	      q_block_offset[p]=j;
	      p++;
	    };
	};
      
      /*
       *  Now, read in the cost vector C.q
       */

      for (i=1; i<=q_vars; i++)
	{
	  ret=fscanf(fid,"%lf",&foo);
	  if (ret != 1)
	    {
	      printf("Incorrect SDPpack file. \n");
	      printf("Bad C.q entry. \n");
	      exit(1);
	    };
	};
      
      /*
       *  Next, read in the constraint matrix Aq
       */


      ret=fscanf(fid,"%d",&block_type);
      if (ret != 1)
	{
	  printf("Incorrect SDPpack file. \n");
	  printf("Bad AQ block type. \n");
	  return(1);
	};
      
      if (block_type == 0)
	{
	  /*
	   *  Read in a dense AQ matrix.
	   */

	  for (i=1; i<=q_vars*orig_constraints; i++)
	    {
	      ret=fscanf(fid,"%lf",&foo);
	    };
	  aq_entries=aq_entries+q_vars*orig_constraints;
	}
      else
	{
	  if (block_type == 1)
	    {
	      /*
	       *  Read in a sparse AQ matrix.
	       */
	      
	      ret=fscanf(fid,"%d",&num_entries);
	      for (i=1; i<=num_entries; i++)
		{
		  fscanf(fid,"%d",&indexi);
		  fscanf(fid,"%d",&indexj);
		  fscanf(fid,"%lf",&foo);
		  aq_entries++;
		};
	    }
	  else
	    {
	      printf("Incorrect SDPpack file. \n");
	      printf("Bad AQ type. \n");
	      return(1);
	    };
	};
      
    }
  else
    {
      /*
       *  No QC blocks!
       */
      q_vars=0;
    };


  /*
   * And read through the LP part of the problem.
   */

  ret=fscanf(fid,"%d",&l_vars);
  if (ret != 1)
    {
      printf("Incorrect SDPpack file. \n");
      printf("Bad linear variable count. (phase I) \n");
      return(1);
    };

  if (l_vars != 0)
    {
      /*
       *  Put in one block for the linear variables.
       */
      
      l_blocks=1;
      /*
       * Read in C.l
       */
      
      for (i=1; i<=l_vars; i++)
	{
	  ret=fscanf(fid,"%lf",&foo);
	}
      
      /*
       * Read in the matrix A.l
       */
      
      ret=fscanf(fid,"%d",&block_type);
      if (ret != 1)
	{
	  printf("Incorrect SDPpack file. \n");
	  printf("Bad AL block type.  1\n");
	  return(1);
	};
      
      if (block_type == 0)
	{
	  /*
	   *  Read in a dense AL matrix.
	   */
	  
	  for (i=1; i<=l_vars*orig_constraints; i++)
	    {
	      ret=fscanf(fid,"%lf",&foo);
	    };
	  
	  al_entries=al_entries+l_vars*orig_constraints;
	}
      else
	{
	  if (block_type == 1)
	    {
	      /*
	       *  Read in a sparse AL matrix.
	       */
	      
	      ret=fscanf(fid,"%d",&num_entries);
	      for (i=1; i<=num_entries; i++)
		{
		  fscanf(fid,"%d",&indexi);
		  fscanf(fid,"%d",&indexj);
		  fscanf(fid,"%le",&foo);
		  al_entries++;
		};
	    }
	  else
	    {
	      printf("Incorrect SDPpack file. \n");
	      printf("Bad AL type. \n");
	      return(1);
	    };
	};
    };



  
  /*
   *  Allocate storage for problem data.
   *
   *  CS               C.s matrix.
   *  AS               A.s matrices.
   *  CQ               C.q vector.
   *  AQ               A.q matrix.
   *  CL               C.l vector.
   *  AL               A.l matrix.
   *
   *  All vectors stored as C vectors with 1..n indexing.
   *  All arrays stored in i,j,ent fashion, upper triangles only.
   *  An array of pointers to ASI, ASJ, ASENT arrays.  
   */

  b=(double *) malloc((orig_constraints+1)*sizeof(double));

  CSi=(int *) malloc((cs_entries+1)*sizeof(int));
  if (CSi == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  CSj=(int *) malloc((cs_entries+1)*sizeof(int));
  if (CSj == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  CS=(double *) malloc((cs_entries+1)*sizeof(double));
  if (CS == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  CSblock=(int *) malloc((cs_entries+1)*sizeof(int));
  if (CSblock == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  AS=(dptr *) malloc((orig_constraints+1)*sizeof(dptr));
  if (AS == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  ASi=(iptr *) malloc((orig_constraints+1)*sizeof(iptr));
  if (ASi == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  ASj=(iptr *) malloc((orig_constraints+1)*sizeof(iptr));
  if (ASj == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  ASblock=(iptr *) malloc((orig_constraints+1)*sizeof(iptr));
  if (ASblock == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };

  /*
   *  Now allocate vectors for the individual matrices.
   */
  for (i=1; i<=orig_constraints; i++)
    {
      ASi[i]=(int *) malloc((entry_counts[i]+1)*sizeof(int));
      if (ASi[i] == NULL)
	{
	  printf("Storage allocation failed. \n");
	  exit(1);
	}
      ASj[i]=(int *) malloc((entry_counts[i]+1)*sizeof(int));
      if (ASj[i] == NULL)
	{
	  printf("Storage allocation failed. \n");
	  exit(1);
	}
      AS[i]=(double *) malloc((entry_counts[i]+1)*sizeof(double));
      if (AS[i] == NULL)
	{
	  printf("Storage allocation failed. \n");
	  exit(1);
	}
      ASblock[i]=(int *) malloc((entry_counts[i]+1)*sizeof(int));
      if (ASblock[i] == NULL)
	{
	  printf("Storage allocation failed. \n");
	  exit(1);
	}

    };


  CQ=(double *) malloc((q_vars +1)*sizeof(double));
  if (CQ == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };

  AQi=(int *) malloc((aq_entries+1)*sizeof(int));
  if (AQi == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  AQj=(int *) malloc((aq_entries+1)*sizeof(int));
  if (AQj == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  AQ=(double *) malloc((aq_entries+1)*sizeof(double));
  if (AQ == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };

  CL=(double *) malloc((l_vars+1)*sizeof(double));
  if (CL == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  ALi=(int *) malloc((al_entries+1)*sizeof(int));
  if (ALi == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  ALj=(int *) malloc((al_entries+1)*sizeof(int));
  if (ALj == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  AL=(double *) malloc((al_entries+1)*sizeof(double));
  if (AL == NULL)
    {
      printf("Storage allocation failed. \n");
      exit(1);
    };
  /*
   *  reopen the input file, and read in the problem data.
   */

  fclose(fid);
  fid=fopen(argv[1],"r");

  if (fid == (FILE *) NULL)
    {
      printf("Couldn't open SQLP problem file for reading! \n");
      exit(1);
    };

  /*
   * Get the number of constraints.  Note that additional constraints are
   * needed to translate quadratic cone constraints into SDP form.
   */

  ret=fscanf(fid,"%d",&orig_constraints);
  if (ret != 1)
    {
      printf("Incorrect SDPpack file. \n");
      exit(1);
    };

  /*
   *  Next, read in the constraint rhs's.  
   */

  for (i=1; i<=orig_constraints; i++)
    {
      ret=fscanf(fid,"%lf",b+i);
      if (ret != 1)
	{
	  printf("Incorrect SDPpack file. \n");
	  exit(1);
	};
    };

  /*
   * Read in the number of sdp blocks.
   */

  ret=fscanf(fid,"%d",&sdp_blocks);
  if (ret != 1)
    {
      printf("Incorrect SDPpack file. \n");
      exit(1);
    };

  if (sdp_blocks != 0)
    {
      
      /*
       * Next, read in the SDP block sizes.  
       */
      for (i=1; i<=sdp_blocks; i++)
	{
	  ret=fscanf(fid,"%d",&block_size);
	  if (ret != 1)
	    {
	      printf("Incorrect SDPpack file. \n");
	      exit(1);
	    };
	  sdp_block_sizes[i]=block_size;
	};

      /*
       *  Next, read in CS
       */
 
      p=1;
      base=1;      
      for (k=1; k<=sdp_blocks; k++)
	{
	  ret=fscanf(fid,"%d",&block_type);
	  if (ret != 1)
	    {
	      printf("Incorrect SDPpack file. \n");
	      exit(1);
	    };
	  

	  if (block_type == 0)
	    {
	      /*
	       *  Read in a dense block.
	       */
	      block_size=sdp_block_sizes[k];
	      for (i=1; i<=block_size; i++)
		for (j=i; j<=block_size; j++)
		  {
		    fscanf(fid,"%lf",&foo);
		    CSi[p]=i;
		    CSj[p]=j;
		    CS[p]=foo;
		    CSblock[p]=k;
		    p++;
		  };

	    }
	  else
	    {
	      if (block_type == 1)
		{
		  /*
		   *  Read in a sparse block.
		   */
		  
		  ret=fscanf(fid,"%d",&num_entries);
		  for (i=1; i<=num_entries; i++)
		    {
		      fscanf(fid,"%d",&indexi);
		      fscanf(fid,"%d",&indexj);
		      fscanf(fid,"%lf",&foo);
		      CSi[p]=indexi;
		      CSj[p]=indexj;
		      CS[p]=foo;
		      CSblock[p]=k;
		      p++;
		    };
		}
	      else
		{
		  printf("Incorrect SDPpack file. \n");
		  printf("Bad Block Type. \n");
		  exit(1);
		};
	    };
	  
	  base=base+block_size;
	}; /* End of loop through blocks of Cs */

      /*
       * Now, read through the A.S constraint matrices.
       */

      for (kk=1; kk<= orig_constraints; kk++)
	{
	  thisASi=ASi[kk];
	  thisASj=ASj[kk];
	  thisAS=AS[kk];
	  thisASblock=ASblock[kk];

	  base=1;
	  p=1;
	  for (k=1; k<=sdp_blocks; k++)
	    {
	      ret=fscanf(fid,"%d",&block_type);
	      if (ret != 1)
		{
		  printf("Incorrect SDPpack file. \n");
		  exit(1);
		};
	      
	      if (block_type == 0)
		{
		  /*
		   *  Read in a dense block.
		   */
		  block_size=sdp_block_sizes[k];
		  for (i=1; i<=block_size; i++)
		    for (j=i; j<=block_size; j++)
		      {
			fscanf(fid,"%lf",&foo);
			thisASi[p]=i;
			thisASj[p]=j;
			thisAS[p]=foo;
			thisASblock[p]=k;
			p++;
		      };
		}
	      else
		{
		  if (block_type == 1)
		    {
		      /*
		       *  Read in a sparse block.
		       */
		      
		      ret=fscanf(fid,"%d",&num_entries);
		      for (i=1; i<=num_entries; i++)
			{
			  fscanf(fid,"%d",&indexi);
			  fscanf(fid,"%d",&indexj);
			  fscanf(fid,"%lf",&foo);
			  thisASi[p]=indexi;
			  thisASj[p]=indexj;
			  thisAS[p]=foo;
			  thisASblock[p]=k;
			  p++;
			};
		    }
		  else
		    {
		      printf("Incorrect SDPpack file. \n");
		      printf("Bad Block Type. \n");
		      exit(1);
		    };
		};
	      
	      base=base+block_size;
	    }; /* End of loop through blocks of AS */

	}; /* End of loop through m constraints. */

    }
  else
    {
      /*
       * Nothing in SDP part of the problem.
       */
    };


  /*
   * Next, read the QC part of the problem.  
   */

  ret=fscanf(fid,"%d",&q_blocks);
  if (ret != 1)
    {
      printf("Incorrect SDPpack file. \n");
      printf("Bad Block Count. \n");
      return(1);
    };

  if (q_blocks != 0)
    {
      /*
       *  We've got some QC blocks.
       */

      /*
       * Read in the block sizes.
       */

      for (i=1; i<=q_blocks; i++)
	{
	  ret=fscanf(fid,"%d",&block_size);
	  if (ret != 1)
	    {
	      printf("Incorrect SDPpack file. \n");
	      printf("Bad QC Block Size. \n");
	      return(1);
	    };
	};

      /*
       *  Now, read in the cost vector C.q
       */

      for (i=1; i<=q_vars; i++)
	{
	  ret=fscanf(fid,"%lf",&foo);
	  if (ret != 1)
	    {
	      printf("Incorrect SDPpack file. \n");
	      printf("Bad C.q entry. \n");
	      exit(1);
	    };
	  CQ[i]=foo;
	};
      
      /*
       *  Next, read in the constraint matrix Aq
       */


      ret=fscanf(fid,"%d",&block_type);
      if (ret != 1)
	{
	  printf("Incorrect SDPpack file. \n");
	  printf("Bad AQ block type. \n");
	  return(1);
	};
      
      if (block_type == 0)
	{
	  /*
	   *  Read in a dense AQ matrix.
	   */

	  p=1;


	  for (j=1; j<=q_vars; j++)
	    for (i=1; i<=orig_constraints; i++)
	      {
		ret=fscanf(fid,"%lf",&foo);
		AQi[p]=i;
		AQj[p]=j;
		AQ[p]=foo;
		p++;
	      };
	}
      else
	{
	  if (block_type == 1)
	    {
	      /*
	       *  Read in a sparse AQ matrix.
	       */
	      
	      p=1;
	      ret=fscanf(fid,"%d",&num_entries);
	      for (i=1; i<=num_entries; i++)
		{
		  fscanf(fid,"%d",&indexi);
		  fscanf(fid,"%d",&indexj);
		  fscanf(fid,"%lf",&foo);
		  AQi[p]=indexi;
		  AQj[p]=indexj;
		  AQ[p]=foo;
		  p++;
		};
	    }
	  else
	    {
	      printf("Incorrect SDPpack file. \n");
	      printf("Bad AQ type. \n");
	      return(1);
	    };
	};
      
    }
  else
    {
      /*
       *  No QC blocks!
       */
    };


  /*
   * And read the LP part of the problem.
   */

  ret=fscanf(fid,"%d",&l_vars);
  if (ret != 1)
    {
      printf("Incorrect SDPpack file. \n");
      printf("Bad linear variable count. (phase 2) \n");
      return(1);
    };

  if (l_vars != 0)
    {
      /*
       *  Put in one block for the linear variables.
       */
      
      l_blocks=1;

      /*
       * Read in C.l
       */
      
      for (i=1; i<=l_vars; i++)
	{
	  ret=fscanf(fid,"%lf",&foo);
	  CL[i]=foo;
	}
      
      /*
       * Read in the matrix A.l
       */
      
      ret=fscanf(fid,"%d",&block_type);
      if (ret != 1)
	{
	  printf("Incorrect SDPpack file. \n");
	  printf("Bad AL block type. \n");
	  return(1);
	};
      
      if (block_type == 0)
	{
	  /*
	   *  Read in a dense AL matrix.
	   */

	  p=1;

	  for (j=1; j<=l_vars; j++)
	    for (i=1; i<=orig_constraints; i++)
	      {
		ret=fscanf(fid,"%lf",&foo);
		ALi[p]=i;
		ALj[p]=j;
		AL[p]=foo;
		p++;
	      };
	}
      else
	{
	  if (block_type == 1)
	    {
	      /*
	       *  Read in a sparse AL matrix.
	       */
	      p=1;
	      ret=fscanf(fid,"%d",&num_entries);
	      for (i=1; i<=num_entries; i++)
		{
		  fscanf(fid,"%d",&indexi);
		  fscanf(fid,"%d",&indexj);
		  fscanf(fid,"%lf",&foo);
		  ALi[p]=indexi;
		  ALj[p]=indexj;
		  AL[p]=foo;
		  p++;
		};
	    }
	  else
	    {
	      printf("Incorrect SDPpack file. \n");
	      printf("Bad AL type. \n");
	      return(1);
	    };
	};
    };



  /*
   *  Now, go back and write out the problem data in SDPA format.
   */

  /*
   * Open up the file for output.
   */
  fclose(fid);
  fid=fopen(argv[2],"w");

  if (fid == (FILE *) NULL)
    { 
      printf("Opening output file failed. \n");
      exit(1);
    };

  /*
   * Write out the basic problem size info.
   */
  fprintf(fid,"%d \n",orig_constraints+extra_constraints);
  fprintf(fid,"%d \n",sdp_blocks+q_blocks+l_blocks);
  for (i=1; i<=sdp_blocks; i++)
    fprintf(fid,"%d ",sdp_block_sizes[i]);
  for (i=1; i<=q_blocks; i++)
    fprintf(fid,"%d ",q_block_sizes[i]);
  if (l_vars != 0)
    fprintf(fid,"%d ",-l_vars);
  fprintf(fid,"\n");

  /*
   * Write out the rhs vector.  (c in SDPA terminology)
   */
  for (i=1; i<=orig_constraints; i++)
    fprintf(fid,"%.18e ",b[i]);
  for (i=1; i<=extra_constraints; i++)
    fprintf(fid,"%.18e ",0.0);
  fprintf(fid,"\n");

  /*
   *  Write out the C matrix.
   */

  /*
   * First, CS parts.
   */
  for (j=1; j<=cs_entries; j++)
    {
      if (CS[j] != 0.0)
	fprintf(fid,"0 %d %d %d %.18e \n",CSblock[j],CSi[j],CSj[j],-CS[j]);
    };

  /*
   * Next, the QC parts.
   */

  for (i=1; i<=q_vars; i++)
    {
      if (q_block_offset[i] == 1)
	{
	  if (CQ[i] != 0.0)
	    fprintf(fid,"0 %d %d %d %.18e \n",which_q_block[i]+sdp_blocks,
		    q_block_offset[i],q_block_offset[i],-CQ[i]);
	}
      else
	{
	  if (CQ[i] != 0.0)
	    fprintf(fid,"0 %d %d %d %.18e \n",which_q_block[i]+sdp_blocks,1,
		    q_block_offset[i],-CQ[i]/2.0);
	};
    };
  /*
   * Next, the LP parts.
   */
  for (i=1; i<=l_vars; i++)
    {
      if (CL[i] != 0.0 )
	fprintf(fid,"0 %d %d %d %.18e \n",sdp_blocks+q_blocks+1,i,i,-CL[i]);
    };

  /*
   *  Write out the A matrices, one after another.  
   */

  /*
   * First the user's constraints.
   */

  for (i=1; i<=orig_constraints; i++)
    {
      /*
       *  First, the SDP part.
       */

      thisASi=ASi[i];
      thisASj=ASj[i];
      thisAS=AS[i];
      thisASblock=ASblock[i];

      for (j=1; j<=entry_counts[i]; j++)
	{
	  if (thisAS[j] != 0.0)
	    fprintf(fid,"%d %d %d %d %.18e \n",i,thisASblock[j],thisASi[j],
		    thisASj[j],thisAS[j]);
	};

      /*
       * Next, the QC part.
       */
      
      for (j=1; j<=aq_entries; j++)
	{
	  if (AQi[j] == i)
	    {
	      if (q_block_offset[AQj[j]] == 1)
		{
		  if (AQ[j] != 0.0)
		    fprintf(fid,"%d %d %d %d %.18e \n",i,sdp_blocks+which_q_block[AQj[j]],1,1,AQ[j]);
		}
	      else
		{
		  if (AQ[j] != 0.0)
		    fprintf(fid,"%d %d %d %d %.18e \n",i,sdp_blocks+which_q_block[AQj[j]],
			    1,q_block_offset[AQj[j]],AQ[j]/2.0);
		};

	    };
	};
      
      /*
       * Finally, the LP part.
       */

      for (j=1; j<=al_entries; j++)
	{
	  if (ALi[j] == i)
	    {
	      if (AL[j] != 0.0)
		fprintf(fid,"%d %d %d %d %.18e \n",i,sdp_blocks+q_blocks+1,
			ALj[j],ALj[j],AL[j]);
	    };
	};
    };

  /*
   *  Next, the extra QC constraints.
   */

  p=1;
  for (i=1; i<=q_blocks; i++)
    {
      for (j=2; j<=q_block_sizes[i]; j++)
	{
	  fprintf(fid,"%d %d %d %d %.18e \n",p+orig_constraints,i+sdp_blocks,
		  1,1,1.0);
	  fprintf(fid,"%d %d %d %d %.18e \n",p+orig_constraints,i+sdp_blocks,
		  j,j,-1.0);
	  p=p+1;  
	};

      if (q_block_sizes[i] > 2)
	{
	  for (j=2; j<=q_block_sizes[i]-1; j++)
	    for (k=j+1; k<=q_block_sizes[i]; k++)
	      {
		fprintf(fid,"%d %d %d %d %.18e \n",p+orig_constraints,i+sdp_blocks,
			j,k,1.0);
		p++;
	      };
	};
    };


  /*
   *  Close up and exit.
   */
  fclose(fid);
  return(0);

}



