nmatrix 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8dd60ade9441cfcdc2c70cd18a60571110c18145
4
- data.tar.gz: 3ae0a112c051f510718a2d7afad97327bb6808c2
3
+ metadata.gz: f0860add5c9502fe90139d362beaf61c116b07a9
4
+ data.tar.gz: c3880411c97cdf56a9bff9e2b35df05cf218f2c7
5
5
  SHA512:
6
- metadata.gz: 6d9fcb8e0ba7ebb62cd30fa7aba1aafe0bcf1dba7ce7e77a12f3e249280212c668313c94b3e80ce40528829061ef0a6e8b140eda8d8f66175023133712393f72
7
- data.tar.gz: ba0a384a026c56c01595b7de0b3a3a741bbe021d2b44e358a14c8f5d665c020262d0b400f6eade6a20ee91d65f90e47d730cc015430db5a0539ad4d684ceb6eb
6
+ metadata.gz: d9e8f203ce54fb5a53fef9011b6ba6fed3b4080e0d28364625ef63892cb5381153cb0aef6e5e6d1ad9d286f0df588f591263cd9f50872df543fba146da58ce73
7
+ data.tar.gz: 0c4e726871ca3c69d4b522acd9c5c05caba55bcce54339330762ca39d100c9159730ae16430f3319e9042e09b9a76b6d7cb54cb1b0bdfe77e1d25ad1f1693e79
@@ -110,7 +110,7 @@ class RubyObject {
110
110
  inline operator VALUE() const { return rval; }
111
111
  //inline operator uint32_t() const { return NUM2ULONG(this->rval); }
112
112
  inline operator int64_t() const { RETURN_OBJ2NUM(NUM2LONG) }
113
- inline operator uint64_t() const { RETURN_OBJ2NUM(NUM2ULONG) }
113
+ //inline operator uint64_t() const { RETURN_OBJ2NUM(NUM2ULONG) }
114
114
  inline operator double() const { RETURN_OBJ2NUM(NUM2DBL) }
115
115
  inline operator float() const { RETURN_OBJ2NUM(NUM2DBL) }
116
116
 
@@ -188,14 +188,14 @@ extern "C" {
188
188
  // Math Functions //
189
189
  ////////////////////
190
190
 
191
- namespace nm {
191
+ namespace nm {
192
192
  namespace math {
193
193
 
194
194
  /*
195
195
  * Calculate the determinant for a dense matrix (A [elements]) of size 2 or 3. Return the result.
196
196
  */
197
197
  template <typename DType>
198
- void det_exact(const int M, const void* A_elements, const int lda, void* result_arg) {
198
+ void det_exact_from_dense(const int M, const void* A_elements, const int lda, void* result_arg) {
199
199
  DType* result = reinterpret_cast<DType*>(result_arg);
200
200
  const DType* A = reinterpret_cast<const DType*>(A_elements);
201
201
 
@@ -203,7 +203,6 @@ namespace nm {
203
203
 
204
204
  if (M == 2) {
205
205
  *result = A[0] * A[lda+1] - A[1] * A[lda];
206
-
207
206
  } else if (M == 3) {
208
207
  x = A[lda+1] * A[2*lda+2] - A[lda+2] * A[2*lda+1]; // ei - fh
209
208
  y = A[lda] * A[2*lda+2] - A[lda+2] * A[2*lda]; // fg - di
@@ -220,9 +219,99 @@ namespace nm {
220
219
 
221
220
  //we can't do det_exact on byte, because it will want to return a byte (unsigned), but determinants can be negative, even if all elements of the matrix are positive
222
221
  template <>
223
- void det_exact<uint8_t>(const int M, const void* A_elements, const int lda, void* result_arg) {
222
+ void det_exact_from_dense<uint8_t>(const int M, const void* A_elements, const int lda, void* result_arg) {
224
223
  rb_raise(nm_eDataTypeError, "cannot call det_exact on unsigned type");
225
224
  }
225
+ /*
226
+ * Calculate the determinant for a yale matrix (storage) of size 2 or 3. Return the result.
227
+ */
228
+ template <typename DType>
229
+ void det_exact_from_yale(const int M, const YALE_STORAGE* storage, const int lda, void* result_arg) {
230
+ DType* result = reinterpret_cast<DType*>(result_arg);
231
+ IType* ija = reinterpret_cast<IType *>(storage->ija);
232
+ DType* a = reinterpret_cast<DType*>(storage->a);
233
+ IType col_pos = storage->shape[0] + 1;
234
+ if (M == 2) {
235
+ if (ija[2] - ija[0] == 2) {
236
+ *result = a[0] * a[1] - a[col_pos] * a[col_pos+1];
237
+ }
238
+ else { *result = a[0] * a[1]; }
239
+ } else if (M == 3) {
240
+ DType m[3][3];
241
+ for (int i = 0; i < 3; ++i) {
242
+ m[i][i] = a[i];
243
+ switch(ija[i+1] - ija[i]) {
244
+ case 2:
245
+ m[i][ija[col_pos]] = a[col_pos];
246
+ m[i][ija[col_pos+1]] = a[col_pos+1];
247
+ col_pos += 2;
248
+ break;
249
+ case 1:
250
+ m[i][(i+1)%3] = m[i][(i+2)%3] = 0;
251
+ m[i][ija[col_pos]] = a[col_pos];
252
+ ++col_pos;
253
+ break;
254
+ case 0:
255
+ m[i][(i+1)%3] = m[i][(i+2)%3] = 0;
256
+ break;
257
+ default:
258
+ rb_raise(rb_eArgError, "some value in IJA is incorrect!");
259
+ }
260
+ }
261
+ *result =
262
+ m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[1][0] * m[2][1]
263
+ - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] - m[0][2] * m[1][1] * m[2][0];
264
+
265
+ } else if (M < 2) {
266
+ rb_raise(rb_eArgError, "can only calculate exact determinant of a square matrix of size 2 or larger");
267
+ } else {
268
+ rb_raise(rb_eNotImpError, "exact determinant calculation needed for matrices larger than 3x3");
269
+ }
270
+ }
271
+
272
+ /*
273
+ * Solve a system of linear equations using forward-substution followed by
274
+ * back substution from the LU factorization of the matrix of co-efficients.
275
+ * Replaces x_elements with the result. Works only with non-integer, non-object
276
+ * data types.
277
+ *
278
+ * args - r -> The number of rows of the matrix.
279
+ * lu_elements -> Elements of the LU decomposition of the co-efficients
280
+ * matrix, as a contiguos array.
281
+ * b_elements -> Elements of the the right hand sides, as a contiguous array.
282
+ * x_elements -> The array that will contain the results of the computation.
283
+ * pivot -> Positions of permuted rows.
284
+ */
285
+ template <typename DType>
286
+ void solve(const int r, const void* lu_elements, const void* b_elements, void* x_elements, const int* pivot) {
287
+ int ii = 0, ip;
288
+ DType sum;
289
+
290
+ const DType* matrix = reinterpret_cast<const DType*>(lu_elements);
291
+ const DType* b = reinterpret_cast<const DType*>(b_elements);
292
+ DType* x = reinterpret_cast<DType*>(x_elements);
293
+
294
+ for (int i = 0; i < r; ++i) { x[i] = b[i]; }
295
+ for (int i = 0; i < r; ++i) { // forward substitution loop
296
+ ip = pivot[i];
297
+ sum = x[ip];
298
+ x[ip] = x[i];
299
+
300
+ if (ii != 0) {
301
+ for (int j = ii - 1;j < i; ++j) { sum = sum - matrix[i * r + j] * x[j]; }
302
+ }
303
+ else if (sum != 0.0) {
304
+ ii = i + 1;
305
+ }
306
+ x[i] = sum;
307
+ }
308
+
309
+ for (int i = r - 1; i >= 0; --i) { // back substitution loop
310
+ sum = x[i];
311
+ for (int j = i + 1; j < r; j++) { sum = sum - matrix[i * r + j] * x[j]; }
312
+ x[i] = sum/matrix[i * r + i];
313
+ }
314
+ }
226
315
 
227
316
  /*
228
317
  * Calculates in-place inverse of A_elements. Uses Gauss-Jordan elimination technique.
@@ -246,18 +335,18 @@ namespace nm {
246
335
  for (int row = k + 1; row < M; ++row) {
247
336
  typename MagnitudeDType<DType>::type big;
248
337
  big = magnitude( matrix[M*row + k] ); // element below the temp pivot
249
-
338
+
250
339
  if ( big > akk ) {
251
340
  interchange = row;
252
- akk = big;
341
+ akk = big;
253
342
  }
254
- }
343
+ }
255
344
 
256
345
  if (interchange != k) { // check if rows need flipping
257
346
  DType temp;
258
347
 
259
348
  for (int col = 0; col < M; ++col) {
260
- NM_SWAP(matrix[interchange*M + col], matrix[k*M + col], temp);
349
+ NM_SWAP(matrix[interchange*M + col], matrix[k*M + col], temp);
261
350
  }
262
351
  }
263
352
 
@@ -271,7 +360,7 @@ namespace nm {
271
360
  DType pivot = matrix[k * (M + 1)];
272
361
  matrix[k * (M + 1)] = (DType)(1); // set diagonal as 1 for in-place inversion
273
362
 
274
- for (int col = 0; col < M; ++col) {
363
+ for (int col = 0; col < M; ++col) {
275
364
  // divide each element in the kth row with the pivot
276
365
  matrix[k*M + col] = matrix[k*M + col] / pivot;
277
366
  }
@@ -280,7 +369,7 @@ namespace nm {
280
369
  if (kk == k) continue;
281
370
 
282
371
  DType dum = matrix[k + M*kk];
283
- matrix[k + M*kk] = (DType)(0); // prepare for inplace inversion
372
+ matrix[k + M*kk] = (DType)(0); // prepare for inplace inversion
284
373
  for (int col = 0; col < M; ++col) {
285
374
  matrix[M*kk + col] = matrix[M*kk + col] - matrix[M*k + col] * dum;
286
375
  }
@@ -295,7 +384,7 @@ namespace nm {
295
384
 
296
385
  for (int row = 0; row < M; ++row) {
297
386
  NM_SWAP(matrix[row * M + row_index[k]], matrix[row * M + col_index[k]],
298
- temp);
387
+ temp);
299
388
  }
300
389
  }
301
390
  }
@@ -321,14 +410,14 @@ namespace nm {
321
410
  DType sum_of_squares, *p_row, *psubdiag, *p_a, scale, innerproduct;
322
411
  int i, k, col;
323
412
 
324
- // For each column use a Householder transformation to zero all entries
413
+ // For each column use a Householder transformation to zero all entries
325
414
  // below the subdiagonal.
326
- for (psubdiag = a + nrows, col = 0; col < nrows - 2; psubdiag += nrows + 1,
415
+ for (psubdiag = a + nrows, col = 0; col < nrows - 2; psubdiag += nrows + 1,
327
416
  col++) {
328
417
  // Calculate the signed square root of the sum of squares of the
329
418
  // elements below the diagonal.
330
419
 
331
- for (p_a = psubdiag, sum_of_squares = 0.0, i = col + 1; i < nrows;
420
+ for (p_a = psubdiag, sum_of_squares = 0.0, i = col + 1; i < nrows;
332
421
  p_a += nrows, i++) {
333
422
  sum_of_squares += *p_a * *p_a;
334
423
  }
@@ -358,7 +447,7 @@ namespace nm {
358
447
  *p_a -= u[k] * innerproduct;
359
448
  }
360
449
  }
361
-
450
+
362
451
  // Postmultiply QA by Q
363
452
  for (p_row = a, i = 0; i < nrows; p_row += nrows, i++) {
364
453
  for (innerproduct = 0.0, k = col + 1; k < nrows; k++) {
@@ -375,33 +464,34 @@ namespace nm {
375
464
  delete[] u;
376
465
  }
377
466
 
467
+ void raise_not_invertible_error() {
468
+ rb_raise(nm_eNotInvertibleError,
469
+ "matrix must have non-zero determinant to be invertible (not getting this error does not mean matrix is invertible if you're dealing with floating points)");
470
+ }
471
+
378
472
  /*
379
473
  * Calculate the exact inverse for a dense matrix (A [elements]) of size 2 or 3. Places the result in B_elements.
380
474
  */
381
475
  template <typename DType>
382
- void inverse_exact(const int M, const void* A_elements, const int lda, void* B_elements, const int ldb) {
476
+ void inverse_exact_from_dense(const int M, const void* A_elements,
477
+ const int lda, void* B_elements, const int ldb) {
478
+
383
479
  const DType* A = reinterpret_cast<const DType*>(A_elements);
384
480
  DType* B = reinterpret_cast<DType*>(B_elements);
385
481
 
386
482
  if (M == 2) {
387
483
  DType det = A[0] * A[lda+1] - A[1] * A[lda];
388
- if (det == 0) {
389
- rb_raise(nm_eNotInvertibleError,
390
- "matrix must have non-zero determinant to be invertible (not getting this error does not mean matrix is invertible if you're dealing with floating points)");
391
- }
484
+ if (det == 0) { raise_not_invertible_error(); }
392
485
  B[0] = A[lda+1] / det;
393
486
  B[1] = -A[1] / det;
394
487
  B[ldb] = -A[lda] / det;
395
- B[ldb+1] = -A[0] / det;
488
+ B[ldb+1] = A[0] / det;
396
489
 
397
490
  } else if (M == 3) {
398
491
  // Calculate the exact determinant.
399
492
  DType det;
400
- det_exact<DType>(M, A_elements, lda, reinterpret_cast<void*>(&det));
401
- if (det == 0) {
402
- rb_raise(nm_eNotInvertibleError,
403
- "matrix must have non-zero determinant to be invertible (not getting this error does not mean matrix is invertible if you're dealing with floating points)");
404
- }
493
+ det_exact_from_dense<DType>(M, A_elements, lda, reinterpret_cast<void*>(&det));
494
+ if (det == 0) { raise_not_invertible_error(); }
405
495
 
406
496
  B[0] = ( A[lda+1] * A[2*lda+2] - A[lda+2] * A[2*lda+1]) / det; // A = ei - fh
407
497
  B[1] = (- A[1] * A[2*lda+2] + A[2] * A[2*lda+1]) / det; // D = -bi + ch
@@ -419,6 +509,113 @@ namespace nm {
419
509
  }
420
510
  }
421
511
 
512
+ template <typename DType>
513
+ void inverse_exact_from_yale(const int M, const YALE_STORAGE* storage,
514
+ const int lda, YALE_STORAGE* inverse, const int ldb) {
515
+
516
+ // inverse is a clone of storage
517
+ const DType* a = reinterpret_cast<const DType*>(storage->a);
518
+ const IType* ija = reinterpret_cast<const IType *>(storage->ija);
519
+ DType* b = reinterpret_cast<DType*>(inverse->a);
520
+ IType* ijb = reinterpret_cast<IType *>(inverse->ija);
521
+ IType col_pos = storage->shape[0] + 1;
522
+ // Calculate the exact determinant.
523
+ DType det;
524
+
525
+ if (M == 2) {
526
+ IType ndnz = ija[2] - ija[0];
527
+ if (ndnz == 2) {
528
+ det = a[0] * a[1] - a[col_pos] * a[col_pos+1];
529
+ }
530
+ else { det = a[0] * a[1]; }
531
+ if (det == 0) { raise_not_invertible_error(); }
532
+ b[0] = a[1] / det;
533
+ b[1] = a[0] / det;
534
+ if (ndnz == 2) {
535
+ b[col_pos] = -a[col_pos] / det;
536
+ b[col_pos+1] = -a[col_pos+1] / det;
537
+ }
538
+ else if (ndnz == 1) {
539
+ b[col_pos] = -a[col_pos] / det;
540
+ }
541
+
542
+ } else if (M == 3) {
543
+ DType *A = new DType[lda*3];
544
+ for (int i = 0; i < lda; ++i) {
545
+ A[i*3+i] = a[i];
546
+ switch (ija[i+1] - ija[i]) {
547
+ case 2:
548
+ A[i*3 + ija[col_pos]] = a[col_pos];
549
+ A[i*3 + ija[col_pos+1]] = a[col_pos+1];
550
+ col_pos += 2;
551
+ break;
552
+ case 1:
553
+ A[i*3 + (i+1)%3] = A[i*3 + (i+2)%3] = 0;
554
+ A[i*3 + ija[col_pos]] = a[col_pos];
555
+ col_pos += 1;
556
+ break;
557
+ case 0:
558
+ A[i*3 + (i+1)%3] = A[i*3 + (i+2)%3] = 0;
559
+ break;
560
+ default:
561
+ rb_raise(rb_eArgError, "some value in IJA is incorrect!");
562
+ }
563
+ }
564
+ det =
565
+ A[0] * A[lda+1] * A[2*lda+2] + A[1] * A[lda+2] * A[2*lda] + A[2] * A[lda] * A[2*lda+1]
566
+ - A[0] * A[lda+2] * A[2*lda+1] - A[1] * A[lda] * A[2*lda+2] - A[2] * A[lda+1] * A[2*lda];
567
+ if (det == 0) { raise_not_invertible_error(); }
568
+
569
+ DType *B = new DType[3*ldb];
570
+ B[0] = ( A[lda+1] * A[2*lda+2] - A[lda+2] * A[2*lda+1]) / det; // A = ei - fh
571
+ B[1] = (- A[1] * A[2*lda+2] + A[2] * A[2*lda+1]) / det; // D = -bi + ch
572
+ B[2] = ( A[1] * A[lda+2] - A[2] * A[lda+1]) / det; // G = bf - ce
573
+ B[ldb] = (- A[lda] * A[2*lda+2] + A[lda+2] * A[2*lda]) / det; // B = -di + fg
574
+ B[ldb+1] = ( A[0] * A[2*lda+2] - A[2] * A[2*lda]) / det; // E = ai - cg
575
+ B[ldb+2] = (- A[0] * A[lda+2] + A[2] * A[lda]) / det; // H = -af + cd
576
+ B[2*ldb] = ( A[lda] * A[2*lda+1] - A[lda+1] * A[2*lda]) / det; // C = dh - eg
577
+ B[2*ldb+1]= ( -A[0] * A[2*lda+1] + A[1] * A[2*lda]) / det; // F = -ah + bg
578
+ B[2*ldb+2]= ( A[0] * A[lda+1] - A[1] * A[lda]) / det; // I = ae - bd
579
+
580
+ // Calculate the size of ijb and b, then reallocate them.
581
+ IType ndnz = 0;
582
+ for (int i = 0; i < 3; ++i) {
583
+ for (int j = 0; j < 3; ++j) {
584
+ if (j != i && B[i*ldb + j] != 0) { ++ndnz; }
585
+ }
586
+ }
587
+ inverse->ndnz = ndnz;
588
+ col_pos = 4; // shape[0] + 1
589
+ inverse->capacity = 4 + ndnz;
590
+ NM_REALLOC_N(inverse->a, DType, 4 + ndnz);
591
+ NM_REALLOC_N(inverse->ija, IType, 4 + ndnz);
592
+ b = reinterpret_cast<DType*>(inverse->a);
593
+ ijb = reinterpret_cast<IType *>(inverse->ija);
594
+
595
+ for (int i = 0; i < 3; ++i) {
596
+ ijb[i] = col_pos;
597
+ for (int j = 0; j < 3; ++j) {
598
+ if (j == i) {
599
+ b[i] = B[i*ldb + j];
600
+ }
601
+ else if (B[i*ldb + j] != 0) {
602
+ b[col_pos] = B[i*ldb + j];
603
+ ijb[col_pos] = j;
604
+ ++col_pos;
605
+ }
606
+ }
607
+ }
608
+ b[3] = 0;
609
+ ijb[3] = col_pos;
610
+ delete [] B;
611
+ delete [] A;
612
+ } else if (M == 1) {
613
+ b[0] = 1 / a[0];
614
+ } else {
615
+ rb_raise(rb_eNotImpError, "exact inverse calculation needed for matrices larger than 3x3");
616
+ }
617
+ }
618
+
422
619
  /*
423
620
  * Function signature conversion for calling CBLAS' gemm functions as directly as possible.
424
621
  *
@@ -1068,14 +1265,43 @@ static VALUE nm_clapack_laswp(VALUE self, VALUE n, VALUE a, VALUE lda, VALUE k1,
1068
1265
 
1069
1266
 
1070
1267
  /*
1071
- * C accessor for calculating an exact determinant.
1268
+ * C accessor for calculating an exact determinant. Dense matrix version.
1072
1269
  */
1073
- void nm_math_det_exact(const int M, const void* elements, const int lda, nm::dtype_t dtype, void* result) {
1074
- NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::det_exact, void, const int M, const void* A_elements, const int lda, void* result_arg);
1270
+ void nm_math_det_exact_from_dense(const int M, const void* elements, const int lda,
1271
+ nm::dtype_t dtype, void* result) {
1272
+ NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::det_exact_from_dense, void, const int M,
1273
+ const void* A_elements, const int lda, void* result_arg);
1075
1274
 
1076
1275
  ttable[dtype](M, elements, lda, result);
1077
1276
  }
1078
1277
 
1278
+ /*
1279
+ * C accessor for calculating an exact determinant. Yale matrix version.
1280
+ */
1281
+ void nm_math_det_exact_from_yale(const int M, const YALE_STORAGE* storage, const int lda,
1282
+ nm::dtype_t dtype, void* result) {
1283
+ NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::det_exact_from_yale, void, const int M,
1284
+ const YALE_STORAGE* storage, const int lda, void* result_arg);
1285
+
1286
+ ttable[dtype](M, storage, lda, result);
1287
+ }
1288
+
1289
+ /*
1290
+ * C accessor for solving a system of linear equations.
1291
+ */
1292
+ void nm_math_solve(VALUE lu, VALUE b, VALUE x, VALUE ipiv) {
1293
+ int* pivot = new int[RARRAY_LEN(ipiv)];
1294
+
1295
+ for (int i = 0; i < RARRAY_LEN(ipiv); ++i) {
1296
+ pivot[i] = FIX2INT(rb_ary_entry(ipiv, i));
1297
+ }
1298
+
1299
+ NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::solve, void, const int, const void*, const void*, void*, const int*);
1300
+
1301
+ ttable[NM_DTYPE(x)](NM_SHAPE0(b), NM_STORAGE_DENSE(lu)->elements,
1302
+ NM_STORAGE_DENSE(b)->elements, NM_STORAGE_DENSE(x)->elements, pivot);
1303
+ }
1304
+
1079
1305
  /*
1080
1306
  * C accessor for reducing a matrix to hessenberg form.
1081
1307
  */
@@ -1087,7 +1313,7 @@ void nm_math_hessenberg(VALUE a) {
1087
1313
  NULL, NULL, // does not support Complex
1088
1314
  NULL // no support for Ruby Object
1089
1315
  };
1090
-
1316
+
1091
1317
  ttable[NM_DTYPE(a)](NM_SHAPE0(a), NM_STORAGE_DENSE(a)->elements);
1092
1318
  }
1093
1319
  /*
@@ -1100,14 +1326,29 @@ void nm_math_inverse(const int M, void* a_elements, nm::dtype_t dtype) {
1100
1326
  }
1101
1327
 
1102
1328
  /*
1103
- * C accessor for calculating an exact inverse.
1329
+ * C accessor for calculating an exact inverse. Dense matrix version.
1104
1330
  */
1105
- void nm_math_inverse_exact(const int M, const void* A_elements, const int lda, void* B_elements, const int ldb, nm::dtype_t dtype) {
1106
- NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::inverse_exact, void, const int, const void*, const int, void*, const int);
1331
+ void nm_math_inverse_exact_from_dense(const int M, const void* A_elements,
1332
+ const int lda, void* B_elements, const int ldb, nm::dtype_t dtype) {
1333
+
1334
+ NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::inverse_exact_from_dense, void,
1335
+ const int, const void*, const int, void*, const int);
1107
1336
 
1108
1337
  ttable[dtype](M, A_elements, lda, B_elements, ldb);
1109
1338
  }
1110
1339
 
1340
+ /*
1341
+ * C accessor for calculating an exact inverse. Yale matrix version.
1342
+ */
1343
+ void nm_math_inverse_exact_from_yale(const int M, const YALE_STORAGE* storage,
1344
+ const int lda, YALE_STORAGE* inverse, const int ldb, nm::dtype_t dtype) {
1345
+
1346
+ NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::math::inverse_exact_from_yale, void,
1347
+ const int, const YALE_STORAGE*, const int, YALE_STORAGE*, const int);
1348
+
1349
+ ttable[dtype](M, storage, lda, inverse, ldb);
1350
+ }
1351
+
1111
1352
  /*
1112
1353
  * Transpose an array of elements that represent a row-major dense matrix. Does not allocate anything, only does an memcpy.
1113
1354
  */