#include <gsl/gsl_test.h>
#include <gsl/gsl_ieee_utils.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_cblas.h>

#include "tests.h"

void
test_symm (void) {
const double flteps = 1e-4, dbleps = 1e-6;
  {
   int order = 101;
   int side = 141;
   int uplo = 121;
   int M = 1;
   int N = 2;
   float alpha = -0.3f;
   float beta = -1.0f;
   float A[] = { -0.581f };
   int lda = 1;
   float B[] = { 0.157f, 0.451f };
   int ldb = 2;
   float C[] = { -0.869f, -0.871f };
   int ldc = 2;
   float C_expected[] = { 0.896365f, 0.949609f };
   cblas_ssymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], flteps, "ssymm(case 1518)");
     }
   };
  };

  {
   int order = 102;
   int side = 141;
   int uplo = 121;
   int M = 1;
   int N = 2;
   float alpha = -0.3f;
   float beta = -1.0f;
   float A[] = { 0.874f };
   int lda = 1;
   float B[] = { 0.085f, 0.069f };
   int ldb = 1;
   float C[] = { -0.495f, -0.828f };
   int ldc = 1;
   float C_expected[] = { 0.472713f, 0.809908f };
   cblas_ssymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], flteps, "ssymm(case 1519)");
     }
   };
  };

  {
   int order = 101;
   int side = 142;
   int uplo = 121;
   int M = 1;
   int N = 2;
   float alpha = -1.0f;
   float beta = 0.0f;
   float A[] = { -0.671f, -0.343f, 0.6f, 0.177f };
   int lda = 2;
   float B[] = { 0.043f, 0.01f };
   int ldb = 2;
   float C[] = { 0.988f, 0.478f };
   int ldc = 2;
   float C_expected[] = { 0.032283f, 0.012979f };
   cblas_ssymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], flteps, "ssymm(case 1520)");
     }
   };
  };

  {
   int order = 102;
   int side = 142;
   int uplo = 121;
   int M = 1;
   int N = 2;
   float alpha = -1.0f;
   float beta = 0.0f;
   float A[] = { 0.069f, 0.096f, 0.139f, -0.044f };
   int lda = 2;
   float B[] = { -0.448f, 0.07f };
   int ldb = 1;
   float C[] = { 0.361f, 0.995f };
   int ldc = 1;
   float C_expected[] = { 0.021182f, 0.065352f };
   cblas_ssymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], flteps, "ssymm(case 1521)");
     }
   };
  };

  {
   int order = 101;
   int side = 141;
   int uplo = 122;
   int M = 1;
   int N = 2;
   float alpha = 0.0f;
   float beta = -0.3f;
   float A[] = { 0.745f };
   int lda = 1;
   float B[] = { -0.269f, 0.448f };
   int ldb = 2;
   float C[] = { -0.986f, 0.2f };
   int ldc = 2;
   float C_expected[] = { 0.2958f, -0.06f };
   cblas_ssymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], flteps, "ssymm(case 1522)");
     }
   };
  };

  {
   int order = 102;
   int side = 141;
   int uplo = 122;
   int M = 1;
   int N = 2;
   float alpha = 0.0f;
   float beta = -0.3f;
   float A[] = { 0.96f };
   int lda = 1;
   float B[] = { 0.392f, -0.07f };
   int ldb = 1;
   float C[] = { -0.235f, 0.554f };
   int ldc = 1;
   float C_expected[] = { 0.0705f, -0.1662f };
   cblas_ssymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], flteps, "ssymm(case 1523)");
     }
   };
  };

  {
   int order = 101;
   int side = 142;
   int uplo = 122;
   int M = 1;
   int N = 2;
   float alpha = -0.3f;
   float beta = 0.1f;
   float A[] = { -0.839f, 0.498f, -0.215f, -0.314f };
   int lda = 2;
   float B[] = { -0.66f, 0.593f };
   int ldb = 2;
   float C[] = { -0.806f, 0.525f };
   int ldc = 2;
   float C_expected[] = { -0.208474f, 0.0657906f };
   cblas_ssymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], flteps, "ssymm(case 1524)");
     }
   };
  };

  {
   int order = 102;
   int side = 142;
   int uplo = 122;
   int M = 1;
   int N = 2;
   float alpha = -0.3f;
   float beta = 0.1f;
   float A[] = { 0.994f, -0.117f, -0.639f, 0.925f };
   int lda = 2;
   float B[] = { -0.478f, 0.147f };
   int ldb = 1;
   float C[] = { -0.814f, 0.316f };
   int ldc = 1;
   float C_expected[] = { 0.0662993f, -0.0259703f };
   cblas_ssymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], flteps, "ssymm(case 1525)");
     }
   };
  };

  {
   int order = 101;
   int side = 141;
   int uplo = 121;
   int M = 1;
   int N = 2;
   double alpha = -0.3;
   double beta = 1;
   double A[] = { -0.981 };
   int lda = 1;
   double B[] = { -0.823, 0.83 };
   int ldb = 2;
   double C[] = { 0.991, 0.382 };
   int ldc = 2;
   double C_expected[] = { 0.7487911, 0.626269 };
   cblas_dsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], dbleps, "dsymm(case 1526)");
     }
   };
  };

  {
   int order = 102;
   int side = 141;
   int uplo = 121;
   int M = 1;
   int N = 2;
   double alpha = -0.3;
   double beta = 1;
   double A[] = { -0.248 };
   int lda = 1;
   double B[] = { 0.74, 0.068 };
   int ldb = 1;
   double C[] = { -0.905, 0.742 };
   int ldc = 1;
   double C_expected[] = { -0.849944, 0.7470592 };
   cblas_dsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], dbleps, "dsymm(case 1527)");
     }
   };
  };

  {
   int order = 101;
   int side = 142;
   int uplo = 121;
   int M = 1;
   int N = 2;
   double alpha = -1;
   double beta = 1;
   double A[] = { 0.591, -0.01, -0.192, -0.376 };
   int lda = 2;
   double B[] = { 0.561, 0.946 };
   int ldb = 2;
   double C[] = { 0.763, 0.189 };
   int ldc = 2;
   double C_expected[] = { 0.440909, 0.550306 };
   cblas_dsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], dbleps, "dsymm(case 1528)");
     }
   };
  };

  {
   int order = 102;
   int side = 142;
   int uplo = 121;
   int M = 1;
   int N = 2;
   double alpha = -1;
   double beta = 1;
   double A[] = { -0.786, 0.87, 0.222, -0.043 };
   int lda = 2;
   double B[] = { -0.503, -0.526 };
   int ldb = 1;
   double C[] = { -0.027, -0.391 };
   int ldc = 1;
   double C_expected[] = { -0.305586, -0.301952 };
   cblas_dsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], dbleps, "dsymm(case 1529)");
     }
   };
  };

  {
   int order = 101;
   int side = 141;
   int uplo = 122;
   int M = 1;
   int N = 2;
   double alpha = 0.1;
   double beta = 0.1;
   double A[] = { -0.468 };
   int lda = 1;
   double B[] = { -0.881, 0.692 };
   int ldb = 2;
   double C[] = { -0.812, -0.395 };
   int ldc = 2;
   double C_expected[] = { -0.0399692, -0.0718856 };
   cblas_dsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], dbleps, "dsymm(case 1530)");
     }
   };
  };

  {
   int order = 102;
   int side = 141;
   int uplo = 122;
   int M = 1;
   int N = 2;
   double alpha = 0.1;
   double beta = 0.1;
   double A[] = { 0.849 };
   int lda = 1;
   double B[] = { -0.887, 0.518 };
   int ldb = 1;
   double C[] = { 0.414, -0.251 };
   int ldc = 1;
   double C_expected[] = { -0.0339063, 0.0188782 };
   cblas_dsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], dbleps, "dsymm(case 1531)");
     }
   };
  };

  {
   int order = 101;
   int side = 142;
   int uplo = 122;
   int M = 1;
   int N = 2;
   double alpha = -1;
   double beta = 1;
   double A[] = { 0.457, 0.624, 0.807, 0.349 };
   int lda = 2;
   double B[] = { -0.609, 0.03 };
   int ldb = 2;
   double C[] = { 0.719, -0.624 };
   int ldc = 2;
   double C_expected[] = { 0.973103, -0.143007 };
   cblas_dsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], dbleps, "dsymm(case 1532)");
     }
   };
  };

  {
   int order = 102;
   int side = 142;
   int uplo = 122;
   int M = 1;
   int N = 2;
   double alpha = -1;
   double beta = 1;
   double A[] = { -0.133, -0.117, -0.163, 0.795 };
   int lda = 2;
   double B[] = { -0.882, 0.549 };
   int ldb = 1;
   double C[] = { 0.715, -0.327 };
   int ldc = 1;
   double C_expected[] = { 0.661927, -0.866649 };
   cblas_dsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[i], C_expected[i], dbleps, "dsymm(case 1533)");
     }
   };
  };

  {
   int order = 101;
   int side = 141;
   int uplo = 121;
   int M = 1;
   int N = 2;
   float alpha[2] = {-1.0f, 0.0f};
   float beta[2] = {1.0f, 0.0f};
   float A[] = { 0.476f, 0.816f };
   int lda = 1;
   float B[] = { 0.282f, 0.852f, -0.891f, -0.588f };
   int ldb = 2;
   float C[] = { 0.9f, 0.486f, -0.78f, -0.637f };
   int ldc = 2;
   float C_expected[] = { 1.461f, -0.149664f, -0.835692f, 0.369944f };
   cblas_csymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], flteps, "csymm(case 1534) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], flteps, "csymm(case 1534) imag");
     };
   };
  };

  {
   int order = 102;
   int side = 141;
   int uplo = 121;
   int M = 1;
   int N = 2;
   float alpha[2] = {-1.0f, 0.0f};
   float beta[2] = {1.0f, 0.0f};
   float A[] = { 0.048f, 0.172f };
   int lda = 1;
   float B[] = { 0.786f, 0.783f, 0.809f, -0.569f };
   int ldb = 1;
   float C[] = { -0.227f, -0.215f, 0.881f, 0.233f };
   int ldc = 1;
   float C_expected[] = { -0.130052f, -0.387776f, 0.7443f, 0.121164f };
   cblas_csymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], flteps, "csymm(case 1535) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], flteps, "csymm(case 1535) imag");
     };
   };
  };

  {
   int order = 101;
   int side = 142;
   int uplo = 121;
   int M = 1;
   int N = 2;
   float alpha[2] = {0.0f, 1.0f};
   float beta[2] = {0.0f, 1.0f};
   float A[] = { -0.495f, -0.012f, 0.843f, -0.986f, -0.243f, 0.833f, 0.921f, 0.004f };
   int lda = 2;
   float B[] = { 0.876f, 0.612f, 0.805f, -0.57f };
   int ldb = 2;
   float C[] = { 0.938f, -0.24f, -0.874f, -0.062f };
   int ldc = 2;
   float C_expected[] = { 1.82769f, 0.628319f, 0.93157f, 1.21158f };
   cblas_csymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], flteps, "csymm(case 1536) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], flteps, "csymm(case 1536) imag");
     };
   };
  };

  {
   int order = 102;
   int side = 142;
   int uplo = 121;
   int M = 1;
   int N = 2;
   float alpha[2] = {0.0f, 1.0f};
   float beta[2] = {0.0f, 1.0f};
   float A[] = { -0.812f, 0.83f, 0.705f, 0.15f, -0.463f, 0.901f, -0.547f, -0.483f };
   int lda = 2;
   float B[] = { -0.808f, -0.664f, 0.352f, -0.102f };
   int ldb = 1;
   float C[] = { -0.64f, 0.399f, 0.896f, -0.163f };
   int ldc = 1;
   float C_expected[] = { -0.631906f, 0.496142f, 0.697798f, 1.62656f };
   cblas_csymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], flteps, "csymm(case 1537) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], flteps, "csymm(case 1537) imag");
     };
   };
  };

  {
   int order = 101;
   int side = 141;
   int uplo = 122;
   int M = 1;
   int N = 2;
   float alpha[2] = {-1.0f, 0.0f};
   float beta[2] = {0.0f, 1.0f};
   float A[] = { 0.342f, -0.906f };
   int lda = 1;
   float B[] = { 0.676f, 0.863f, -0.517f, -0.138f };
   int ldb = 2;
   float C[] = { 0.274f, 0.388f, -0.271f, 0.205f };
   int ldc = 2;
   float C_expected[] = { -1.40107f, 0.59131f, 0.096842f, -0.692206f };
   cblas_csymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], flteps, "csymm(case 1538) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], flteps, "csymm(case 1538) imag");
     };
   };
  };

  {
   int order = 102;
   int side = 141;
   int uplo = 122;
   int M = 1;
   int N = 2;
   float alpha[2] = {-1.0f, 0.0f};
   float beta[2] = {0.0f, 1.0f};
   float A[] = { 0.418f, 0.354f };
   int lda = 1;
   float B[] = { -0.74f, 0.018f, 0.395f, 0.248f };
   int ldb = 1;
   float C[] = { -0.162f, 0.175f, -0.853f, 0.652f };
   int ldc = 1;
   float C_expected[] = { 0.140692f, 0.092436f, -0.729318f, -1.09649f };
   cblas_csymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], flteps, "csymm(case 1539) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], flteps, "csymm(case 1539) imag");
     };
   };
  };

  {
   int order = 101;
   int side = 142;
   int uplo = 122;
   int M = 1;
   int N = 2;
   float alpha[2] = {-0.3f, 0.1f};
   float beta[2] = {0.0f, 0.1f};
   float A[] = { 0.12f, 0.496f, 0.313f, -0.136f, 0.987f, 0.532f, 0.58f, -0.687f };
   int lda = 2;
   float B[] = { -0.587f, 0.278f, 0.857f, 0.136f };
   int ldb = 2;
   float C[] = { 0.162f, 0.249f, -0.665f, 0.456f };
   int ldc = 2;
   float C_expected[] = { -0.22769f, -0.0269913f, 0.0502096f, 0.0841558f };
   cblas_csymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], flteps, "csymm(case 1540) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], flteps, "csymm(case 1540) imag");
     };
   };
  };

  {
   int order = 102;
   int side = 142;
   int uplo = 122;
   int M = 1;
   int N = 2;
   float alpha[2] = {-0.3f, 0.1f};
   float beta[2] = {0.0f, 0.1f};
   float A[] = { 0.579f, -0.859f, 0.192f, -0.737f, 0.396f, -0.498f, 0.751f, -0.379f };
   int lda = 2;
   float B[] = { 0.84f, -0.755f, -0.019f, -0.063f };
   int ldb = 1;
   float C[] = { 0.04f, 0.639f, -0.876f, -0.778f };
   int ldc = 1;
   float C_expected[] = { 0.115459f, 0.329813f, 0.288206f, 0.110315f };
   cblas_csymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], flteps, "csymm(case 1541) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], flteps, "csymm(case 1541) imag");
     };
   };
  };

  {
   int order = 101;
   int side = 141;
   int uplo = 121;
   int M = 1;
   int N = 2;
   double alpha[2] = {0, 0};
   double beta[2] = {0, 0};
   double A[] = { 0.511, -0.486 };
   int lda = 1;
   double B[] = { 0.985, -0.923, -0.234, -0.756 };
   int ldb = 2;
   double C[] = { -0.16, 0.049, 0.618, -0.349 };
   int ldc = 2;
   double C_expected[] = { 0.0, 0.0, 0.0, 0.0 };
   cblas_zsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], dbleps, "zsymm(case 1542) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], dbleps, "zsymm(case 1542) imag");
     };
   };
  };

  {
   int order = 102;
   int side = 141;
   int uplo = 121;
   int M = 1;
   int N = 2;
   double alpha[2] = {0, 0};
   double beta[2] = {0, 0};
   double A[] = { 0.46, -0.816 };
   int lda = 1;
   double B[] = { 0.404, 0.113, -0.904, -0.627 };
   int ldb = 1;
   double C[] = { 0.114, 0.318, 0.636, -0.839 };
   int ldc = 1;
   double C_expected[] = { 0.0, 0.0, 0.0, 0.0 };
   cblas_zsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], dbleps, "zsymm(case 1543) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], dbleps, "zsymm(case 1543) imag");
     };
   };
  };

  {
   int order = 101;
   int side = 142;
   int uplo = 121;
   int M = 1;
   int N = 2;
   double alpha[2] = {-1, 0};
   double beta[2] = {-0.3, 0.1};
   double A[] = { -0.835, 0.344, 0.975, 0.634, 0.312, -0.659, -0.624, -0.175 };
   int lda = 2;
   double B[] = { -0.707, -0.846, 0.825, -0.661 };
   int ldb = 2;
   double C[] = { 0.352, -0.499, 0.267, 0.548 };
   int ldc = 2;
   double C_expected[] = { -2.160518, -0.156877, 0.648536, 0.867299 };
   cblas_zsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], dbleps, "zsymm(case 1544) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], dbleps, "zsymm(case 1544) imag");
     };
   };
  };

  {
   int order = 102;
   int side = 142;
   int uplo = 121;
   int M = 1;
   int N = 2;
   double alpha[2] = {-1, 0};
   double beta[2] = {-0.3, 0.1};
   double A[] = { -0.409, 0.013, -0.308, -0.317, -0.535, -0.697, -0.385, 0.119 };
   int lda = 2;
   double B[] = { 0.299, -0.233, 0.093, 0.664 };
   int ldb = 1;
   double C[] = { 0.699, 0.47, -0.347, -0.182 };
   int ldc = 1;
   double C_expected[] = { -0.550491, 0.249777, 0.559487, 0.348221 };
   cblas_zsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], dbleps, "zsymm(case 1545) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], dbleps, "zsymm(case 1545) imag");
     };
   };
  };

  {
   int order = 101;
   int side = 141;
   int uplo = 122;
   int M = 1;
   int N = 2;
   double alpha[2] = {1, 0};
   double beta[2] = {0, 1};
   double A[] = { -0.151, 0.635 };
   int lda = 1;
   double B[] = { 0.711, -0.869, 0.153, 0.647 };
   int ldb = 2;
   double C[] = { -0.299, 0.43, -0.307, 0.133 };
   int ldc = 2;
   double C_expected[] = { 0.014454, 0.283704, -0.566948, -0.307542 };
   cblas_zsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], dbleps, "zsymm(case 1546) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], dbleps, "zsymm(case 1546) imag");
     };
   };
  };

  {
   int order = 102;
   int side = 141;
   int uplo = 122;
   int M = 1;
   int N = 2;
   double alpha[2] = {1, 0};
   double beta[2] = {0, 1};
   double A[] = { 0.793, -0.543 };
   int lda = 1;
   double B[] = { 0.054, -0.045, 0.989, 0.453 };
   int ldb = 1;
   double C[] = { 0.443, -0.641, -0.809, -0.83 };
   int ldc = 1;
   double C_expected[] = { 0.659387, 0.377993, 1.860256, -0.986798 };
   cblas_zsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], dbleps, "zsymm(case 1547) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], dbleps, "zsymm(case 1547) imag");
     };
   };
  };

  {
   int order = 101;
   int side = 142;
   int uplo = 122;
   int M = 1;
   int N = 2;
   double alpha[2] = {1, 0};
   double beta[2] = {-1, 0};
   double A[] = { -0.432, -0.293, -0.819, 0.44, -0.818, -0.258, -0.836, 0.683 };
   int lda = 2;
   double B[] = { -0.259, -0.878, 0.161, 0.744 };
   int ldb = 2;
   double C[] = { 0.436, -0.655, -0.61, -0.875 };
   int ldc = 2;
   double C_expected[] = { -0.521112, 0.460053, -0.04741, 1.148005 };
   cblas_zsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], dbleps, "zsymm(case 1548) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], dbleps, "zsymm(case 1548) imag");
     };
   };
  };

  {
   int order = 102;
   int side = 142;
   int uplo = 122;
   int M = 1;
   int N = 2;
   double alpha[2] = {1, 0};
   double beta[2] = {-1, 0};
   double A[] = { -0.656, 0.378, -0.688, 0.676, 0.967, -0.804, 0.455, -0.425 };
   int lda = 2;
   double B[] = { 0.791, -0.947, -0.945, -0.444 };
   int ldb = 1;
   double C[] = { 0.014, -0.814, -0.091, -0.417 };
   int ldc = 1;
   double C_expected[] = { 0.775374, 1.400882, -0.431711, 1.802857 };
   cblas_zsymm(order, side, uplo, M, N, alpha, A, lda, B, ldb, beta, C, ldc);
   {
     int i;
     for (i = 0; i < 2; i++) {
       gsl_test_rel(C[2*i], C_expected[2*i], dbleps, "zsymm(case 1549) real");
       gsl_test_rel(C[2*i+1], C_expected[2*i+1], dbleps, "zsymm(case 1549) imag");
     };
   };
  };

}


/**
 *
 * @file testing_spemv.c
 *
 *  PLASMA testing routines
 *  PLASMA is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 2.6.0
 * @author Dulceneia Becker
 * @date 2011-10-06
 * @generated s Tue Jan  7 11:45:19 2014
 *
 **/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include <plasma.h>
#include <cblas.h>
#include <lapacke.h>
#include <core_blas.h>
#include "testing_smain.h"

#define REAL
#undef COMPLEX

/*--------------------------------------------------------------
 * Check the pemv
 */
static int check_solution(PLASMA_enum trans, PLASMA_enum storev,
                          int M, int N, int L,
                          float alpha, float *A, int LDA,
                                                    float *X, int INCX,
                          float beta,  float *Y0, int INCY0,
                                                    float *Y,  int INCY,
                          float *W, float *Rnorm)
{
    int k;
    float eps = LAPACKE_slamch_work('e');
    float *work;
    float mzone = -1.0;

    /* Copy x to w */
    if ( trans == PlasmaNoTrans ) {
        k = N;
    } else {
        k = M;
    }

    work = (float *)malloc(k * sizeof(float));
    cblas_scopy(k, Y0, INCY0, W, 1);

    /* w = a A x + b w */
    cblas_sgemv(CblasColMajor, (CBLAS_TRANSPOSE)trans,
                M, N,
                (alpha), A,  LDA,
                                    X,  INCX,
                (beta),  W,  1);

    /* y - w */
    cblas_saxpy(k, (mzone), Y, INCY, W, 1);

    /* Max Norm */
    *Rnorm = LAPACKE_slange_work(LAPACK_COL_MAJOR, 'm', 1, k, W, 1, work);

    if ( (*Rnorm / (M*N)) > eps) {
        return 1;
    } else {
        return 0;
    }
}

/*--------------------------------------------------------------
 * Testing SPEMV
 */
int testing_spemv(int argc, char **argv)
{
    /* Check for number of arguments*/
    if ( argc != 1) {
        USAGE("PEMV", "N",
              "   - N      : number of columns\n");
        return -1;
    }

    /* Args */
    int arg_n = atoi(argv[0]);

    /* Local variables */
    float *A, *X, *Y, *A0, *Y0, *work;
    float alpha, beta, alpha0, beta0;
    int n    = arg_n;
    int lda  = arg_n;

    int info_solution = 0;
    int i, j, k, t;
    int nbtests = 0;
    int nfails = 0;
    int storev;
    int l = 0;
    int m = n;
    int incx = 1;
    int incy = 1;
    char *cstorev;
    float rnorm;
    float eps = LAPACKE_slamch_work('e');

    /* Allocate Data */
    A    = (float *)malloc(lda*n*sizeof(float));
    A0   = (float *)malloc(lda*n*sizeof(float));
    X    = (float *)malloc(lda*n*sizeof(float));
    Y    = (float *)malloc(lda*n*sizeof(float));
    Y0   = (float *)malloc(    n*sizeof(float));
    work = (float *)malloc(  2*n*sizeof(float));

    LAPACKE_slarnv_work(1, ISEED, 1, &alpha0);
    LAPACKE_slarnv_work(1, ISEED, 1, &beta0 );

    /* Check if unable to allocate memory */
    if ( (!A) || (!X) || (!Y0) || (!work) ) {
        printf("Out of Memory \n ");
        exit(0);
    }

     /* Initialize Data */
    PLASMA_splrnt(n, n, A,  lda, 479 );
    PLASMA_splrnt(n, n, X,  lda, 320 );
    PLASMA_splrnt(n, 1, Y0, n,   573 );

    printf("\n");
    printf("------ TESTS FOR PLASMA SPEMV ROUTINE -------  \n");
    printf("\n");
    printf(" The matrix A is randomly generated for each test.\n");
    printf(" The relative machine precision (eps) is %e \n",eps);
    printf(" Computational tests pass if scaled residual is less than eps.\n");
    printf("\n");

    nfails = 0;
    for (i=0; i<6; i++) {

        /* m and n cannot be greater than lda (arg_n) */
        switch (i) {
        case 0: l = 0;       m = arg_n;   n = m;        break;
        case 1: l = 0;       m = arg_n;   n = arg_n/2;  break; /**/
        case 2: l = arg_n;   m = l;       n = l;        break;
        case 3: l = arg_n/2; m = l;       n = arg_n;    break;
        case 4: l = arg_n/2; m = arg_n-l; n = l;        break;
        case 5: l = arg_n/3; m = arg_n-l; n = arg_n/2;  break; /**/
        }

        /* Colwise ConjTrans & Rowwise NoTrans */
#ifdef COMPLEX
        for (t=0; t<3; t++) {
#else
        for (t=0; t<2; t++) {
#endif

            /* Swap m and n for transpose cases */
            if ( t == 1 ) {
                k = m; m = n; n = k;
            }

            LAPACKE_slacpy_work( LAPACK_COL_MAJOR, 'A', m, n,
                                 A, lda, A0, lda);

            if ( trans[t] == PlasmaNoTrans ) {
                storev = PlasmaRowwise;
                cstorev = storevstr[0];

                /* zeroed the upper right triangle */
                int64_t i, j;
                for (j=(n-l); j<n; j++) {
                    for (i=0; i<(j-(n-l)); i++) {
                        A0[i+j*lda] = 0.0;
                    }
                }
            }
            else {
                storev = PlasmaColumnwise;
                cstorev = storevstr[1];

                /* zeroed the lower left triangle */
                int64_t i, j;
                for (j=0; j<(l-1); j++) {
                    for (i=(m-l+1+j); i<m; i++) {
                        A0[i+j*lda] = 0.0;
                    }
                }
            }

            for (j=0; j<3; j++) {

                /* Choose alpha and beta */
                alpha = ( j==1 ) ? 0.0 : alpha0;
                beta  = ( j==2 ) ? 0.0 : beta0;

                /* incx and incy: 1 or lda */
                for (k=0; k<4; k++) {
                    switch (k) {
                    case 0:  incx = 1;    incy = 1;    break;
                    case 1:  incx = 1;    incy = lda;  break;
                    case 2:  incx = lda;  incy = 1;    break;
                    case 3:  incx = lda;  incy = lda;  break;
                    }

                    /* initialize Y with incy */
                    cblas_scopy(n, Y0, 1, Y, incy);

                    /* SPEMV */
                    CORE_spemv( trans[t], storev, m, n, l,
                                alpha, A, lda,
                                       X, incx,
                                beta,  Y, incy,
                                work);

                    /* Check the solution */
                    info_solution = check_solution(trans[t], storev,
                                                   m, n, l,
                                                   alpha, A0,  lda,
                                                          X,   incx,
                                                   beta,  Y0,  1,
                                                          Y,   incy,
                                                   work, &rnorm);

                    if ( info_solution != 0 ) {
                        nfails++;
                        printf("Failed: t=%s, s=%s, M=%3d, N=%3d, L=%3d, alpha=%e, incx=%3d, beta=%e, incy=%3d, rnorm=%e\n",
                               transstr[t], cstorev, m, n, l, (alpha), incx, (beta), incy, rnorm );
                    }
                    nbtests++;
                }
            }
        }
    }

    if ( nfails )
        printf("%d / %d tests failed\n", nfails, nbtests);

    printf("***************************************************\n");
    if (nfails == 0) {
        printf(" ---- TESTING SPEMV ...... PASSED !\n");
    }
    else {
        printf(" ---- TESTING SPEMV ... FAILED !\n");
    }
    printf("***************************************************\n");

    free( A0 );
    free( A );
    free( X );
    free( Y0 );
    free( Y );

    return 0;
}


/* Copyright (c) 2011-2012, Jérémy Fix. All rights reserved. */

/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are met: */

/* * Redistributions of source code must retain the above copyright notice, */
/* this list of conditions and the following disclaimer. */
/* * Redistributions in binary form must reproduce the above copyright notice, */
/* this list of conditions and the following disclaimer in the documentation */
/* and/or other materials provided with the distribution. */
/* * None of the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. */

/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND */
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE */
/* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */
/* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR */
/* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER */
/* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#ifndef UKF_PARAMETER_NDIM_H
#define UKF_PARAMETER_NDIM_H

#include <gsl/gsl_linalg.h> // For the Cholesky decomposition
#include <gsl/gsl_math.h>
#include <gsl/gsl_blas.h>

#include "ukf_types.h"

namespace ukf
{
    namespace parameter
    {

        /**
          * @short Allocation of the vectors/matrices and initialization
          *
          */
        void ukf_init(ukf_param &p, ukf_state &s)
        {
            // Init the lambda
            p.lambda = p.alpha * p.alpha * (p.n + p.kpa) - p.n;
            p.gamma = sqrt(p.n + p.lambda);
            p.nbSamples = 2 * p.n + 1;

            // Init the matrices used to iterate
            s.Kk = gsl_matrix_alloc(p.n,p.no); // Kalman gain
            gsl_matrix_set_zero(s.Kk);

            s.Kk_T = gsl_matrix_alloc(p.no,p.n);
            gsl_matrix_set_zero(s.Kk_T);

            s.Pwdk = gsl_matrix_alloc(p.n,p.no);
            gsl_matrix_set_zero(s.Pwdk);

            // Whatever the type of evolution noise, its covariance is set to evolution_noise
            s.Prrk = gsl_matrix_alloc(p.n,p.n);
            p.evolution_noise->init(p,s);

            // Whatever the type of observation noise, its covariance is set to observation_noise
            s.Peek = gsl_matrix_alloc(p.no,p.no);
            gsl_matrix_set_identity(s.Peek);
            gsl_matrix_scale(s.Peek, p.observation_noise);

            s.Pddk = gsl_matrix_alloc(p.no, p.no); // Covariance of the output
            gsl_matrix_set_zero(s.Pddk);

            s.w = gsl_vector_alloc(p.n); // Parameter vector
            gsl_vector_set_zero(s.w);

            s.wk = gsl_vector_alloc(p.n); // Vector holding one sigma point
            gsl_vector_set_zero(s.wk);

            s.Pk = gsl_matrix_alloc(p.n,p.n); // Covariance matrix
            gsl_matrix_set_identity(s.Pk);
            gsl_matrix_scale(s.Pk,p.prior_pi);

            s.Sk = gsl_matrix_alloc(p.n,p.n); // Matrix holding the cholesky decomposition of Pk
            // Initialize Sk to the cholesky decomposition of Pk
            gsl_matrix_memcpy(s.Sk, s.Pk);
            gsl_linalg_cholesky_decomp(s.Sk);
            // Set all the elements of Lpi strictly above the diagonal to zero
            for(int k = 0 ; k < p.n ; k++)
                for(int j = 0 ; j < k ; j++)
                    gsl_matrix_set(s.Sk,j,k,0.0);

            s.cSk = gsl_vector_alloc(p.n); // Vector holding one column of Lpi
            gsl_vector_set_zero(s.cSk);

            s.wm  = gsl_vector_alloc(p.nbSamples); // Weights used to compute the mean of the sigma points images
            s.wc = gsl_vector_alloc(p.nbSamples); // Weights used to update the covariance matrices

            // Set the weights
            gsl_vector_set(s.wm, 0, p.lambda / (p.n + p.lambda));
            gsl_vector_set(s.wc, 0, p.lambda / (p.n + p.lambda) + (1.0 - p.alpha*p.alpha + p.beta));
            for(int j = 1 ; j < p.nbSamples; j ++)
            {
                gsl_vector_set(s.wm, j, 1.0 / (2.0 * (p.n + p.lambda)));
                gsl_vector_set(s.wc, j, 1.0 / (2.0 * (p.n + p.lambda)));
            }

            s.dk = gsl_matrix_alloc(p.no, p.nbSamples); // Holds the image of the sigma points
            gsl_matrix_set_zero(s.dk);

            s.ino_dk = gsl_vector_alloc(p.no); // Holds the inovation
            gsl_vector_set_zero(s.ino_dk);

            s.d_mean = gsl_vector_alloc(p.no); // Holds the mean of the sigma points images
            gsl_vector_set_zero(s.d_mean);

            s.sigmaPoints = gsl_matrix_alloc(p.n,p.nbSamples); // Holds the sigma points in the columns
            gsl_matrix_set_zero(s.sigmaPoints);

            // Temporary vectors/matrices
            s.vec_temp_n = gsl_vector_alloc(p.n);
            s.vec_temp_output = gsl_vector_alloc(p.no);

            s.mat_temp_n_1 = gsl_matrix_alloc(p.n,1);
            s.mat_temp_n_output = gsl_matrix_alloc(p.n, p.no);
            s.mat_temp_output_n = gsl_matrix_alloc(p.no, p.n);
            s.mat_temp_1_output = gsl_matrix_alloc(1,p.no);
            s.mat_temp_output_1 = gsl_matrix_alloc(p.no, 1);
            s.mat_temp_output_output = gsl_matrix_alloc(p.no, p.no);
            s.mat_temp_n_n = gsl_matrix_alloc(p.n, p.n);
        }

        /**
          * @short Free of memory allocation
          *
          */
        void ukf_free(ukf_param &p, ukf_state &s)
        {
            gsl_matrix_free(s.Kk);
            gsl_matrix_free(s.Kk_T);
            gsl_matrix_free(s.Pwdk);
            gsl_matrix_free(s.Pddk);
            gsl_matrix_free(s.Peek);
            gsl_matrix_free(s.Prrk);

            gsl_vector_free(s.w);
            gsl_vector_free(s.wk);

            gsl_matrix_free(s.Pk);
            gsl_matrix_free(s.Sk);
            gsl_vector_free(s.cSk);

            gsl_vector_free(s.wm);
            gsl_vector_free(s.wc);

            gsl_matrix_free(s.dk);
            gsl_vector_free(s.ino_dk);
            gsl_vector_free(s.d_mean);

            gsl_matrix_free(s.sigmaPoints);

            gsl_vector_free(s.vec_temp_n);
            gsl_vector_free(s.vec_temp_output);

            gsl_matrix_free(s.mat_temp_n_1);
            gsl_matrix_free(s.mat_temp_n_output);
            gsl_matrix_free(s.mat_temp_output_n);
            gsl_matrix_free(s.mat_temp_1_output);
            gsl_matrix_free(s.mat_temp_output_1);

            gsl_matrix_free(s.mat_temp_output_output);
            gsl_matrix_free(s.mat_temp_n_n);
        }

        /**
          * @short Iteration for the statistical linearization
          *
          */
	template<typename GFUNC>
	void ukf_iterate(ukf_param &p, ukf_state &s,
			 GFUNC g,
			 gsl_vector * xk, gsl_vector* dk)
        {

            // Here, we implement the UKF for parameter estimation in the vectorial case
            // The notations follow p93 of the PhD thesis of Van Der Merwe, "Sigma-Point Kalman Filters for Probabilistic Inference in Dynamic State-Space Models"

            // ************************************************** //
            // ************ Time update equations    ************ //
            // ************************************************** //
            // Add the evolution noise to the parameter covariance Eq 3.137
            gsl_matrix_add(s.Pk, s.Prrk);

            // ************************************************** //
            // ************ Compute the sigma points ************ //
            // ************************************************** //
            // Equations 3.138
            // w_k^j = w_(k-1)  <-- this is here denoted s.w
            // w_k^j = w_(k-1) + gamma Sk_j for 1 <= j <= n
            // w_k^j = w_(k-1) - gamma Sk_j for n+1 <= j <= 2n

            // Perform a cholesky decomposition of Pk
            gsl_matrix_memcpy(s.Sk, s.Pk);
            gsl_linalg_cholesky_decomp(s.Sk);
            // Set all the elements of Lpi strictly above the diagonal to zero
            for(int k = 0 ; k < p.n ; ++k)
                for(int j = 0 ; j < k ; ++j)
                    gsl_matrix_set(s.Sk,j,k,0.0);

            gsl_matrix_set_col(s.sigmaPoints,0, s.w);
            for(int j = 1 ; j < p.n+1 ; ++j)
                for(int i = 0 ; i < p.n ; ++i)
                    gsl_matrix_set(s.sigmaPoints, i, j, gsl_vector_get(s.w, i) + p.gamma * gsl_matrix_get(s.Sk,i,j-1));

            for(int j = p.n+1 ; j < p.nbSamples ; ++j)
                for(int i = 0 ; i < p.n ; ++i)
                    gsl_matrix_set(s.sigmaPoints, i, j, gsl_vector_get(s.w, i) - p.gamma * gsl_matrix_get(s.Sk,i,j-(p.n+1)));

            /**************************************************/
            /***** Compute the images of the sigma points *****/
            /**************************************************/

            // Compute the images of the sigma points
            // and the mean of the dk
            gsl_vector_set_zero(s.d_mean);
            for(int j = 0 ; j < p.nbSamples ; j++)
            {
                // Equation 3.129
                gsl_matrix_get_col(s.wk, s.sigmaPoints,j);
                g(s.wk,xk, s.vec_temp_output);
                gsl_matrix_set_col(s.dk, j, s.vec_temp_output);

                // Equation 3.140
                // Update the mean : y_mean = sum_[j=0..2n] w_j y_j
                gsl_vector_scale(s.vec_temp_output, gsl_vector_get(s.wm,j));
                gsl_vector_add(s.d_mean, s.vec_temp_output);
            }

            /**************************************************/
            /************** Update the statistics *************/
            /**************************************************/

            gsl_matrix_set_zero(s.Pwdk);
            gsl_matrix_memcpy(s.Pddk, s.Peek); // Add R^e_k to Pddk, Eq 3.142
            for(int j = 0 ; j < p.nbSamples ; ++j)
            {
                // Update of Pwdk
                // (wk - w)
                gsl_matrix_get_col(s.wk, s.sigmaPoints,j);
                gsl_vector_sub(s.wk, s.w);
                gsl_matrix_set_col(s.mat_temp_n_1, 0, s.wk);

                // (dk - d_mean)
                gsl_matrix_get_col(s.vec_temp_output, s.dk, j);
                gsl_vector_sub(s.vec_temp_output, s.d_mean);
                gsl_matrix_set_col(s.mat_temp_output_1, 0, s.vec_temp_output);

                // compute wc_j . (wk - w_mean) * (dk - d_mean)^T
                gsl_blas_dgemm(CblasNoTrans, CblasTrans, gsl_vector_get(s.wc,j) , s.mat_temp_n_1, s.mat_temp_output_1, 0.0, s.mat_temp_n_output);

                // Equation 3.142
                // And add it to Pwdk
                gsl_matrix_add(s.Pwdk, s.mat_temp_n_output);

                // Equation 3.143
                // Update of Pddk
                gsl_matrix_get_col(s.vec_temp_output, s.dk, j);
                gsl_vector_sub(s.vec_temp_output, s.d_mean);
                gsl_matrix_set_col(s.mat_temp_output_1, 0, s.vec_temp_output);
                gsl_blas_dgemm(CblasNoTrans, CblasTrans, gsl_vector_get(s.wc,j) , s.mat_temp_output_1, s.mat_temp_output_1, 0.0, s.mat_temp_output_output);

                gsl_matrix_add(s.Pddk, s.mat_temp_output_output);
            }

            // ************************************************** //
            // ******* Kalman gain and parameters update ******** //
            // ************************************************** //

            //*** Ki = Pwdk Pddk^-1
            // Compute the inverse of Pddk
            gsl_matrix_memcpy(s.mat_temp_output_output, s.Pddk);
            gsl_linalg_cholesky_decomp(s.mat_temp_output_output);
            gsl_linalg_cholesky_invert(s.mat_temp_output_output);

            // Compute the product : Pwdk . Pddk^-1
            // Equation 3.144
            gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0 , s.Pwdk, s.mat_temp_output_output, 0.0, s.Kk);

            // Update of the parameters
            // wk = w_(k-1) + Kk * (dk - d_mean)
            // Equation 3.145

            // Set the inovations
            /*for(int i = 0 ; i < p.no; ++i)
                s.ino_dk->data[i] = dk->data[i] - s.d_mean->data[i];
            gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0 , s.Kk, &gsl_matrix_view_array(s.ino_dk->data,p.no,1).matrix, 0.0, s.mat_temp_n_1);
            gsl_matrix_get_col(s.vec_temp_n, s.mat_temp_n_1, 0);
            gsl_vector_add(s.w, s.vec_temp_n);*/

            for(int i = 0 ; i < p.no; ++i)
                s.ino_dk->data[i] = dk->data[i] - s.d_mean->data[i];
            gsl_blas_dgemv(CblasNoTrans, 1.0, s.Kk, s.ino_dk, 1.0, s.w);

            // Update of the parameter covariance
            // Pk = P_(k-1) - Kk Pddk Kk^T
            // Equation 3.146
            gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0 , s.Kk, s.Pddk, 0.0, s.mat_temp_n_output);
            gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1.0, s.mat_temp_n_output , s.Kk, 0.0, s.mat_temp_n_n);
            gsl_matrix_sub(s.Pk, s.mat_temp_n_n);

            // Update of the evolution noise
            p.evolution_noise->updateEvolutionNoise(p, s);
        }

        /**
          * @short Evaluation of the output from the sigma points
          *
          */
      void ukf_evaluate(ukf_param &p, ukf_state &s,
			void(*g)(gsl_vector*, gsl_vector*, gsl_vector*),
			gsl_vector * xk, gsl_vector * dk)
        {
            // ************************************************** //
            // ************ Compute the sigma points ************ //
            // ************************************************** //
            // Equations 3.138
            // w_k^j = w_(k-1)  <-- this is here denoted s.w
            // w_k^j = w_(k-1) + gamma Sk_j for 1 <= j <= n
            // w_k^j = w_(k-1) - gamma Sk_j for n+1 <= j <= 2n

            // Perform a cholesky decomposition of Pk
            gsl_matrix_memcpy(s.mat_temp_n_n, s.Pk);
            gsl_linalg_cholesky_decomp(s.mat_temp_n_n);
            // Set all the elements of Lpi strictly above the diagonal to zero
            for(int k = 0 ; k < p.n ; ++k)
                for(int j = 0 ; j < k ; ++j)
                    gsl_matrix_set(s.mat_temp_n_n,j,k,0.0);

            gsl_matrix_set_col(s.sigmaPoints,0, s.w);
            for(int j = 1 ; j < p.n+1 ; ++j)
                for(int i = 0 ; i < p.n ; ++i)
                    gsl_matrix_set(s.sigmaPoints, i, j, gsl_vector_get(s.w, i) + p.gamma * gsl_matrix_get(s.mat_temp_n_n,i,j-1));

            for(int j = p.n+1 ; j < p.nbSamples ; ++j)
                for(int i = 0 ; i < p.n ; ++i)
                    gsl_matrix_set(s.sigmaPoints, i, j, gsl_vector_get(s.w, i) - p.gamma * gsl_matrix_get(s.mat_temp_n_n,i,j-(p.n+1)));

            /**************************************************/
            /***** Compute the images of the sigma points *****/
            /**************************************************/

            // Compute the images of the sigma points
            // and the mean of the dk
            gsl_vector_set_zero(dk);
            for(int j = 0 ; j < p.nbSamples ; j++)
            {
                // Equation 3.129
                gsl_matrix_get_col(s.wk, s.sigmaPoints,j);
                g(s.wk,xk, s.vec_temp_output);
                gsl_matrix_set_col(s.dk, j, s.vec_temp_output);

                // Equation 3.140
                // Update the mean : y_mean = sum_[j=0..2n] w_j y_j
                gsl_vector_scale(s.vec_temp_output, gsl_vector_get(s.wm,j));
                gsl_vector_add(dk, s.vec_temp_output);
            }
        }

        /**
          * @short Returns a set of sigma points
          */
        void getSigmaPoints(ukf_param &p, ukf_state &s, gsl_matrix * sigmaPoints)
        {
            //gsl_matrix * sigmaPoints = gsl_matrix_alloc(p.n, p.nbSamples);

            // ************************************************** //
            // ************ Compute the sigma points ************ //
            // ************************************************** //
            // Equations 3.138
            // w_k^j = w_(k-1)  <-- this is here denoted s.w
            // w_k^j = w_(k-1) + gamma Sk_j for 1 <= j <= n
            // w_k^j = w_(k-1) - gamma Sk_j for n+1 <= j <= 2n

            // Perform a cholesky decomposition of Pk
            gsl_matrix_memcpy(s.mat_temp_n_n, s.Pk);
            gsl_linalg_cholesky_decomp(s.mat_temp_n_n);
            // Set all the elements of Lpi strictly above the diagonal to zero
            for(int k = 0 ; k < p.n ; ++k)
                for(int j = 0 ; j < k ; ++j)
                    gsl_matrix_set(s.mat_temp_n_n,j,k,0.0);

            gsl_matrix_set_col(sigmaPoints,0, s.w);
            for(int j = 1 ; j < p.n+1 ; ++j)
                for(int i = 0 ; i < p.n ; ++i)
                    gsl_matrix_set(sigmaPoints, i, j, gsl_vector_get(s.w, i) + p.gamma * gsl_matrix_get(s.mat_temp_n_n,i,j-1));

            for(int j = p.n+1 ; j < p.nbSamples ; ++j)
                for(int i = 0 ; i < p.n ; ++i)
                    gsl_matrix_set(sigmaPoints, i, j, gsl_vector_get(s.w, i) - p.gamma * gsl_matrix_get(s.mat_temp_n_n,i,j-(p.n+1)));

        }

    } // parameter
} // ukf

#endif // SL_PARAMETER_NDIM_H


// align.h
//
// prototypes for align.cc
//
// dw, 12/12/3

#include <gsl/gsl_matrix.h>

#include "pdb.h"
#include <map>

// find rigid body transformation z=Rx+t minimizing
// least squares error ||y-z||**2
// find rigid body transformation z=Rx+t minimizing
// least squares error ||y-z||**2
void align(gsl_matrix_const_view , gsl_matrix_const_view, gsl_matrix *, gsl_vector *, double *);

double align(vector<atom>&, vector<atom>&, map<int, int>&, int, vector<atom>&,
    vector<atom>&, map<int, int>&, int);


/* StdVarTrajs_Sampling.c

Simulation for calculating allele trajectories, adaptation from standing variation
To be fed into MSMS

Simulation uses routines found with the GNU Scientific Library (GSL)
(http://www.gnu.org/software/gsl/)
Since GSL is distributed under the GNU General Public License
(http://www.gnu.org/copyleft/gpl.html), you must download it
separately from this file.

This program can be compiled with e.g. GCC using a command like:
gcc StdVarTrajs_Sampling -lm -lgsl -lgslcblas -I/usr/local/include -L/usr/local/lib StdVarTrajs_Sampling.c

Then run by executing:
./StdVarTrajs_Sampling N s h x0 reps cutoff
Where:
- N is the (haploid) size
- s is the selection coefficient of the beneficial allele
- h is dominance of the beneficial allele
- x0 is frequency of the allele when it started to be selected for
- reps is how many times the second allele should FIX before simulation stops
(the number of actual runs is greater due to stochastic loss)
- cutoff denotes how high the derived allele can be in the neutral phase ('0' for fixation, '1' for x0 + 1/2N)
*/

/* Preprocessor statements */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stddef.h>
#include <string.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_complex_math.h>
#include <sys/stat.h>
#include <sys/types.h>

#define INITTS 310000

/* Function prototypes */
void geninit(double *geninit, double pee);
void selection(double *geninit, double h, double s);
void reproduction(double *geninit);
void bentraj(double *XFreq, unsigned int *btime, double *genotype, double x0, unsigned int rep, unsigned int N, double s, double h, const gsl_rng *r);
void neutraj(double *NFreq, unsigned int *ntime, double *genotype, double x0, unsigned int rep, unsigned int N, unsigned int cutoff, const gsl_rng *r);
void trajprint(double **AFreq, unsigned int *ttime, unsigned int rep);
void Wait();

/* Initialising genotypes */
void geninit(double *geninit, double pee){

	*(geninit + 0) = (1-pee)*(1-pee);
	*(geninit + 1) = 2*pee*(1-pee);
	*(geninit + 2) = pee*pee;

}	/* End of gen initiation routine */

/* Selection routine (single locus) */
void selection(double *geninit, double h, double s){
	/* Fitness of each genotype */
	double WAA, WAa, Waa;
	double Wmean;				/* Mean fitness */

	Waa = 1;
	WAa = 1 + h*s;
	WAA = 1 + s;

	/* Mean fitness calculation */
	Wmean = ((*(geninit + 0))*Waa) + ((*(geninit + 1))*WAa) + ((*(geninit + 2))*WAA);

	/* Changing frequencies by selection */
	*(geninit + 0) = ((*(geninit + 0))*Waa)/Wmean;
	*(geninit + 1) = ((*(geninit + 1))*WAa)/Wmean;
	*(geninit + 2) = ((*(geninit + 2))*WAA)/Wmean;

}	/* End of selection routine */

/* Reproduction routine */
void reproduction(double *geninit){

	/* Fed-in genotype frequencies (for ease of programming) */
	double gaas, gAas, gAAs;
	/* Haplotypes */
	double xA, xa;

	/* Initial definition of genotypes */
	gaas = *(geninit + 0);
	gAas = *(geninit + 1);
	gAAs = *(geninit + 2);

	/* Baseline change in haplotype frequencies with obligate outcrossing */
	xA = gAAs + (gAas)/2.0;
	xa = gaas + (gAas)/2.0;

	/* Change in frequencies (HWE) */
	*(geninit + 0) = pow(xa,2);
	*(geninit + 1) = 2.0*xA*xa;
	*(geninit + 2) = pow(xA,2);

}	/* End of reproduction routine */

/* Routine to simulate beneficial allele trajectory */
void bentraj(double *XFreq, unsigned int *btime, double *genotype, double x0, unsigned int rep, unsigned int N, double s, double h, const gsl_rng *r){

	unsigned int gt = 1;		/* Generation time */
	unsigned int done = 0;		/* Counter if routine done or not */
	unsigned int exitl = 0;		/* Decide if exit loop or not */
	unsigned int i;				/* Genotype counter */
	double x = 0;				/* Beneficial allele frequency */

	unsigned int *gensamp = calloc(3,sizeof(unsigned int));		/* New population samples */

	while(done == 0){
		exitl = 0;
		gt = 1;
		x = x0;
		*(XFreq + 0) = x0;
		/* Initiating genotypes */
		geninit(genotype,x0);
		while(exitl == 0){

			/* Selection routine */
    		selection(genotype,h,s);

			/* Reproduction routine */
    		reproduction(genotype);

    		/* Sampling based on new frequencies */
	       	gsl_ran_multinomial(r,3,N,genotype,gensamp);
       		for(i = 0; i < 3; i++){
    	   		*(genotype + i) = (*(gensamp + i))/(1.0*N);
	       	}

	       	x = 0.5*(*(genotype + 1)) + (*(genotype + 2));
			*(XFreq + gt) = x;
			gt += 1;
			if(gt > INITTS){
				fprintf(stderr,"Number of generations in selection trajectory exceed vector length (INITTS).\n");
				exit(1);
			}

			if( (x == 1) || (x == 0) ){
				exitl = 1;
			}
		}

		if(x == 1){
			done = 1;
			*(btime + rep) = (gt - 1);
		}
	}

	free(gensamp);

}

/* Routine to simulate neutral allele trajectory */
void neutraj(double *NFreq, unsigned int *ntime, double *genotype, double x0, unsigned int rep, unsigned int N, unsigned int cutoff, const gsl_rng *r){

	unsigned int gt = 1;		/* Generation time */
	unsigned int done = 0;		/* Counter if routine done or not */
	unsigned int exitl = 0;		/* Decide if exit loop or not */
	unsigned int i;				/* Genotype counter */
	double x = 0;				/* Neutral allele frequency */
	double xmax = 1;			/* Value of x to use as maximum cutoff */

	unsigned int *gensamp = calloc(3,sizeof(unsigned int));		/* New population samples */

	if(cutoff == 0){
		xmax = 1;
	}else if(cutoff == 1){
		xmax = x0 + (1.0/(2.0*N));
		if(xmax > 1){
			xmax = 1;
		}
	}
/*	printf("xmax is %lf\n",xmax);	*/

	while(done == 0){
		exitl = 0;
		gt = 0;		/* Note start from zero here since x0 case defined in selection trajectory */
		x = x0;

		/* Initiating genotypes */
		geninit(genotype,x0);

		while(exitl==0){

			/* Reproduction routine */
    		reproduction(genotype);

			/* Random sampling of allele frequencies (drift) */
	       	gsl_ran_multinomial(r,3,N,genotype,gensamp);
       		for(i = 0; i < 3; i++){
    	   		*(genotype + i) = (*(gensamp + i))/(1.0*N);
	       	}
	       	x = 0.5*(*(genotype + 1)) + (*(genotype + 2));
			*(NFreq + gt) = x;

			gt++;
			if(gt > INITTS){
				printf("Number of generations in neutral trajectory exceed vector length (INITTS).\n");
				exit(1);
			}

			if( (x == 0) || (x >= xmax) ){
				exitl = 1;
			}
		}

		if(x == 0){
			done = 1;
			*(ntime + rep) = (gt - 1);
		}
	}

	free(gensamp);

}

/* Print out trajectories to file */
void trajprint(double **AFreq, unsigned int *ttime, unsigned int rep){
	unsigned int j;
	char filename[32];
	FILE *ofp_tr;				/* Pointer for file output */

	sprintf(filename,"Traj/ATraj%d.dat",(rep + 1));
	ofp_tr = fopen(filename,"w");

	for(j = 0; j < *(ttime + rep); j++){
		fprintf(ofp_tr,"%lf %lf %lf\n",*((*(AFreq + 0)) + j),*((*(AFreq + 1)) + j),*((*(AFreq + 2)) + j));
	}

	fclose(ofp_tr);

}

void Wait(){
	printf("Press Enter to Continue");
	while( getchar() != '\n' );
	printf("\n");
}

/* Main program */
int main(int argc, char *argv[]){

	/* Declare variables here */
	unsigned int i, a;			/* Rep counter, memory counter */
	unsigned int N = 0;			/* Population Size */
	unsigned int Nreps = 0;		/* Number of repetitions */
	unsigned int acc = 0;		/* Accumulator (when merging two trajectories) */
	unsigned int es = 10;		/* How many extra steps to put in the trajectory files */
	unsigned int cutoff = 0;	/* What kind of back-in-time cutoff to use */
	int j;						/* Timestep counter */
	double s = 0;				/* Strength of selection */
	double h = 0;				/* Dominance level */
	double x0 = 0;				/* Initial allele frequency */
	double lim = 0;				/* Limit of acceptable allele frequencies */
	double dx = 0;				/* Rescaled timestep so can be used by MSMS */
	FILE *ofp_sd;				/* Pointer for seed output */

	/* GSL random number definitions */
	const gsl_rng_type * T;
	gsl_rng * r;

	/* Reading in data from command line */
	/* <Program> N s h x0 NReps cutoff */
	if(argc != 7){
		fprintf(stderr,"Six inputs are needed (N s h x0 Reps cutoff).\n");
		exit(1);
	}

	N = atoi(argv[1]);
	if(N <= 0){
		fprintf(stderr,"Total Population size N is zero or negative, not allowed.\n");
		exit(1);
	}

	/* Defining min frequency limit ** based on unscaled N ** */
	lim = (1.0/(1.0*N));

	/* Defining timestep, dx = 1/4N since that's what MSMS uses */
	dx = (1.0/(4.0*N));

	s = strtod(argv[2],NULL);
	if(s < 0){
		fprintf(stderr,"Allele strength s is negative, not allowed.\n");
		exit(1);
	}

	h = strtod(argv[3],NULL);
	if(h < 0 || h > 1){
		fprintf(stderr,"Dominance value must lie between 0 and 1.\n");
		exit(1);
	}

	x0 = strtod(argv[4],NULL);
	if(x0 < lim || x0 > (1-lim)){
		fprintf(stderr,"Initial mutant frequency must lie between %0.5lf and %0.5lf.\n",lim,1-lim);
		exit(1);
	}

	/* Number of samples/reps to take */
	Nreps = atoi(argv[5]);
	if(Nreps <= 0){
		fprintf(stderr,"Must set positive number of repetitions.\n");
		exit(1);
	}

	/* Determining cutoff */
	cutoff = atoi(argv[6]);
	if(!(cutoff == 0 || cutoff == 1)){
		fprintf(stderr,"'Cutoff' switch must equal 0 or 1.\n");
		exit(1);
	}

	unsigned int *btime = calloc(Nreps,sizeof(unsigned int));			/* Number of generations needed for ben allele fixation */
	unsigned int *ntime = calloc(Nreps,sizeof(unsigned int));			/* Number of generations needed for neut allele loss */
	unsigned int *ttime = calloc(Nreps,sizeof(unsigned int));			/* Number of generations needed for whole processes */
	double *genotype = calloc(3,sizeof(double));						/* Genotype frequencies */

	/* create a generator chosen by the
    environment variable GSL_RNG_TYPE */

	gsl_rng_env_setup();
	if (!getenv("GSL_RNG_SEED")) gsl_rng_default_seed = time(0);
	T = gsl_rng_default;
	r = gsl_rng_alloc(T);
	ofp_sd = fopen("Seed.dat","w");
	fprintf(ofp_sd,"%lu\n",gsl_rng_default_seed);
	fclose(ofp_sd);

	mkdir("Traj/", 0777);

	/* Executing simulation */
	for(i = 0; i < Nreps; i++){

		if(Nreps > 100){
			if(i%100 == 0){
				printf("Starting run %d\n",i);
			}
		}

		double *XFreq = calloc(INITTS,sizeof(double));			/* Beneficial allele frequency */
		double *NFreq = calloc(INITTS,sizeof(double));			/* Neutral allele frequency */

		/* Simulating beneficial trajectories */
		bentraj(XFreq, btime, genotype, x0, i, N, s, h, r);

		/* Simulation neutral trajectory */
		neutraj(NFreq, ntime, genotype, x0, i, N, cutoff, r);

		*(ttime + i) = (*(btime+i)) + (*(ntime+i) + 2 + es);
/*		printf("%d %d %d\n",*(btime+i),*(ntime+i),*(ttime+i));	*/

		/* Defining memory for AFreq */
		double **AFreq = calloc(3,sizeof(double *));					/* Allele frequency over time */
		for(a = 0; a < 3; a++){											/* Assigning space for each run */
			AFreq[a] = calloc(*(ttime + i),sizeof(double));
		}

		/* Merging trajectories
		Timing is set up so tfix = 0
		And discrete generations is scaled by timestep, dx
		*/

		/* First add ten timesteps for x = 0
		So trajectory fully covered in MSMS */
		acc = 0;
		for(j = 0; j < es; j++){
			*((*(AFreq + 0)) + j) = ((*(ttime + i) - es - 1)*dx) + (es - j);
			*((*(AFreq + 1)) + j) = 1.0;
			*((*(AFreq + 2)) + j) = 0.0;
		}
		for(j = *(ntime + i); j >= 0; j--){
			*((*(AFreq + 0)) + acc + es) = (*(ttime + i) - acc - es - 1)*dx;
			*((*(AFreq + 1)) + acc + es) = 1.0-(*(NFreq + j));
			*((*(AFreq + 2)) + acc + es) = *(NFreq + j);
			acc++;
		}
		for(j = 0; j <= *(btime + i); j++){
			*((*(AFreq + 0)) + acc + es) = (*(ttime + i) - acc - es - 1)*dx;
			*((*(AFreq + 1)) + acc + es) = 1.0-(*(XFreq + j));
			*((*(AFreq + 2)) + acc + es) = *(XFreq + j);
			acc++;
		}
		/*
		*(ttime + i) = (acc-1);
		printf("%d\n",*(ttime+i));
		*/

		free(NFreq);
		free(XFreq);

		/* Printout of trajectories */
		trajprint(AFreq, ttime, i);

		for(a = 0; a < 3; a++){
	 		free(AFreq[a]);
		}
		free(AFreq);

	}

	gsl_rng_free(r);
	free(genotype);
	free(ttime);
	free(ntime);
	free(btime);

	return 0;

}	/* End of main program */

/* End of File */


#include <stdlib.h>
#include <cblas.h>

#include "tasks.h"

void syrk_task_par_reconfigure(int nth)
{
    // empty
}

void syrk_task_par_finalize(void)
{
    // empty
}

void syrk_task_par(void *ptr, int nth, int me)
{
    struct syrk_task_arg *arg = (struct syrk_task_arg*) ptr;

    int n       = arg->n;
    int k       = arg->k;
    double *A21 = arg->A21;
    double *A22 = arg->A22;
    int ldA     = arg->ldA;

    // Balance the load by flops.
    int part[nth + 1];
    const int total_work = n * (n + 1) / 2;
    const int ideal_part_work = total_work / nth;
    part[0] = 0;
    part[nth] = n;
    for (int k = 1; k < nth; ++k) {
        part[k] = part[k - 1];
        int work = 0;
        while (work < ideal_part_work && part[k] < n) {
            work += n - part[k];
            part[k] += 1;
        }
    }

    const int my_first_col = part[me];
    const int my_num_cols  = part[me + 1] - part[me];
    const int i1 = my_first_col;
    const int i2 = i1 + my_num_cols;
    const int m2 = n - i2;

    // TODO Insert picture (see krnl_syrk in task_chol_par).

    if (my_num_cols > 0) {
        cblas_dsyrk(CblasColMajor, CblasLower, CblasNoTrans,
                    my_num_cols, k,
                    -1.0, A21 + i1,                           ldA,
                     1.0, A22 + i1 + my_first_col * ldA,      ldA);
    }

    if (m2 > 0) {
        cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans,
                    m2, my_num_cols, k,
                    -1.0, A21 + i2,                      ldA,
                          A21 + my_first_col,            ldA,
                     1.0, A22 + i2 + my_first_col * ldA, ldA);
    }
}


/**
* Drizzle utilities
*/

#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_statistics.h>
#include <math.h>

#include "aXe_grism.h"
#include "aXe_utils.h"
#include "spc_trace_functions.h"
#include "crossdisp_utils.h"
#include "aper_conf.h"
#include "trace_conf.h"
#include "disp_conf.h"
#include "spc_wl_calib.h"
#include "drizzle_utils.h"

d_point
get_refwave_position(dispstruct * disp, trace_func * trace, d_point refpix,
                     aperture_conf *conf)
{
  double a=0.0;
  double b, c, c_star;
  double *cf;
  double rot;
  double dx, dy, dtr;
  d_point res;

  // check for a dispersion solution
  // higher that quadratic order
  if (disp->pol->size > 3)
    // this can not be solved; give an error
    aXe_message(aXe_M_FATAL, __FILE__, __LINE__,
                "Order of dispersion solution: %i!\n"
                "At most qudratic solutions are allowed!\n",
                disp->pol->size-1);
  else if (disp->pol->size > 2)
    // store the quadratic term, if it exists
    a = gsl_vector_get(disp->pol, 2);  // ddlambda-term
  else
    // set the qudratic term to zero
    a=0.0;

  // store the constant and linear terms
  b = gsl_vector_get(disp->pol, 1);  // dlambda-term
  c = gsl_vector_get(disp->pol, 0);  // lambda0-term

  // store the dydx value
  cf = trace->data;

  // dydx -->  rotation angle
  rot = get_rotation_angle(cf[2]);

  // determine the wavelength difference
  c_star = c - conf->drz_lamb0;

  // transform the wavelength difference
  // into a path length difference
  if (a)
    dtr = (-1.0*b+sqrt(b*b - 4.0*a*c_star))/(2.0*a);
  else
    dtr = c_star/b;

  // path length difference --> dx, dy
  dx = dtr*cos(rot);
  dy = dtr*sin(rot);

  // compute the absolute values
  // for the reference position
  // in the stamp images
  res.x = refpix.x + dx;
  res.y = refpix.y + dy;

  // return the result
  return res;
}

double
get_drizzle_width(object *ob, int beamnum,trace_func * trace)
{
  double drizzle_width, drizzle_orient;
  double orig_width, orig_orient;
  double rotation, angle, oangle, factor;
  double *cf;
  beam *b = ob->beams+beamnum;

  cf = trace->data;
  rotation = get_rotation_angle(cf[2]);

  orig_orient = b->orient;
  orig_width  = b->width;

  drizzle_orient = orig_orient-rotation;

  angle  = drizzle_orient / M_PI * 180.;
  oangle = orig_orient / M_PI * 180.;

  drizzle_width = fabs(orig_width * sin (drizzle_orient));
  factor = drizzle_width/orig_width;

  if (angle > 180.0)
    angle = angle-180.0;
  if (angle < 30.0 || angle > 150.0)
     fprintf (stdout,
              "Angle: %4.0f --> %4.0f, Width: %5.1f --> %5.1f, %5.3f\n",
              oangle, angle, orig_width, drizzle_width, factor);

  return drizzle_width;
}

gsl_matrix  *
get_drizzle_coeffs(dispstruct * disp, trace_func * trace,
                   int boxwidth, int boxheight, int trlength,
                   double relx, double rely, aperture_conf *conf,
                   double orient, dispstruct * outdisp, double cdcorr,
                   double sprefreso, double spmeanreso)
{
  double a, b, c;
  double ao, bo, co, bref, cref;
  double a11, a12, a21, a22;
  double xr, yr;
  //double lambda0;
  //double dlambda;
  double tmp, rotation;
  double *cf;
  double shear_term;

  gsl_matrix * ret = gsl_matrix_alloc(2,11);
  gsl_matrix * rotcoeffs;

  gsl_matrix_set_all (ret, 0.0);

  /* get the dispersion at the objects point */
  if (disp->pol->size > 2)
    a = gsl_vector_get(disp->pol, 2);
    //    fprintf (stdout, "quadratic solution:  %f\n", a);
  else
    a = 0.0;

  b = gsl_vector_get(disp->pol, 1);  // dlambda-term
  c = gsl_vector_get(disp->pol, 0);  // lambda0-term

  /* get the dispersion at the mean reference point */
  if (outdisp->pol->size > 2){
    ao = gsl_vector_get(outdisp->pol, 2);
    //    fprintf (stdout, "quadratic solution:  %f, old: %f\n", a, ao);
  }
  else{
    ao = 0.0;
  }
  bo = gsl_vector_get(outdisp->pol, 1);  // dlambda-term
  co = gsl_vector_get(outdisp->pol, 0);  // lambda0-term
  if (conf->drz_resol == 0.0) {
    conf->drz_resol = bo + ao*((double)trlength)/2.0;
  }
  if (conf->drz_lamb0 == 0.0) {
    conf->drz_lamb0 = co;
  }

  //  fprintf (stdout, "lambda terms:  4785.0 <-> %f, 24.0 <-> %f\n", cref, bref);

  cref = conf->drz_lamb0;
  bref = conf->drz_resol;
  bref = sprefreso;

  // Bugfix on Sept. 15th 2010:
  // Check whether the ratio of the average dispersion on the grism images
  // and the dispersion on the drizzled images is outsidethe range 0.95 < ratio < 1.05.
  // If yes, adjust "trlength" which, from now on, is the length of the
  // drizzled image. This fix is necessary to allow a different sampling
  // in axedrizzle. The range was introduced such that the bug-fixed
  // version delivers identical results when using the default sampling.
  if ((spmeanreso / sprefreso > 1.05) || (spmeanreso / sprefreso < 0.95))
    trlength = (int)(spmeanreso / sprefreso * (double)trlength) + 0.5;

  /* put the below lines to go BACK to
   * the old computation of the length of
   * the aXedrizzled images:
  fprintf(stdout, "New spectral length: %i", trlength);
  trlength = (int)ceil(bo/bref*sqrt(pow((double)boxwidth,2.0)
                                    +pow((double)boxheight,2.0)));
  trlength = (int)ceil(spmeanreso/sprefreso*sqrt(pow((double)boxwidth,2.0)
                                                 +pow((double)boxheight,2.0)));
  fprintf(stdout, "<--> old spectral length: %i\n", trlength);
  */

  //fprintf (stdout,"Drizzled to resolution: %e, mean resolution for object: %e\n", sprefreso, spmeanreso);

  gsl_matrix_set(ret, 0,10,trlength);
  //  gsl_matrix_set(ret, 1,10,bref);

  cf = trace->data;
  rotation = get_rotation_angle(cf[2]);
  rotcoeffs = get_coeffs_back(trace);
  a11 = gsl_matrix_get(rotcoeffs,0,0);
  a12 = gsl_matrix_get(rotcoeffs,0,1);
  a21 = gsl_matrix_get(rotcoeffs,1,0);
  a22 = gsl_matrix_get(rotcoeffs,1,1);

  // the following lines have to be changed
  // in order to go from a integer
  // center definition to floating point center
  // definition.
  xr = (relx+1.0)-((double)(boxwidth/2)+1);  // +1.0 to compensate for "sp_sex.c" around line 537
  yr = (rely+1.0)-((double)(boxheight/2)+1); // +1.0 to compensate for "sp_sex.c" around line 537

  if (b < 0.0)
    shear_term = -tan(orient-rotation);
  else
    shear_term = tan(orient-rotation);

  // Transformations for X, without the lambda-terms, only rotation:
  //  tmp = xoffs-(((double)trlength/2.0)+1)-a11*xr-a12*yr;
  //  gsl_matrix_set(ret, 0,0,tmp);  // constant term

  //  tmp = a11;
  //  gsl_matrix_set(ret, 0,1,tmp);  // x-term

  //  tmp = a12;
  //  gsl_matrix_set(ret, 0,2,tmp);  // y-term
  //----------------------------------------------------------------------------------

  //------------------------------------------------------------------
  // Mathematica based run
  tmp = 1.0/bref*(c - cref - a11*b*xr + a*a11*a11*xr*xr - a12*b*yr + 2*a*a11*a12*xr*yr + a*a12*a12*yr*yr) +
    (a21*xr + a22*yr)/shear_term - ((double)(trlength/2)+1.0) + conf->drz_xstart;
  gsl_matrix_set(ret, 0,0,tmp);  // constant term

  tmp = 1.0/bref*(a11*b - 2*a*a11*a11*xr - 2*a*a11*a12*yr) - a21/shear_term;
  gsl_matrix_set(ret, 0,1,tmp);  // x-term

  tmp = 1.0/bref*(a12*b - 2*a*a12*a12*yr - 2*a*a11*a12*xr) - a22/shear_term;
  gsl_matrix_set(ret, 0,2,tmp);  // y-term

  tmp = a*a11*a11/bref;
  gsl_matrix_set(ret, 0,3,tmp);  // x^2-term

  tmp = 2*a*a11*a12/bref;
  gsl_matrix_set(ret, 0,4,tmp); ; // xy-term

  tmp = a*a12*a12/bref;
  gsl_matrix_set(ret, 0,5,tmp);  // y^2-term

  //------------------------------------------------------------------

  // Transformations for Y:
  tmp = -1.0*(a21*xr+a22*yr) * cdcorr; // -1.5  is some kind of a fudge factor, no idea where it comes from
  gsl_matrix_set(ret, 1,0,tmp);  // constant term

  tmp = a21 * cdcorr;
  gsl_matrix_set(ret, 1,1,tmp);  // x-term

  tmp = a22 * cdcorr;
  gsl_matrix_set(ret, 1,2,tmp);  // y-term

  gsl_matrix_free(rotcoeffs);

  return ret;
}

gsl_matrix *
get_coeffs_back(trace_func * trace)
{
  double *cf;
  double rotation;
  gsl_matrix * ret = gsl_matrix_alloc(2,2);

  //  ret = gsl_matrix_alloc (2,2);
  gsl_matrix_set_all (ret, 0.0);

  cf = trace->data;

  rotation = get_rotation_angle(cf[2]);

  gsl_matrix_set(ret, 0, 0,      cos(rotation));
  gsl_matrix_set(ret, 0, 1,      sin(rotation));
  gsl_matrix_set(ret, 1, 0, -1.0*sin(rotation));
  gsl_matrix_set(ret, 1, 1,      cos(rotation));

  return ret;
}

double
get_rotation_angle(double dxdy){
  double rotation=0.0;

  rotation = atan2(dxdy, 1.0);

  return rotation;
}

// Start functions for an alternative approach to store the object information
objectobs **
malloc_objectobs(){
  objectobs **allobjects;

  allobjects = (objectobs **) malloc (NMAXOBJ*sizeof(objectobs *));

  return allobjects;
}

void
free_objectobs(objectobs **allobjects){
  //  int i, nobjs=0;
  //  while (allobjects[nobjs])
  //    nobjs++;
  //  for (i=0; i<nobjs; i++){
  //      free(allobjects[i]);
  //      //    allobjects[i] = NULL;
  //  }
  free(allobjects);
}

int
add_observation(char * filename, char *  conf_file, objectobs ** allobjects, int nobjects,
                object ** oblist, int list_size, px_point pixmax, int sci_numext)
{

  int i, j, dec;
  int beamID = 0;
  int get_scale=0;
  int tlength;
  gsl_matrix * drzcoeffs;
  double cdscale;
  double drzscale;
  dispstruct * disp;
  calib_function *wl_calib;
  double l1, l2, spreso;

  drzcoeffs = get_crossdisp_matrix(filename, sci_numext);

  if (drzcoeffs->size1 > 1 && drzcoeffs->size2)
    get_scale = 1;

  if (get_scale){
    drzscale =  (double)get_float_from_keyword(filename, 1, "DRZSCALE");
  }
  for (i=0; i < list_size; i++){
    if (oblist[i]->beams[beamID].ignore == 0){
      dec = 0;

      if (get_scale)
        cdscale = drzscale * get_crossdisp_scale(oblist[i]->beams[beamID].spec_trace,
                                                 oblist[i]->beams[beamID].refpoint, drzcoeffs, pixmax);
      else
        cdscale=1.0;

      disp = get_dispstruct_at_pos(conf_file, 1, beamID,oblist[i]->beams[beamID].refpoint);
      wl_calib = create_calib_from_gsl_vector(1, disp->pol);
      l1 =  wl_calib->func (0.0,  wl_calib->order,  wl_calib->coeffs);
      l2 =  wl_calib->func (1.0,  wl_calib->order,  wl_calib->coeffs);
      spreso = fabs(l2-l1);

      // compute the tracelength
      tlength = get_beam_trace_length(oblist[i]->beams[beamID]);

      for (j=0; j < nobjects; j++){
        if (allobjects[j]->OBJID == oblist[i]->ID){
          add_obs_to_allobj(allobjects[j], oblist[i], pixmax, cdscale, spreso, tlength);
          dec = 1;
        }
      }
      if (dec == 0) {
        nobjects = add_obj_to_allobj(allobjects, nobjects, oblist[i], pixmax, cdscale, spreso, tlength);
      }
      free_dispstruct(disp);
      free_calib(wl_calib);
    }
  }
  gsl_matrix_free(drzcoeffs);
  return nobjects;
}

void
add_obs_to_allobj(objectobs *actobject, object * actobs, px_point pixmax, double cdscale, double spreso, int tlength)
{

  int xmin, xmax, ymin, ymax;
  //double m, b;
  gsl_vector_int * xvec;
  gsl_vector_int * yvec;
  px_point bbox;
  px_point mins;

  double *gaga;

  xvec = gsl_vector_int_alloc (4);
  yvec = gsl_vector_int_alloc (4);

  /* Store the refpoint */
  actobject->refpoint[actobject->nobs].x = actobs->beams[0].refpoint.x;
  actobject->refpoint[actobject->nobs].y = actobs->beams[0].refpoint.y;

  //*************************************************
  // patch to correct the reference point in case
  // that the the trace descritpion
  // does have a non negligeable first order term!
  gaga = actobs->beams[0].spec_trace->data;
  actobject->refpoint[actobject->nobs].y = actobject->refpoint[actobject->nobs].y + gaga[1];
  //*************************************************

  gsl_vector_int_set(xvec, 0, actobs->beams[0].corners[0].x);
  gsl_vector_int_set(xvec, 1, actobs->beams[0].corners[1].x);
  gsl_vector_int_set(xvec, 2, actobs->beams[0].corners[2].x);
  gsl_vector_int_set(xvec, 3, actobs->beams[0].corners[3].x);
  xmin = gsl_stats_int_min(xvec->data, 1, 4);
  xmax = gsl_stats_int_max(xvec->data, 1, 4);
  gsl_vector_int_set(yvec, 0, actobs->beams[0].corners[0].y);
  gsl_vector_int_set(yvec, 1, actobs->beams[0].corners[1].y);
  gsl_vector_int_set(yvec, 2, actobs->beams[0].corners[2].y);
  gsl_vector_int_set(yvec, 3, actobs->beams[0].corners[3].y);
  ymin = gsl_stats_int_min(yvec->data, 1, 4);
  ymax = gsl_stats_int_max(yvec->data, 1, 4);

  bbox = recalc_bbox(xmin, xmax, ymin, ymax, pixmax);
  mins = recalc_mins(xmin, xmax, ymin, ymax, pixmax);

  actobject->width[actobject->nobs]    = bbox.x;
  actobject->height[actobject->nobs]   = bbox.y;
  actobject->tlength[actobject->nobs]  = tlength;
  actobject->objwidth[actobject->nobs] = actobs->beams[0].width;
  actobject->orient[actobject->nobs]   = actobs->beams[0].orient;
  actobject->cdscale[actobject->nobs]   = cdscale;
  actobject->spreso[actobject->nobs]   = spreso;

  actobject->relrefpt[actobject->nobs].x = actobs->beams[0].refpoint.x - (double)mins.x;
  actobject->relrefpt[actobject->nobs].y = actobs->beams[0].refpoint.y - (double)mins.y;

  actobject->nobs = actobject->nobs + 1;

  gsl_vector_int_free(xvec);
  gsl_vector_int_free(yvec);
}

int
add_obj_to_allobj(objectobs **allobjects, int nobjects, object * actobs,
                   px_point pixmax, double cdscale, double spreso, int tlength)
{
  int xmin, xmax, ymin, ymax;
  //double m, b;

  gsl_vector_int * xvec;
  gsl_vector_int * yvec;

  px_point bbox;
  px_point mins;

  double *gaga;

  //  object *ob = malloc (sizeof (object));
  objectobs *objobs = malloc (sizeof (objectobs));

  xvec = gsl_vector_int_alloc (4);
  yvec = gsl_vector_int_alloc (4);

  allobjects[nobjects] = objobs;
  /* Store the refpoint */
  allobjects[nobjects]->refpoint[0].x = actobs->beams[0].refpoint.x;
  allobjects[nobjects]->refpoint[0].y = actobs->beams[0].refpoint.y;

  //*************************************************
  // patch to correct the reference point in case
  // that the the trace descritpion
  // does have a non negligeable first order term!
  gaga = actobs->beams[0].spec_trace->data;
  allobjects[nobjects]->refpoint[0].y = allobjects[nobjects]->refpoint[0].y + gaga[1];
  //*************************************************

  allobjects[nobjects]->OBJID = actobs->ID;
  allobjects[nobjects]->nobs = 1;
  allobjects[nobjects]->pointer = 0;

  gsl_vector_int_set(xvec, 0, actobs->beams[0].corners[0].x);
  gsl_vector_int_set(xvec, 1, actobs->beams[0].corners[1].x);
  gsl_vector_int_set(xvec, 2, actobs->beams[0].corners[2].x);
  gsl_vector_int_set(xvec, 3, actobs->beams[0].corners[3].x);
  xmin = gsl_stats_int_min(xvec->data, 1, 4);
  xmax = gsl_stats_int_max(xvec->data, 1, 4);

  gsl_vector_int_set(yvec, 0, actobs->beams[0].corners[0].y);
  gsl_vector_int_set(yvec, 1, actobs->beams[0].corners[1].y);
  gsl_vector_int_set(yvec, 2, actobs->beams[0].corners[2].y);
  gsl_vector_int_set(yvec, 3, actobs->beams[0].corners[3].y);
  ymin = gsl_stats_int_min(yvec->data, 1, 4);
  ymax = gsl_stats_int_max(yvec->data, 1, 4);

  bbox = recalc_bbox(xmin, xmax, ymin, ymax, pixmax);
  mins = recalc_mins(xmin, xmax, ymin, ymax, pixmax);

  allobjects[nobjects]->width[0]   = bbox.x;
  allobjects[nobjects]->height[0]  = bbox.y;
  allobjects[nobjects]->tlength[0] = tlength;
  allobjects[nobjects]->objwidth[0] = actobs->beams[0].width;
  allobjects[nobjects]->orient[0]   = actobs->beams[0].orient;
  allobjects[nobjects]->cdscale[0]  = cdscale;
  allobjects[nobjects]->spreso[0]   = spreso;

  allobjects[nobjects]->relrefpt[0].x = actobs->beams[0].refpoint.x - (double)mins.x;
  allobjects[nobjects]->relrefpt[0].y = actobs->beams[0].refpoint.y - (double)mins.y;

  ++nobjects;

  gsl_vector_int_free(xvec);
  gsl_vector_int_free(yvec);

  return nobjects;
}

void print_objectobs(objectobs **allobjects, int nobjects){
  int i, j;

  for (i = 0; i < nobjects; i++){
   fprintf(stdout, "OBJID: %i, no of observ.: %i\n", allobjects[i]->OBJID, allobjects[i]->nobs);
    for (j = 0; j < allobjects[i]->nobs; j++){
      fprintf(stdout, "No %i: width %f, height: %f, \n", j, allobjects[i]->relrefpt[j].x, allobjects[i]->relrefpt[j].y);
    }
  }
}
void print_objectobs2(objectobs allobjects[], int nobjects){
  int i, j;

  for (i = 0; i < nobjects; i++){
   fprintf(stdout, "OBJID: %i, no of observ.: %i\n", allobjects[i].OBJID, allobjects[i].nobs);
    for (j = 0; j < allobjects[i].nobs; j++){
      fprintf(stdout, "No %i: width %f, height: %f, \n", j, allobjects[i].relrefpt[j].x, allobjects[i].relrefpt[j].y);
    }
  }
}
int make_refpoints( char * conf_file, char * filename, px_point pixmax, objectobs **allobjects, int nobjects)
{
  int i, j;
  int nobs;
  int max_width, max_height, omax;
  double xmean, ymean;
  //double xdata[NMAXOBS];
  //double ydata[NMAXOBS];
  //  objectobs  oneobject;
  objectobs *oneobject; // = malloc (sizeof (objectobs));

  gsl_vector * xvec;
  gsl_vector * yvec;
  aperture_conf *conf;
  gsl_matrix * drzcoeffs;
  //double cdscale;
  double drzscale;
  trace_func  *trace;
  int beamID=0;
  dispstruct * disp;
  calib_function *wl_calib;
  double l1, l2;

  conf = get_aperture_descriptor(conf_file);
  get_extension_numbers(filename, conf,conf->optkey1,conf->optval1);
  drzcoeffs = get_crossdisp_matrix(filename,conf->science_numext);
  drzscale =  (double)get_float_from_keyword(filename, 1, "DRZSCALE");

  for (i=0; i < nobjects; i++){
    oneobject = allobjects[i];
    nobs = oneobject->nobs;

    xvec = gsl_vector_alloc (nobs);
    yvec = gsl_vector_alloc (nobs);
    for (j=0; j < nobs; j++){
      gsl_vector_set(xvec, j, oneobject->refpoint[j].x);
      gsl_vector_set(yvec, j, oneobject->refpoint[j].y);
    }
    xmean = gsl_stats_mean(xvec->data, 1, nobs);
    ymean = gsl_stats_mean(yvec->data, 1, nobs);

    max_width  = gsl_stats_int_max(oneobject->width,  1, nobs);
    max_height = gsl_stats_int_max(oneobject->height, 1, nobs);
    omax       = gsl_stats_max(oneobject->objwidth, 1, nobs);

    allobjects[i]->mean_refpoint.x = xmean;
    allobjects[i]->mean_refpoint.y = ymean;
    allobjects[i]->max_width  = max_width;
    allobjects[i]->max_height = max_height;
    allobjects[i]->owidthmax  = omax;

    allobjects[i]->max_tlength = gsl_stats_int_max(oneobject->tlength, 1, nobs);

    /*
     * Look whether the cross dispersion scale is given in the configuration.
     * If not determine the cross dispersion scale at the mean reference point an store it
     * store also the mean correction in for to correct the width.
     *
     */
    if (conf->drz_scale < 1.0e-16){
      trace = get_tracefunc_at(conf_file, allobjects[i]->mean_refpoint);
      allobjects[i]->cdrefscale = drzscale * get_crossdisp_scale(trace, allobjects[i]->mean_refpoint, drzcoeffs, pixmax);
    }
    else{
      allobjects[i]->cdrefscale = conf->drz_scale;
    }
    for (j=0; j < nobs; j++){
      gsl_vector_set(xvec, j, oneobject->cdscale[j]);
    }
    xmean = gsl_stats_mean(xvec->data, 1, nobs);
    allobjects[i]->cdmeanscale  = xmean;

    /*
     * look whether the wavelength dispersion is given in the conig file
     * if not determine the wavelength dispersion at the mean reference point amd store
     * it. Store also the mean wavelength dispersion to correct the length
     */
    if (conf->drz_resol < 1.0e-16){
      disp = get_dispstruct_at_pos(conf_file, 1, beamID, allobjects[i]->mean_refpoint);
      wl_calib = create_calib_from_gsl_vector(1, disp->pol);
      l1 =  wl_calib->func (0.0,  wl_calib->order,  wl_calib->coeffs);
      l2 =  wl_calib->func (1.0,  wl_calib->order,  wl_calib->coeffs);
      allobjects[i]->sprefreso = fabs(l2-l1);
    }
    else{
       allobjects[i]->sprefreso = conf->drz_resol;
    }
    for (j=0; j < nobs; j++){
      gsl_vector_set(xvec, j, oneobject->spreso[j]);
    }
    xmean = gsl_stats_mean(xvec->data, 1, nobs);
    allobjects[i]->spmeanreso  = xmean;

    gsl_vector_free(xvec);
    gsl_vector_free(yvec);
  }

  gsl_matrix_free(drzcoeffs);
  free(conf);

  return 0;
}

d_point
get_mean_refpoint(objectobs **allobjects, int nobjects, int ID,int * boxwidth,
                  int * boxheight, double * relx, double * rely,
                  double * objwidth, double *orient, double * cdref,
                  double *cdscale, double *cdmeanscale, double *sprefreso, double *spreso,
                  double *spmeanreso, int *tlength)
{
  int i, dec=0;
  d_point mpoint;

  for (i=0; i < nobjects; i++){
    if (allobjects[i]->OBJID == ID){
      mpoint.x = allobjects[i]->mean_refpoint.x;
      mpoint.y = allobjects[i]->mean_refpoint.y;
      *boxwidth  = allobjects[i]->max_width;
      *boxheight = allobjects[i]->max_height;
      *tlength   = allobjects[i]->max_tlength;
      *objwidth  = allobjects[i]->owidthmax;
      *cdref     = allobjects[i]->cdrefscale;
      *cdmeanscale     = allobjects[i]->cdmeanscale;
      *spmeanreso= allobjects[i]->spmeanreso;
      *sprefreso = allobjects[i]->sprefreso;
      *orient    = allobjects[i]->orient[allobjects[i]->pointer];
      *cdscale   = allobjects[i]->cdscale[allobjects[i]->pointer];
      *spreso    = allobjects[i]->spreso[allobjects[i]->pointer];
      *relx      = allobjects[i]->relrefpt[allobjects[i]->pointer].x;
      *rely      = allobjects[i]->relrefpt[allobjects[i]->pointer].y;
      ++allobjects[i]->pointer;
      dec=1;
    }
  }
  return mpoint;
}
px_point
recalc_bbox(int xmin, int xmax, int ymin, int ymax, px_point pixmax)
{
  px_point ret;

  if (xmax > pixmax.x)
    xmax = pixmax.x;
  if (ymax > pixmax.y)
    ymax = pixmax.y;
  if (xmin < 1)
    xmin = 1;
  if (ymin < 1)
    ymin = 1;

  ret.x = xmax - xmin + 2;
  ret.y = ymax - ymin + 2;

  return ret;
}
/*
I am not sure what this routine is doing,
but one should make it better.
*/
px_point
recalc_mins(int xmin, int xmax, int ymin, int ymax, px_point pixmax)
{
  double m, b;
  px_point ret;

  m = ((double)ymin - (double)ymax)/((double)xmax - (double)xmin);
  b = (double)ymin - m * (double)xmax;
  if (xmin < 1){
    ymax = (int)ceil(1.0*m + b);
    xmin=1;
  }
  if (xmax > pixmax.x){
    ymin = (int)ceil((float)pixmax.x*m + b);
    xmax = pixmax.x;
  }
  if (ymin < 1){
    xmax = (int)ceil((1-b)/m);
    ymin=1;
  }
  if (ymax > pixmax.y){
    xmin = (int)ceil(((float)pixmax.y-b)/m);
    ymax=pixmax.y;
  }
  ret.x = xmin;
  ret.y = ymin;

  return ret;
}

int
get_beam_trace_length(const beam actbeam)
{
  int trlength=0;
  double diagonal_1 = 0.0;
  double diagonal_2 = 0.0;
  double xdiff, ydiff;

  // compute the x- and y- differences for one corner pair
  xdiff = (float)actbeam.corners[0].x - (float)actbeam.corners[2].x;
  ydiff = (float)actbeam.corners[0].y - (float)actbeam.corners[2].y;

  // compute the diagonal distance
  diagonal_1 = xdiff*xdiff + ydiff*ydiff;

  // compute the x- and y- differences for the other corner pair
  xdiff = (float)actbeam.corners[1].x - (float)actbeam.corners[3].x;
  ydiff = (float)actbeam.corners[1].y - (float)actbeam.corners[3].y;

  // compute the diagonal distance
  diagonal_2 = xdiff*xdiff + ydiff*ydiff;

  // compute the tracelength
  // from the larger diagonal
  if (diagonal_1 > diagonal_2)
    trlength = (int)ceil(sqrt(diagonal_1)+3.0);
  else
    trlength = (int)ceil(sqrt(diagonal_2)+3.0);

  // return the result
  return trlength;
}