#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_rotg (void) {
const double flteps = 1e-4, dbleps = 1e-6;
  {
   float a = -1.5f;
   float b = -1.5f;
   float c;
   float s;
   float r_expected = -2.12132034356f;
   float z_expected = 1.41421356237f;
   float c_expected = 0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 166)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 167)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 168)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 169)");
  };

  {
   float a = -1.5f;
   float b = -1.0f;
   float c;
   float s;
   float r_expected = -1.80277563773f;
   float z_expected = 0.554700196225f;
   float c_expected = 0.832050294338f;
   float s_expected = 0.554700196225f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 170)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 171)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 172)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 173)");
  };

  {
   float a = -1.5f;
   float b = -0.1f;
   float c;
   float s;
   float r_expected = -1.50332963784f;
   float z_expected = 0.0665190105238f;
   float c_expected = 0.997785157857f;
   float s_expected = 0.0665190105238f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 174)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 175)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 176)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 177)");
  };

  {
   float a = -1.5f;
   float b = 0.0f;
   float c;
   float s;
   float r_expected = -1.5f;
   float z_expected = -0.0f;
   float c_expected = 1.0f;
   float s_expected = -0.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 178)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 179)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 180)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 181)");
  };

  {
   float a = -1.5f;
   float b = 0.1f;
   float c;
   float s;
   float r_expected = -1.50332963784f;
   float z_expected = -0.0665190105238f;
   float c_expected = 0.997785157857f;
   float s_expected = -0.0665190105238f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 182)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 183)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 184)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 185)");
  };

  {
   float a = -1.5f;
   float b = 1.0f;
   float c;
   float s;
   float r_expected = -1.80277563773f;
   float z_expected = -0.554700196225f;
   float c_expected = 0.832050294338f;
   float s_expected = -0.554700196225f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 186)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 187)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 188)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 189)");
  };

  {
   float a = -1.5f;
   float b = 1.5f;
   float c;
   float s;
   float r_expected = 2.12132034356f;
   float z_expected = -1.41421356237f;
   float c_expected = -0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 190)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 191)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 192)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 193)");
  };

  {
   float a = -1.0f;
   float b = -1.5f;
   float c;
   float s;
   float r_expected = -1.80277563773f;
   float z_expected = 1.80277563773f;
   float c_expected = 0.554700196225f;
   float s_expected = 0.832050294338f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 194)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 195)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 196)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 197)");
  };

  {
   float a = -1.0f;
   float b = -1.0f;
   float c;
   float s;
   float r_expected = -1.41421356237f;
   float z_expected = 1.41421356237f;
   float c_expected = 0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 198)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 199)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 200)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 201)");
  };

  {
   float a = -1.0f;
   float b = -0.1f;
   float c;
   float s;
   float r_expected = -1.00498756211f;
   float z_expected = 0.099503719021f;
   float c_expected = 0.99503719021f;
   float s_expected = 0.099503719021f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 202)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 203)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 204)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 205)");
  };

  {
   float a = -1.0f;
   float b = 0.0f;
   float c;
   float s;
   float r_expected = -1.0f;
   float z_expected = -0.0f;
   float c_expected = 1.0f;
   float s_expected = -0.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 206)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 207)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 208)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 209)");
  };

  {
   float a = -1.0f;
   float b = 0.1f;
   float c;
   float s;
   float r_expected = -1.00498756211f;
   float z_expected = -0.099503719021f;
   float c_expected = 0.99503719021f;
   float s_expected = -0.099503719021f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 210)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 211)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 212)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 213)");
  };

  {
   float a = -1.0f;
   float b = 1.0f;
   float c;
   float s;
   float r_expected = 1.41421356237f;
   float z_expected = -1.41421356237f;
   float c_expected = -0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 214)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 215)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 216)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 217)");
  };

  {
   float a = -1.0f;
   float b = 1.5f;
   float c;
   float s;
   float r_expected = 1.80277563773f;
   float z_expected = -1.80277563773f;
   float c_expected = -0.554700196225f;
   float s_expected = 0.832050294338f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 218)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 219)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 220)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 221)");
  };

  {
   float a = -0.1f;
   float b = -1.5f;
   float c;
   float s;
   float r_expected = -1.50332963784f;
   float z_expected = 15.0332963784f;
   float c_expected = 0.0665190105238f;
   float s_expected = 0.997785157857f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 222)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 223)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 224)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 225)");
  };

  {
   float a = -0.1f;
   float b = -1.0f;
   float c;
   float s;
   float r_expected = -1.00498756211f;
   float z_expected = 10.0498756211f;
   float c_expected = 0.099503719021f;
   float s_expected = 0.99503719021f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 226)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 227)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 228)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 229)");
  };

  {
   float a = -0.1f;
   float b = -0.1f;
   float c;
   float s;
   float r_expected = -0.141421356237f;
   float z_expected = 1.41421356237f;
   float c_expected = 0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 230)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 231)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 232)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 233)");
  };

  {
   float a = -0.1f;
   float b = 0.0f;
   float c;
   float s;
   float r_expected = -0.1f;
   float z_expected = -0.0f;
   float c_expected = 1.0f;
   float s_expected = -0.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 234)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 235)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 236)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 237)");
  };

  {
   float a = -0.1f;
   float b = 0.1f;
   float c;
   float s;
   float r_expected = 0.141421356237f;
   float z_expected = -1.41421356237f;
   float c_expected = -0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 238)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 239)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 240)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 241)");
  };

  {
   float a = -0.1f;
   float b = 1.0f;
   float c;
   float s;
   float r_expected = 1.00498756211f;
   float z_expected = -10.0498756211f;
   float c_expected = -0.099503719021f;
   float s_expected = 0.99503719021f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 242)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 243)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 244)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 245)");
  };

  {
   float a = -0.1f;
   float b = 1.5f;
   float c;
   float s;
   float r_expected = 1.50332963784f;
   float z_expected = -15.0332963784f;
   float c_expected = -0.0665190105238f;
   float s_expected = 0.997785157857f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 246)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 247)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 248)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 249)");
  };

  {
   float a = 0.0f;
   float b = -1.5f;
   float c;
   float s;
   float r_expected = -1.5f;
   float z_expected = 1.0f;
   float c_expected = -0.0f;
   float s_expected = 1.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 250)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 251)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 252)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 253)");
  };

  {
   float a = 0.0f;
   float b = -1.0f;
   float c;
   float s;
   float r_expected = -1.0f;
   float z_expected = 1.0f;
   float c_expected = -0.0f;
   float s_expected = 1.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 254)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 255)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 256)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 257)");
  };

  {
   float a = 0.0f;
   float b = -0.1f;
   float c;
   float s;
   float r_expected = -0.1f;
   float z_expected = 1.0f;
   float c_expected = -0.0f;
   float s_expected = 1.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 258)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 259)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 260)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 261)");
  };

  {
   float a = 0.0f;
   float b = 0.0f;
   float c;
   float s;
   float r_expected = 0.0f;
   float z_expected = 0.0f;
   float c_expected = 1.0f;
   float s_expected = 0.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 262)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 263)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 264)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 265)");
  };

  {
   float a = 0.0f;
   float b = 0.1f;
   float c;
   float s;
   float r_expected = 0.1f;
   float z_expected = 1.0f;
   float c_expected = 0.0f;
   float s_expected = 1.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 266)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 267)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 268)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 269)");
  };

  {
   float a = 0.0f;
   float b = 1.0f;
   float c;
   float s;
   float r_expected = 1.0f;
   float z_expected = 1.0f;
   float c_expected = 0.0f;
   float s_expected = 1.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 270)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 271)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 272)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 273)");
  };

  {
   float a = 0.0f;
   float b = 1.5f;
   float c;
   float s;
   float r_expected = 1.5f;
   float z_expected = 1.0f;
   float c_expected = 0.0f;
   float s_expected = 1.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 274)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 275)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 276)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 277)");
  };

  {
   float a = 0.1f;
   float b = -1.5f;
   float c;
   float s;
   float r_expected = -1.50332963784f;
   float z_expected = -15.0332963784f;
   float c_expected = -0.0665190105238f;
   float s_expected = 0.997785157857f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 278)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 279)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 280)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 281)");
  };

  {
   float a = 0.1f;
   float b = -1.0f;
   float c;
   float s;
   float r_expected = -1.00498756211f;
   float z_expected = -10.0498756211f;
   float c_expected = -0.099503719021f;
   float s_expected = 0.99503719021f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 282)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 283)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 284)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 285)");
  };

  {
   float a = 0.1f;
   float b = -0.1f;
   float c;
   float s;
   float r_expected = -0.141421356237f;
   float z_expected = -1.41421356237f;
   float c_expected = -0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 286)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 287)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 288)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 289)");
  };

  {
   float a = 0.1f;
   float b = 0.0f;
   float c;
   float s;
   float r_expected = 0.1f;
   float z_expected = 0.0f;
   float c_expected = 1.0f;
   float s_expected = 0.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 290)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 291)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 292)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 293)");
  };

  {
   float a = 0.1f;
   float b = 0.1f;
   float c;
   float s;
   float r_expected = 0.141421356237f;
   float z_expected = 1.41421356237f;
   float c_expected = 0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 294)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 295)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 296)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 297)");
  };

  {
   float a = 0.1f;
   float b = 1.0f;
   float c;
   float s;
   float r_expected = 1.00498756211f;
   float z_expected = 10.0498756211f;
   float c_expected = 0.099503719021f;
   float s_expected = 0.99503719021f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 298)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 299)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 300)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 301)");
  };

  {
   float a = 0.1f;
   float b = 1.5f;
   float c;
   float s;
   float r_expected = 1.50332963784f;
   float z_expected = 15.0332963784f;
   float c_expected = 0.0665190105238f;
   float s_expected = 0.997785157857f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 302)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 303)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 304)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 305)");
  };

  {
   float a = 1.0f;
   float b = -1.5f;
   float c;
   float s;
   float r_expected = -1.80277563773f;
   float z_expected = -1.80277563773f;
   float c_expected = -0.554700196225f;
   float s_expected = 0.832050294338f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 306)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 307)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 308)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 309)");
  };

  {
   float a = 1.0f;
   float b = -1.0f;
   float c;
   float s;
   float r_expected = -1.41421356237f;
   float z_expected = -1.41421356237f;
   float c_expected = -0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 310)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 311)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 312)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 313)");
  };

  {
   float a = 1.0f;
   float b = -0.1f;
   float c;
   float s;
   float r_expected = 1.00498756211f;
   float z_expected = -0.099503719021f;
   float c_expected = 0.99503719021f;
   float s_expected = -0.099503719021f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 314)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 315)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 316)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 317)");
  };

  {
   float a = 1.0f;
   float b = 0.0f;
   float c;
   float s;
   float r_expected = 1.0f;
   float z_expected = 0.0f;
   float c_expected = 1.0f;
   float s_expected = 0.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 318)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 319)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 320)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 321)");
  };

  {
   float a = 1.0f;
   float b = 0.1f;
   float c;
   float s;
   float r_expected = 1.00498756211f;
   float z_expected = 0.099503719021f;
   float c_expected = 0.99503719021f;
   float s_expected = 0.099503719021f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 322)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 323)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 324)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 325)");
  };

  {
   float a = 1.0f;
   float b = 1.0f;
   float c;
   float s;
   float r_expected = 1.41421356237f;
   float z_expected = 1.41421356237f;
   float c_expected = 0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 326)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 327)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 328)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 329)");
  };

  {
   float a = 1.0f;
   float b = 1.5f;
   float c;
   float s;
   float r_expected = 1.80277563773f;
   float z_expected = 1.80277563773f;
   float c_expected = 0.554700196225f;
   float s_expected = 0.832050294338f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 330)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 331)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 332)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 333)");
  };

  {
   float a = 1.5f;
   float b = -1.5f;
   float c;
   float s;
   float r_expected = -2.12132034356f;
   float z_expected = -1.41421356237f;
   float c_expected = -0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 334)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 335)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 336)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 337)");
  };

  {
   float a = 1.5f;
   float b = -1.0f;
   float c;
   float s;
   float r_expected = 1.80277563773f;
   float z_expected = -0.554700196225f;
   float c_expected = 0.832050294338f;
   float s_expected = -0.554700196225f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 338)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 339)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 340)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 341)");
  };

  {
   float a = 1.5f;
   float b = -0.1f;
   float c;
   float s;
   float r_expected = 1.50332963784f;
   float z_expected = -0.0665190105238f;
   float c_expected = 0.997785157857f;
   float s_expected = -0.0665190105238f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 342)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 343)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 344)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 345)");
  };

  {
   float a = 1.5f;
   float b = 0.0f;
   float c;
   float s;
   float r_expected = 1.5f;
   float z_expected = 0.0f;
   float c_expected = 1.0f;
   float s_expected = 0.0f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 346)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 347)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 348)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 349)");
  };

  {
   float a = 1.5f;
   float b = 0.1f;
   float c;
   float s;
   float r_expected = 1.50332963784f;
   float z_expected = 0.0665190105238f;
   float c_expected = 0.997785157857f;
   float s_expected = 0.0665190105238f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 350)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 351)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 352)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 353)");
  };

  {
   float a = 1.5f;
   float b = 1.0f;
   float c;
   float s;
   float r_expected = 1.80277563773f;
   float z_expected = 0.554700196225f;
   float c_expected = 0.832050294338f;
   float s_expected = 0.554700196225f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 354)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 355)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 356)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 357)");
  };

  {
   float a = 1.5f;
   float b = 1.5f;
   float c;
   float s;
   float r_expected = 2.12132034356f;
   float z_expected = 1.41421356237f;
   float c_expected = 0.707106781187f;
   float s_expected = 0.707106781187f;
   cblas_srotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, flteps, "srotg(case 358)");
   gsl_test_rel(b, z_expected, flteps, "srotg(case 359)");
   gsl_test_rel(c, c_expected, flteps, "srotg(case 360)");
   gsl_test_rel(s, s_expected, flteps, "srotg(case 361)");
  };

  {
   double a = -1.5;
   double b = -1.5;
   double c;
   double s;
   double r_expected = -2.12132034356;
   double z_expected = 1.41421356237;
   double c_expected = 0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 362)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 363)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 364)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 365)");
  };

  {
   double a = -1.5;
   double b = -1;
   double c;
   double s;
   double r_expected = -1.80277563773;
   double z_expected = 0.554700196225;
   double c_expected = 0.832050294338;
   double s_expected = 0.554700196225;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 366)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 367)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 368)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 369)");
  };

  {
   double a = -1.5;
   double b = -0.1;
   double c;
   double s;
   double r_expected = -1.50332963784;
   double z_expected = 0.0665190105238;
   double c_expected = 0.997785157857;
   double s_expected = 0.0665190105238;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 370)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 371)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 372)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 373)");
  };

  {
   double a = -1.5;
   double b = 0;
   double c;
   double s;
   double r_expected = -1.5;
   double z_expected = -0;
   double c_expected = 1;
   double s_expected = -0;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 374)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 375)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 376)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 377)");
  };

  {
   double a = -1.5;
   double b = 0.1;
   double c;
   double s;
   double r_expected = -1.50332963784;
   double z_expected = -0.0665190105238;
   double c_expected = 0.997785157857;
   double s_expected = -0.0665190105238;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 378)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 379)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 380)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 381)");
  };

  {
   double a = -1.5;
   double b = 1;
   double c;
   double s;
   double r_expected = -1.80277563773;
   double z_expected = -0.554700196225;
   double c_expected = 0.832050294338;
   double s_expected = -0.554700196225;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 382)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 383)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 384)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 385)");
  };

  {
   double a = -1.5;
   double b = 1.5;
   double c;
   double s;
   double r_expected = 2.12132034356;
   double z_expected = -1.41421356237;
   double c_expected = -0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 386)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 387)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 388)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 389)");
  };

  {
   double a = -1;
   double b = -1.5;
   double c;
   double s;
   double r_expected = -1.80277563773;
   double z_expected = 1.80277563773;
   double c_expected = 0.554700196225;
   double s_expected = 0.832050294338;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 390)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 391)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 392)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 393)");
  };

  {
   double a = -1;
   double b = -1;
   double c;
   double s;
   double r_expected = -1.41421356237;
   double z_expected = 1.41421356237;
   double c_expected = 0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 394)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 395)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 396)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 397)");
  };

  {
   double a = -1;
   double b = -0.1;
   double c;
   double s;
   double r_expected = -1.00498756211;
   double z_expected = 0.099503719021;
   double c_expected = 0.99503719021;
   double s_expected = 0.099503719021;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 398)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 399)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 400)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 401)");
  };

  {
   double a = -1;
   double b = 0;
   double c;
   double s;
   double r_expected = -1;
   double z_expected = -0;
   double c_expected = 1;
   double s_expected = -0;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 402)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 403)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 404)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 405)");
  };

  {
   double a = -1;
   double b = 0.1;
   double c;
   double s;
   double r_expected = -1.00498756211;
   double z_expected = -0.099503719021;
   double c_expected = 0.99503719021;
   double s_expected = -0.099503719021;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 406)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 407)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 408)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 409)");
  };

  {
   double a = -1;
   double b = 1;
   double c;
   double s;
   double r_expected = 1.41421356237;
   double z_expected = -1.41421356237;
   double c_expected = -0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 410)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 411)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 412)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 413)");
  };

  {
   double a = -1;
   double b = 1.5;
   double c;
   double s;
   double r_expected = 1.80277563773;
   double z_expected = -1.80277563773;
   double c_expected = -0.554700196225;
   double s_expected = 0.832050294338;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 414)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 415)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 416)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 417)");
  };

  {
   double a = -0.1;
   double b = -1.5;
   double c;
   double s;
   double r_expected = -1.50332963784;
   double z_expected = 15.0332963784;
   double c_expected = 0.0665190105238;
   double s_expected = 0.997785157857;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 418)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 419)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 420)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 421)");
  };

  {
   double a = -0.1;
   double b = -1;
   double c;
   double s;
   double r_expected = -1.00498756211;
   double z_expected = 10.0498756211;
   double c_expected = 0.099503719021;
   double s_expected = 0.99503719021;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 422)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 423)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 424)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 425)");
  };

  {
   double a = -0.1;
   double b = -0.1;
   double c;
   double s;
   double r_expected = -0.141421356237;
   double z_expected = 1.41421356237;
   double c_expected = 0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 426)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 427)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 428)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 429)");
  };

  {
   double a = -0.1;
   double b = 0;
   double c;
   double s;
   double r_expected = -0.1;
   double z_expected = -0;
   double c_expected = 1;
   double s_expected = -0;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 430)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 431)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 432)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 433)");
  };

  {
   double a = -0.1;
   double b = 0.1;
   double c;
   double s;
   double r_expected = 0.141421356237;
   double z_expected = -1.41421356237;
   double c_expected = -0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 434)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 435)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 436)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 437)");
  };

  {
   double a = -0.1;
   double b = 1;
   double c;
   double s;
   double r_expected = 1.00498756211;
   double z_expected = -10.0498756211;
   double c_expected = -0.099503719021;
   double s_expected = 0.99503719021;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 438)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 439)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 440)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 441)");
  };

  {
   double a = -0.1;
   double b = 1.5;
   double c;
   double s;
   double r_expected = 1.50332963784;
   double z_expected = -15.0332963784;
   double c_expected = -0.0665190105238;
   double s_expected = 0.997785157857;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 442)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 443)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 444)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 445)");
  };

  {
   double a = 0;
   double b = -1.5;
   double c;
   double s;
   double r_expected = -1.5;
   double z_expected = 1;
   double c_expected = -0;
   double s_expected = 1;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 446)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 447)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 448)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 449)");
  };

  {
   double a = 0;
   double b = -1;
   double c;
   double s;
   double r_expected = -1;
   double z_expected = 1;
   double c_expected = -0;
   double s_expected = 1;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 450)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 451)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 452)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 453)");
  };

  {
   double a = 0;
   double b = -0.1;
   double c;
   double s;
   double r_expected = -0.1;
   double z_expected = 1;
   double c_expected = -0;
   double s_expected = 1;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 454)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 455)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 456)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 457)");
  };

  {
   double a = 0;
   double b = 0;
   double c;
   double s;
   double r_expected = 0;
   double z_expected = 0;
   double c_expected = 1;
   double s_expected = 0;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 458)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 459)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 460)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 461)");
  };

  {
   double a = 0;
   double b = 0.1;
   double c;
   double s;
   double r_expected = 0.1;
   double z_expected = 1;
   double c_expected = 0;
   double s_expected = 1;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 462)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 463)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 464)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 465)");
  };

  {
   double a = 0;
   double b = 1;
   double c;
   double s;
   double r_expected = 1;
   double z_expected = 1;
   double c_expected = 0;
   double s_expected = 1;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 466)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 467)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 468)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 469)");
  };

  {
   double a = 0;
   double b = 1.5;
   double c;
   double s;
   double r_expected = 1.5;
   double z_expected = 1;
   double c_expected = 0;
   double s_expected = 1;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 470)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 471)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 472)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 473)");
  };

  {
   double a = 0.1;
   double b = -1.5;
   double c;
   double s;
   double r_expected = -1.50332963784;
   double z_expected = -15.0332963784;
   double c_expected = -0.0665190105238;
   double s_expected = 0.997785157857;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 474)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 475)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 476)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 477)");
  };

  {
   double a = 0.1;
   double b = -1;
   double c;
   double s;
   double r_expected = -1.00498756211;
   double z_expected = -10.0498756211;
   double c_expected = -0.099503719021;
   double s_expected = 0.99503719021;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 478)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 479)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 480)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 481)");
  };

  {
   double a = 0.1;
   double b = -0.1;
   double c;
   double s;
   double r_expected = -0.141421356237;
   double z_expected = -1.41421356237;
   double c_expected = -0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 482)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 483)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 484)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 485)");
  };

  {
   double a = 0.1;
   double b = 0;
   double c;
   double s;
   double r_expected = 0.1;
   double z_expected = 0;
   double c_expected = 1;
   double s_expected = 0;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 486)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 487)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 488)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 489)");
  };

  {
   double a = 0.1;
   double b = 0.1;
   double c;
   double s;
   double r_expected = 0.141421356237;
   double z_expected = 1.41421356237;
   double c_expected = 0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 490)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 491)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 492)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 493)");
  };

  {
   double a = 0.1;
   double b = 1;
   double c;
   double s;
   double r_expected = 1.00498756211;
   double z_expected = 10.0498756211;
   double c_expected = 0.099503719021;
   double s_expected = 0.99503719021;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 494)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 495)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 496)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 497)");
  };

  {
   double a = 0.1;
   double b = 1.5;
   double c;
   double s;
   double r_expected = 1.50332963784;
   double z_expected = 15.0332963784;
   double c_expected = 0.0665190105238;
   double s_expected = 0.997785157857;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 498)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 499)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 500)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 501)");
  };

  {
   double a = 1;
   double b = -1.5;
   double c;
   double s;
   double r_expected = -1.80277563773;
   double z_expected = -1.80277563773;
   double c_expected = -0.554700196225;
   double s_expected = 0.832050294338;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 502)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 503)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 504)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 505)");
  };

  {
   double a = 1;
   double b = -1;
   double c;
   double s;
   double r_expected = -1.41421356237;
   double z_expected = -1.41421356237;
   double c_expected = -0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 506)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 507)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 508)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 509)");
  };

  {
   double a = 1;
   double b = -0.1;
   double c;
   double s;
   double r_expected = 1.00498756211;
   double z_expected = -0.099503719021;
   double c_expected = 0.99503719021;
   double s_expected = -0.099503719021;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 510)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 511)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 512)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 513)");
  };

  {
   double a = 1;
   double b = 0;
   double c;
   double s;
   double r_expected = 1;
   double z_expected = 0;
   double c_expected = 1;
   double s_expected = 0;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 514)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 515)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 516)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 517)");
  };

  {
   double a = 1;
   double b = 0.1;
   double c;
   double s;
   double r_expected = 1.00498756211;
   double z_expected = 0.099503719021;
   double c_expected = 0.99503719021;
   double s_expected = 0.099503719021;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 518)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 519)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 520)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 521)");
  };

  {
   double a = 1;
   double b = 1;
   double c;
   double s;
   double r_expected = 1.41421356237;
   double z_expected = 1.41421356237;
   double c_expected = 0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 522)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 523)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 524)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 525)");
  };

  {
   double a = 1;
   double b = 1.5;
   double c;
   double s;
   double r_expected = 1.80277563773;
   double z_expected = 1.80277563773;
   double c_expected = 0.554700196225;
   double s_expected = 0.832050294338;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 526)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 527)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 528)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 529)");
  };

  {
   double a = 1.5;
   double b = -1.5;
   double c;
   double s;
   double r_expected = -2.12132034356;
   double z_expected = -1.41421356237;
   double c_expected = -0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 530)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 531)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 532)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 533)");
  };

  {
   double a = 1.5;
   double b = -1;
   double c;
   double s;
   double r_expected = 1.80277563773;
   double z_expected = -0.554700196225;
   double c_expected = 0.832050294338;
   double s_expected = -0.554700196225;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 534)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 535)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 536)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 537)");
  };

  {
   double a = 1.5;
   double b = -0.1;
   double c;
   double s;
   double r_expected = 1.50332963784;
   double z_expected = -0.0665190105238;
   double c_expected = 0.997785157857;
   double s_expected = -0.0665190105238;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 538)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 539)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 540)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 541)");
  };

  {
   double a = 1.5;
   double b = 0;
   double c;
   double s;
   double r_expected = 1.5;
   double z_expected = 0;
   double c_expected = 1;
   double s_expected = 0;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 542)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 543)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 544)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 545)");
  };

  {
   double a = 1.5;
   double b = 0.1;
   double c;
   double s;
   double r_expected = 1.50332963784;
   double z_expected = 0.0665190105238;
   double c_expected = 0.997785157857;
   double s_expected = 0.0665190105238;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 546)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 547)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 548)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 549)");
  };

  {
   double a = 1.5;
   double b = 1;
   double c;
   double s;
   double r_expected = 1.80277563773;
   double z_expected = 0.554700196225;
   double c_expected = 0.832050294338;
   double s_expected = 0.554700196225;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 550)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 551)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 552)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 553)");
  };

  {
   double a = 1.5;
   double b = 1.5;
   double c;
   double s;
   double r_expected = 2.12132034356;
   double z_expected = 1.41421356237;
   double c_expected = 0.707106781187;
   double s_expected = 0.707106781187;
   cblas_drotg(&a, &b, &c, &s);
   gsl_test_rel(a, r_expected, dbleps, "drotg(case 554)");
   gsl_test_rel(b, z_expected, dbleps, "drotg(case 555)");
   gsl_test_rel(c, c_expected, dbleps, "drotg(case 556)");
   gsl_test_rel(s, s_expected, dbleps, "drotg(case 557)");
  };

}


/* matrixio.c */

// 8.4.13 Example programs for matrices of gsl-ref.pdf
// GNU GSL GNU Scientific Library reference book
// pp. 99,100

/*
  Compiling advice:
  gcc matrixio.c -lgsl -lgslcblas

 */

#include <stdio.h>
#include <gsl/gsl_matrix.h>

int main (void) {
  int i, j, k = 0;
  gsl_matrix * m = gsl_matrix_alloc (100, 100);
  gsl_matrix * a = gsl_matrix_alloc (100, 100);

  for (i = 0; i < 100; i++)
    for (j = 0; j < 100; j++)
      gsl_matrix_set (m, i, j, 0.23 + 100*i + j);

  {
    FILE * f = fopen("test.dat", "wb");
    gsl_matrix_fwrite (f, m);
    fclose (f);
  }

  {
    FILE * f = fopen ("test.dat", "rb") ;
    gsl_matrix_fread(f, a);
    fclose (f);
  }

  for (i = 0; i < 100; i++)
    for (j = 0; j < 100; j++)
      {
	double mij = gsl_matrix_get (m, i, j);
	double aij = gsl_matrix_get (a, i, j);
	if (mij != aij) k++;
      }

  gsl_matrix_free(m);
  gsl_matrix_free(a);

  printf("differences = %d (should be zero)\n", k);

  return (k > 0);
}


/* =======================================
 * SUSY
 *
 * TODO:
 * - still giving qualitatively wrong answer
 * =======================================
 */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define sq(x) pow((x),2.0)
#define cb(x) pow((x),3.0)
#define qd(x) pow((x),4.0)

// GSL Random Number Generator (https://www.gnu.org/software/gsl/)
#include <gsl/gsl_rng.h>
const gsl_rng_type * T; gsl_rng * r;

// GSL Spline (for smoothing)
#include <gsl/gsl_errno.h>
#include <gsl/gsl_spline.h>
gsl_interp_accel *spline_accel;
gsl_spline *spline;
#define N_spl 5       // Factor of N_bin +1 (end points inclusive)

// Parameters
#define N_lat   2000  // Lattice size
#define a       0.1   // Lattice spacing
#define N_therm 500   // Thermalization
#define N_meas  1000  // Number of configuration to measure
#define N_skip  50    // Decorrelation
#define alpha   0     // Strength of potential (harmonic)
#define lambda  1     // Strength of potential (anharmonic)
#define epsilon 0.2   // Size of fluctuation

// SUSY Parameters
#define epsilon_susy 0.4   // Size of fluctuation

#define N_bin 100
#define dx 0.04   // x_range*2 / bin
#define x_range 2 // x in [-range, range]

// Globals
double x[N_lat];           // Lattice
int N_acc,N_tot;           // Acceptance rate = acc/tot
double E0;                 // Ground state energy
double C[N_lat];           // Correlator
double psi[N_bin];         // Wavefunction
double psip[N_bin];        // 1st derivative of wavefunction
double psipp[N_bin];       // 2nd derivative of wavefunction
double H_susy[N_bin];      // SUSY action

// Output Files
FILE *fE0, *fpsi0, *fpsi;

// Prototypes
void setup();
void cleanup();
void update();
void update_susy();
int xtoi(double x);
double itox(int i);

int main(void){
  setup();

  // Thermalize
  for(int n=0;n<N_therm;n++){
    update();
  }

  // Calculate Wavefunction
  for(int n=0;n<N_meas;n++){
    // Decorrelate
    for(int m=0;m<N_skip;m++){ update(); }

    for(int i=0;i<N_lat;i++){
      if(abs(x[i])<x_range){
        psi[xtoi(x[i])]+=1;
      }
    }
  }

  printf("1st round acceptance rate: %f \n", (double)N_acc/N_tot);

  // Normalize wavefunction
  for(int i=0;i<N_bin;i++){
    psi[i] = sqrt(psi[i]/(dx*N_meas*N_lat));
  }

  // Pick points for smoothing spline
  double x_arr[N_spl];
  double y_arr[N_spl];
  int skip = nearbyint(N_bin/(N_spl-1));
  for(int i=0;i<N_bin;i++){
    if(i%skip==0){
      x_arr[(i/skip)]=itox(i);
      y_arr[(i/skip)]=psi[i];
    }
  }
  // manual add end point
  x_arr[N_spl-1]=x_range;
  y_arr[N_spl-1]=psi[N_bin-1];

  // Smoothing spline
  gsl_spline_init(spline, x_arr, y_arr, N_spl);

  for(int i=0;i<N_bin;i++){
    psi[i]  = gsl_spline_eval(spline,itox(i),spline_accel);
    if(psi[i]<0){psi[i]=0;}
    psip[i] = gsl_spline_eval_deriv(spline, itox(i), spline_accel);
    psipp[i] = gsl_spline_eval_deriv2(spline, itox(i), spline_accel);
  }

  // Smoothing second derivative
  for(int i=0;i<N_bin;i++){
    if(i%skip==0){
      y_arr[(i/skip)]=psipp[i];
    }
  }
  // manual add end point
  y_arr[N_spl-1]=psipp[N_bin-1];
  // Smoothing spline
  gsl_spline_init(spline, x_arr, y_arr, N_spl);

  for(int i=0;i<N_bin;i++){
    psipp[i]  = gsl_spline_eval(spline,itox(i),spline_accel);

    if(psi[i]>0){
      H_susy[i] =  - (psipp[i]/psi[i]-sq(psip[i]/psi[i]))/sqrt(2); // TODO: This is technically wrong...
    }else{
      H_susy[i]=9999999;
    }
  }

  // Plot wavefunction and derivatives
  for(int i=0;i<N_bin;i++){
    fprintf(fpsi0,"%f %f %f %f\n", itox(i), psi[i], psip[i], psipp[i]);
    fprintf(fE0,"%f %f\n", itox(i), H_susy[i]);
  }

  // Reinitialize
  for(int i=0;i<N_bin;i++){psi[i]=0;}
  for(int i=0;i<N_lat;i++){x[i]=0;}
  N_acc=0;N_tot=0;

  // Thermalize
  for(int n=0;n<N_therm*10;n++){
    update_susy();
  }

  // Calculate Wavefunction
  for(int n=0;n<N_meas;n++){
    // Decorrelate
    for(int m=0;m<N_skip*2;m++){ update_susy(); }
      for(int i=0;i<N_lat;i++){
      if(abs(x[i])<x_range){
        psi[xtoi(x[i])]+=1;
      }
    }
  }

  printf("2nd round acceptance rate: %f \n", (double)N_acc/N_tot);

  // Plot wavefunction
  for(int i=0;i<N_bin;i++){
    fprintf(fpsi,"%f, %f\n", itox(i), sqrt(psi[i]/(dx*N_meas*N_lat)));
  }

  cleanup();
  return 0;
}

// Convert x into bin index
int xtoi(double x){
  return nearbyint((x+x_range)/dx);
}

// Convert bin index to x
double itox(int i){
  return i*dx-x_range;
}

// Calculate difference in action
double dS(int i, double x_old){
  return (x[i]*(x[i]-x[(i+1)%N_lat]-x[(i-1+N_lat)%N_lat])/a
          + alpha*a*sq(x[i]) + lambda*a*qd(x[i]))
          - (x_old*(x_old-x[(i+1)%N_lat]-x[(i-1+N_lat)%N_lat])/a
               + alpha*a*sq(x_old) + lambda*a*qd(x_old));
}

double dS_susy(int i, double x_old){
  return (x[i]*(x[i]-x[(i+1)%N_lat]-x[(i-1+N_lat)%N_lat])/a
          + a*H_susy[xtoi(x[i])])
          - (x_old*(x_old-x[(i+1)%N_lat]-x[(i-1+N_lat)%N_lat])/a
               + a*H_susy[xtoi(x_old)]);
}

void update(){
  double x_old;
  double d; // Difference in action
  for(int i=0;i<N_lat;i++){
    x_old=x[i];
    x[i]=x[i] + epsilon * (gsl_rng_uniform(r)-0.5)*2;
    N_acc++; N_tot++;
    d=dS(i,x_old);
    if(d>0){
      if(exp(-d)<gsl_rng_uniform(r)){ x[i]=x_old; N_acc--; } // Revert to old value
    }
  }
}

void update_susy(){
  double x_old;
  double d; // Difference in action
  for(int i=0;i<N_lat;i++){
    x_old=x[i];
    x[i]=x[i] + epsilon_susy * (gsl_rng_uniform(r)-0.5)*2;
    N_acc++; N_tot++;
    d=dS_susy(i,x_old);
    if(d>0){
      if(exp(-d)<gsl_rng_uniform(r)){ x[i]=x_old; N_acc--; } // Revert to old value
    }
  }
}

void setup(){
  // Cold start
  for(int i=0;i<N_lat;i++){ x[i]=0; C[i]=0; }

  // Initialize variables
  N_acc = 0;
  N_tot = 0;
  E0 = 0;
  for(int i=0;i<N_bin;i++){ psi[i]=0; psip[i]=0; psipp[i]=0; H_susy[i]=0;}

  // Create Files
  fE0=fopen("E0.txt", "w+");
  fpsi0=fopen("psi0.txt", "w+");
  fpsi=fopen("psi.txt", "w+");

  // Setup random environment
  gsl_rng_env_setup();
  T = gsl_rng_mt19937;
  r = gsl_rng_alloc (T);

  // Setup spline
  spline_accel = gsl_interp_accel_alloc();
  spline = gsl_spline_alloc(gsl_interp_cspline, N_spl);
}

void cleanup(){
  gsl_rng_free (r);

  gsl_spline_free(spline);
  gsl_interp_accel_free(spline_accel);

  // Close Files
  fclose(fE0);
  fclose(fpsi0);
  fclose(fpsi);
}


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

void inverse(double* A, lapack_int N)
{
    lapack_int *IPIV = (lapack_int *) malloc(N * sizeof(lapack_int));
    int INFO;

    /*
        DGETRF computes an LU factorization of a general M-by-N matrix A
        using partial pivoting with row interchanges.

        The factorization has the form
            A = P * L * U
        where P is a permutation matrix, L is lower triangular with unit
        diagonal elements (lower trapezoidal if m > n), and U is upper
        triangular (upper trapezoidal if m < n).

        This is the right-looking Level 3 BLAS version of the algorithm.

        lapack_int LAPACKE_dgetrf( int matrix_layout, lapack_int m, lapack_int n,
                        double* a, lapack_int lda, lapack_int* ipiv );

        INFO is INTEGER
          = 0:  successful exit
          < 0:  if INFO = -i, the i-th argument had an illegal value
          > 0:  if INFO = i, U(i,i) is exactly zero. The factorization
                has been completed, but the factor U is exactly
                singular, and division by zero will occur if it is used
                to solve a system of equations.
    */

    INFO = LAPACKE_dgetrf(LAPACK_ROW_MAJOR,N,N,A,N,IPIV);
    printf("%d ", INFO);

    //DGETRI computes the inverse of a matrix using the LU factorization
    //computed by DGETRF.

    //This method inverts U and then computes inv(A) by solving the system
    //inv(A)*L = inv(U) for inv(A).
    //lapack_int LAPACKE_dgetri( int matrix_layout, lapack_int n, double* a,
    //          lapack_int lda, const lapack_int* ipiv );
    INFO = LAPACKE_dgetri(LAPACK_ROW_MAJOR,N,A,N,IPIV);
    printf("%d \n", INFO);

    free(IPIV);
}

int main(){

    double A [2*2] = {
        1,2,
        3,4
    };

    inverse(A, 2);

    printf("%f %f\n", A[0], A[1]);
    printf("%f %f\n", A[2], A[3]);

    return 0;
}


/*
 * knnring_sequential.c
 *
 *  Created on: Nov 21, 2019
 *      Author: Lambis
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <cblas.h>
#include "knnring.h"

knnresult kNN(double * X, double * Y, int n, int m, int d, int k) {

	knnresult knn;

    // Allocating memory for the knnresult.
	knn.nidx = (int *)malloc(m*k*sizeof(int));
	knn.ndist = (double *)malloc(m*k*sizeof(double));

	// Passing m and k values to knnresult.
	knn.m = m;
	knn.k = k;

    // Allocating memory for the distances array.
	double *D = (double *)malloc(m*n*sizeof(double));

	// Calculation of sum(X.^2,2).
	double *a = (double *)malloc(n*sizeof(double));
	for (int i=0; i<n; i++) {
		a[i] = cblas_dnrm2(d, &X[i*d], 1);
		a[i] = a[i]*a[i];
	}

    // Calculation of sum(Y.^2,2).
	double *b = (double *)malloc(m*sizeof(double));
	for (int i=0; i<m; i++) {
		b[i] = cblas_dnrm2(d, &Y[i*d], 1);
		b[i] = b[i]*b[i];
	}

    // Calculation of -2*X*Y.' multiplication.
    double *c = (double *)malloc(n*m*sizeof(double));
	cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, n, m, d, -2, X, d, Y, d, 0, c, m);

	// Adding sum(X.^2,2) sum(Y.^2,2).' to the c array.
    for (int i=0; i<n; i++)
		for(int j=0; j<m; j++)
			c[i*m+j] += a[i] + b[j];

    // Cleanup.
    free(a);
    free(b);

    // Applying elementwise square root to the c array.
	for (int i=0; i<n; i++)
		for(int j=0; j<m; j++)
			c[i*m+j] = sqrt(fabs(c[i*m+j]));

    // Creates a nxn identity array.
    double *iA = (double *)calloc(n*n, sizeof(double));
    for (int i=0; i<n; i++)
        iA[i*n+i] = 1;

    // Transposing c array and storing it in D.
	cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, m, n, n, 1, c, m, iA, n, 0, D, n);

    // More efficient than the multiplication above. This can only be used with openblas.
    //cblas_domatcopy(CblasRowMajor, CblasTrans, n, m, 1, c, m, D, n);

    // Cleanup.
    free(iA);
    free(c);

    // Setup of idx number for corpus points.
	int *idx = (int *)malloc(m*n*sizeof(int));
	for (int i=0; i<m; i++)
        for (int j=0; j<n; j++)
            idx[i*n+j]= j;

    // Sorting of all distances.
	for (int i=0; i<m; i++)
		quickSort(D, i*n, ((i+1)*n)-1, idx);

    // Passing the k nearest neighbors' indexes and distances to knnresult.
	for (int i=0; i<m; i++) {
		for (int j=0; j<k; j++) {
			knn.nidx[i*k+j] = idx[i*n+j];
			knn.ndist[i*k+j] = D[i*n+j];
		}
	}

	return knn;

}

// A utility function to swap two elements.
void swap(void* a, void* b, size_t s) {
    void* tmp = malloc(s);
    memcpy(tmp, a, s);
    memcpy(a, b, s);
    memcpy(b, tmp, s);
    free(tmp);
}

/* This function takes last element as pivot, places the pivot element at its correct position in sorted array
 * and places all smaller (smaller than pivot) to left of pivot and all greater elements to right of pivot */
int partition(double *arr, int low, int high, int *idx) {
    double pivot = arr[high];    		// Pivot
    int i = (low - 1);  			// Index of smaller element

    for (int j=low; j<=high-1; j++) {
        // If current element is smaller than the pivot
        if (arr[j] < pivot) {
            i++;    				// Increment index of smaller element
            swap(&arr[i], &arr[j], sizeof(double));
            swap(&idx[i], &idx[j], sizeof(int));
        }
    }
    swap(&arr[i + 1], &arr[high], sizeof(double));
    swap(&idx[i + 1], &idx[high], sizeof(int));
    return (i + 1);
}

// The main function that implements QuickSort arr[] --> Array to be sorted, low  --> Starting index, high  --> Ending index
void quickSort(double *arr, int low, int high, int *idx) {
    if (low < high) {
        // pi is partitioning index, arr[pi] is now at right place
        int pi = partition(arr, low, high, idx);

        // Separately sort elements before partition and after partition
        quickSort(arr, low, pi - 1, idx);
        quickSort(arr, pi + 1, high, idx);
    }
}


/* linalg/test_qrc.c
 *
 * Copyright (C) 2020 Patrick Alken
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <config.h>
#include <stdlib.h>
#include <gsl/gsl_test.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_ieee_utils.h>
#include <gsl/gsl_permute_vector.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_permutation.h>

static int
test_QRc_decomp_eps(const gsl_matrix_complex * m, const double eps, const char * desc)
{
  int s = 0;
  const size_t M = m->size1;
  const size_t N = m->size2;
  size_t i, j;

  gsl_matrix_complex * qr = gsl_matrix_complex_alloc(M, N);
  gsl_matrix_complex * a  = gsl_matrix_complex_alloc(M, N);
  gsl_matrix_complex * q  = gsl_matrix_complex_alloc(M, M);
  gsl_matrix_complex * r  = gsl_matrix_complex_alloc(M, N);
  gsl_vector_complex * d = gsl_vector_complex_alloc(N);

  gsl_matrix_complex_memcpy(qr, m);

  s += gsl_linalg_complex_QR_decomp(qr, d);
  s += gsl_linalg_complex_QR_unpack(qr, d, q, r);

  /* compute a = q r */
  gsl_blas_zgemm (CblasNoTrans, CblasNoTrans, GSL_COMPLEX_ONE, q, r, GSL_COMPLEX_ZERO, a);

  for (i = 0; i < M; i++) {
    for (j = 0; j < N; j++) {
      gsl_complex aij = gsl_matrix_complex_get(a, i, j);
      gsl_complex mij = gsl_matrix_complex_get(m, i, j);
      int foo_r = check(GSL_REAL(aij), GSL_REAL(mij), eps);
      int foo_i = check(GSL_IMAG(aij), GSL_IMAG(mij), eps);
      if (foo_r || foo_i)
        {
          printf("%s (%3lu,%3lu)[%lu,%lu]: %22.18g   %22.18g\n", desc, M, N, i, j, GSL_REAL(aij), GSL_REAL(mij));
          printf("%s (%3lu,%3lu)[%lu,%lu]: %22.18g   %22.18g\n", desc, M, N, i, j, GSL_IMAG(aij), GSL_IMAG(mij));
        }
      s += foo_r + foo_i;
    }
  }

  gsl_vector_complex_free(d);
  gsl_matrix_complex_free(qr);
  gsl_matrix_complex_free(a);
  gsl_matrix_complex_free(q);
  gsl_matrix_complex_free(r);

  return s;
}

static int
test_QRc_decomp(gsl_rng * r)
{
  int s = 0;
  size_t N, M;

  /* test random matrices */
  for (N = 1; N <= 20; ++N)
    {
      for (M = 1; M <= 20; ++M)
        {
          gsl_matrix_complex * A = gsl_matrix_complex_alloc(N, M);

          create_random_complex_matrix(A, r);
          test_QRc_decomp_eps(A, 1.0e6 * GSL_MAX(N, M) * GSL_DBL_EPSILON, "complex_QR_decomp random");

          gsl_matrix_complex_free(A);
        }
    }

  return s;
}

static int
test_QRc_solve_eps(const gsl_matrix_complex * A, const gsl_vector_complex * rhs, const gsl_vector_complex * sol,
                   const double eps, const char * desc)
{
  int s = 0;
  const size_t M = A->size1;
  const size_t N = A->size2;
  size_t i;

  gsl_matrix_complex * QR = gsl_matrix_complex_alloc(M, N);
  gsl_vector_complex * tau = gsl_vector_complex_alloc(N);
  gsl_vector_complex * x  = gsl_vector_complex_alloc(N);

  gsl_matrix_complex_memcpy(QR, A);

  s += gsl_linalg_complex_QR_decomp(QR, tau);
  s += gsl_linalg_complex_QR_solve(QR, tau, rhs, x);

  for (i = 0; i < M; i++)
    {
      gsl_complex xi = gsl_vector_complex_get(x, i);
      gsl_complex yi = gsl_vector_complex_get(sol, i);

      gsl_test_rel(GSL_REAL(xi), GSL_REAL(yi), eps, "%s real (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, xi, yi);
      gsl_test_rel(GSL_IMAG(xi), GSL_IMAG(yi), eps, "%s imag (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, xi, yi);
    }

  gsl_matrix_complex_free(QR);
  gsl_vector_complex_free(tau);
  gsl_vector_complex_free(x);

  return s;
}

static int
test_QRc_solve(gsl_rng * r)
{
  int s = 0;
  size_t N;

  for (N = 1; N <= 50; ++N)
    {
      gsl_matrix_complex * A = gsl_matrix_complex_alloc(N, N);
      gsl_vector_complex * sol = gsl_vector_complex_alloc(N);
      gsl_vector_complex * rhs = gsl_vector_complex_alloc(N);

      create_random_complex_matrix(A, r);
      create_random_complex_vector(sol, r);
      gsl_blas_zgemv(CblasNoTrans, GSL_COMPLEX_ONE, A, sol, GSL_COMPLEX_ZERO, rhs);

      s += test_QRc_solve_eps(A, rhs, sol, 1.0e5 * N * GSL_DBL_EPSILON, "complex QR_solve_r random");

      gsl_matrix_complex_free(A);
      gsl_vector_complex_free(sol);
      gsl_vector_complex_free(rhs);
    }

  return s;
}

static int
test_QRc_lssolve_eps(const gsl_matrix_complex * A, const gsl_vector_complex * rhs, const gsl_vector_complex * sol,
                     const double eps, const char * desc)
{
  int s = 0;
  const size_t M = A->size1;
  const size_t N = A->size2;
  size_t i;

  gsl_matrix_complex * QR = gsl_matrix_complex_alloc(M, N);
  gsl_vector_complex * tau = gsl_vector_complex_alloc(N);
  gsl_vector_complex * x  = gsl_vector_complex_alloc(N);
  gsl_vector_complex * r  = gsl_vector_complex_alloc(M);
  gsl_vector_complex * r2  = gsl_vector_complex_alloc(M);

  gsl_matrix_complex_memcpy(QR, A);

  s += gsl_linalg_complex_QR_decomp(QR, tau);
  s += gsl_linalg_complex_QR_lssolve(QR, tau, rhs, x, r);

  for (i = 0; i < N; i++)
    {
      gsl_complex xi = gsl_vector_complex_get(x, i);
      gsl_complex yi = gsl_vector_complex_get(sol, i);

      gsl_test_rel(GSL_REAL(xi), GSL_REAL(yi), eps, "%s sol real (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, GSL_REAL(xi), GSL_REAL(yi));
      gsl_test_rel(GSL_IMAG(xi), GSL_IMAG(yi), eps, "%s sol imag (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, GSL_IMAG(xi), GSL_IMAG(yi));
    }

  /* compute residual and check */
  gsl_vector_complex_memcpy(r2, rhs);
  gsl_blas_zgemv(CblasNoTrans, GSL_COMPLEX_NEGONE, A, sol, GSL_COMPLEX_ONE, r2);

  for (i = 0; i < M; i++)
    {
      gsl_complex xi = gsl_vector_complex_get(r, i);
      gsl_complex yi = gsl_vector_complex_get(r2, i);

      gsl_test_rel(GSL_REAL(xi), GSL_REAL(yi), eps, "%s res real (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, GSL_REAL(xi), GSL_REAL(yi));
      gsl_test_rel(GSL_IMAG(xi), GSL_IMAG(yi), eps, "%s res imag (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, GSL_IMAG(xi), GSL_IMAG(yi));
    }

  gsl_matrix_complex_free(QR);
  gsl_vector_complex_free(tau);
  gsl_vector_complex_free(x);
  gsl_vector_complex_free(r);
  gsl_vector_complex_free(r2);

  return s;
}

static int
test_QRc_lssolve()
{
  int s = 0;
  const double tol = 1.0e-10;

  {
    const double A_data[] = { 6.70178096995592e-01, 2.51765675689489e-01, 7.18387884271362e-01, 3.61106008613644e-01,
                              3.36342428526987e-02, 5.25755806084206e-01, 5.87596968507183e-01, 5.27700895952418e-01,
                              6.85871226549483e-01, 3.71216051930735e-01, 4.40045953339814e-01, 2.08875308141557e-01,
                              8.62676230425306e-01, 5.79995188556082e-01, 4.86983443637474e-02, 2.82915411954634e-01,
                              2.92843706013013e-01, 5.61536446182319e-01, 6.85137614758495e-02, 8.90853425372411e-01,
                              4.38527971314087e-01, 4.78136089625096e-01, 1.57942824868494e-01, 8.38451530279972e-01,
                              6.36273325487226e-01, 7.74039464290391e-02, 5.45646256301364e-01, 7.80075219450629e-01,
                              9.27400956530167e-01, 7.01700239834713e-02, 1.09682812589509e-01, 5.64047584357803e-01,
                              4.46922541620762e-02, 3.03438549353353e-01, 8.09200219159660e-01, 1.44245237525133e-01 };
    const double rhs_data[] = { 5.82246876454474e-01, 1.42259458199622e-02, 6.25588177982770e-01, 3.79195077388159e-01,
                                8.45448918385455e-02, 3.20808711881935e-01, 8.02701461544476e-01, 5.65141425118050e-01,
                                8.34227120735637e-01, 4.69005326248388e-01, 9.73712086117648e-01, 3.47197650692321e-01 };
    const double sol_data[] = { -2.07103028285037e-01, -3.77392587461962e-01,
                                 7.46590544020302e-01, -1.10976592416587e-01,
                                 6.07653916072011e-01,  2.05471935567110e-01 };
    gsl_matrix_complex_const_view A = gsl_matrix_complex_const_view_array(A_data, 6, 3);
    gsl_vector_complex_const_view rhs = gsl_vector_complex_const_view_array(rhs_data, 6);
    gsl_vector_complex_const_view sol = gsl_vector_complex_const_view_array(sol_data, 3);

    test_QRc_lssolve_eps(&A.matrix, &rhs.vector, &sol.vector, tol, "complex QR_lssolve test1");
  }

  return s;
}

static int
test_QRc_decomp_r_eps(const gsl_matrix_complex * m, const double eps, const char * desc)
{
  int s = 0;
  const size_t M = m->size1;
  const size_t N = m->size2;
  size_t i, j;

  gsl_matrix_complex * QR = gsl_matrix_complex_alloc(M, N);
  gsl_matrix_complex * T = gsl_matrix_complex_alloc(N, N);
  gsl_matrix_complex * A  = gsl_matrix_complex_alloc(M, N);
  gsl_matrix_complex * R  = gsl_matrix_complex_alloc(N, N);
  gsl_matrix_complex * Q  = gsl_matrix_complex_alloc(M, M);
  gsl_matrix_complex_view Q1 = gsl_matrix_complex_submatrix(Q, 0, 0, M, N);
  gsl_vector_complex_const_view tau = gsl_matrix_complex_const_diagonal(T);

  gsl_matrix_complex_memcpy(QR, m);

  s += gsl_linalg_complex_QR_decomp_r(QR, T);
  s += gsl_linalg_complex_QR_unpack_r(QR, T, Q, R);

  /* compute A = Q R */
  gsl_matrix_complex_memcpy(A, &Q1.matrix);
  gsl_blas_ztrmm (CblasRight, CblasUpper, CblasNoTrans, CblasNonUnit, GSL_COMPLEX_ONE, R, A);

  for (i = 0; i < M; i++)
    {
      for (j = 0; j < N; j++)
        {
          gsl_complex aij = gsl_matrix_complex_get(A, i, j);
          gsl_complex mij = gsl_matrix_complex_get(m, i, j);

          gsl_test_rel(GSL_REAL(aij), GSL_REAL(mij), eps, "%s real (%3lu,%3lu)[%lu,%lu]: %22.18g   %22.18g\n",
                       desc, M, N, i,j, GSL_REAL(aij), GSL_REAL(mij));
          gsl_test_rel(GSL_IMAG(aij), GSL_IMAG(mij), eps, "%s imag (%3lu,%3lu)[%lu,%lu]: %22.18g   %22.18g\n",
                       desc, M, N, i,j, GSL_IMAG(aij), GSL_IMAG(mij));
        }
    }

  if (M > N)
    {
      gsl_matrix_complex * R_alt  = gsl_matrix_complex_alloc(M, N);
      gsl_matrix_complex * Q_alt  = gsl_matrix_complex_alloc(M, M);

      /* test that Q2 was computed correctly by comparing with Level 2 algorithm */
      gsl_linalg_complex_QR_unpack(QR, &tau.vector, Q_alt, R_alt);

      for (i = 0; i < M; i++)
        {
          for (j = 0; j < M; j++)
            {
              gsl_complex aij = gsl_matrix_complex_get(Q, i, j);
              gsl_complex bij = gsl_matrix_complex_get(Q_alt, i, j);

              gsl_test_rel(GSL_REAL(aij), GSL_REAL(bij), eps, "%s real Q (%3lu,%3lu)[%lu,%lu]: %22.18g   %22.18g\n",
                           desc, M, N, i, j, GSL_REAL(aij), GSL_REAL(bij));
              gsl_test_rel(GSL_IMAG(aij), GSL_IMAG(bij), eps, "%s imag Q (%3lu,%3lu)[%lu,%lu]: %22.18g   %22.18g\n",
                           desc, M, N, i, j, GSL_IMAG(aij), GSL_IMAG(bij));
            }
        }

      gsl_matrix_complex_free(R_alt);
      gsl_matrix_complex_free(Q_alt);
    }

  gsl_matrix_complex_free(QR);
  gsl_matrix_complex_free(T);
  gsl_matrix_complex_free(A);
  gsl_matrix_complex_free(Q);
  gsl_matrix_complex_free(R);

  return s;
}

static int
test_QRc_decomp_r(gsl_rng * r)
{
  int s = 0;
  size_t M, N;

  for (M = 1; M <= 50; ++M)
    {
      for (N = 1; N <= M; ++N)
        {
          gsl_matrix_complex * A = gsl_matrix_complex_alloc(M, N);

          create_random_complex_matrix(A, r);
          s += test_QRc_decomp_r_eps(A, 1.0e6 * M * GSL_DBL_EPSILON, "complex_QR_decomp_r random");

          gsl_matrix_complex_free(A);
        }
    }

  return s;
}

static int
test_QRc_solve_r_eps(const gsl_matrix_complex * A, const gsl_vector_complex * rhs, const gsl_vector_complex * sol,
                     const double eps, const char * desc)
{
  int s = 0;
  const size_t M = A->size1;
  const size_t N = A->size2;
  size_t i;

  gsl_matrix_complex * QR = gsl_matrix_complex_alloc(M, N);
  gsl_matrix_complex * T = gsl_matrix_complex_alloc(N, N);
  gsl_vector_complex * x  = gsl_vector_complex_alloc(N);

  gsl_matrix_complex_memcpy(QR, A);

  s += gsl_linalg_complex_QR_decomp_r(QR, T);
  s += gsl_linalg_complex_QR_solve_r(QR, T, rhs, x);

  for (i = 0; i < M; i++)
    {
      gsl_complex xi = gsl_vector_complex_get(x, i);
      gsl_complex yi = gsl_vector_complex_get(sol, i);

      gsl_test_rel(GSL_REAL(xi), GSL_REAL(yi), eps, "%s real (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, GSL_REAL(xi), GSL_REAL(yi));
      gsl_test_rel(GSL_IMAG(xi), GSL_IMAG(yi), eps, "%s imag (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, GSL_IMAG(xi), GSL_IMAG(yi));
    }

  gsl_matrix_complex_free(QR);
  gsl_matrix_complex_free(T);
  gsl_vector_complex_free(x);

  return s;
}

static int
test_QRc_solve_r(gsl_rng * r)
{
  int s = 0;
  size_t N;

  for (N = 1; N <= 50; ++N)
    {
      gsl_matrix_complex * A = gsl_matrix_complex_alloc(N, N);
      gsl_vector_complex * sol = gsl_vector_complex_alloc(N);
      gsl_vector_complex * rhs = gsl_vector_complex_alloc(N);

      create_random_complex_matrix(A, r);
      create_random_complex_vector(sol, r);
      gsl_blas_zgemv(CblasNoTrans, GSL_COMPLEX_ONE, A, sol, GSL_COMPLEX_ZERO, rhs);

      s += test_QRc_solve_r_eps(A, rhs, sol, 1.0e6 * N * GSL_DBL_EPSILON, "complex_QR_solve_r random");

      gsl_matrix_complex_free(A);
      gsl_vector_complex_free(sol);
      gsl_vector_complex_free(rhs);
    }

  return s;
}

static int
test_QRc_lssolve_r_eps(const gsl_matrix_complex * A, const gsl_vector_complex * rhs, const gsl_vector_complex * sol,
                       const double eps, const char * desc)
{
  int s = 0;
  const size_t M = A->size1;
  const size_t N = A->size2;
  size_t i;

  gsl_matrix_complex * QR = gsl_matrix_complex_alloc(M, N);
  gsl_matrix_complex * T = gsl_matrix_complex_alloc(N, N);
  gsl_vector_complex * x  = gsl_vector_complex_alloc(M);
  gsl_vector_complex * r  = gsl_vector_complex_alloc(M);
  gsl_vector_complex * work = gsl_vector_complex_alloc(N);
  gsl_vector_complex_const_view x1 = gsl_vector_complex_const_subvector(x, N, M - N);
  double rnorm_expected, rnorm;

  gsl_matrix_complex_memcpy(QR, A);

  s += gsl_linalg_complex_QR_decomp_r(QR, T);
  s += gsl_linalg_complex_QR_lssolve_r(QR, T, rhs, x, work);

  for (i = 0; i < N; i++)
    {
      gsl_complex xi = gsl_vector_complex_get(x, i);
      gsl_complex yi = gsl_vector_complex_get(sol, i);

      gsl_test_rel(GSL_REAL(xi), GSL_REAL(yi), eps, "%s sol real (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, GSL_REAL(xi), GSL_REAL(yi));
      gsl_test_rel(GSL_IMAG(xi), GSL_IMAG(yi), eps, "%s sol imag (%3lu)[%lu]: %22.18g   %22.18g\n",
                   desc, N, i, GSL_IMAG(xi), GSL_IMAG(yi));
    }

  /* compute residual and check */
  gsl_vector_complex_memcpy(r, rhs);
  gsl_blas_zgemv(CblasNoTrans, GSL_COMPLEX_NEGONE, A, sol, GSL_COMPLEX_ONE, r);

  rnorm_expected = gsl_blas_dznrm2(r);
  rnorm = gsl_blas_dznrm2(&x1.vector);
  gsl_test_rel(rnorm, rnorm_expected, eps, "%s rnorm (%3lu): %22.18g   %22.18g\n",
               desc, N, rnorm, rnorm_expected);

  gsl_matrix_complex_free(QR);
  gsl_matrix_complex_free(T);
  gsl_vector_complex_free(x);
  gsl_vector_complex_free(r);
  gsl_vector_complex_free(work);

  return s;
}

static int
test_QRc_lssolve_r()
{
  int s = 0;
  const double tol = 1.0e-10;

  {
    const double A_data[] = { 6.70178096995592e-01, 2.51765675689489e-01, 7.18387884271362e-01, 3.61106008613644e-01,
                              3.36342428526987e-02, 5.25755806084206e-01, 5.87596968507183e-01, 5.27700895952418e-01,
                              6.85871226549483e-01, 3.71216051930735e-01, 4.40045953339814e-01, 2.08875308141557e-01,
                              8.62676230425306e-01, 5.79995188556082e-01, 4.86983443637474e-02, 2.82915411954634e-01,
                              2.92843706013013e-01, 5.61536446182319e-01, 6.85137614758495e-02, 8.90853425372411e-01,
                              4.38527971314087e-01, 4.78136089625096e-01, 1.57942824868494e-01, 8.38451530279972e-01,
                              6.36273325487226e-01, 7.74039464290391e-02, 5.45646256301364e-01, 7.80075219450629e-01,
                              9.27400956530167e-01, 7.01700239834713e-02, 1.09682812589509e-01, 5.64047584357803e-01,
                              4.46922541620762e-02, 3.03438549353353e-01, 8.09200219159660e-01, 1.44245237525133e-01 };
    const double rhs_data[] = { 5.82246876454474e-01, 1.42259458199622e-02, 6.25588177982770e-01, 3.79195077388159e-01,
                                8.45448918385455e-02, 3.20808711881935e-01, 8.02701461544476e-01, 5.65141425118050e-01,
                                8.34227120735637e-01, 4.69005326248388e-01, 9.73712086117648e-01, 3.47197650692321e-01 };
    const double sol_data[] = { -2.07103028285037e-01, -3.77392587461962e-01,
                                 7.46590544020302e-01, -1.10976592416587e-01,
                                 6.07653916072011e-01,  2.05471935567110e-01 };
    gsl_matrix_complex_const_view A = gsl_matrix_complex_const_view_array(A_data, 6, 3);
    gsl_vector_complex_const_view rhs = gsl_vector_complex_const_view_array(rhs_data, 6);
    gsl_vector_complex_const_view sol = gsl_vector_complex_const_view_array(sol_data, 3);

    test_QRc_lssolve_r_eps(&A.matrix, &rhs.vector, &sol.vector, tol, "complex_QR_lssolve_r test1");
  }

  return s;
}


/* randist/poisson.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 James Theiler, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <config.h>
#include <math.h>
#include <gsl/gsl_sf_gamma.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

/* The poisson distribution has the form

   p(n) = (mu^n / n!) exp(-mu)

   for n = 0, 1, 2, ... . The method used here is the one from Knuth. */

unsigned int
gsl_ran_poisson (const gsl_rng * r, double mu)
{
  double emu;
  double prod = 1.0;
  unsigned int k = 0;

  while (mu > 10)
    {
      unsigned int m = mu * (7.0 / 8.0);

      double X = gsl_ran_gamma_int (r, m);

      if (X >= mu)
        {
          return k + gsl_ran_binomial (r, mu / X, m - 1);
        }
      else
        {
          k += m;
          mu -= X;
        }
    }

  /* This following method works well when mu is small */

  emu = exp (-mu);

  do
    {
      prod *= gsl_rng_uniform (r);
      k++;
    }
  while (prod > emu);

  return k - 1;

}

void
gsl_ran_poisson_array (const gsl_rng * r, size_t n, unsigned int array[],
                       double mu)
{
  size_t i;

  for (i = 0; i < n; i++)
    {
      array[i] = gsl_ran_poisson (r, mu);
    }

  return;
}

double
gsl_ran_poisson_pdf (const unsigned int k, const double mu)
{
  double p;
  double lf = gsl_sf_lnfact (k);

  p = exp (log (mu) * k - lf - mu);
  return p;
}


/* specfunc/gsl_sf_gamma.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/* Author:  G. Jungman */

#ifndef __GSL_SF_GAMMA_H__
#define __GSL_SF_GAMMA_H__

#include <gsl/gsl_sf_result.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

/* Log[Gamma(x)], x not a negative integer
 * Uses real Lanczos method.
 * Returns the real part of Log[Gamma[x]] when x < 0,
 * i.e. Log[|Gamma[x]|].
 *
 * exceptions: GSL_EDOM, GSL_EROUND
 */
int gsl_sf_lngamma_e(double x, gsl_sf_result * result);
double gsl_sf_lngamma(const double x);

/* Log[Gamma(x)], x not a negative integer
 * Uses real Lanczos method. Determines
 * the sign of Gamma[x] as well as Log[|Gamma[x]|] for x < 0.
 * So Gamma[x] = sgn * Exp[result_lg].
 *
 * exceptions: GSL_EDOM, GSL_EROUND
 */
int gsl_sf_lngamma_sgn_e(double x, gsl_sf_result * result_lg, double *sgn);

/* Gamma(x), x not a negative integer
 * Uses real Lanczos method.
 *
 * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EROUND
 */
int gsl_sf_gamma_e(const double x, gsl_sf_result * result);
double gsl_sf_gamma(const double x);

/* Regulated Gamma Function, x > 0
 * Gamma^*(x) = Gamma(x)/(Sqrt[2Pi] x^(x-1/2) exp(-x))
 *            = (1 + 1/(12x) + ...),  x->Inf
 * A useful suggestion of Temme.
 *
 * exceptions: GSL_EDOM
 */
int gsl_sf_gammastar_e(const double x, gsl_sf_result * result);
double gsl_sf_gammastar(const double x);

/* 1/Gamma(x)
 * Uses real Lanczos method.
 *
 * exceptions: GSL_EUNDRFLW, GSL_EROUND
 */
int gsl_sf_gammainv_e(const double x, gsl_sf_result * result);
double gsl_sf_gammainv(const double x);

/* Log[Gamma(z)] for z complex, z not a negative integer
 * Uses complex Lanczos method. Note that the phase part (arg)
 * is not well-determined when |z| is very large, due
 * to inevitable roundoff in restricting to (-Pi,Pi].
 * This will raise the GSL_ELOSS exception when it occurs.
 * The absolute value part (lnr), however, never suffers.
 *
 * Calculates:
 *   lnr = log|Gamma(z)|
 *   arg = arg(Gamma(z))  in (-Pi, Pi]
 *
 * exceptions: GSL_EDOM, GSL_ELOSS
 */
int gsl_sf_lngamma_complex_e(double zr, double zi, gsl_sf_result * lnr, gsl_sf_result * arg);

/* x^n / n!
 *
 * x >= 0.0, n >= 0
 * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW
 */
int gsl_sf_taylorcoeff_e(const int n, const double x, gsl_sf_result * result);
double gsl_sf_taylorcoeff(const int n, const double x);

/* n!
 *
 * exceptions: GSL_EDOM, GSL_OVRFLW
 */
int gsl_sf_fact_e(const unsigned int n, gsl_sf_result * result);
double gsl_sf_fact(const unsigned int n);

/* n!! = n(n-2)(n-4) ...
 *
 * exceptions: GSL_EDOM, GSL_OVRFLW
 */
int gsl_sf_doublefact_e(const unsigned int n, gsl_sf_result * result);
double gsl_sf_doublefact(const unsigned int n);

/* log(n!)
 * Faster than ln(Gamma(n+1)) for n < 170; defers for larger n.
 *
 * exceptions: none
 */
int gsl_sf_lnfact_e(const unsigned int n, gsl_sf_result * result);
double gsl_sf_lnfact(const unsigned int n);

/* log(n!!)
 *
 * exceptions: none
 */
int gsl_sf_lndoublefact_e(const unsigned int n, gsl_sf_result * result);
double gsl_sf_lndoublefact(const unsigned int n);

/* log(n choose m)
 *
 * exceptions: GSL_EDOM
 */
int gsl_sf_lnchoose_e(unsigned int n, unsigned int m, gsl_sf_result * result);
double gsl_sf_lnchoose(unsigned int n, unsigned int m);

/* n choose m
 *
 * exceptions: GSL_EDOM, GSL_EOVRFLW
 */
int gsl_sf_choose_e(unsigned int n, unsigned int m, gsl_sf_result * result);
double gsl_sf_choose(unsigned int n, unsigned int m);

/* Logarithm of Pochhammer (Apell) symbol
 *   log( (a)_x )
 *   where (a)_x := Gamma[a + x]/Gamma[a]
 *
 * a > 0, a+x > 0
 *
 * exceptions:  GSL_EDOM
 */
int gsl_sf_lnpoch_e(const double a, const double x, gsl_sf_result * result);
double gsl_sf_lnpoch(const double a, const double x);

/* Logarithm of Pochhammer (Apell) symbol, with sign information.
 *   result = log( |(a)_x| )
 *   sgn    = sgn( (a)_x )
 *   where (a)_x := Gamma[a + x]/Gamma[a]
 *
 * a != neg integer, a+x != neg integer
 *
 * exceptions:  GSL_EDOM
 */
int gsl_sf_lnpoch_sgn_e(const double a, const double x, gsl_sf_result * result, double * sgn);

/* Pochhammer (Apell) symbol
 *   (a)_x := Gamma[a + x]/Gamma[x]
 *
 * a != neg integer, a+x != neg integer
 *
 * exceptions:  GSL_EDOM, GSL_EOVRFLW
 */
int gsl_sf_poch_e(const double a, const double x, gsl_sf_result * result);
double gsl_sf_poch(const double a, const double x);

/* Relative Pochhammer (Apell) symbol
 *   ((a,x) - 1)/x
 *   where (a,x) = (a)_x := Gamma[a + x]/Gamma[a]
 *
 * exceptions:  GSL_EDOM
 */
int gsl_sf_pochrel_e(const double a, const double x, gsl_sf_result * result);
double gsl_sf_pochrel(const double a, const double x);

/* Normalized Incomplete Gamma Function
 *
 * Q(a,x) = 1/Gamma(a) Integral[ t^(a-1) e^(-t), {t,x,Infinity} ]
 *
 * a >= 0, x >= 0
 *   Q(a,0) := 1
 *   Q(0,x) := 0, x != 0
 *
 * exceptions: GSL_EDOM
 */
int gsl_sf_gamma_inc_Q_e(const double a, const double x, gsl_sf_result * result);
double gsl_sf_gamma_inc_Q(const double a, const double x);

/* Complementary Normalized Incomplete Gamma Function
 *
 * P(a,x) = 1/Gamma(a) Integral[ t^(a-1) e^(-t), {t,0,x} ]
 *
 * a > 0, x >= 0
 *
 * exceptions: GSL_EDOM
 */
int gsl_sf_gamma_inc_P_e(const double a, const double x, gsl_sf_result * result);
double gsl_sf_gamma_inc_P(const double a, const double x);

/* Non-normalized Incomplete Gamma Function
 *
 * Gamma(a,x) := Integral[ t^(a-1) e^(-t), {t,x,Infinity} ]
 *
 * x >= 0.0
 *   Gamma(a, 0) := Gamma(a)
 *
 * exceptions: GSL_EDOM
 */
int gsl_sf_gamma_inc_e(const double a, const double x, gsl_sf_result * result);
double gsl_sf_gamma_inc(const double a, const double x);

/* Logarithm of Beta Function
 * Log[B(a,b)]
 *
 * a > 0, b > 0
 * exceptions: GSL_EDOM
 */
int gsl_sf_lnbeta_e(const double a, const double b, gsl_sf_result * result);
double gsl_sf_lnbeta(const double a, const double b);

int gsl_sf_lnbeta_sgn_e(const double x, const double y, gsl_sf_result * result, double * sgn);

/* Beta Function
 * B(a,b)
 *
 * a > 0, b > 0
 * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW
 */
int gsl_sf_beta_e(const double a, const double b, gsl_sf_result * result);
double gsl_sf_beta(const double a, const double b);

/* Normalized Incomplete Beta Function
 * B_x(a,b)/B(a,b)
 *
 * a > 0, b > 0, 0 <= x <= 1
 * exceptions: GSL_EDOM, GSL_EUNDRFLW
 */
int gsl_sf_beta_inc_e(const double a, const double b, const double x, gsl_sf_result * result);
double gsl_sf_beta_inc(const double a, const double b, const double x);

/* The maximum x such that gamma(x) is not
 * considered an overflow.
 */
#define GSL_SF_GAMMA_XMAX  171.0

/* The maximum n such that gsl_sf_fact(n) does not give an overflow. */
#define GSL_SF_FACT_NMAX 170

/* The maximum n such that gsl_sf_doublefact(n) does not give an overflow. */
#define GSL_SF_DOUBLEFACT_NMAX 297

__END_DECLS

#endif /* __GSL_SF_GAMMA_H__ */


#ifndef _LINEAR_ALGEBRA_HELPERS_H_
#define _LINEAR_ALGEBRA_HELPERS_H_
#include <stddef.h>

#ifdef HAVE_LAPACK
#include <lapacke.h>
#include <cblas.h>
#endif

/* Define constants */
#define LAH_PI 3.14159265358979323846

/*--- Data types ------------------------------------------------------------*/

#ifdef HAVE_LAPACK
typedef size_t lah_index;
#else
typedef size_t lah_index;
#endif

/* Choose type of data */
#ifdef USE_SINGLE  /* Single or double precission */
    typedef float lah_value;
#else
    typedef double lah_value;
#endif

/* Automatically choose BLAS/Lapack routines based on data type */
/* If not OpenBLAS (cblas, lapacke) is used,
 * here is the place to account for another calling convention */
#ifdef HAVE_LAPACK
    #ifdef USE_SINGLE
        #define GEMM cblas_sgemm
        #define POTRF LAPACKE_spotrf
        #define POTRS LAPACKE_spotrs
        #define GETRF LAPACKE_sgetrf
        #define GETRS LAPACKE_sgetrs
        #define GEQRF LAPACKE_sgeqrf
        #define SYEVR LAPACKE_ssyevr
        #define GESDD LAPACKE_sgesdd
        #define LAMCH LAPACKE_slamch
    #else
        #define GEMM cblas_dgemm
        #define POTRF LAPACKE_dpotrf /* Chol Decomposition */
        #define POTRS LAPACKE_dpotrs /* Solving Triangular System */
        #define GETRF LAPACKE_dgetrf /* LU Decomposition */
        #define GETRS LAPACKE_dgetrs /* Solving Triangular System */
        #define GEQRF LAPACKE_dgeqrf /* QR factorization */
        #define SYEVR LAPACKE_dsyevr /* SVD for matSqrt (symmetric matrix) */
        #define GESDD LAPACKE_dgesdd /* General SVD with divide and conquer */
        #define LAMCH LAPACKE_dlamch /* Helper to obtain machine precision */
    #endif /* end Data_Types*/
#endif /* end HAVE_LAPACK*/

/* Check if called from C++ */
#ifdef __cplusplus
	extern "C" {
#endif

/*--- Definitions for Linear Algebra subroutines*/
/* Specifies whether Row- or ColMajor */
typedef enum
{
    lahRowMajor=101,
    lahColMajor=102
} lah_layout;

#define LAH_LAYOUT lahRowMajor
/*#define LAH_LAYOUT(A) (((A)->matType & lahTypeColMajor) ? lahColMajor : lahRowMajor) */
#ifdef HAVE_LAPACK
    #if LAH_LAYOUT == lahColMajor
        #define LAH_CBLAS_LAYOUT CblasColMajor
        #define LAH_LAPACK_LAYOUT LAPACK_COL_MAJOR
        #define LAH_LEADING_DIM(A) ((A)->nR)
    #else
        #define LAH_CBLAS_LAYOUT CblasRowMajor
        #define LAH_LAPACK_LAYOUT LAPACK_ROW_MAJOR
        #define LAH_LEADING_DIM(A) ((A)->nC)
    #endif
#endif

/* Option for LA operations: Transpose Input before Computation or not? */
typedef enum
{
    lahTrans = 'T',
    lahNorm = 'N'
} lah_MatOp;

/* Error Types definition*/
typedef enum
{
    lahReturnOk = 0,          /* Success */
    lahReturnParameterError,  /* Wrong Parameters */
    lahReturnMathError,       /* General Math Error, either error while
                                 * computing or prerequisit not met */
    lahReturnFPError,          /* Error when evaluating function pointer */
    lahReturnExternError          /* Error when evaluating function pointer */
} lah_Return;

typedef enum
{
    /* Properties, which are known in matAlloc */
    lahTypeColMajor = 0x01,     /* 0000 0001 */
    lahTypeNoData = 0x02,       /* 0000 0010 */
    lahTypeVector = 0x04,       /* 0000 0100 */
    lahTypeSquare = 0x08,       /* 0000 1000 */

    /* Properties, which are not known in matAlloc */
    lahTypeDiagonal = 0x10,     /* 0001 0000 */
    lahTypeSymmetric = 0x20,    /* 0010 0000 */
    lahTypePositive = 0x40,     /* 0100 0000 */
    lahTypeOrthogonal = 0x80    /* 1000 0000 */
} lah_MatType;

/* lah_mat: Matrix format */
typedef struct
{
    lah_index nC;          /* Number of Columns */
    lah_index nR;          /* Number of Rows */
    lah_index incRow;      /* increment of rows */
    lah_index incCol;      /* increment of columns */
    lah_value *data;       /* pointer to data */
    lah_MatType matType;   /* flags for several properties of Matrix */
} lah_mat;

/*---------------------------------------------------------------------------*/

/*--- Common Linear Algebra helpers ----------------------------------------*/
/* If provided, these functions are using a CBLAS/LAPACKE library           */
/* else they use a simple handwritten defintion                             */
/*--------------------------------------------------------------------------*/

/* Computes the general Matrix mulitplikation of form:
 * C = alpha*C + beta*op(A)*op(B)
 * similar to the BLAS routine ?gemm.
 * op(A) = A for transA=koopNorm or op(A) = At for transA = koopTrans */
lah_Return lah_matMul(lah_MatOp transA, lah_MatOp transB,
                        lah_value alpha, lah_value beta,
                        lah_mat *C, lah_mat const *A, lah_mat const *B);

/* Adds two matrices C = alpha*A + beta*B */
lah_Return lah_matAdd(lah_mat *C, lah_value alpha, lah_mat const *A,
                      lah_value beta, lah_mat const *B);

/* This will return a lah_mat struct At with inverted order
 * (RowMajor <-> ColMajor). If At is not needed anymore, call free(At)
 * NOT lah_matFree(At), as this will also delete A->data                   */
lah_mat *lah_matTrans(lah_mat const *A);

/* Computes the Cholesky factorization of the form P = L * Lt
 * where P is a symmetric positive-definite matrix, L is a lower triangular
 * matrix and Lt denotes its transpose.                                     */
lah_Return lah_chol(lah_mat *P, lah_index setZero);

/* Computes a rank-1 Update to a Cholesky factorization.
 * Let L is the Cholesky factor of a spd matrix P = L * Lt, then
 * the update is the Cholesky factor of the matrix P_new = P + x * x' */
lah_Return lah_cholUpdate(lah_mat *L, lah_mat *x, lah_value alpha);

/* Computes the Forward Substitution of the linear equation system L * X = B
 * where L is a lower triangular matrix,
 * x and b are matrices with the same number of columns.                    */
lah_Return lah_forwardSub(lah_mat *B, lah_mat const *L);

/* Computes an Update to a matrix C of form D = A*C*A'+B  */
/* workspace needed for special case C = A*C*A'+B         */
lah_Return lah_matUpdate(lah_mat *D, lah_mat const *C,
                           lah_mat const *A, lah_mat const *B,
                           lah_mat *W);
/*--------------------------------------------------------------------------*/

/*--- Function only defined for HAVE_LAPACK --------------------------------*/

#ifdef HAVE_LAPACK

/* Computes the LU factorization of the form A = L * U,
 * as an alternative to Cholesky for general matrices*/
lah_Return lah_LU(lah_mat *A, lah_index setZero, lapack_int *ipiv);

/* Solves the linear equation system L * X = B
 * arising from the LU factorization */
/*lah_Return lah_solveLU(lah_mat *X, const lah_mat *L,
                       const lah_mat *B, lah_index *ipiv);
*/
lah_Return lah_solveLU(lah_mat *B, const lah_mat *L, lapack_int *ipiv);

/* Computes the QR factorization of the form A = L * U,
 * as an alternative to Cholesky for general matrices*/
lah_Return lah_QR(lah_mat *A, lah_value *tau);

/* Computes the eigen values and vectors of a symmetric matrix P*/
lah_Return lah_eigenValue(lah_mat *P, lah_value *S, lah_mat *Z);

/* Computes the Sqrt of a positive Matrix by computing the eigen values */
lah_Return lah_matSqrt(lah_mat *P, lah_mat *Psqrt, lah_mat *Work);

/*General Singular Value Decomposition */
lah_Return lah_SVD(lah_mat *A, lah_mat *U, lah_value *S, lah_mat *Vt);
#endif

/*--------------------------------------------------------------------------*/

/*--- Helper functions -----------------------------------------------------*/

/*--- Utility functions ---*/
/* allocation for the Matrix struct lah_mat */
lah_mat* lah_matAlloc(lah_index nC, lah_index nR, lah_index AllocData);

/* Free all data used bei the Matrix struct lah_mat */
lah_mat* lah_matFree(lah_mat *mat);

/* load a matrix from a file */
lah_mat* lah_matLoad(const char *fname);

/* Print a lah_mat Matrix struct (used for debugging) */
lah_Return lah_matPrint(lah_mat const *A, lah_index brief);

/*--- Noise Generators ---*/
/* Returns a random number from a Gaussian distribution */
lah_value lah_gaussNoise();

/* Returns a random number from a Lorentz (Cauchy) distribution */
lah_value lah_lorentzNoise();

/*--- Property checks ---*/
/* Checks if matrix is symmetric.
 * It compares with $(precision) significant digits */
lah_index lah_isSymmetric(lah_mat *A, lah_index precision);

/* Checks if matrix is positive definite. It tries to compute a Cholesky
 * factorization, which only works for positive definite matrices*/
lah_index lah_isPositive(lah_mat *A);

/*--- Construct different Matrix types ---*/
/* Construct a diagonal matrix from n parameters */
lah_mat *lah_matConstructDiag(lah_index nC, const lah_value *parameter_vec);

/* Construct a symmetric Matrix from n(n+1)/2 parameters */
lah_mat *lah_matConstructSy(lah_index nC, const lah_value *parameter_vec);

/* Construct a orthogonal Matrix from n(n+1)/2 parameters */
lah_mat *lah_matConstructOrtho(lah_index nC, lah_value *parameter_vec);

/* Construct a positive Matrix from n(n+3)/2 parameters */
lah_mat *lah_matConstructPo(lah_index nC, lah_value *parameter_vec);

/* Construct a positive Matrix the simple way from a nxn Maxtrix */
lah_mat *lah_matConstructPo_simple(lah_mat *A);

/*--- Macro definitions ----------------------------------------------------*/

/* Macro to access element of Matrix A[i,j] */
#define LAH_ENTRY(A, i, j) ((A)->data[(i) * (A)->incRow + (j) * (A)->incCol])
#define LAH_MAX(A, B) (((A) > (B)) ? (A) : (B))
#define LAH_MIN(A, B) (((A) < (B)) ? (A) : (B))
#define LAH_SIGN(A) ((A) < 0) ? (-1) : (1))

/*--- Property MACROS---*/
#define LAH_ISTYPE(A, Type) ((A)->matType & (Type))        /* AND */
#define LAH_SETTYPE(A, Type) ((A)->matType |= (Type))      /* OR */
#define LAH_UNSETTYPE(A, Type) ((A)->matType &= (~Type)) /* NAND */
#define LAH_TOGGLETYPE(A, Type) ((A)->matType ^= (Type))   /* XOR */

/*--- LAPACK_ONLY HEADERS ---*/
#ifdef HAVE_LAPACK

#endif

/*--------------------------------------------------------------------------*/
#ifdef __cplusplus
}
#endif

#endif