nmatrix 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Gemfile +1 -1
  2. data/History.txt +31 -3
  3. data/Manifest.txt +5 -0
  4. data/README.rdoc +29 -27
  5. data/ext/nmatrix/binary_format.txt +53 -0
  6. data/ext/nmatrix/data/data.cpp +18 -18
  7. data/ext/nmatrix/data/data.h +38 -7
  8. data/ext/nmatrix/data/rational.h +13 -0
  9. data/ext/nmatrix/data/ruby_object.h +10 -0
  10. data/ext/nmatrix/extconf.rb +2 -0
  11. data/ext/nmatrix/nmatrix.cpp +655 -103
  12. data/ext/nmatrix/nmatrix.h +26 -14
  13. data/ext/nmatrix/ruby_constants.cpp +4 -0
  14. data/ext/nmatrix/ruby_constants.h +2 -0
  15. data/ext/nmatrix/storage/dense.cpp +99 -41
  16. data/ext/nmatrix/storage/dense.h +3 -3
  17. data/ext/nmatrix/storage/list.cpp +36 -14
  18. data/ext/nmatrix/storage/list.h +4 -4
  19. data/ext/nmatrix/storage/storage.cpp +19 -19
  20. data/ext/nmatrix/storage/storage.h +11 -11
  21. data/ext/nmatrix/storage/yale.cpp +17 -20
  22. data/ext/nmatrix/storage/yale.h +13 -11
  23. data/ext/nmatrix/util/io.cpp +25 -23
  24. data/ext/nmatrix/util/io.h +5 -5
  25. data/ext/nmatrix/util/math.cpp +634 -17
  26. data/ext/nmatrix/util/math.h +958 -9
  27. data/ext/nmatrix/util/sl_list.cpp +7 -7
  28. data/ext/nmatrix/util/sl_list.h +2 -2
  29. data/lib/nmatrix.rb +9 -0
  30. data/lib/nmatrix/blas.rb +4 -4
  31. data/lib/nmatrix/io/market.rb +227 -0
  32. data/lib/nmatrix/io/mat_reader.rb +7 -7
  33. data/lib/nmatrix/lapack.rb +80 -0
  34. data/lib/nmatrix/nmatrix.rb +78 -52
  35. data/lib/nmatrix/shortcuts.rb +486 -0
  36. data/lib/nmatrix/version.rb +1 -1
  37. data/spec/2x2_dense_double.mat +0 -0
  38. data/spec/blas_spec.rb +59 -9
  39. data/spec/elementwise_spec.rb +25 -12
  40. data/spec/io_spec.rb +69 -1
  41. data/spec/lapack_spec.rb +53 -4
  42. data/spec/math_spec.rb +9 -0
  43. data/spec/nmatrix_list_spec.rb +95 -0
  44. data/spec/nmatrix_spec.rb +10 -53
  45. data/spec/nmatrix_yale_spec.rb +17 -15
  46. data/spec/shortcuts_spec.rb +154 -0
  47. metadata +22 -15
@@ -73,11 +73,11 @@ extern "C" {
73
73
  /*
74
74
  * C accessors.
75
75
  */
76
- dtype_t nm_dtype_from_rbsymbol(VALUE sym);
77
- dtype_t nm_dtype_from_rbstring(VALUE str);
78
- stype_t nm_stype_from_rbsymbol(VALUE sym);
79
- stype_t nm_stype_from_rbstring(VALUE str);
80
- itype_t nm_itype_from_rbsymbol(VALUE sym);
76
+ nm::dtype_t nm_dtype_from_rbsymbol(VALUE sym);
77
+ nm::dtype_t nm_dtype_from_rbstring(VALUE str);
78
+ nm::stype_t nm_stype_from_rbsymbol(VALUE sym);
79
+ nm::stype_t nm_stype_from_rbstring(VALUE str);
80
+ nm::itype_t nm_itype_from_rbsymbol(VALUE sym);
81
81
 
82
82
  void nm_init_io(void);
83
83
 
@@ -127,18 +127,31 @@ extern "C" {
127
127
  #include <clapack.h>
128
128
  #endif
129
129
 
130
+ static VALUE nm_cblas_rot(VALUE self, VALUE n, VALUE x, VALUE incx, VALUE y, VALUE incy, VALUE c, VALUE s);
131
+ static VALUE nm_cblas_rotg(VALUE self, VALUE ab);
132
+
130
133
  static VALUE nm_cblas_gemm(VALUE self, VALUE order, VALUE trans_a, VALUE trans_b, VALUE m, VALUE n, VALUE k, VALUE vAlpha,
131
134
  VALUE a, VALUE lda, VALUE b, VALUE ldb, VALUE vBeta, VALUE c, VALUE ldc);
132
-
133
135
  static VALUE nm_cblas_gemv(VALUE self, VALUE trans_a, VALUE m, VALUE n, VALUE vAlpha, VALUE a, VALUE lda,
134
136
  VALUE x, VALUE incx, VALUE vBeta, VALUE y, VALUE incy);
135
-
136
137
  static VALUE nm_cblas_trsm(VALUE self, VALUE order, VALUE side, VALUE uplo, VALUE trans_a, VALUE diag, VALUE m, VALUE n,
137
138
  VALUE vAlpha, VALUE a, VALUE lda, VALUE b, VALUE ldb);
139
+ static VALUE nm_cblas_trmm(VALUE self, VALUE order, VALUE side, VALUE uplo, VALUE trans_a, VALUE diag, VALUE m, VALUE n,
140
+ VALUE alpha, VALUE a, VALUE lda, VALUE b, VALUE ldb);
141
+ static VALUE nm_cblas_herk(VALUE self, VALUE order, VALUE uplo, VALUE trans, VALUE n, VALUE k, VALUE alpha, VALUE a,
142
+ VALUE lda, VALUE beta, VALUE c, VALUE ldc);
143
+ static VALUE nm_cblas_syrk(VALUE self, VALUE order, VALUE uplo, VALUE trans, VALUE n, VALUE k, VALUE alpha, VALUE a,
144
+ VALUE lda, VALUE beta, VALUE c, VALUE ldc);
138
145
 
139
146
  static VALUE nm_clapack_getrf(VALUE self, VALUE order, VALUE m, VALUE n, VALUE a, VALUE lda);
140
-
147
+ static VALUE nm_clapack_potrf(VALUE self, VALUE order, VALUE uplo, VALUE n, VALUE a, VALUE lda);
148
+ static VALUE nm_clapack_getrs(VALUE self, VALUE order, VALUE trans, VALUE n, VALUE nrhs, VALUE a, VALUE lda, VALUE ipiv, VALUE b, VALUE ldb);
149
+ static VALUE nm_clapack_potrs(VALUE self, VALUE order, VALUE uplo, VALUE n, VALUE nrhs, VALUE a, VALUE lda, VALUE b, VALUE ldb);
150
+ static VALUE nm_clapack_getri(VALUE self, VALUE order, VALUE n, VALUE a, VALUE lda, VALUE ipiv);
151
+ static VALUE nm_clapack_potri(VALUE self, VALUE order, VALUE uplo, VALUE n, VALUE a, VALUE lda);
152
+ static VALUE nm_clapack_laswp(VALUE self, VALUE n, VALUE a, VALUE lda, VALUE k1, VALUE k2, VALUE ipiv, VALUE incx);
141
153
  static VALUE nm_clapack_scal(VALUE self, VALUE n, VALUE scale, VALUE vector, VALUE incx);
154
+ static VALUE nm_clapack_lauum(VALUE self, VALUE order, VALUE uplo, VALUE n, VALUE a, VALUE lda);
142
155
 
143
156
  } // end of extern "C" block
144
157
 
@@ -238,6 +251,37 @@ inline static void cblas_trsm(const enum CBLAS_ORDER order, const enum CBLAS_SID
238
251
  }
239
252
 
240
253
 
254
+ /*
255
+ * Function signature conversion for calling CBLAS' trmm functions as directly as possible.
256
+ *
257
+ * For documentation: http://www.netlib.org/blas/dtrmm.f
258
+ */
259
+ template <typename DType>
260
+ inline static void cblas_trmm(const enum CBLAS_ORDER order, const enum CBLAS_SIDE side, const enum CBLAS_UPLO uplo,
261
+ const enum CBLAS_TRANSPOSE ta, const enum CBLAS_DIAG diag, const int m, const int n, const void* alpha,
262
+ const void* A, const int lda, void* B, const int ldb)
263
+ {
264
+ trmm<DType>(order, side, uplo, ta, diag, m, n, reinterpret_cast<const DType*>(alpha),
265
+ reinterpret_cast<const DType*>(A), lda, reinterpret_cast<DType*>(B), ldb);
266
+ }
267
+
268
+
269
+ /*
270
+ * Function signature conversion for calling CBLAS' syrk functions as directly as possible.
271
+ *
272
+ * For documentation: http://www.netlib.org/blas/dsyrk.f
273
+ */
274
+ template <typename DType>
275
+ inline static void cblas_syrk(const enum CBLAS_ORDER order, const enum CBLAS_UPLO uplo, const enum CBLAS_TRANSPOSE trans,
276
+ const int n, const int k, const void* alpha,
277
+ const void* A, const int lda, const void* beta, void* C, const int ldc)
278
+ {
279
+ syrk<DType>(order, uplo, trans, n, k, reinterpret_cast<const DType*>(alpha),
280
+ reinterpret_cast<const DType*>(A), lda, reinterpret_cast<const DType*>(beta), reinterpret_cast<DType*>(C), ldc);
281
+ }
282
+
283
+
284
+
241
285
 
242
286
  }} // end of namespace nm::math
243
287
 
@@ -252,13 +296,26 @@ void nm_math_init_blas() {
252
296
  cNMatrix_LAPACK = rb_define_module_under(cNMatrix, "LAPACK");
253
297
 
254
298
  rb_define_singleton_method(cNMatrix_LAPACK, "clapack_getrf", (METHOD)nm_clapack_getrf, 5);
255
- rb_define_singleton_method(cNMatrix_LAPACK, "clapack_scal", (METHOD)nm_clapack_scal, 4);
299
+ rb_define_singleton_method(cNMatrix_LAPACK, "clapack_potrf", (METHOD)nm_clapack_potrf, 5);
300
+ rb_define_singleton_method(cNMatrix_LAPACK, "clapack_getrs", (METHOD)nm_clapack_getrs, 9);
301
+ rb_define_singleton_method(cNMatrix_LAPACK, "clapack_potrs", (METHOD)nm_clapack_potrs, 8);
302
+ rb_define_singleton_method(cNMatrix_LAPACK, "clapack_getri", (METHOD)nm_clapack_getri, 5);
303
+ rb_define_singleton_method(cNMatrix_LAPACK, "clapack_potri", (METHOD)nm_clapack_potri, 5);
304
+ rb_define_singleton_method(cNMatrix_LAPACK, "clapack_laswp", (METHOD)nm_clapack_laswp, 7);
305
+ rb_define_singleton_method(cNMatrix_LAPACK, "clapack_scal", (METHOD)nm_clapack_scal, 4);
306
+ rb_define_singleton_method(cNMatrix_LAPACK, "clapack_lauum", (METHOD)nm_clapack_lauum, 5);
256
307
 
257
308
  cNMatrix_BLAS = rb_define_module_under(cNMatrix, "BLAS");
258
309
 
310
+ rb_define_singleton_method(cNMatrix_BLAS, "cblas_rot", (METHOD)nm_cblas_rot, 7);
311
+ rb_define_singleton_method(cNMatrix_BLAS, "cblas_rotg", (METHOD)nm_cblas_rotg, 1);
312
+
259
313
  rb_define_singleton_method(cNMatrix_BLAS, "cblas_gemm", (METHOD)nm_cblas_gemm, 14);
260
314
  rb_define_singleton_method(cNMatrix_BLAS, "cblas_gemv", (METHOD)nm_cblas_gemv, 11);
261
315
  rb_define_singleton_method(cNMatrix_BLAS, "cblas_trsm", (METHOD)nm_cblas_trsm, 12);
316
+ rb_define_singleton_method(cNMatrix_BLAS, "cblas_trmm", (METHOD)nm_cblas_trmm, 12);
317
+ rb_define_singleton_method(cNMatrix_BLAS, "cblas_syrk", (METHOD)nm_cblas_syrk, 11);
318
+ rb_define_singleton_method(cNMatrix_BLAS, "cblas_herk", (METHOD)nm_cblas_herk, 11);
262
319
  }
263
320
 
264
321
 
@@ -325,6 +382,139 @@ static inline enum CBLAS_ORDER blas_order_sym(VALUE op) {
325
382
  }
326
383
 
327
384
 
385
+ /*
386
+ * Call any of the cblas_xrotg functions as directly as possible.
387
+ *
388
+ * xROTG computes the elements of a Givens plane rotation matrix such that:
389
+ *
390
+ * | c s | | a | | r |
391
+ * | -s c | * | b | = | 0 |
392
+ *
393
+ * where r = +- sqrt( a**2 + b**2 ) and c**2 + s**2 = 1.
394
+ *
395
+ * The Givens plane rotation can be used to introduce zero elements into a matrix selectively.
396
+ *
397
+ * This function differs from most of the other raw BLAS accessors. Instead of providing a, b, c, s as arguments, you
398
+ * should only provide a and b (the inputs), and you should provide them as a single NVector (or the first two elements
399
+ * of any dense NMatrix or NVector type, specifically).
400
+ *
401
+ * The outputs [c,s] will be returned in a Ruby Array at the end; the input NVector will also be modified in-place.
402
+ *
403
+ * If you provide rationals, be aware that there's a high probability of an error, since rotg includes a square root --
404
+ * and most rationals' square roots are irrational. You're better off converting to Float first.
405
+ *
406
+ * This function, like the other cblas_ functions, does minimal type-checking.
407
+ */
408
+ static VALUE nm_cblas_rotg(VALUE self, VALUE ab) {
409
+ static void (*ttable[nm::NUM_DTYPES])(void* a, void* b, void* c, void* s) = {
410
+ NULL, NULL, NULL, NULL, NULL, // can't represent c and s as integers, so no point in having integer operations.
411
+ nm::math::cblas_rotg<float>,
412
+ nm::math::cblas_rotg<double>,
413
+ nm::math::cblas_rotg<nm::Complex64>,
414
+ nm::math::cblas_rotg<nm::Complex128>,
415
+ nm::math::cblas_rotg<nm::Rational32>,
416
+ nm::math::cblas_rotg<nm::Rational64>,
417
+ nm::math::cblas_rotg<nm::Rational128>,
418
+ nm::math::cblas_rotg<nm::RubyObject>
419
+ };
420
+
421
+ nm::dtype_t dtype = NM_DTYPE(ab);
422
+
423
+ if (!ttable[dtype]) {
424
+ rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
425
+ return Qnil;
426
+
427
+ } else {
428
+ void *pC = ALLOCA_N(char, DTYPE_SIZES[dtype]),
429
+ *pS = ALLOCA_N(char, DTYPE_SIZES[dtype]);
430
+
431
+ // extract A and B from the NVector (first two elements)
432
+ void* pA = NM_STORAGE_DENSE(ab)->elements;
433
+ void* pB = (char*)(NM_STORAGE_DENSE(ab)->elements) + DTYPE_SIZES[dtype];
434
+ // c and s are output
435
+
436
+ ttable[dtype](pA, pB, pC, pS);
437
+
438
+ VALUE result = rb_ary_new2(2);
439
+ rb_ary_store(result, 0, rubyobj_from_cval(pC, dtype).rval);
440
+ rb_ary_store(result, 1, rubyobj_from_cval(pS, dtype).rval);
441
+
442
+ return result;
443
+ }
444
+ }
445
+
446
+
447
+ /*
448
+ * Call any of the cblas_xrot functions as directly as possible.
449
+ *
450
+ * xROT is a BLAS level 1 routine (taking two vectors) which applies a plane rotation.
451
+ *
452
+ * It's tough to find documentation on xROT. Here are what we think the arguments are for:
453
+ * * n :: number of elements to consider in x and y
454
+ * * x :: a vector (expects an NVector)
455
+ * * incx :: stride of x
456
+ * * y :: a vector (expects an NVector)
457
+ * * incy :: stride of y
458
+ * * c :: cosine of the angle of rotation
459
+ * * s :: sine of the angle of rotation
460
+ *
461
+ * Note that c and s will be the same dtype as x and y, except when x and y are complex. If x and y are complex, c and s
462
+ * will be float for Complex64 or double for Complex128.
463
+ *
464
+ * You probably don't want to call this function. Instead, why don't you try rot, which is more flexible
465
+ * with its arguments?
466
+ *
467
+ * This function does almost no type checking. Seriously, be really careful when you call it! There's no exception
468
+ * handling, so you can easily crash Ruby!
469
+ */
470
+ static VALUE nm_cblas_rot(VALUE self, VALUE n, VALUE x, VALUE incx, VALUE y, VALUE incy, VALUE c, VALUE s) {
471
+ static void (*ttable[nm::NUM_DTYPES])(const int N, void*, const int, void*, const int, const void*, const void*) = {
472
+ NULL, NULL, NULL, NULL, NULL, // can't represent c and s as integers, so no point in having integer operations.
473
+ nm::math::cblas_rot<float,float>,
474
+ nm::math::cblas_rot<double,double>,
475
+ nm::math::cblas_rot<nm::Complex64,float>,
476
+ nm::math::cblas_rot<nm::Complex128,double>,
477
+ nm::math::cblas_rot<nm::Rational32,nm::Rational32>,
478
+ nm::math::cblas_rot<nm::Rational64,nm::Rational64>,
479
+ nm::math::cblas_rot<nm::Rational128,nm::Rational128>,
480
+ nm::math::cblas_rot<nm::RubyObject,nm::RubyObject>
481
+ };
482
+
483
+ nm::dtype_t dtype = NM_DTYPE(x);
484
+
485
+
486
+ if (!ttable[dtype]) {
487
+ rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
488
+ return Qfalse;
489
+ } else {
490
+ void *pC, *pS;
491
+
492
+ // We need to ensure the cosine and sine arguments are the correct dtype -- which may differ from the actual dtype.
493
+ if (dtype == nm::COMPLEX64) {
494
+ pC = ALLOCA_N(float,1);
495
+ pS = ALLOCA_N(float,1);
496
+ rubyval_to_cval(c, nm::FLOAT32, pC);
497
+ rubyval_to_cval(s, nm::FLOAT32, pS);
498
+ } else if (dtype == nm::COMPLEX128) {
499
+ pC = ALLOCA_N(double,1);
500
+ pS = ALLOCA_N(double,1);
501
+ rubyval_to_cval(c, nm::FLOAT64, pC);
502
+ rubyval_to_cval(s, nm::FLOAT64, pS);
503
+ } else {
504
+ pC = ALLOCA_N(char, DTYPE_SIZES[dtype]);
505
+ pS = ALLOCA_N(char, DTYPE_SIZES[dtype]);
506
+ rubyval_to_cval(c, dtype, pC);
507
+ rubyval_to_cval(s, dtype, pS);
508
+ }
509
+
510
+
511
+ ttable[dtype](FIX2INT(n), NM_STORAGE_DENSE(x)->elements, FIX2INT(incx), NM_STORAGE_DENSE(y)->elements, FIX2INT(incy), pC, pS);
512
+
513
+ return Qtrue;
514
+ }
515
+ }
516
+
517
+
328
518
  /* Call any of the cblas_xgemm functions as directly as possible.
329
519
  *
330
520
  * The cblas_xgemm functions (dgemm, sgemm, cgemm, and zgemm) define the following operation:
@@ -340,7 +530,7 @@ static inline enum CBLAS_ORDER blas_order_sym(VALUE op) {
340
530
  * == Arguments
341
531
  * See: http://www.netlib.org/blas/dgemm.f
342
532
  *
343
- * You probably don't want to call this function. Instead, why don't you try cblas_gemm, which is more flexible
533
+ * You probably don't want to call this function. Instead, why don't you try gemm, which is more flexible
344
534
  * with its arguments?
345
535
  *
346
536
  * This function does almost no type checking. Seriously, be really careful when you call it! There's no exception
@@ -358,7 +548,7 @@ static VALUE nm_cblas_gemm(VALUE self,
358
548
  {
359
549
  NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::cblas_gemm, void, const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE trans_a, const enum CBLAS_TRANSPOSE trans_b, int m, int n, int k, void* alpha, void* a, int lda, void* b, int ldb, void* beta, void* c, int ldc);
360
550
 
361
- dtype_t dtype = NM_DTYPE(a);
551
+ nm::dtype_t dtype = NM_DTYPE(a);
362
552
 
363
553
  void *pAlpha = ALLOCA_N(char, DTYPE_SIZES[dtype]),
364
554
  *pBeta = ALLOCA_N(char, DTYPE_SIZES[dtype]);
@@ -403,7 +593,7 @@ static VALUE nm_cblas_gemv(VALUE self,
403
593
  {
404
594
  NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::cblas_gemv, bool, const enum CBLAS_TRANSPOSE trans_a, int m, int n, void* alpha, void* a, int lda, void* x, int incx, void* beta, void* y, int incy);
405
595
 
406
- dtype_t dtype = NM_DTYPE(a);
596
+ nm::dtype_t dtype = NM_DTYPE(a);
407
597
 
408
598
  void *pAlpha = ALLOCA_N(char, DTYPE_SIZES[dtype]),
409
599
  *pBeta = ALLOCA_N(char, DTYPE_SIZES[dtype]);
@@ -425,7 +615,7 @@ static VALUE nm_cblas_trsm(VALUE self,
425
615
  {
426
616
  static void (*ttable[nm::NUM_DTYPES])(const enum CBLAS_ORDER, const enum CBLAS_SIDE, const enum CBLAS_UPLO,
427
617
  const enum CBLAS_TRANSPOSE, const enum CBLAS_DIAG,
428
- const int, const int, const void* alpha, const void* a,
618
+ const int m, const int n, const void* alpha, const void* a,
429
619
  const int lda, void* b, const int ldb) = {
430
620
  NULL, NULL, NULL, NULL, NULL, // integers not allowed due to division
431
621
  nm::math::cblas_trsm<float>,
@@ -437,12 +627,121 @@ static VALUE nm_cblas_trsm(VALUE self,
437
627
  nm::math::cblas_trsm<nm::RubyObject>
438
628
  };
439
629
 
440
- dtype_t dtype = NM_DTYPE(a);
630
+ nm::dtype_t dtype = NM_DTYPE(a);
441
631
 
442
- void *pAlpha = ALLOCA_N(char, DTYPE_SIZES[dtype]);
443
- rubyval_to_cval(alpha, dtype, pAlpha);
632
+ if (!ttable[dtype]) {
633
+ rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
634
+ } else {
635
+ void *pAlpha = ALLOCA_N(char, DTYPE_SIZES[dtype]);
636
+ rubyval_to_cval(alpha, dtype, pAlpha);
637
+
638
+ ttable[dtype](blas_order_sym(order), blas_side_sym(side), blas_uplo_sym(uplo), blas_transpose_sym(trans_a), blas_diag_sym(diag), FIX2INT(m), FIX2INT(n), pAlpha, NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), NM_STORAGE_DENSE(b)->elements, FIX2INT(ldb));
639
+ }
640
+
641
+ return Qtrue;
642
+ }
643
+
644
+
645
+ static VALUE nm_cblas_trmm(VALUE self,
646
+ VALUE order,
647
+ VALUE side, VALUE uplo,
648
+ VALUE trans_a, VALUE diag,
649
+ VALUE m, VALUE n,
650
+ VALUE alpha,
651
+ VALUE a, VALUE lda,
652
+ VALUE b, VALUE ldb)
653
+ {
654
+ static void (*ttable[nm::NUM_DTYPES])(const enum CBLAS_ORDER,
655
+ const enum CBLAS_SIDE, const enum CBLAS_UPLO,
656
+ const enum CBLAS_TRANSPOSE, const enum CBLAS_DIAG,
657
+ const int m, const int n, const void* alpha, const void* a,
658
+ const int lda, void* b, const int ldb) = {
659
+ NULL, NULL, NULL, NULL, NULL, // integers not allowed due to division
660
+ nm::math::cblas_trmm<float>,
661
+ nm::math::cblas_trmm<double>,
662
+ cblas_ctrmm, cblas_ztrmm // call directly, same function signature!
663
+ /*
664
+ nm::math::cblas_trmm<nm::Rational32>,
665
+ nm::math::cblas_trmm<nm::Rational64>,
666
+ nm::math::cblas_trmm<nm::Rational128>,
667
+ nm::math::cblas_trmm<nm::RubyObject>*/
668
+ };
669
+
670
+ nm::dtype_t dtype = NM_DTYPE(a);
671
+
672
+ if (!ttable[dtype]) {
673
+ rb_raise(nm_eDataTypeError, "this matrix operation not yet defined for non-BLAS dtypes");
674
+ } else {
675
+ void *pAlpha = ALLOCA_N(char, DTYPE_SIZES[dtype]);
676
+ rubyval_to_cval(alpha, dtype, pAlpha);
677
+
678
+ ttable[dtype](blas_order_sym(order), blas_side_sym(side), blas_uplo_sym(uplo), blas_transpose_sym(trans_a), blas_diag_sym(diag), FIX2INT(m), FIX2INT(n), pAlpha, NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), NM_STORAGE_DENSE(b)->elements, FIX2INT(ldb));
679
+ }
680
+
681
+ return b;
682
+ }
683
+
684
+
685
+ static VALUE nm_cblas_syrk(VALUE self,
686
+ VALUE order,
687
+ VALUE uplo,
688
+ VALUE trans,
689
+ VALUE n, VALUE k,
690
+ VALUE alpha,
691
+ VALUE a, VALUE lda,
692
+ VALUE beta,
693
+ VALUE c, VALUE ldc)
694
+ {
695
+ static void (*ttable[nm::NUM_DTYPES])(const enum CBLAS_ORDER, const enum CBLAS_UPLO, const enum CBLAS_TRANSPOSE,
696
+ const int n, const int k, const void* alpha, const void* a,
697
+ const int lda, const void* beta, void* c, const int ldc) = {
698
+ NULL, NULL, NULL, NULL, NULL, // integers not allowed due to division
699
+ nm::math::cblas_syrk<float>,
700
+ nm::math::cblas_syrk<double>,
701
+ cblas_csyrk, cblas_zsyrk// call directly, same function signature!
702
+ /*nm::math::cblas_trsm<nm::Rational32>,
703
+ nm::math::cblas_trsm<nm::Rational64>,
704
+ nm::math::cblas_trsm<nm::Rational128>,
705
+ nm::math::cblas_trsm<nm::RubyObject>*/
706
+ };
707
+
708
+ nm::dtype_t dtype = NM_DTYPE(a);
709
+
710
+ if (!ttable[dtype]) {
711
+ rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
712
+ } else {
713
+ void *pAlpha = ALLOCA_N(char, DTYPE_SIZES[dtype]),
714
+ *pBeta = ALLOCA_N(char, DTYPE_SIZES[dtype]);
715
+ rubyval_to_cval(alpha, dtype, pAlpha);
716
+ rubyval_to_cval(beta, dtype, pBeta);
717
+
718
+ ttable[dtype](blas_order_sym(order), blas_uplo_sym(uplo), blas_transpose_sym(trans), FIX2INT(n), FIX2INT(k), pAlpha, NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), pBeta, NM_STORAGE_DENSE(c)->elements, FIX2INT(ldc));
719
+ }
720
+
721
+ return Qtrue;
722
+ }
723
+
724
+
725
+ static VALUE nm_cblas_herk(VALUE self,
726
+ VALUE order,
727
+ VALUE uplo,
728
+ VALUE trans,
729
+ VALUE n, VALUE k,
730
+ VALUE alpha,
731
+ VALUE a, VALUE lda,
732
+ VALUE beta,
733
+ VALUE c, VALUE ldc)
734
+ {
735
+
736
+ nm::dtype_t dtype = NM_DTYPE(a);
737
+
738
+ if (dtype == nm::COMPLEX64) {
739
+ cblas_cherk(blas_order_sym(order), blas_uplo_sym(uplo), blas_transpose_sym(trans), FIX2INT(n), FIX2INT(k), NUM2DBL(alpha), NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), NUM2DBL(beta), NM_STORAGE_DENSE(c)->elements, FIX2INT(ldc));
740
+ } else if (dtype == nm::COMPLEX128) {
741
+ cblas_zherk(blas_order_sym(order), blas_uplo_sym(uplo), blas_transpose_sym(trans), FIX2INT(n), FIX2INT(k), NUM2DBL(alpha), NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), NUM2DBL(beta), NM_STORAGE_DENSE(c)->elements, FIX2INT(ldc));
742
+ } else
743
+ rb_raise(rb_eNotImpError, "this matrix operation undefined for non-complex dtypes");
444
744
 
445
- ttable[dtype](blas_order_sym(order), blas_side_sym(side), blas_uplo_sym(uplo), blas_transpose_sym(trans_a), blas_diag_sym(diag), FIX2INT(m), FIX2INT(n), pAlpha, NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), NM_STORAGE_DENSE(b)->elements, FIX2INT(ldb));
446
745
 
447
746
  return Qtrue;
448
747
  }
@@ -454,7 +753,7 @@ static VALUE nm_cblas_trsm(VALUE self,
454
753
  * In-place modification; returns the modified vector as well.
455
754
  */
456
755
  static VALUE nm_clapack_scal(VALUE self, VALUE n, VALUE scale, VALUE vector, VALUE incx) {
457
- dtype_t dtype = NM_DTYPE(vector);
756
+ nm::dtype_t dtype = NM_DTYPE(vector);
458
757
 
459
758
  void* da = ALLOCA_N(char, DTYPE_SIZES[dtype]);
460
759
  rubyval_to_cval(scale, dtype, da);
@@ -467,7 +766,43 @@ static VALUE nm_clapack_scal(VALUE self, VALUE n, VALUE scale, VALUE vector, VAL
467
766
  }
468
767
 
469
768
 
470
- /* Call any of the clpack_xgetrf functions as directly as possible.
769
+ static VALUE nm_clapack_lauum(VALUE self, VALUE order, VALUE uplo, VALUE n, VALUE a, VALUE lda) {
770
+ static int (*ttable[nm::NUM_DTYPES])(const enum CBLAS_ORDER, const enum CBLAS_UPLO, const int n, void* a, const int lda) = {
771
+ /*nm::math::clapack_lauum<uint8_t, false>,
772
+ nm::math::clapack_lauum<int8_t, false>,
773
+ nm::math::clapack_lauum<int16_t, false>,
774
+ nm::math::clapack_lauum<uint32_t, false>,
775
+ nm::math::clapack_lauum<uint64_t, false>,*/
776
+ NULL, NULL, NULL, NULL, NULL,
777
+ nm::math::clapack_lauum<false, float>,
778
+ nm::math::clapack_lauum<false, double>,
779
+ #ifdef HAVE_CLAPACK_H
780
+ clapack_clauum, clapack_zlauum, // call directly, same function signature!
781
+ #else // Especially important for Mac OS, which doesn't seem to include the ATLAS clapack interface.
782
+ nm::math::clapack_lauum<true, nm::Complex64>,
783
+ nm::math::clapack_lauum<true, nm::Complex128>,
784
+ #endif
785
+ /*
786
+ nm::math::clapack_lauum<nm::Rational32, false>,
787
+ nm::math::clapack_lauum<nm::Rational64, false>,
788
+ nm::math::clapack_lauum<nm::Rational128, false>,
789
+ nm::math::clapack_lauum<nm::RubyObject, false>
790
+
791
+ */
792
+ };
793
+
794
+ if (!ttable[NM_DTYPE(a)]) {
795
+ rb_raise(rb_eNotImpError, "does not yet work for non-BLAS dtypes (needs herk, syrk, trmm)");
796
+ } else {
797
+ // Call either our version of lauum or the LAPACK version.
798
+ ttable[NM_DTYPE(a)](blas_order_sym(order), blas_uplo_sym(uplo), FIX2INT(n), NM_STORAGE_DENSE(a)->elements, FIX2INT(lda));
799
+ }
800
+
801
+ return a;
802
+ }
803
+
804
+
805
+ /* Call any of the clapack_xgetrf functions as directly as possible.
471
806
  *
472
807
  * The clapack_getrf functions (dgetrf, sgetrf, cgetrf, and zgetrf) compute an LU factorization of a general M-by-N
473
808
  * matrix A using partial pivoting with row interchanges.
@@ -515,8 +850,12 @@ static VALUE nm_clapack_getrf(VALUE self, VALUE order, VALUE m, VALUE n, VALUE a
515
850
  size_t ipiv_size = std::min(M,N);
516
851
  int* ipiv = ALLOCA_N(int, ipiv_size);
517
852
 
518
- // Call either our version of getrf or the LAPACK version.
519
- ttable[NM_DTYPE(a)](blas_order_sym(order), M, N, NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), ipiv);
853
+ if (!ttable[NM_DTYPE(a)]) {
854
+ rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
855
+ } else {
856
+ // Call either our version of getrf or the LAPACK version.
857
+ ttable[NM_DTYPE(a)](blas_order_sym(order), M, N, NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), ipiv);
858
+ }
520
859
 
521
860
  // Result will be stored in a. We return ipiv as an array.
522
861
  VALUE ipiv_array = rb_ary_new2(ipiv_size);
@@ -528,10 +867,288 @@ static VALUE nm_clapack_getrf(VALUE self, VALUE order, VALUE m, VALUE n, VALUE a
528
867
  }
529
868
 
530
869
 
870
+ /* Call any of the clapack_xpotrf functions as directly as possible.
871
+ *
872
+ * You probably don't want to call this function. Instead, why don't you try clapack_potrf, which is more flexible
873
+ * with its arguments?
874
+ *
875
+ * This function does almost no type checking. Seriously, be really careful when you call it! There's no exception
876
+ * handling, so you can easily crash Ruby!
877
+ *
878
+ * Returns an array giving the pivot indices (normally these are argument #5).
879
+ */
880
+ static VALUE nm_clapack_potrf(VALUE self, VALUE order, VALUE uplo, VALUE n, VALUE a, VALUE lda) {
881
+ #ifndef HAVE_CLAPACK_H
882
+ rb_raise(rb_eNotImpError, "potrf currently requires LAPACK");
883
+ #endif
884
+
885
+ static int (*ttable[nm::NUM_DTYPES])(const enum CBLAS_ORDER, const enum CBLAS_UPLO, const int n, void* a, const int lda) = {
886
+ NULL, NULL, NULL, NULL, NULL, // integers not allowed due to division
887
+ nm::math::clapack_potrf<float>,
888
+ nm::math::clapack_potrf<double>,
889
+ #ifdef HAVE_CLAPACK_H
890
+ clapack_cpotrf, clapack_zpotrf, // call directly, same function signature!
891
+ #else // Especially important for Mac OS, which doesn't seem to include the ATLAS clapack interface.
892
+ nm::math::clapack_potrf<nm::Complex64>,
893
+ nm::math::clapack_potrf<nm::Complex128>,
894
+ #endif
895
+ NULL, NULL, NULL, NULL /*
896
+ nm::math::clapack_potrf<nm::Rational32>,
897
+ nm::math::clapack_potrf<nm::Rational64>,
898
+ nm::math::clapack_potrf<nm::Rational128>,
899
+ nm::math::clapack_potrf<nm::RubyObject> */
900
+ };
901
+
902
+ if (!ttable[NM_DTYPE(a)]) {
903
+ rb_raise(rb_eNotImpError, "this operation not yet implemented for non-BLAS dtypes");
904
+ // FIXME: Once BLAS dtypes are implemented, replace error above with the error below.
905
+ //rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
906
+ } else {
907
+ // Call either our version of potrf or the LAPACK version.
908
+ ttable[NM_DTYPE(a)](blas_order_sym(order), blas_uplo_sym(uplo), FIX2INT(n), NM_STORAGE_DENSE(a)->elements, FIX2INT(lda));
909
+ }
910
+
911
+ return a;
912
+ }
913
+
914
+
915
+ /*
916
+ * Call any of the clapack_xgetrs functions as directly as possible.
917
+ */
918
+ static VALUE nm_clapack_getrs(VALUE self, VALUE order, VALUE trans, VALUE n, VALUE nrhs, VALUE a, VALUE lda, VALUE ipiv, VALUE b, VALUE ldb) {
919
+ static int (*ttable[nm::NUM_DTYPES])(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE Trans, const int N,
920
+ const int NRHS, const void* A, const int lda, const int* ipiv, void* B,
921
+ const int ldb) = {
922
+ NULL, NULL, NULL, NULL, NULL, // integers not allowed due to division
923
+ nm::math::clapack_getrs<float>,
924
+ nm::math::clapack_getrs<double>,
925
+ #ifdef HAVE_CLAPACK_H
926
+ clapack_cgetrs, clapack_zgetrs, // call directly, same function signature!
927
+ #else // Especially important for Mac OS, which doesn't seem to include the ATLAS clapack interface.
928
+ nm::math::clapack_getrs<nm::Complex64>,
929
+ nm::math::clapack_getrs<nm::Complex128>,
930
+ #endif
931
+ nm::math::clapack_getrs<nm::Rational32>,
932
+ nm::math::clapack_getrs<nm::Rational64>,
933
+ nm::math::clapack_getrs<nm::Rational128>,
934
+ nm::math::clapack_getrs<nm::RubyObject>
935
+ };
936
+
937
+ // Allocate the C version of the pivot index array
938
+ // TODO: Allow for an NVector here also, maybe?
939
+ int* ipiv_;
940
+ if (TYPE(ipiv) != T_ARRAY) {
941
+ rb_raise(rb_eArgError, "ipiv must be of type Array");
942
+ } else {
943
+ ipiv_ = ALLOCA_N(int, RARRAY_LEN(ipiv));
944
+ for (int index = 0; index < RARRAY_LEN(ipiv); ++index) {
945
+ ipiv_[index] = FIX2INT( RARRAY_PTR(ipiv)[index] );
946
+ }
947
+ }
948
+
949
+ if (!ttable[NM_DTYPE(a)]) {
950
+ rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
951
+ } else {
952
+
953
+ // Call either our version of getrs or the LAPACK version.
954
+ ttable[NM_DTYPE(a)](blas_order_sym(order), blas_transpose_sym(trans), FIX2INT(n), FIX2INT(nrhs), NM_STORAGE_DENSE(a)->elements, FIX2INT(lda),
955
+ ipiv_, NM_STORAGE_DENSE(b)->elements, FIX2INT(ldb));
956
+ }
957
+
958
+ // b is both returned and modified directly in the argument list.
959
+ return b;
960
+ }
961
+
962
+
963
+ /*
964
+ * Call any of the clapack_xpotrs functions as directly as possible.
965
+ */
966
+ static VALUE nm_clapack_potrs(VALUE self, VALUE order, VALUE uplo, VALUE n, VALUE nrhs, VALUE a, VALUE lda, VALUE b, VALUE ldb) {
967
+ static int (*ttable[nm::NUM_DTYPES])(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, const int N,
968
+ const int NRHS, const void* A, const int lda, void* B, const int ldb) = {
969
+ NULL, NULL, NULL, NULL, NULL, // integers not allowed due to division
970
+ nm::math::clapack_potrs<float,false>,
971
+ nm::math::clapack_potrs<double,false>,
972
+ #ifdef HAVE_CLAPACK_H
973
+ clapack_cpotrs, clapack_zpotrs, // call directly, same function signature!
974
+ #else // Especially important for Mac OS, which doesn't seem to include the ATLAS clapack interface.
975
+ nm::math::clapack_potrs<nm::Complex64,true>,
976
+ nm::math::clapack_potrs<nm::Complex128,true>,
977
+ #endif
978
+ nm::math::clapack_potrs<nm::Rational32,false>,
979
+ nm::math::clapack_potrs<nm::Rational64,false>,
980
+ nm::math::clapack_potrs<nm::Rational128,false>,
981
+ nm::math::clapack_potrs<nm::RubyObject,false>
982
+ };
983
+
984
+
985
+ if (!ttable[NM_DTYPE(a)]) {
986
+ rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
987
+ } else {
988
+
989
+ // Call either our version of potrs or the LAPACK version.
990
+ ttable[NM_DTYPE(a)](blas_order_sym(order), blas_uplo_sym(uplo), FIX2INT(n), FIX2INT(nrhs), NM_STORAGE_DENSE(a)->elements, FIX2INT(lda),
991
+ NM_STORAGE_DENSE(b)->elements, FIX2INT(ldb));
992
+ }
993
+
994
+ // b is both returned and modified directly in the argument list.
995
+ return b;
996
+ }
997
+
998
+
999
+ /* Call any of the clapack_xgetri functions as directly as possible.
1000
+ *
1001
+ * You probably don't want to call this function. Instead, why don't you try clapack_getri, which is more flexible
1002
+ * with its arguments?
1003
+ *
1004
+ * This function does almost no type checking. Seriously, be really careful when you call it! There's no exception
1005
+ * handling, so you can easily crash Ruby!
1006
+ *
1007
+ * Returns an array giving the pivot indices (normally these are argument #5).
1008
+ */
1009
+ static VALUE nm_clapack_getri(VALUE self, VALUE order, VALUE n, VALUE a, VALUE lda, VALUE ipiv) {
1010
+ #ifndef HAVE_CLAPACK_H
1011
+ rb_raise(rb_eNotImpError, "getri currently requires LAPACK");
1012
+ #endif
1013
+
1014
+ static int (*ttable[nm::NUM_DTYPES])(const enum CBLAS_ORDER, const int n, void* a, const int lda, const int* ipiv) = {
1015
+ NULL, NULL, NULL, NULL, NULL, // integers not allowed due to division
1016
+ nm::math::clapack_getri<float>,
1017
+ nm::math::clapack_getri<double>,
1018
+ #ifdef HAVE_CLAPACK_H
1019
+ clapack_cgetri, clapack_zgetri, // call directly, same function signature!
1020
+ #else // Especially important for Mac OS, which doesn't seem to include the ATLAS clapack interface.
1021
+ nm::math::clapack_getri<nm::Complex64>,
1022
+ nm::math::clapack_getri<nm::Complex128>,
1023
+ #endif
1024
+ NULL, NULL, NULL, NULL /*
1025
+ nm::math::clapack_getri<nm::Rational32>,
1026
+ nm::math::clapack_getri<nm::Rational64>,
1027
+ nm::math::clapack_getri<nm::Rational128>,
1028
+ nm::math::clapack_getri<nm::RubyObject> */
1029
+ };
1030
+
1031
+ // Allocate the C version of the pivot index array
1032
+ // TODO: Allow for an NVector here also, maybe?
1033
+ int* ipiv_;
1034
+ if (TYPE(ipiv) != T_ARRAY) {
1035
+ rb_raise(rb_eArgError, "ipiv must be of type Array");
1036
+ } else {
1037
+ ipiv_ = ALLOCA_N(int, RARRAY_LEN(ipiv));
1038
+ for (int index = 0; index < RARRAY_LEN(ipiv); ++index) {
1039
+ ipiv_[index] = FIX2INT( RARRAY_PTR(ipiv)[index] );
1040
+ }
1041
+ }
1042
+
1043
+ if (!ttable[NM_DTYPE(a)]) {
1044
+ rb_raise(rb_eNotImpError, "this operation not yet implemented for non-BLAS dtypes");
1045
+ // FIXME: Once BLAS dtypes are implemented, replace error above with the error below.
1046
+ //rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
1047
+ } else {
1048
+ // Call either our version of getri or the LAPACK version.
1049
+ ttable[NM_DTYPE(a)](blas_order_sym(order), FIX2INT(n), NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), ipiv_);
1050
+ }
1051
+
1052
+ return a;
1053
+ }
1054
+
1055
+
1056
+ /* Call any of the clapack_xpotri functions as directly as possible.
1057
+ *
1058
+ * You probably don't want to call this function. Instead, why don't you try clapack_potri, which is more flexible
1059
+ * with its arguments?
1060
+ *
1061
+ * This function does almost no type checking. Seriously, be really careful when you call it! There's no exception
1062
+ * handling, so you can easily crash Ruby!
1063
+ *
1064
+ * Returns an array giving the pivot indices (normally these are argument #5).
1065
+ */
1066
+ static VALUE nm_clapack_potri(VALUE self, VALUE order, VALUE uplo, VALUE n, VALUE a, VALUE lda) {
1067
+ #ifndef HAVE_CLAPACK_H
1068
+ rb_raise(rb_eNotImpError, "getri currently requires LAPACK");
1069
+ #endif
1070
+
1071
+ static int (*ttable[nm::NUM_DTYPES])(const enum CBLAS_ORDER, const enum CBLAS_UPLO, const int n, void* a, const int lda) = {
1072
+ NULL, NULL, NULL, NULL, NULL, // integers not allowed due to division
1073
+ nm::math::clapack_potri<float>,
1074
+ nm::math::clapack_potri<double>,
1075
+ #ifdef HAVE_CLAPACK_H
1076
+ clapack_cpotri, clapack_zpotri, // call directly, same function signature!
1077
+ #else // Especially important for Mac OS, which doesn't seem to include the ATLAS clapack interface.
1078
+ nm::math::clapack_potri<nm::Complex64>,
1079
+ nm::math::clapack_potri<nm::Complex128>,
1080
+ #endif
1081
+ NULL, NULL, NULL, NULL /*
1082
+ nm::math::clapack_getri<nm::Rational32>,
1083
+ nm::math::clapack_getri<nm::Rational64>,
1084
+ nm::math::clapack_getri<nm::Rational128>,
1085
+ nm::math::clapack_getri<nm::RubyObject> */
1086
+ };
1087
+
1088
+ if (!ttable[NM_DTYPE(a)]) {
1089
+ rb_raise(rb_eNotImpError, "this operation not yet implemented for non-BLAS dtypes");
1090
+ // FIXME: Once BLAS dtypes are implemented, replace error above with the error below.
1091
+ //rb_raise(nm_eDataTypeError, "this matrix operation undefined for integer matrices");
1092
+ } else {
1093
+ // Call either our version of getri or the LAPACK version.
1094
+ ttable[NM_DTYPE(a)](blas_order_sym(order), blas_uplo_sym(uplo), FIX2INT(n), NM_STORAGE_DENSE(a)->elements, FIX2INT(lda));
1095
+ }
1096
+
1097
+ return a;
1098
+ }
1099
+
1100
+
1101
+ /*
1102
+ * Call any of the clapack_xlaswp functions as directly as possible.
1103
+ *
1104
+ * Note that LAPACK's xlaswp functions accept a column-order matrix, but NMatrix uses row-order. Thus, n should be the
1105
+ * number of rows and lda should be the number of columns, no matter what it says in the documentation for dlaswp.f.
1106
+ */
1107
+ static VALUE nm_clapack_laswp(VALUE self, VALUE n, VALUE a, VALUE lda, VALUE k1, VALUE k2, VALUE ipiv, VALUE incx) {
1108
+ static void (*ttable[nm::NUM_DTYPES])(const int n, void* a, const int lda, const int k1, const int k2, const int* ipiv, const int incx) = {
1109
+ nm::math::clapack_laswp<uint8_t>,
1110
+ nm::math::clapack_laswp<int8_t>,
1111
+ nm::math::clapack_laswp<int16_t>,
1112
+ nm::math::clapack_laswp<int32_t>,
1113
+ nm::math::clapack_laswp<int64_t>,
1114
+ nm::math::clapack_laswp<float>,
1115
+ nm::math::clapack_laswp<double>,
1116
+ //#ifdef HAVE_CLAPACK_H // laswp doesn't actually exist in clapack.h!
1117
+ // clapack_claswp, clapack_zlaswp, // call directly, same function signature!
1118
+ //#else // Especially important for Mac OS, which doesn't seem to include the ATLAS clapack interface.
1119
+ nm::math::clapack_laswp<nm::Complex64>,
1120
+ nm::math::clapack_laswp<nm::Complex128>,
1121
+ //#endif
1122
+ nm::math::clapack_laswp<nm::Rational32>,
1123
+ nm::math::clapack_laswp<nm::Rational64>,
1124
+ nm::math::clapack_laswp<nm::Rational128>,
1125
+ nm::math::clapack_laswp<nm::RubyObject>
1126
+ };
1127
+
1128
+ // Allocate the C version of the pivot index array
1129
+ // TODO: Allow for an NVector here also, maybe?
1130
+ int* ipiv_;
1131
+ if (TYPE(ipiv) != T_ARRAY) {
1132
+ rb_raise(rb_eArgError, "ipiv must be of type Array");
1133
+ } else {
1134
+ ipiv_ = ALLOCA_N(int, RARRAY_LEN(ipiv));
1135
+ for (int index = 0; index < RARRAY_LEN(ipiv); ++index) {
1136
+ ipiv_[index] = FIX2INT( RARRAY_PTR(ipiv)[index] );
1137
+ }
1138
+ }
1139
+
1140
+ // Call either our version of laswp or the LAPACK version.
1141
+ ttable[NM_DTYPE(a)](FIX2INT(n), NM_STORAGE_DENSE(a)->elements, FIX2INT(lda), FIX2INT(k1), FIX2INT(k2), ipiv_, FIX2INT(incx));
1142
+
1143
+ // a is both returned and modified directly in the argument list.
1144
+ return a;
1145
+ }
1146
+
1147
+
531
1148
  /*
532
1149
  * C accessor for calculating an exact determinant.
533
1150
  */
534
- void nm_math_det_exact(const int M, const void* elements, const int lda, dtype_t dtype, void* result) {
1151
+ void nm_math_det_exact(const int M, const void* elements, const int lda, nm::dtype_t dtype, void* result) {
535
1152
  NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::det_exact, void, const int M, const void* A_elements, const int lda, void* result_arg);
536
1153
 
537
1154
  ttable[dtype](M, elements, lda, result);