#include "cppsim_classes.h"
#include "cppsim_gsl_interface.h"

/////////////////////////////////////////////////////////////////////////
//////////////////// Interface functions to GSL library /////////////////
/////////////////////////////////////////////////////////////////////////

void copy(const Matrix &in, gsl_matrix *out)
{
int i,j,rows,cols;

rows = in.get_rows();
cols = in.get_cols();

for (i = 0; i < rows; i++)
   for (j = 0; j < cols; j++)
       gsl_matrix_set(out,i,j,in.get_elem(i,j));
}

void copy(gsl_matrix *in, const Matrix &out)
{
int i,j,rows,cols;

rows = in->size1;
cols = in->size2;
out.set_size(rows,cols);

for (i = 0; i < rows; i++)
   for (j = 0; j < cols; j++)
      out.set_elem(i,j,gsl_matrix_get(in,i,j));
}

void copy(const Vector &in, gsl_vector *out)
{
int i,length;

length = in.get_length();

for (i = 0; i < length; i++)
   gsl_vector_set(out,i,in.get_elem(i));
}


void copy(gsl_vector *in, const Vector &out)
{
int i,length;

length = in->size;

out.set_length(length);

for (i = 0; i < length; i++)
   out.set_elem(i,gsl_vector_get(in,i));
}

/// The compute_svd_gsl() function provides a CppSim interface to GSL SVD routines //
/// choices are "default" and "jacobi"

int compute_svd_gsl(const Matrix &A, const Matrix &U, const Matrix &W,
             const Matrix &V, const char *svd_algorithm)
{
int i, j, return_flag;
gsl_matrix *A_gsl, *V_gsl;
gsl_vector *S_gsl, *work_gsl;

A_gsl = gsl_matrix_calloc(A.get_rows(),A.get_cols());
V_gsl = gsl_matrix_calloc(A.get_rows(),A.get_cols());
S_gsl = gsl_vector_calloc(A.get_rows());
work_gsl = gsl_vector_calloc(A.get_rows());

copy(A,A_gsl);

if (strcmp(svd_algorithm,"default") == 0)
   return_flag = gsl_linalg_SV_decomp(A_gsl,V_gsl,S_gsl,work_gsl);
else if (strcmp(svd_algorithm,"jacobi") == 0)
   return_flag = gsl_linalg_SV_decomp_jacobi(A_gsl,V_gsl,S_gsl);

if (return_flag == 0)
   {
   copy(A_gsl,U);
   W.set_size(A.get_rows(),A.get_cols());
   for (i = 0; i < A.get_rows(); i++)
      for (j = 0; j < A.get_cols(); j++)
         W.set_elem(i,j,0.0);

   for (i = 0; i < A.get_rows(); i++)
      W.set_elem(i,i,gsl_vector_get(S_gsl,i));
   copy(V_gsl,V);
   }

gsl_matrix_free(A_gsl);
gsl_matrix_free(V_gsl);
gsl_vector_free(S_gsl);
gsl_vector_free(work_gsl);

return(return_flag);
}


//////////////////// End of Interface functions to GSL library /////////////////
