The OpenD Programming Language

1 /++
2 Low level ndslice wrapper for LAPACK.
3 
4 $(RED Attention: LAPACK and this module has column major API.)
5 ndslice rows correspond to LAPACK columns.
6 
7 Functions with `*_wq` suffix are wrappers for workspace queries.
8 
9 Authors: Ilya Yaroshenko
10 Copyright:  Copyright © 2017, Symmetry Investments & Kaleidic Associates
11 +/
12 module mir.lapack;
13 
14 import mir.ndslice.slice;
15 import mir.ndslice.topology: retro;
16 import mir.ndslice.iterator;
17 import mir.utility: min, max;
18 import mir.internal.utility : realType, isComplex;
19 
20 static import lapack;
21 
22 public import lapack: lapackint;
23 
24 import lapack.lapack: _cfloat, _cdouble;
25 
26 @trusted pure nothrow @nogc:
27 
28 ///
29 lapackint ilaenv()(lapackint ispec, scope const(char)* name, scope const(char)* opts, lapackint n1, lapackint n2, lapackint n3, lapackint n4)
30 {
31     return ilaenv_(ispec, name, opts, n1, n2, n3, n4);
32 }
33 
34 ///
35 lapackint ilaenv2stage()(lapackint ispec, scope const(char)* name, scope const(char)* opts, lapackint n1, lapackint n2, lapackint n3, lapackint n4)
36 {
37     return ilaenv2stage_(ispec, name, opts, n1, n2, n3, n4);
38 }
39 
40 /// `getri` work space query.
41 size_t getri_wq(T)(Slice!(T*, 2, Canonical) a)
42 in
43 {
44     assert(a.length!0 == a.length!1, "getri: The input 'a' must be a square matrix.");
45 }
46 do
47 {
48     lapackint n = cast(lapackint) a.length;
49     lapackint lda = cast(lapackint) a._stride.max(1);
50     T work;
51     lapackint lwork = -1;
52     lapackint info;
53 
54     lapack.getri_(n, null, lda, null, &work, lwork, info);
55 
56     assert(info == 0);
57     return cast(size_t) work.re;
58 }
59 
60 unittest
61 {
62     alias s = getri_wq!float;
63     alias d = getri_wq!double;
64     alias c = getri_wq!_cfloat;
65     alias z = getri_wq!_cdouble;
66 }
67 
68 ///
69 size_t getri(T)(
70     Slice!(T*, 2, Canonical) a,
71     Slice!(lapackint*) ipiv,
72     Slice!(T*) work,
73     )
74 in
75 {
76     assert(a.length!0 == a.length!1, "getri: The input 'a' must be a square matrix.");
77     assert(ipiv.length == a.length!0, "getri: The length of 'ipiv' must be equal to the number of rows of 'a'.");
78     assert(work.length, "getri: work must have a non-zero length.");
79 }
80 do
81 {
82     lapackint n = cast(lapackint) a.length;
83     lapackint lda = cast(lapackint) a._stride.max(1);
84     lapackint lwork = cast(lapackint) work.length;
85     lapackint info;
86 
87     lapack.getri_(n, a.iterator, lda, ipiv.iterator, work.iterator, lwork, info);
88 
89     assert(info >= 0);
90     return info;
91 }
92 
93 unittest
94 {
95     alias s = getri!float;
96     alias d = getri!double;
97     alias c = getri!_cfloat;
98     alias z = getri!_cdouble;
99 }
100 
101 ///
102 size_t getrf(T)(
103     Slice!(T*, 2, Canonical) a,
104     Slice!(lapackint*) ipiv,
105     )
106 in
107 {
108     assert(ipiv.length >= min(a.length!0, a.length!1), "getrf: The length of 'ipiv' must be at least the smaller of 'a''s dimensions");
109 }
110 do
111 {
112     lapackint m = cast(lapackint) a.length!1;
113     lapackint n = cast(lapackint) a.length!0;
114     lapackint lda = cast(lapackint) a._stride.max(1);
115     lapackint info;
116 
117     lapack.getrf_(m, n, a.iterator, lda, ipiv.iterator, info);
118 
119     assert(info >= 0);
120     return info;
121 }
122 
123 unittest
124 {
125     alias s = getrf!float;
126     alias d = getrf!double;
127     alias c = getrf!_cfloat;
128     alias z = getrf!_cdouble;
129 }
130 
131 ///
132 template sptrf(T)
133 {
134     /// `sptrf` for upper triangular input.
135     size_t sptrf(
136         Slice!(StairsIterator!(T*, "+")) ap,
137         Slice!(lapackint*) ipiv,
138         )
139     in
140     {
141         assert(ipiv.length == ap.length, "sptrf: The length of 'ipiv' must be equal to the length 'ap'.");
142     }
143     do
144     {
145         char uplo = 'U';
146         lapackint n = cast(lapackint) ap.length;
147         lapackint info;
148 
149         lapack.sptrf_(uplo, n, &ap[0][0], ipiv.iterator, info);
150 
151         assert(info >= 0);
152         return info;
153     }
154 
155     /// `sptrf` for lower triangular input.
156     size_t sptrf(
157         Slice!(StairsIterator!(T*, "-")) ap,
158         Slice!(lapackint*) ipiv,
159         )
160     in
161     {
162         assert(ipiv.length == ap.length, "sptrf: The length of 'ipiv' must be equal to the length 'ap'.");
163     }
164     do
165     {
166         char uplo = 'L';
167         lapackint n = cast(lapackint) ap.length;
168         lapackint info;
169 
170         lapack.sptrf_(uplo, n, &ap[0][0], ipiv.iterator, info);
171 
172         assert(info >= 0);
173         return info;
174     }
175 }
176 
177 unittest
178 {
179     alias s = sptrf!float;
180     alias d = sptrf!double;
181 }
182 
183 ///
184 size_t gesv(T)(
185     Slice!(T*, 2, Canonical) a,
186     Slice!(lapackint*) ipiv,
187     Slice!(T*, 2, Canonical) b,
188     )
189 in
190 {
191     assert(a.length!0 == a.length!1, "gesv: The input 'a' must be a square matrix.");
192     assert(ipiv.length == a.length!0, "gesv: The length of 'ipiv' must be equal to the number of rows of 'a'.");
193     assert(b.length!1 == a.length!0, "gesv: The number of columns of 'b' must equal the number of rows of 'a'");
194 }
195 do
196 {
197     lapackint n = cast(lapackint) a.length;
198     lapackint nrhs = cast(lapackint) b.length;
199     lapackint lda = cast(lapackint) a._stride.max(1);
200     lapackint ldb = cast(lapackint) b._stride.max(1);
201     lapackint info;
202 
203     lapack.gesv_(n, nrhs, a.iterator, lda, ipiv.iterator, b.iterator, ldb, info);
204 
205     assert(info >= 0);
206     return info;
207 }
208 
209 unittest
210 {
211     alias s = gesv!float;
212     alias d = gesv!double;
213 }
214 
215 /// `gelsd` work space query.
216 size_t gelsd_wq(T)(
217     Slice!(T*, 2, Canonical) a,
218     Slice!(T*, 2, Canonical) b,
219     ref size_t liwork,
220     )
221     if(!isComplex!T)
222 in
223 {
224     assert(b.length!1 == a.length!1, "gelsd_wq: The number of columns of 'b' must equal the number of columns of 'a'");
225 }
226 do
227 {
228     lapackint m = cast(lapackint) a.length!1;
229     lapackint n = cast(lapackint) a.length!0;
230     lapackint nrhs = cast(lapackint) b.length;
231     lapackint lda = cast(lapackint) a._stride.max(1);
232     lapackint ldb = cast(lapackint) b._stride.max(1);
233     T rcond;
234     lapackint rank;
235     T work;
236     lapackint lwork = -1;
237     lapackint iwork;
238     lapackint info;
239 
240     lapack.gelsd_(m, n, nrhs, a.iterator, lda, b.iterator, ldb, null, rcond, rank, &work, lwork, &iwork, info);
241 
242     assert(info == 0);
243     liwork = iwork;
244     return cast(size_t) work.re;
245 }
246 
247 
248 /// ditto
249 size_t gelsd_wq(T)(
250     Slice!(T*, 2, Canonical) a,
251     Slice!(T*, 2, Canonical) b,
252     ref size_t lrwork,
253     ref size_t liwork,
254     )
255     if(isComplex!T)
256 in
257 {
258     assert(b.length!1 == a.length!1, "gelsd_wq: The number of columns of 'b' must equal the number of columns of 'a'");
259 }
260 do
261 {
262     lapackint m = cast(lapackint) a.length!1;
263     lapackint n = cast(lapackint) a.length!0;
264     lapackint nrhs = cast(lapackint) b.length;
265     lapackint lda = cast(lapackint) a._stride.max(1);
266     lapackint ldb = cast(lapackint) b._stride.max(1);
267     realType!T rcond;
268     lapackint rank;
269     T work;
270     lapackint lwork = -1;
271     realType!T rwork;
272     lapackint iwork;
273     lapackint info;
274 
275     lapack.gelsd_(m, n, nrhs, a.iterator, lda, b.iterator, ldb, null, rcond, rank, &work, lwork, &rwork, &iwork, info);
276     
277     assert(info == 0);
278     lrwork = cast(size_t)rwork;
279     liwork = iwork;
280     return cast(size_t) work.re;
281 }
282 
283 unittest
284 {
285     alias s = gelsd_wq!float;
286     alias d = gelsd_wq!double;
287     alias c = gelsd_wq!_cfloat;
288     alias z = gelsd_wq!_cdouble;
289 }
290 
291 ///
292 size_t gelsd(T)(
293     Slice!(T*, 2, Canonical) a,
294     Slice!(T*, 2, Canonical) b,
295     Slice!(T*) s,
296     T rcond,
297     ref size_t rank,
298     Slice!(T*) work,
299     Slice!(lapackint*) iwork,
300     )
301     if(!isComplex!T)
302 in
303 {
304     assert(b.length!1 == a.length!1, "gelsd: The number of columns of 'b' must equal the number of columns of 'a'");
305     assert(s.length == min(a.length!0, a.length!1), "gelsd: The length of 's' must equal the smaller of the dimensions of 'a'");
306 }
307 do
308 {
309     lapackint m = cast(lapackint) a.length!1;
310     lapackint n = cast(lapackint) a.length!0;
311     lapackint nrhs = cast(lapackint) b.length;
312     lapackint lda = cast(lapackint) a._stride.max(1);
313     lapackint ldb = cast(lapackint) b._stride.max(1);
314     lapackint rank_;
315     lapackint lwork = cast(lapackint) work.length;
316     lapackint info;
317 
318     lapack.gelsd_(m, n, nrhs, a.iterator, lda, b.iterator, ldb, s.iterator, rcond, rank_, work.iterator, lwork, iwork.iterator, info);
319 
320     assert(info >= 0);
321     rank = rank_;
322     return info;
323 }
324 
325 /// ditto
326 size_t gelsd(T)(
327     Slice!(T*, 2, Canonical) a,
328     Slice!(T*, 2, Canonical) b,
329     Slice!(realType!T*) s,
330     realType!T rcond,
331     ref size_t rank,
332     Slice!(T*) work,
333     Slice!(realType!T*) rwork,
334     Slice!(lapackint*) iwork,
335     )
336     if(isComplex!T)
337 in
338 {
339     assert(b.length!1 == a.length!1, "gelsd: The number of columns of 'b' must equal the number of columns of 'a'");
340     assert(s.length == min(a.length!0, a.length!1), "gelsd: The length of 's' must equal the smaller of the dimensions of 'a'");
341 }
342 do
343 {
344     lapackint m = cast(lapackint) a.length!1;
345     lapackint n = cast(lapackint) a.length!0;
346     lapackint nrhs = cast(lapackint) b.length;
347     lapackint lda = cast(lapackint) a._stride.max(1);
348     lapackint ldb = cast(lapackint) b._stride.max(1);
349     lapackint rank_;
350     lapackint lwork = cast(lapackint) work.length;
351     lapackint info;
352 
353     lapack.gelsd_(m, n, nrhs, a.iterator, lda, b.iterator, ldb, s.iterator, rcond, rank_, work.iterator, lwork, rwork.iterator, iwork.iterator, info);
354 
355     assert(info >= 0);
356     rank = rank_;
357     return info;
358 }
359 
360 unittest
361 {
362     alias s = gelsd!float;
363     alias d = gelsd!double;
364     alias c = gelsd!_cfloat;
365     alias z = gelsd!_cdouble;
366 }
367 
368 /// `gesdd` work space query
369 size_t gesdd_wq(T)(
370     char jobz,
371     Slice!(T*, 2, Canonical) a,
372     Slice!(T*, 2, Canonical) u,
373     Slice!(T*, 2, Canonical) vt,
374     )
375 {
376     lapackint m = cast(lapackint) a.length!1;
377     lapackint n = cast(lapackint) a.length!0;
378     lapackint lda = cast(lapackint) a._stride.max(1);
379     lapackint ldu = cast(lapackint) u._stride.max(1);
380     lapackint ldvt = cast(lapackint) vt._stride.max(1);
381     T work;
382     lapackint lwork = -1;
383     lapackint info;
384 
385     static if(!isComplex!T)
386     {
387         lapack.gesdd_(jobz, m, n, null, lda, null, null, ldu, null, ldvt, &work, lwork, null, info);
388     }
389     else
390     {
391         lapack.gesdd_(jobz, m, n, null, lda, null, null, ldu, null, ldvt, &work, lwork, null, null, info);
392     }
393 
394     assert(info == 0);
395     return cast(size_t) work.re;
396 }
397 
398 unittest
399 {
400     alias s = gesdd_wq!float;
401     alias d = gesdd_wq!double;
402     alias c = gesdd_wq!_cfloat;
403     alias z = gesdd_wq!_cdouble;
404 }
405 
406 ///
407 size_t gesdd(T)(
408     char jobz,
409     Slice!(T*, 2, Canonical) a,
410     Slice!(T*) s,
411     Slice!(T*, 2, Canonical) u,
412     Slice!(T*, 2, Canonical) vt,
413     Slice!(T*) work,
414     Slice!(lapackint*) iwork,
415     )
416     if(!isComplex!T)
417 {
418     lapackint m = cast(lapackint) a.length!1;
419     lapackint n = cast(lapackint) a.length!0;
420     lapackint lda = cast(lapackint) a._stride.max(1);
421     lapackint ldu = cast(lapackint) u._stride.max(1);
422     lapackint ldvt = cast(lapackint) vt._stride.max(1);
423     lapackint lwork = cast(lapackint) work.length;
424     lapackint info;
425 
426     lapack.gesdd_(jobz, m, n, a.iterator, lda, s.iterator, u.iterator, ldu, vt.iterator, ldvt, work.iterator, lwork, iwork.iterator, info);
427 
428     assert(info >= 0);
429     return info;
430 }
431 
432 /// ditto
433 size_t gesdd(T)(
434     char jobz,
435     Slice!(T*, 2, Canonical) a,
436     Slice!(realType!T*) s,
437     Slice!(T*, 2, Canonical) u,
438     Slice!(T*, 2, Canonical) vt,
439     Slice!(T*) work,
440     Slice!(realType!T*) rwork,
441     Slice!(lapackint*) iwork,
442     )
443     if(isComplex!T)
444 {
445     lapackint m = cast(lapackint) a.length!1;
446     lapackint n = cast(lapackint) a.length!0;
447     lapackint lda = cast(lapackint) a._stride.max(1);
448     lapackint ldu = cast(lapackint) u._stride.max(1);
449     lapackint ldvt = cast(lapackint) vt._stride.max(1);
450     lapackint lwork = cast(lapackint) work.length;
451     lapackint info;
452 
453     lapack.gesdd_(jobz, m, n, a.iterator, lda, s.iterator, u.iterator, ldu, vt.iterator, ldvt, work.iterator, lwork, rwork.iterator, iwork.iterator, info);
454 
455     assert(info >= 0);
456     return info;
457 }
458 
459 unittest
460 {
461     alias s = gesdd!float;
462     alias d = gesdd!double;
463     alias c = gesdd!_cfloat;
464     alias z = gesdd!_cdouble;
465 }
466 
467 /// `gesvd` work space query
468 size_t gesvd_wq(T)(
469     char jobu,
470     char jobvt,
471     Slice!(T*, 2, Canonical) a,
472     Slice!(T*, 2, Canonical) u,
473     Slice!(T*, 2, Canonical) vt,
474     )
475 {
476     lapackint m = cast(lapackint) a.length!1;
477     lapackint n = cast(lapackint) a.length!0;
478     lapackint lda = cast(lapackint) a._stride.max(1);
479     lapackint ldu = cast(lapackint) u._stride.max(1);
480     lapackint ldvt = cast(lapackint) vt._stride.max(1);
481     T work;
482     lapackint lwork = -1;
483     lapackint info;
484 
485     static if(!isComplex!T)
486     {
487         lapack.gesvd_(jobu, jobvt, m, n, null, lda, null, null, ldu, null, ldvt, &work, lwork, info);
488     }
489     else
490     {
491         lapack.gesvd_(jobu, jobvt, m, n, null, lda, null, null, ldu, null, ldvt, &work, lwork, null, info);
492     }
493 
494     assert(info == 0);
495     return cast(size_t) work.re;
496 }
497 
498 unittest
499 {
500     alias s = gesvd_wq!float;
501     alias d = gesvd_wq!double;
502     alias c = gesvd_wq!_cfloat;
503     alias z = gesvd_wq!_cdouble;
504 }
505 
506 ///
507 size_t gesvd(T)(
508     char jobu,
509     char jobvt,
510     Slice!(T*, 2, Canonical) a,
511     Slice!(T*) s,
512     Slice!(T*, 2, Canonical) u,
513     Slice!(T*, 2, Canonical) vt,
514     Slice!(T*) work,
515     )
516     if(!isComplex!T)
517 {
518     lapackint m = cast(lapackint) a.length!1;
519     lapackint n = cast(lapackint) a.length!0;
520     lapackint lda = cast(lapackint) a._stride.max(1);
521     lapackint ldu = cast(lapackint) u._stride.max(1);
522     lapackint ldvt = cast(lapackint) vt._stride.max(1);
523     lapackint lwork = cast(lapackint) work.length;
524     lapackint info;
525 
526     lapack.gesvd_(jobu, jobvt, m, n, a.iterator, lda, s.iterator, u.iterator, ldu, vt.iterator, ldvt, work.iterator, lwork, info);
527 
528     assert(info >= 0);
529     return info;
530 }
531 
532 /// ditto
533 size_t gesvd(T)(
534     char jobu,
535     char jobvt,
536     Slice!(T*, 2, Canonical) a,
537     Slice!(realType!T*) s,
538     Slice!(T*, 2, Canonical) u,
539     Slice!(T*, 2, Canonical) vt,
540     Slice!(T*) work,
541     Slice!(realType!T*) rwork,
542     )
543     if(isComplex!T)
544 {
545     lapackint m = cast(lapackint) a.length!1;
546     lapackint n = cast(lapackint) a.length!0;
547     lapackint lda = cast(lapackint) a._stride.max(1);
548     lapackint ldu = cast(lapackint) u._stride.max(1);
549     lapackint ldvt = cast(lapackint) vt._stride.max(1);
550     lapackint lwork = cast(lapackint) work.length;
551     lapackint info;
552 
553     lapack.gesvd_(jobu, jobvt, m, n, a.iterator, lda, s.iterator, u.iterator, ldu, vt.iterator, ldvt, work.iterator, lwork, rwork.iterator, info);
554 
555     assert(info >= 0);
556     return info;
557 }
558 
559 unittest
560 {
561     alias s = gesvd!float;
562     alias d = gesvd!double;
563     alias c = gesvd!_cfloat;
564     alias z = gesvd!_cdouble;
565 }
566 
567 ///
568 template spev(T)
569 {
570     ///
571     size_t spev(
572         char jobz,
573         Slice!(StairsIterator!(T*, "+")) ap,
574         Slice!(T*) w,
575         Slice!(T*, 2, Canonical) z,
576         Slice!(T*) work,
577         )
578     in
579     {
580         assert(work.length == 3 * ap.length, "spev: The length of 'work' must equal three times the length of 'ap'.");
581         assert(w.length == ap.length, "spev: The length of 'w' must equal the length of 'ap'.");
582     }
583     do
584     {
585         char uplo = 'U';
586         lapackint n = cast(lapackint) ap.length;
587         lapackint ldz = cast(lapackint) z._stride.max(1);
588         lapackint info;
589 
590         lapack.spev_(jobz, uplo, n, &ap[0][0], w.iterator, z.iterator, ldz, work.iterator, info);
591 
592         assert(info >= 0);
593         return info;
594     }
595 
596     ///
597     size_t spev(
598         char jobz,
599         Slice!(StairsIterator!(T*, "-")) ap,
600         Slice!(T*) w,
601         Slice!(T*, 2, Canonical) z,
602         Slice!(T*) work,
603         )
604     in
605     {
606         assert(work.length == 3 * ap.length, "spev: The length of 'work' must equal three times the length of 'ap'.");
607         assert(w.length == ap.length, "spev: The length of 'w' must equal the length of 'ap'.");
608     }
609     do
610     {
611         char uplo = 'L';
612         lapackint n = cast(lapackint) ap.length;
613         lapackint ldz = cast(lapackint) z._stride.max(1);
614         lapackint info;
615 
616         lapack.spev_(jobz, uplo, n, &ap[0][0], w.iterator, z.iterator, ldz, work.iterator, info);
617 
618         assert(info >= 0);
619         return info;
620     }
621 }
622 
623 unittest
624 {
625     alias s = spev!float;
626     alias d = spev!double;
627 }
628 
629 ///
630 size_t sytrf(T)(
631     char uplo,
632     Slice!(T*, 2, Canonical) a,
633     Slice!(lapackint*) ipiv,
634     Slice!(T*) work,
635     )
636 in
637 {
638     assert(a.length!0 == a.length!1, "sytrf: The input 'a' must be a square matrix.");
639 }
640 do
641 {
642     lapackint info;
643     lapackint n = cast(lapackint) a.length;
644     lapackint lda = cast(lapackint) a._stride.max(1);
645     lapackint lwork = cast(lapackint) work.length;
646 
647     lapack.sytrf_(uplo, n, a.iterator, lda, ipiv.iterator, work.iterator, lwork, info);
648     ///if info = 0: successful exit.
649     ///if info > 0: if info = i, D(i, i) is exactly zero. The factorization has been
650     ///completed, but the block diagonal matrix D is exactly singular, and division by
651     ///zero will occur if it is used to solve a system of equations.
652     ///if info < 0: if info == -i, the i-th argument had an illegal value.
653     assert(info >= 0);
654     return info;
655 }
656 
657 unittest
658 {
659     alias s = sytrf!float;
660     alias d = sytrf!double;
661     alias c = sytrf!_cfloat;
662     alias z = sytrf!_cdouble;
663 }
664 
665 ///
666 size_t geqrf(T)(
667     Slice!(T*, 2, Canonical) a,
668     Slice!(T*) tau,
669     Slice!(T*) work
670     )
671 in
672 {
673     assert(a.length!0 >= 0, "geqrf: The number of columns of 'a' must be " ~ 
674         "greater than or equal to zero."); //n>=0
675     assert(a.length!1 >= a.length!0, "geqrf: The number of columns of 'a' " ~ 
676         "must be greater than or equal to the number of its rows."); //m>=n
677     assert(tau.length >= 0, "geqrf: The input 'tau' must have length greater " ~ 
678         "than or equal to zero."); //k>=0
679     assert(a.length!0 >= tau.length, "geqrf: The number of columns of 'a' " ~ 
680         "must be greater than or equal to the length of 'tau'."); //n>=k
681     assert(work.length >= a.length!0, "geqrf: The length of 'work' must be " ~ 
682         "greater than or equal to the number of rows of 'a'."); //lwork>=n
683 }
684 do
685 {
686     lapackint m = cast(lapackint) a.length!1;
687     lapackint n = cast(lapackint) a.length!0;
688     lapackint lda = cast(lapackint) a._stride.max(1);
689     lapackint lwork = cast(lapackint) work.length;
690     lapackint info;
691 
692     lapack.geqrf_(m, n, a.iterator, lda, tau.iterator, work.iterator, lwork, info);
693 
694     ///if info == 0: successful exit;
695     ///if info < 0: if info == -i, the i-th argument had an illegal value.
696     assert(info >= 0);
697     return info;
698 }
699 
700 unittest
701 {
702     alias s = geqrf!float;
703     alias d = geqrf!double;
704     alias c = geqrf!_cfloat;
705     alias z = geqrf!_cdouble;
706 }
707 
708 ///
709 size_t getrs(T)(
710     char trans,
711     Slice!(T*, 2, Canonical) a,
712     Slice!(T*, 2, Canonical) b,
713     Slice!(lapackint*) ipiv,
714     )
715 in
716 {
717     assert(a.length!0 == a.length!1, "getrs: The input 'a' must be a square matrix.");
718     assert(ipiv.length == a.length!0, "getrs: The length of 'ipiv' must be equal to the number of rows of 'a'.");
719 }
720 do
721 {
722     lapackint n = cast(lapackint) a.length;
723     lapackint nrhs = cast(lapackint) b.length;
724     lapackint lda = cast(lapackint) a._stride.max(1);
725     lapackint ldb = cast(lapackint) b._stride.max(1);
726     lapackint info;
727 
728     lapack.getrs_(trans, n, nrhs, a.iterator, lda, ipiv.iterator, b.iterator, ldb, info);
729 
730     ///if info == 0: successful exit.
731     ///if info < 0: if info == -i, the i-th argument had an illegal value.
732     assert(info >= 0);
733     return info;
734 }
735 
736 unittest
737 {
738     alias s = getrs!float;
739     alias d = getrs!double;
740     alias c = getrs!_cfloat;
741     alias z = getrs!_cdouble;
742 }
743 
744 ///
745 size_t potrs(T)(
746     char uplo,
747     Slice!(T*, 2, Canonical) a,
748     Slice!(T*, 2, Canonical) b,
749     )
750 in
751 {
752     assert(a.length!0 == a.length!1, "potrs: The input 'a' must be a square matrix.");
753 }
754 do
755 {
756     lapackint n = cast(lapackint) a.length;
757     lapackint nrhs = cast(lapackint) b.length;
758     lapackint lda = cast(lapackint) a._stride.max(1);
759     lapackint ldb = cast(lapackint) b._stride.max(1);
760     lapackint info;
761 
762     lapack.potrs_(uplo, n, nrhs, a.iterator, lda, b.iterator, ldb, info);
763 
764     ///if info == 0: successful exit.
765     ///if info < 0: if info == -i, the i-th argument had an illegal value.
766     assert(info >= 0);
767     return info;
768 }
769 
770 unittest
771 {
772     alias s = potrs!float;
773     alias d = potrs!double;
774     alias c = potrs!_cfloat;
775     alias z = potrs!_cdouble;
776 }
777 
778 ///
779 size_t sytrs2(T)(
780     Slice!(T*, 2, Canonical) a,
781     Slice!(T*, 2, Canonical) b,
782     Slice!(lapackint*) ipiv,
783     Slice!(T*) work,
784     char uplo,
785     )
786 in
787 {
788     assert(a.length!0 == a.length!1, "sytrs2: The input 'a' must be a square matrix.");
789 }
790 do
791 {
792     lapackint n = cast(lapackint) a.length;
793     lapackint nrhs = cast(lapackint) b.length;
794     lapackint lda = cast(lapackint) a._stride.max(1);
795     lapackint ldb = cast(lapackint) b._stride.max(1);
796     lapackint info;
797 
798     lapack.sytrs2_(uplo, n, nrhs, a.iterator, lda, ipiv.iterator, b.iterator, ldb, work.iterator, info);
799 
800     ///if info == 0: successful exit.
801     ///if info < 0: if info == -i, the i-th argument had an illegal value.
802     assert(info >= 0);
803     return info;
804 }
805 
806 unittest
807 {
808     alias s = sytrs2!float;
809     alias d = sytrs2!double;
810     alias c = sytrs2!_cfloat;
811     alias z = sytrs2!_cdouble;
812 }
813 
814 ///
815 size_t geqrs(T)(
816     Slice!(T*, 2, Canonical) a,
817     Slice!(T*, 2, Canonical) b,
818     Slice!(T*) tau,
819     Slice!(T*) work
820     )
821 in
822 {
823     assert(a.length!0 >= 0, "geqrs: The number of columns of 'a' must be " ~ 
824         "greater than or equal to zero."); //n>=0
825     assert(a.length!1 >= a.length!0, "geqrs: The number of columns of 'a' " ~ 
826         "must be greater than or equal to the number of its rows."); //m>=n
827     assert(tau.length >= 0, "geqrs: The input 'tau' must have length greater " ~ 
828         "than or equal to zero."); //k>=0
829     assert(a.length!0 >= tau.length, "geqrs: The number of columns of 'a' " ~ 
830         "must be greater than or equal to the length of 'tau'."); //n>=k
831     assert(work.length >= a.length!0, "geqrs: The length of 'work' must be " ~ 
832         "greater than or equal to the number of rows of 'a'."); //lwork>=n
833 }
834 do
835 {
836     lapackint m = cast(lapackint) a.length!1;
837     lapackint n = cast(lapackint) a.length!0;
838     lapackint nrhs = cast(lapackint) b.length;
839     lapackint lda = cast(lapackint) a._stride.max(1);
840     lapackint ldb = cast(lapackint) b._stride.max(1);
841     lapackint lwork = cast(lapackint) work.length;
842     lapackint info;
843 
844     lapack.geqrs_(m, n, nrhs, a.iterator, lda, tau.iterator, b.iterator, ldb, work.iterator, lwork, info);
845 
846     ///if info == 0: successful exit.
847     ///if info < 0: if info == -i, the i-th argument had an illegal value.
848     assert(info >= 0);
849     return info;
850 }
851 
852 version(none)
853 unittest
854 {
855     alias s = geqrs!float;
856     alias d = geqrs!double;
857     alias c = geqrs!_cfloat;
858     alias z = geqrs!_cdouble;
859 }
860 
861 ///
862 size_t sysv_rook_wk(T)(
863     char uplo,
864     Slice!(T*, 2, Canonical) a,
865     Slice!(T*, 2, Canonical) b,
866     ) 
867 in
868 {
869     assert(a.length!0 == a.length!1, "sysv_rook_wk: The input 'a' must be a square matrix.");
870     assert(b.length!1 == a.length!0, "sysv_rook_wk: The number of columns of 'b' must equal the number of rows of 'a'.");
871 }
872 do
873 {
874     lapackint n = cast(lapackint) a.length;
875     lapackint nrhs = cast(lapackint) b.length;
876     lapackint lda = cast(lapackint) a._stride.max(1);
877     lapackint ldb = cast(lapackint) b._stride.max(1);
878     T work;
879     lapackint lwork = -1;
880     lapackint info;
881 
882     lapack.sysv_rook_(uplo, n, nrhs, a._iterator, lda, null, b._iterator, ldb, &work, lwork, info);
883 
884     return cast(size_t) work.re;
885 }
886 
887 unittest
888 {
889     alias s = sysv_rook_wk!float;
890     alias d = sysv_rook_wk!double;
891     alias c = sysv_rook_wk!_cfloat;
892     alias z = sysv_rook_wk!_cdouble;
893 }
894 
895 ///
896 size_t sysv_rook(T)(
897     char uplo,
898     Slice!(T*, 2, Canonical) a,
899     Slice!(lapackint*) ipiv,
900     Slice!(T*, 2, Canonical) b,
901     Slice!(T*) work,
902     )
903 in
904 {
905     assert(a.length!0 == a.length!1, "sysv_rook: The input 'a' must be a square matrix.");
906     assert(ipiv.length == a.length!0, "sysv_rook: The length of 'ipiv' must be equal to the number of rows of 'a'");
907     assert(b.length!1 == a.length!0, "sysv_rook: The number of columns of 'b' must equal the number of rows of 'a'.");
908 }
909 do
910 {
911     lapackint n = cast(lapackint) a.length;
912     lapackint nrhs = cast(lapackint) b.length;
913     lapackint lda = cast(lapackint) a._stride.max(1);
914     lapackint ldb = cast(lapackint) b._stride.max(1);
915     lapackint lwork = cast(lapackint) work.length;
916     lapackint info;
917 
918     lapack.sysv_rook_(uplo, n, nrhs, a._iterator, lda, ipiv._iterator, b._iterator, ldb, work._iterator, lwork, info);
919 
920     assert(info >= 0);
921     return info;
922 }
923 
924 unittest
925 {
926     alias s = sysv_rook!float;
927     alias d = sysv_rook!double;
928     alias c = sysv_rook!_cfloat;
929     alias z = sysv_rook!_cdouble;
930 }
931 
932 ///
933 size_t syev_wk(T)(
934     char jobz,
935     char uplo,
936     Slice!(T*, 2, Canonical) a,
937     Slice!(T*) w,
938     )
939 in
940 {
941     assert(a.length!0 == a.length!1, "syev_wk: The input 'a' must be a square matrix.");
942     assert(w.length == a.length!0, "syev_wk: The length of 'w' must equal the number of rows of 'a'.");
943 }
944 do
945 {
946     lapackint n = cast(lapackint) a.length;
947     lapackint lda = cast(lapackint) a._stride.max(1);
948     T work;
949     lapackint lwork = -1;
950     lapackint info;
951 
952     lapack.syev_(jobz, uplo, n, a._iterator, lda, w._iterator, &work, lwork, info);
953 
954     return cast(size_t) work.re;
955 }
956 
957 unittest
958 {
959     alias s = syev_wk!float;
960     alias d = syev_wk!double;
961 }
962 
963 ///
964 size_t syev(T)(
965     char jobz,
966     char uplo,
967     Slice!(T*, 2, Canonical) a,
968     Slice!(T*) w,
969     Slice!(T*) work,
970     )
971 in
972 {
973     assert(a.length!0 == a.length!1, "syev: The input 'a' must be a square matrix.");
974     assert(w.length == a.length!0, "syev: The length of 'w' must equal the number of rows of 'a'.");
975 }
976 do
977 {
978     lapackint n = cast(lapackint) a.length;
979     lapackint lda = cast(lapackint) a._stride.max(1);
980     lapackint lwork = cast(lapackint) work.length;
981     lapackint info;
982 
983     lapack.syev_(jobz, uplo, n, a._iterator, lda, w._iterator, work._iterator, lwork, info);
984 
985     assert(info >= 0);
986     return info;
987 }
988 
989 unittest
990 {
991     alias s = syev!float;
992     alias d = syev!double;
993 }
994 
995 ///
996 size_t syev_2stage_wk(T)(
997     char jobz,
998     char uplo,
999     Slice!(T*, 2, Canonical) a,
1000     Slice!(T*) w,
1001     )
1002 in
1003 {
1004     assert(a.length!0 == a.length!1, "syev_2stage_wk: The input 'a' must be a square matrix.");
1005     assert(w.length == a.length, "syev_2stage_wk: The length of 'w' must equal the number of rows of 'a'.");
1006 }
1007 do
1008 {
1009     lapackint n = cast(lapackint) a.length;
1010     lapackint lda = cast(lapackint) a._stride.max(1);
1011     T work;
1012     lapackint lwork = -1;
1013     lapackint info;
1014 
1015     lapack.syev_2stage_(jobz, uplo, n, a._iterator, lda, w._iterator, &work, lwork, info);
1016 
1017     return cast(size_t) work.re;
1018 }
1019 
1020 version(none)
1021 unittest
1022 {
1023     alias s = syev_2stage_wk!float;
1024     alias d = syev_2stage_wk!double;
1025 }
1026 
1027 ///
1028 size_t syev_2stage(T)(
1029     char jobz,
1030     char uplo,
1031     Slice!(T*, 2, Canonical) a,
1032     Slice!(T*) w,
1033     Slice!(T*) work,
1034     )
1035 in
1036 {
1037     assert(a.length!0 == a.length!1, "syev_2stage: The input 'a' must be a square matrix.");
1038     assert(w.length == a.length, "syev_2stage: The length of 'w' must equal the number of rows of 'a'.");
1039 }
1040 do
1041 {
1042     lapackint n = cast(lapackint) a.length;
1043     lapackint lda = cast(lapackint) a._stride.max(1);
1044     lapackint lwork = cast(lapackint) work.length;
1045     lapackint info;
1046 
1047     lapack.syev_2stage_(jobz, uplo, n, a._iterator, lda, w._iterator, work._iterator, lwork, info);
1048 
1049     assert(info >= 0);
1050     return info;
1051 }
1052 
1053 version(none)
1054 unittest
1055 {
1056     alias s = syev_2stage!float;
1057     alias d = syev_2stage!double;
1058 }
1059 
1060 ///
1061 size_t potrf(T)(
1062        char uplo,
1063        Slice!(T*, 2, Canonical) a,
1064        )
1065 in
1066 {
1067     assert(a.length!0 == a.length!1, "potrf: The input 'a' must be a square matrix.");
1068 }
1069 do
1070 {
1071     lapackint n = cast(lapackint) a.length;
1072     lapackint lda = cast(lapackint) a._stride.max(1);
1073     lapackint info;
1074     
1075     lapack.potrf_(uplo, n, a.iterator, lda, info);
1076     
1077     assert(info >= 0);
1078     
1079     return info;
1080 }
1081 
1082 unittest
1083 {
1084     alias s = potrf!float;
1085     alias d = potrf!double;
1086     alias c = potrf!_cfloat;
1087     alias z = potrf!_cdouble;
1088 }
1089 
1090 ///
1091 size_t pptrf(T)(
1092     char uplo,
1093     Slice!(T*, 2, Canonical) ap,
1094     )
1095 {
1096     lapackint n = cast(lapackint) ap.length;
1097     lapackint info;
1098     
1099     lapack.pptrf_(uplo, n, ap.iterator, info);
1100     
1101     assert(info >= 0);
1102     
1103     return info;
1104 }
1105 
1106 unittest
1107 {
1108     alias s = pptrf!float;
1109     alias d = pptrf!double;
1110     alias c = pptrf!_cfloat;
1111     alias z = pptrf!_cdouble;
1112 }
1113 
1114 ///
1115 template sptri(T)
1116 {
1117     /// `sptri` for upper triangular input.
1118     size_t sptri(
1119         Slice!(StairsIterator!(T*, "+")) ap,
1120         Slice!(lapackint*) ipiv,
1121         Slice!(T*) work
1122         )
1123     in
1124     {
1125         assert(ipiv.length == ap.length, "sptri: The length of 'ipiv' must be equal to the length of 'ap'.");
1126         assert(work.length == ap.length, "sptri: The length of 'work' must be equal to the length of 'ap'.");
1127     }
1128     do
1129     {
1130         lapackint n = cast(lapackint) ap.length;
1131         lapackint info;
1132 
1133         char uplo = 'U';
1134         lapack.sptri_(uplo, n, &ap[0][0], ipiv.iterator, work.iterator, info);
1135 
1136         assert(info >= 0);
1137         return info;
1138     }
1139 
1140     /// `sptri` for lower triangular input.
1141     size_t sptri(
1142         Slice!(StairsIterator!(T*, "-")) ap,
1143         Slice!(lapackint*) ipiv,
1144         Slice!(T*) work
1145         )
1146     in
1147     {
1148         assert(ipiv.length == ap.length, "sptri: The length of 'ipiv' must be equal to the length of 'ap'.");
1149         assert(work.length == ap.length, "sptri: The length of 'work' must be equal to the length of 'ap'.");
1150     }
1151     do
1152     {
1153         lapackint n = cast(lapackint) ap.length;
1154         lapackint info;
1155 
1156         char uplo = 'L';
1157         lapack.sptri_(uplo, n, &ap[0][0], ipiv.iterator, work.iterator, info);
1158 
1159         assert(info >= 0);
1160         return info;
1161     }
1162 }
1163 
1164 unittest
1165 {
1166     alias s = sptri!float;
1167     alias d = sptri!double;
1168     alias c = sptri!_cfloat;
1169     alias z = sptri!_cdouble;
1170 }
1171 
1172 ///
1173 size_t potri(T)(
1174     char uplo,
1175     Slice!(T*, 2, Canonical) a,
1176     )
1177 in
1178 {
1179     assert(a.length!0 == a.length!1, "potri: The input 'a' must be a square matrix.");
1180 }
1181 do
1182 {
1183     lapackint n = cast(lapackint) a.length;
1184     lapackint lda = cast(lapackint) a._stride.max(1);
1185     lapackint info;
1186 
1187     lapack.potri_(uplo, n, a.iterator, lda, info);
1188 
1189     assert(info >= 0);
1190     return info;
1191 }
1192 
1193 unittest
1194 {
1195     alias s = potri!float;
1196     alias d = potri!double;
1197     alias c = potri!_cfloat;
1198     alias z = potri!_cdouble;
1199 }
1200 
1201 ///
1202 template pptri(T)
1203 {
1204     /// `pptri` for upper triangular input.
1205     size_t pptri(
1206         Slice!(StairsIterator!(T*, "+")) ap
1207         )
1208     {
1209         lapackint n = cast(lapackint) ap.length;
1210         lapackint info;
1211 
1212         char uplo = 'U';
1213         lapack.pptri_(uplo, n, &ap[0][0], info);
1214 
1215         assert(info >= 0);
1216         return info;
1217     }
1218 
1219     /// `pptri` for lower triangular input.
1220     size_t pptri(
1221         Slice!(StairsIterator!(T*, "-")) ap
1222         )
1223     {
1224         lapackint n = cast(lapackint) ap.length;
1225         lapackint info;
1226 
1227         char uplo = 'L';
1228         lapack.pptri_(uplo, n, &ap[0][0], info);
1229 
1230         assert(info >= 0);
1231         return info;
1232     }
1233 }
1234 
1235 unittest
1236 {
1237     alias s = pptri!float;
1238     alias d = pptri!double;
1239     alias c = pptri!_cfloat;
1240     alias z = pptri!_cdouble;
1241 }
1242 
1243 ///
1244 size_t trtri(T)(
1245     char uplo,
1246     char diag,
1247     Slice!(T*, 2, Canonical) a,
1248     )
1249 in
1250 {
1251     assert(a.length!0 == a.length!1, "trtri: The input 'a' must be a square matrix.");
1252 }
1253 do
1254 {
1255     lapackint n = cast(lapackint) a.length;
1256     lapackint lda = cast(lapackint) a._stride.max(1);
1257     lapackint info;
1258 
1259     lapack.trtri_(uplo, diag, n, a.iterator, lda, info);
1260 
1261     assert(info >= 0);
1262     return info;
1263 }
1264 
1265 unittest
1266 {
1267     alias s = trtri!float;
1268     alias d = trtri!double;
1269     alias c = trtri!_cfloat;
1270     alias z = trtri!_cdouble;
1271 }
1272 
1273 ///
1274 size_t gtsv(T)(
1275     Slice!(T*) dl,
1276     Slice!(T*) d,
1277     Slice!(T*) du,
1278     Slice!(T*, 2, Canonical) b,
1279     )
1280 in (d.length == 0 && dl.length == 0 || dl.length + 1 == d.length, "gtsv: 'dl' has to have length equal to N - 1, where N is length of 'd'.")
1281 in (du.length == dl.length, "gtsv: 'du' has to have length equal to N - 1, where N is length of 'd'.")
1282 in (d.length!0 == b.length!1, "gtsv: The input 'b' has to be N-by-NRHS matrix where N is length of 'd'.")
1283 out (info; info >= 0)
1284 {
1285     
1286     lapackint n = cast(lapackint) b.length!1;
1287     lapackint nrhs = cast(lapackint) b.length;
1288     lapackint ldb = cast(lapackint) b._stride.max(1);
1289     lapackint info;
1290 
1291     lapack.gtsv_(n, nrhs, dl.iterator, d.iterator, du.iterator, b.iterator, ldb, info);
1292     return info;
1293 }
1294 
1295 unittest
1296 {
1297     alias s = gtsv!float;
1298     alias d = gtsv!double;
1299     alias c = gtsv!_cfloat;
1300     alias z = gtsv!_cdouble;
1301 }
1302 
1303 ///
1304 size_t trtrs(T)(
1305     char uplo,
1306     char diag,
1307     char trans,
1308     Slice!(const(T)*, 2, Canonical) a,
1309     Slice!(T*, 2, Canonical) b,
1310     )
1311 in (a.length!0 == a.length!1, "trtrs: The input 'a' must be a square matrix.")
1312 in (a.length!0 == b.length!1, "trtrs: The input 'b' has to be N-by-NRHS matrix where N is order of 'a'.")
1313 out (info; info >= 0)
1314 {
1315     lapackint n = cast(lapackint) a.length;
1316     lapackint nrhs = cast(lapackint) b.length;
1317     lapackint lda = cast(lapackint) a._stride.max(1);
1318     lapackint ldb = cast(lapackint) b._stride.max(1);
1319     lapackint info;
1320 
1321     lapack.trtrs_(uplo, diag, trans, n, nrhs, a.iterator, lda, b.iterator, ldb, info);
1322     return info;
1323 }
1324 
1325 unittest
1326 {
1327     alias s = trtrs!float;
1328     alias d = trtrs!double;
1329     alias c = trtrs!_cfloat;
1330     alias z = trtrs!_cdouble;
1331 }
1332 
1333 ///
1334 template tptri(T)
1335 {
1336     /// `tptri` for upper triangular input.
1337     size_t tptri(
1338         char diag,
1339         Slice!(StairsIterator!(T*, "+")) ap,
1340         )
1341     {
1342         lapackint n = cast(lapackint) ap.length;
1343         lapackint info;
1344 
1345         char uplo = 'U';
1346         lapack.tptri_(uplo, diag, n, &ap[0][0], info);
1347 
1348         assert(info >= 0);
1349         return info;
1350     }
1351 
1352     /// `tptri` for lower triangular input.
1353     size_t tptri(
1354         char diag,
1355         Slice!(StairsIterator!(T*, "-")) ap,
1356         )
1357     {
1358         lapackint n = cast(lapackint) ap.length;
1359         lapackint info;
1360 
1361         char uplo = 'L';
1362         lapack.tptri_(uplo, diag, n, &ap[0][0], info);
1363 
1364         assert(info >= 0);
1365         return info;
1366 
1367     }
1368 }
1369 
1370 unittest
1371 {
1372     alias s = tptri!float;
1373     alias d = tptri!double;
1374     alias c = tptri!_cfloat;
1375     alias z = tptri!_cdouble;
1376 }
1377 
1378 ///
1379 size_t ormqr(T)(
1380     char side,
1381     char trans,
1382     Slice!(T*, 2, Canonical) a,
1383     Slice!(T*) tau,
1384     Slice!(T*, 2, Canonical) c,
1385     Slice!(T*) work,
1386     )
1387 {
1388     lapackint m = cast(lapackint) c.length!1;
1389     lapackint n = cast(lapackint) c.length!0;
1390     lapackint k = cast(lapackint) tau.length;
1391     lapackint lda = cast(lapackint) a._stride.max(1);
1392     lapackint ldc = cast(lapackint) c._stride.max(1);
1393     lapackint lwork = cast(lapackint) work.length;
1394     lapackint info;
1395 
1396     lapack.ormqr_(side, trans, m, n, k, a.iterator, lda, tau.iterator, c.iterator, ldc, work.iterator, lwork, info);
1397 
1398     ///if info == 0: successful exit.
1399     ///if info < 0: if info == -i, the i-th argument had an illegal value.
1400     assert(info >= 0);
1401     return info;
1402 }
1403 
1404 unittest
1405 {
1406     alias s = ormqr!float;
1407     alias d = ormqr!double;
1408 }
1409 
1410 ///
1411 size_t unmqr(T)(
1412     char side,
1413     char trans,
1414     Slice!(T*, 2, Canonical) a,
1415     Slice!(T*) tau,
1416     Slice!(T*, 2, Canonical) c,
1417     Slice!(T*) work,
1418     )
1419 {
1420     lapackint m = cast(lapackint) c.length!1;
1421     lapackint n = cast(lapackint) c.length!0;
1422     lapackint k = cast(lapackint) tau.length;
1423     lapackint lda = cast(lapackint) a._stride.max(1);
1424     lapackint ldc = cast(lapackint) c._stride.max(1);
1425     lapackint lwork = cast(lapackint) work.length;
1426     lapackint info;
1427 
1428     lapack.unmqr_(side, trans, m, n, k, a.iterator, lda, tau.iterator, c.iterator, ldc, work.iterator, lwork, info);
1429 
1430     ///if info == 0: successful exit.
1431     ///if info < 0: if info == -i, the i-th argument had an illegal value.
1432     assert(info >= 0);
1433     return info;
1434 }
1435 
1436 unittest
1437 {
1438     alias s = unmqr!_cfloat;
1439     alias d = unmqr!_cdouble;
1440 }
1441 
1442 ///
1443 size_t orgqr(T)(
1444     Slice!(T*, 2, Canonical) a,
1445     Slice!(T*) tau,
1446     Slice!(T*) work,
1447     )
1448 in
1449 {
1450     assert(a.length!0 >= 0, "orgqr: The number of columns of 'a' must be " ~ 
1451         "greater than or equal to zero."); //n>=0
1452     assert(a.length!1 >= a.length!0, "orgqr: The number of columns of 'a' " ~ 
1453         "must be greater than or equal to the number of its rows."); //m>=n
1454     assert(tau.length >= 0, "orgqr: The input 'tau' must have length greater " ~ 
1455         "than or equal to zero."); //k>=0
1456     assert(a.length!0 >= tau.length, "orgqr: The number of columns of 'a' " ~ 
1457         "must be greater than or equal to the length of 'tau'."); //n>=k
1458     assert(work.length >= a.length!0, "orgqr: The length of 'work' must be " ~ 
1459         "greater than or equal to the number of rows of 'a'."); //lwork>=n
1460 }
1461 do
1462 {
1463     lapackint m = cast(lapackint) a.length!1;
1464     lapackint n = cast(lapackint) a.length!0;
1465     lapackint k = cast(lapackint) tau.length;
1466     lapackint lda = cast(lapackint) a._stride.max(1);
1467     lapackint lwork = cast(lapackint) work.length;
1468     lapackint info;
1469 
1470     lapack.orgqr_(m, n, k, a.iterator, lda, tau.iterator, work.iterator, lwork, info);
1471 
1472     ///if info == 0: successful exit.
1473     ///if info < 0: if info == -i, the i-th argument had an illegal value.
1474     assert(info >= 0);
1475     return info;
1476 }
1477 
1478 unittest
1479 {
1480     alias s = orgqr!float;
1481     alias d = orgqr!double;
1482 }
1483 
1484 ///
1485 size_t ungqr(T)(
1486     Slice!(T*, 2, Canonical) a,
1487     Slice!(T*) tau,
1488     Slice!(T*) work,
1489     )
1490 in
1491 {
1492     assert(a.length!1 >= a.length!0, "ungqr: The number of columns of 'a' must be greater than or equal to the number of its rows."); //m>=n
1493     assert(a.length!0 >= tau.length, "ungqr: The number of columns of 'a' must be greater than or equal to the length of 'tau'."); //n>=k
1494     assert(work.length >= a.length!0, "ungqr: The length of 'work' must be greater than or equal to the number of rows of 'a'."); //lwork>=n
1495 }
1496 do
1497 {
1498     lapackint m = cast(lapackint) a.length!1;
1499     lapackint n = cast(lapackint) a.length!0;
1500     lapackint k = cast(lapackint) tau.length;
1501     lapackint lda = cast(lapackint) a._stride.max(1);
1502     lapackint lwork = cast(lapackint) work.length;
1503     lapackint info;
1504 
1505     lapack.ungqr_(m, n, k, a.iterator, lda, tau.iterator, work.iterator, lwork, info);
1506 
1507     ///if info == 0: successful exit.
1508     ///if info < 0: if info == -i, the i-th argument had an illegal value.
1509     assert(info >= 0);
1510     return info;
1511 }
1512 
1513 unittest
1514 {
1515     alias s = ungqr!_cfloat;
1516     alias d = ungqr!_cdouble;
1517 }
1518 
1519 alias orghr = unghr; // this is the name for the real type vairant of ungqr
1520 
1521 ///
1522 size_t unghr(T)(
1523     Slice!(T*, 2, Canonical) a,
1524     Slice!(T*) tau,
1525     Slice!(T*) work,
1526 )
1527 in
1528 {
1529     assert(a.length!1 >= a.length!0); //m>=n
1530     assert(a.length!0 >= tau.length); //n>=k
1531     assert(work.length >= a.length!0); //lwork>=n
1532 }
1533 do
1534 {
1535     lapackint m = cast(lapackint) a.length!1;
1536     lapackint n = cast(lapackint) a.length!0;
1537     lapackint k = cast(lapackint) tau.length;
1538     lapackint lda = cast(lapackint) a._stride.max(1);
1539     lapackint lwork = cast(lapackint) work.length;
1540     lapackint info;
1541     static if (isComplex!T){
1542         lapack.ungqr_(m, n, k, a.iterator, lda, tau.iterator, work.iterator, lwork, info);
1543     }
1544     else { 
1545         lapack.orgqr_(m, n, k, a.iterator, lda, tau.iterator, work.iterator, lwork, info);
1546     }
1547 
1548     ///if info == 0: successful exit.
1549     ///if info < 0: if info == -i, the i-th argument had an illegal value.
1550     assert(info >= 0);
1551     return cast(size_t)info;
1552 }
1553 
1554 unittest
1555 {
1556     alias orghrf = orghr!float;
1557     alias orghrd = orghr!double;
1558     alias unghrf = unghr!float;
1559     alias unghrd = unghr!double;
1560     alias unghrcf = unghr!_cfloat;
1561     alias unghrcd = unghr!_cdouble;
1562 }
1563 
1564 ///
1565 size_t gehrd(T)(
1566     Slice!(T*, 2, Canonical) a,
1567     Slice!(T*) tau,
1568     Slice!(T*) work,
1569     lapackint ilo,
1570     lapackint ihi
1571 )
1572 in
1573 {
1574     assert(a.length!1 >= a.length!0, "gehrd: The number of columns of 'a' must be greater than or equal to the number of its rows."); //m>=n
1575     assert(a.length!0 >= tau.length, "gehrd: The number of columns of 'a' must be greater than or equal to the length of 'tau'."); //n>=k
1576     assert(work.length >= a.length!0, "gehrd: The length of 'work' must be greater than or equal to the number of rows of 'a'."); //lwork>=n
1577 }
1578 do
1579 {
1580     lapackint n = cast(lapackint) a.length!0;
1581     lapackint lda = cast(lapackint) a._stride.max(1);
1582     lapackint lwork = cast(lapackint) work.length;
1583     lapackint info;    
1584     lapack.gehrd_(n, ilo, ihi, a.iterator, lda, tau.iterator, work.iterator, lwork, info);
1585     ///if info == 0: successful exit.
1586     ///if info < 0: if info == -i, the i-th argument had an illegal value.
1587     assert(info >= 0);
1588     return cast(size_t)info;
1589 }
1590 
1591 unittest
1592 {
1593     alias s = gehrd!_cfloat;
1594     alias d = gehrd!_cdouble;
1595 }
1596 
1597 size_t hsein(T)(
1598     char side,
1599     char eigsrc,
1600     char initv,
1601     ref lapackint select, //actually a logical bitset stored in here
1602     Slice!(T*, 2, Canonical) h,
1603     Slice!(T*) wr,
1604     Slice!(T*) wi,
1605     Slice!(T*, 2, Canonical) vl,
1606     Slice!(T*, 2, Canonical) vr,
1607     ref lapackint m,
1608     Slice!(T*) work,
1609     ref lapackint ifaill,
1610     ref lapackint ifailr,
1611 )
1612     if (!isComplex!T)
1613 in
1614 {
1615     assert(h.length!1 >= h.length!0, "hsein: The number of columns of 'h' " ~ 
1616            "must be greater than or equal to the number of its rows."); //m>=n
1617     assert(wr.length >= 1, "hsein: The input 'wr' must have length greater " ~ 
1618            "than or equal to one.");
1619     assert(wr.length >= h.length!0, "hsein: The input 'wr' must have length greater " ~ 
1620            "than or equal to the number of rows of 'h'.");
1621     assert(wr.length >= 1.0, "hsein: The input 'wr' must have length greater " ~ 
1622            "than or equal to 1.");
1623     assert(wi.length >= 1, "hsein: The input 'wi' must have length greater " ~ 
1624            "than or equal to one.");
1625     assert(wi.length >= h.length!0, "hsein: The input 'wi' must have length greater " ~ 
1626            "than or equal to the number of rows of 'h'.");
1627     assert(wi.length >= 1.0, "hsein: The input 'wi' must have length greater " ~ 
1628            "than or equal to 1.");
1629     assert(work.length >= h.length!0 * (h.length!0 + 2), "hsein: The length of 'work' must be " ~ 
1630            "greater than or equal to the square of the number of rows of 'h' plus two additional rows for real types.");
1631     assert(side == 'R' || side == 'L' || side == 'B', "hsein: The char, 'side' must be " ~ 
1632            "one of 'R', 'L' or 'B'.");
1633     assert(eigsrc == 'Q' || eigsrc == 'N', "hsein: The char, 'eigsrc', must be " ~
1634            "one of 'Q' or 'R'.");
1635     assert(initv == 'N' || initv == 'U', "hsein: The char, 'initv', must be " ~
1636            "one of 'N' or 'U'.");
1637     assert(side != 'L' || side != 'B' || vl.length!1 >= 1, "hsein: Slice 'vl' must be" ~
1638            "at least the size of '1' when 'side' is set to 'L' or 'B'.");
1639     assert(side != 'R' || vl.length!1 >= 1, "hsein: Slice 'vl' must be" ~
1640            "length greater than 1 when 'side' is 'R'.");
1641     assert(side != 'R' || side != 'B' || vr.length!1 >= 1, "hsein: Slice 'vr' must be" ~
1642            "at least the size of '1' when 'side' is set to 'R' or 'B'.");
1643     assert(side != 'L' || vl.length!1 >= 1, "hsein: Slice 'vr' must be" ~
1644            "length greater than 1 when 'side' is 'L'.");
1645 }
1646 do 
1647 {
1648     lapackint info;
1649     lapackint mm = cast(lapackint) vl.length!1;
1650     lapackint n = cast(lapackint) h.length!0;
1651     lapackint ldh = cast(lapackint) h._stride.max(1);
1652     lapackint ldvl = cast(lapackint) vl._stride.max(1);
1653     lapackint ldvr = cast(lapackint) vr._stride.max(1);
1654     //need to seperate these methods then probably provide a wrap which does this as that's the easiest way without bloating the base methods
1655     lapack.hsein_(side, eigsrc, initv, select, n, h.iterator, ldh, wr.iterator, wi.iterator, vl.iterator, ldvl, vr.iterator, ldvr, mm, m, work.iterator, ifaill, ifailr, info);
1656     assert(info >= 0);
1657     ///if any of ifaill or ifailr entries are non-zero then that has failed to converge.
1658     ///ifail?[i] = j > 0 if the eigenvector stored in the i-th column of v?, coresponding to the jth eigenvalue, fails to converge.
1659     assert(ifaill == 0);
1660     assert(ifailr == 0);
1661     return info;
1662 }
1663 
1664 size_t hsein(T, realT)(
1665     char side,
1666     char eigsrc,
1667     char initv,
1668     lapackint select, //actually a logical bitset stored in here
1669     Slice!(T*, 2, Canonical) h,
1670     Slice!(T*) w,
1671     Slice!(T*, 2, Canonical) vl,
1672     Slice!(T*, 2, Canonical) vr,
1673     lapackint* m,
1674     Slice!(T*) work,
1675     Slice!(realT*) rwork,
1676     lapackint ifaill,
1677     lapackint ifailr,
1678 )
1679     if (isComplex!T && is(realType!T == realT))
1680 in
1681 {
1682     assert(h.length!1 >= h.length!0, "hsein: The number of columns of 'h' " ~ 
1683            "must be greater than or equal to the number of its rows."); //m>=n
1684     assert(w.length >= 1, "hsein: The input 'w' must have length greater " ~ 
1685            "than or equal to one.");
1686     assert(w.length >= h.length!0, "hsein: The input 'w' must have length greater " ~ 
1687            "than or equal to the number of rows of 'h'.");
1688     assert(w.length >= 1.0, "hsein: The input 'w' must have length greater " ~ 
1689            "than or equal to 1.");
1690     assert(work.length >= h.length!0 * h.length!0, "hsein: The length of 'work' must be " ~ 
1691            "greater than or equal to the square of the number of rows of 'h' for complex types.");
1692     assert(side == 'R' || side == 'L' || side == 'B', "hsein: The char, 'side' must be " ~ 
1693            "one of 'R', 'L' or 'B'.");
1694     assert(eigsrc == 'Q' || eigsrc == 'N', "hsein: The char, 'eigsrc', must be " ~
1695            "one of 'Q' or 'R'.");
1696     assert(initv == 'N' || initv == 'U', "hsein: The char, 'initv', must be " ~
1697            "one of 'N' or 'U'.");
1698     assert(side != 'L' || side != 'B' || vl.length!1 >= 1, "hsein: Slice 'vl' must be" ~
1699            "at least the size of '1' when 'side' is set to 'L' or 'B'.");
1700     assert(side != 'R' || vl.length!1 >= 1, "hsein: Slice 'vl' must be" ~
1701            "length greater than 1 when 'side' is 'R'.");
1702     assert(side != 'R' || side != 'B' || vr.length!1 >= 1, "hsein: Slice 'vr' must be" ~
1703            "at least the size of '1' when 'side' is set to 'R' or 'B'.");
1704     assert(side != 'L' || vl.length!1 >= 1, "hsein: Slice 'vr' must be" ~
1705            "length greater than 1 when 'side' is 'L'.");
1706 }
1707 do {
1708     lapackint n = cast(lapackint) h.length!0;
1709     lapackint ldh = cast(lapackint) h._stride.max(1);
1710     lapackint ldvl = cast(lapackint) vl._stride.max(1);
1711     lapackint ldvr = cast(lapackint) vr._stride.max(1);
1712     lapackint mm = cast(lapackint) vl.length!1;
1713     lapackint info;
1714     //could compute mm and m from vl and/or vr and T
1715     lapack.hsein_(side, eigsrc, initv, select, n, h.iterator, ldh, w.iterator, vl.iterator, ldvl, vr.iterator, ldvr, mm, *m, work.iterator, rwork.iterator, ifaill, ifailr, info);
1716     assert(info >= 0);
1717     ///if any of ifaill or ifailr entries are non-zero then that has failed to converge.
1718     ///ifail?[i] = j > 0 if the eigenvector stored in the i-th column of v?, coresponding to the jth eigenvalue, fails to converge.
1719     assert(ifaill == 0);
1720     assert(ifailr == 0);
1721     return info;
1722 }
1723 
1724 
1725 unittest
1726 {
1727     alias f = hsein!(float);
1728     alias d = hsein!(double);
1729     alias s = hsein!(_cfloat, float);
1730     alias c = hsein!(_cdouble, double);
1731 }
1732 
1733 alias ormhr = unmhr;
1734 
1735 ///
1736 size_t unmhr(T)(
1737     char side,
1738     char trans,
1739     Slice!(T*, 2, Canonical) a,
1740     Slice!(T*) tau,
1741     Slice!(T*, 2, Canonical) c,
1742     Slice!(T*) work,
1743     lapackint ilo,
1744     lapackint ihi
1745 )
1746 in
1747 {
1748     assert(a.length!0 >= 0, "ormhr: The number of columns of 'a' must be " ~ 
1749            "greater than or equal to zero."); //n>=0
1750     assert(a.length!1 >= a.length!0, "ormhr: The number of columns of 'a' " ~ 
1751            "must be greater than or equal to the number of its rows."); //m>=n
1752     assert(c.length!0 >= 0, "ormhr: The number of columns of 'c' must be " ~ 
1753            "greater than or equal to zero."); //n>=0
1754     assert(c.length!1 >= c.length!0, "ormhr: The number of columns of 'c' " ~ 
1755            "must be greater than or equal to the number of its rows."); //m>=n
1756     assert(tau.length >= 0, "ormhr: The input 'tau' must have length greater " ~ 
1757            "than or equal to zero."); //k>=0
1758     assert(a.length!0 >= tau.length, "ormhr: The number of columns of 'a' " ~ 
1759            "must be greater than or equal to the length of 'tau'."); //n>=k
1760     assert(work.length >= a.length!0, "ormhr: The length of 'work' must be " ~ 
1761            "greater than or equal to the number of rows of 'a'."); //lwork>=n
1762     assert(side == 'L' || side == 'R', "ormhr: 'side' must be" ~
1763            "one of 'L' or 'R'.");
1764     assert(trans == 'N' || trans == 'T', "ormhr: 'trans' must be" ~
1765            "one of 'N' or 'T'.");
1766 }
1767 do
1768 {
1769     lapackint m = cast(lapackint) a.length!0;
1770     lapackint n = cast(lapackint) a.length!1;
1771     lapackint lda = cast(lapackint) a._stride.max(1);
1772     lapackint ldc = cast(lapackint) c._stride.max(1);
1773     lapackint lwork = cast(lapackint) work.length;
1774     lapackint info;
1775     static if (!isComplex!T){
1776         lapack.ormhr_(side, trans, m, n, ilo, ihi, a.iterator, lda, tau.iterator, c.iterator, ldc, work.iterator, lwork, info);
1777     }
1778     else {
1779         lapack.unmhr_(side, trans, m, n, ilo, ihi, a.iterator, lda, tau.iterator, c.iterator, ldc, work.iterator, lwork, info);
1780     }
1781     ///if info == 0: successful exit.
1782     ///if info < 0: if info == -i, the i-th argument had an illegal value.
1783     assert(info >= 0);
1784     return cast(size_t)info;
1785 }
1786 
1787 unittest
1788 {
1789     alias s = unmhr!_cfloat;
1790     alias d = unmhr!_cdouble;
1791     alias a = ormhr!double;
1792     alias b = ormhr!float;
1793 }
1794 
1795 ///
1796 size_t hseqr(T)(
1797     char job,
1798     char compz,
1799     Slice!(T*, 2, Canonical) h,
1800     Slice!(T*) w,
1801     Slice!(T*, 2, Canonical) z,
1802     Slice!(T*) work,
1803     lapackint ilo,
1804     lapackint ihi
1805 )
1806     if (isComplex!T)
1807 in
1808 {
1809     assert(job == 'E' || job == 'S', "hseqr");
1810     assert(compz == 'N' || compz == 'I' || compz == 'V', "hseqr");
1811     assert(h.length!1 >= h.length!0, "hseqr");
1812     assert(h.length!1 >= 1, "hseqr");
1813     assert(compz != 'V' || compz != 'I' || (z.length!1 >= h.length!0 && z.length!1 >= 1), "hseqr");
1814     assert(compz != 'N' || z.length!1 >= 1);
1815     assert(work.length!0 >= 1, "hseqr");
1816     assert(work.length!0 >= h.length!0, "hseqr");
1817 }
1818 do
1819 {
1820     lapackint n = cast(lapackint) h.length!0;
1821     lapackint ldh = cast(lapackint) h._stride.max(1);
1822     lapackint ldz = cast(lapackint) z._stride.max(1);
1823     lapackint lwork = cast(lapackint) work.length!0;
1824     lapackint info;
1825     lapack.hseqr_(job,compz,n,ilo,ihi,h.iterator, ldh, w.iterator, z.iterator, ldz, work.iterator, lwork, info);
1826     assert(info >= 0);
1827     return cast(size_t)info;
1828 }
1829 
1830 ///
1831 size_t hseqr(T)(
1832     char job,
1833     char compz,
1834     Slice!(T*, 2, Canonical) h,
1835     Slice!(T*) wr,
1836     Slice!(T*) wi,
1837     Slice!(T*, 2, Canonical) z,
1838     Slice!(T*) work,
1839     lapackint ilo,
1840     lapackint ihi
1841 )
1842     if (!isComplex!T)
1843 in
1844 {
1845     assert(job == 'E' || job == 'S', "hseqr");
1846     assert(compz == 'N' || compz == 'I' || compz == 'V', "hseqr");
1847     assert(h.length!1 >= h.length!0, "hseqr");
1848     assert(h.length!1 >= 1, "hseqr");
1849     assert(compz != 'V' || compz != 'I' || (z.length!1 >= h.length!0 && z.length!1 >= 1), "hseqr");
1850     assert(compz != 'N' || z.length!1 >= 1);
1851     assert(work.length!0 >= 1, "hseqr");
1852     assert(work.length!0 >= h.length!0, "hseqr");
1853 }
1854 do
1855 {
1856     lapackint n = cast(lapackint) h.length!0;
1857     lapackint ldh = cast(lapackint) h._stride.max(1);
1858     lapackint ldz = cast(lapackint) z._stride.max(1);
1859     lapackint lwork = cast(lapackint) work.length!0;
1860     lapackint info;
1861     lapack.hseqr_(job,compz,n,ilo,ihi,h.iterator, ldh, wr.iterator, wi.iterator, z.iterator, ldz, work.iterator, lwork, info);
1862     assert(info >= 0);
1863     return cast(size_t)info;
1864 }
1865 
1866 unittest
1867 {
1868     alias f = hseqr!float;
1869     alias d = hseqr!double;
1870     alias s = hseqr!_cfloat;
1871     alias c = hseqr!_cdouble;
1872 }
1873 
1874 ///
1875 size_t trevc(T)(char side,
1876     char howmany,
1877     lapackint select,
1878     Slice!(T*, 2, Canonical) t,
1879     Slice!(T*, 2, Canonical) vl,
1880     Slice!(T*, 2, Canonical) vr,
1881     lapackint m,
1882     Slice!(T*) work
1883 )
1884 do
1885 {
1886     lapackint n = cast(lapackint)t.length!0;
1887     lapackint ldt = cast(lapackint) t._stride.max(1);
1888     lapackint ldvl = cast(lapackint) vl._stride.max(1);
1889     lapackint ldvr = cast(lapackint) vr._stride.max(1);
1890     lapackint mm = cast(lapackint) vr.length!1;
1891     //select should be lapack_logical
1892     lapackint info;
1893     static if(!isComplex!T){
1894         lapack.trevc_(side, howmany, select, n, t.iterator, ldt, vl.iterator, ldvl, vr.iterator, ldvr, mm, m, work.iterator, info);
1895     }
1896     else {
1897         lapack.trevc_(side, howmany, select, n, t.iterator, ldt, vl.iterator, ldvl, vr.iterator, ldvr, mm, m, work.iterator, null, info);
1898     }
1899     assert(info >= 0);
1900     return cast(size_t)info;
1901 }
1902 
1903 unittest
1904 {
1905     alias f = trevc!float;
1906     alias d = trevc!double;
1907     alias s = trevc!_cfloat;
1908     alias c = trevc!_cdouble;
1909 }
1910 
1911 ///
1912 size_t gebal(T, realT)(char job,
1913     Slice!(T*, 2, Canonical) a,
1914     lapackint ilo,
1915     lapackint ihi,
1916     Slice!(realT*) scale
1917 )
1918     if (!isComplex!T || (isComplex!T && is(realType!T == realT)))
1919 {
1920     lapackint n = cast(lapackint) a.length!0;
1921     lapackint lda = cast(lapackint) a._stride.max(1);
1922     lapackint info;
1923     lapack.gebal_(job, n, a.iterator, lda, ilo, ihi, scale.iterator, info);
1924     assert(info >= 0);
1925     return cast(size_t)info;
1926 }
1927 
1928 unittest
1929 {
1930     alias a = gebal!(double, double);
1931     alias b = gebal!(_cdouble, double);
1932     alias c = gebal!(float, float);
1933     alias d = gebal!(_cfloat, float);
1934 }
1935 
1936 ///
1937 size_t gebak(T, realT)(
1938     char job,
1939     char side,
1940     lapackint ilo,
1941     lapackint ihi,
1942     Slice!(realT*) scale,
1943     Slice!(T*, 2, Canonical) v
1944 )
1945     if (!isComplex!T || (isComplex!T && is(realType!T == realT)))
1946 {
1947     lapackint n = cast(lapackint) scale.length!0;
1948     lapackint m = cast(lapackint) v.length!1;//num evects
1949     lapackint ldv = cast(lapackint) v._stride.max(1);
1950     lapackint info;
1951     lapack.gebak_(job, side, n, ilo, ihi, scale.iterator, m, v.iterator, ldv, info);
1952     assert(info >= 0);
1953     return cast(size_t)info;
1954 }
1955 
1956 unittest
1957 {
1958     alias a = gebak!(double, double);
1959     alias b = gebak!(_cdouble, double);
1960     alias c = gebak!(float, float);
1961     alias d = gebak!(_cfloat, float);
1962 }
1963 
1964 ///
1965 size_t geev(T, realT)(
1966     char jobvl,
1967     char jobvr,
1968     Slice!(T*, 2, Canonical) a,
1969     Slice!(T*) w,
1970     Slice!(T*, 2, Canonical) vl,
1971     Slice!(T*, 2, Canonical) vr,
1972     Slice!(T*) work,
1973     Slice!(realT*) rwork
1974 )
1975     if (isComplex!T && is(realType!T == realT))
1976 {
1977     lapackint n = cast(lapackint) a.length!0;
1978     lapackint lda = cast(lapackint) a._stride.max(1);
1979     lapackint ldvr = cast(lapackint) vr._stride.max(1);
1980     lapackint ldvl = cast(lapackint) vl._stride.max(1);
1981     lapackint info;
1982     lapackint lwork = cast(lapackint)work.length!0;
1983     lapack.geev_(jobvl, jobvr, n, a.iterator, lda, w.iterator, vl.iterator, ldvl, vr.iterator, ldvr, work.iterator, lwork, rwork.iterator, info);
1984     assert(info >= 0);
1985     return info;
1986 }
1987 
1988 ///
1989 size_t geev(T)(
1990     char jobvl,
1991     char jobvr,
1992     Slice!(T*, 2, Canonical) a,
1993     Slice!(T*) wr,
1994     Slice!(T*) wi,
1995     Slice!(T*, 2, Canonical) vl,
1996     Slice!(T*, 2, Canonical) vr,
1997     Slice!(T*) work
1998 )
1999     if (!isComplex!T)
2000 {
2001     lapackint n = cast(lapackint) a.length!0;
2002     lapackint lda = cast(lapackint) a._stride.max(1);
2003     lapackint ldvr = cast(lapackint) vr._stride.max(1);
2004     lapackint ldvl = cast(lapackint) vl._stride.max(1);
2005     lapackint info;
2006     lapackint lwork = cast(lapackint)work.length!0;
2007     lapack.geev_(jobvl, jobvr, n, a.iterator, lda, wr.iterator, wi.iterator, vl.iterator, ldvl, vr.iterator, ldvr, work.iterator, lwork, info);
2008     assert(info >= 0);
2009     return info;
2010 }
2011 
2012 ///
2013 size_t steqr(T, realT = realType!T)(
2014     char compz,
2015     Slice!(realT*) d,
2016     Slice!(realT*) e,
2017     Slice!(T*, 2, Canonical) z,
2018     Slice!(realT*) work)
2019     if (is(realType!T == realT))
2020 in {
2021     assert(d.length == e.length + 1);
2022     assert(work.length >= (e.length * 2).max(1u));
2023     assert(z.length!0 == d.length);
2024     assert(z.length!1 == d.length);
2025     assert(z._stride >= d.length);
2026 }
2027 do {
2028     lapackint n = cast(lapackint) d.length;
2029     lapackint ldz = cast(lapackint) z._stride.max(1);
2030     lapackint info;
2031 
2032     lapack.steqr_(compz, n, d.iterator, e.iterator, z.iterator, ldz, work.iterator, info);
2033     assert(info >= 0);
2034     return info;
2035 }
2036 
2037 unittest
2038 {
2039     alias a = steqr!float;
2040     alias b = steqr!double;
2041     alias c = steqr!_cfloat;
2042     alias d = steqr!_cdouble;
2043 }
2044 
2045 
2046 ///
2047 @trusted
2048 size_t sytrs_3(T)(
2049     char uplo,
2050     Slice!(const(T)*, 2, Canonical) a,
2051     Slice!(const(T)*) e,
2052     Slice!(const(lapackint)*) ipiv,
2053     Slice!(T*, 2, Canonical) b,
2054     )
2055 in
2056 {
2057     assert(a.length!0 == a.length!1, "sytrs_3: 'a' must be a square matrix.");
2058     assert(e.length == a.length, "sytrs_3: 'e' must have the same length as 'a'.");
2059     assert(b.length!1 == a.length, "sytrs_3: 'b.length!1' must must be equal to 'a.length'.");
2060 }
2061 do
2062 {
2063     lapackint n = cast(lapackint) a.length;
2064     lapackint nrhs = cast(lapackint) b.length;
2065     lapackint lda = cast(lapackint) a._stride.max(1);
2066     lapackint ldb = cast(lapackint) b._stride.max(1);
2067     lapackint info;
2068 // ref char uplo, ref lapackint n, ref lapackint nrhs, float *a, ref lapackint lda, float* e, lapackint *ipiv, float *b, ref lapackint ldb, ref lapackint info
2069     lapack.sytrs_3_(uplo, n, nrhs, a.iterator, lda, e.iterator, ipiv.iterator, b.iterator, ldb, info);
2070     assert(info >= 0);
2071     return info;
2072 }
2073 
2074 version(none)
2075 unittest
2076 {
2077     alias s = sytrs_3!float;
2078     alias d = sytrs_3!double;
2079     alias c = sytrs_3!_cfloat;
2080     alias z = sytrs_3!_cdouble;
2081 }
2082 
2083 ///
2084 @trusted
2085 size_t sytrf_rk(T)(
2086     char uplo,
2087     Slice!(T*, 2, Canonical) a,
2088     Slice!(T*) e,
2089     Slice!(lapackint*) ipiv,
2090     Slice!(T*) work,
2091     )
2092 in
2093 {
2094     assert(a.length!0 == a.length!1, "sytrf_rk: 'a' must be a square matrix.");
2095     assert(e.length == a.length, "sytrf_rk: 'e' must have the same length as 'a'.");
2096 }
2097 do
2098 {
2099     lapackint info;
2100     lapackint n = cast(lapackint) a.length;
2101     lapackint lda = cast(lapackint) a._stride.max(1);
2102     lapackint lwork = cast(lapackint) work.length;
2103     lapack.sytrf_rk_(uplo, n, a.iterator, lda, e.iterator, ipiv.iterator, work.iterator, lwork, info);
2104     assert(info >= 0);
2105     return info;
2106 }
2107 
2108 version(none)
2109 unittest
2110 {
2111     alias s = sytrf_rk!float;
2112     alias d = sytrf_rk!double;
2113     alias c = sytrf_rk!_cfloat;
2114     alias z = sytrf_rk!_cdouble;
2115 }
2116 
2117 
2118 ///
2119 size_t sytrf_rk_wk(T)(
2120     char uplo,
2121     Slice!(T*, 2, Canonical) a,
2122     )
2123 in
2124 {
2125     assert(a.length!0 == a.length!1, "sytrf_rk_wk: 'a' must be a square matrix.");
2126 }
2127 do
2128 {
2129 
2130     lapackint info;
2131     lapackint n = cast(lapackint) a.length;
2132     lapackint lda = cast(lapackint) a._stride.max(1);
2133     lapackint lwork = -1;
2134     lapackint info;
2135     T e;
2136     T work;
2137     lapackint ipiv;
2138 
2139     lapack.sytrf_rk_(uplo, n, a.iterator, lda, &e, &ipiv, &work, lwork, info);
2140 
2141     return cast(size_t) work.re;
2142 }
2143 
2144 version(none)
2145 unittest
2146 {
2147     alias s = sytrf_rk!float;
2148     alias d = sytrf_rk!double;
2149 }
2150 
2151 ///
2152 template posvx(T)
2153     if (is(T == double) || is(T == float))
2154 {
2155     @trusted
2156     size_t posvx(
2157         char fact,
2158         char uplo,
2159         Slice!(T*, 2, Canonical) a,
2160         Slice!(T*, 2, Canonical) af,
2161         char equed,
2162         Slice!(T*) s,
2163         Slice!(T*, 2, Canonical) b,
2164         Slice!(T*, 2, Canonical) x,
2165         out T rcond,
2166         Slice!(T*) ferr,
2167         Slice!(T*) berr,
2168         Slice!(T*) work,
2169         Slice!(lapackint*) iwork,
2170     )
2171     in {
2172         assert(fact == 'F' || fact == 'N' || fact == 'E');
2173         assert(uplo == 'U' || uplo == 'L');
2174         auto n = a.length!0;
2175         auto nrhs = x.length;
2176         assert(a.length!1 == n);
2177         assert(af.length!0 == n);
2178         assert(af.length!1 == n);
2179         assert(x.length!1 == n);
2180         assert(b.length!1 == n);
2181         assert(b.length!0 == nrhs);
2182         assert(ferr.length == nrhs);
2183         assert(berr.length == nrhs);
2184         assert(work.length == n * 3);
2185         assert(iwork.length == n);
2186     }
2187     do {
2188         lapackint n = cast(lapackint) a.length!0;
2189         lapackint nrhs = cast(lapackint) x.length;
2190         lapackint lda = cast(lapackint) a._stride.max(1);
2191         lapackint ldaf = cast(lapackint) af._stride.max(1);
2192         lapackint ldx = cast(lapackint) x._stride.max(1);
2193         lapackint ldb = cast(lapackint) b._stride.max(1);
2194         lapackint info;
2195         lapack.posvx_(fact, uplo, n, nrhs, a._iterator, lda, af._iterator, ldaf, equed, s._iterator, b._iterator, ldb, x._iterator, ldx, rcond, ferr._iterator, berr._iterator, work._iterator, iwork._iterator, info);
2196         assert(info >= 0);
2197         return info;
2198     }
2199 
2200     @trusted
2201     size_t posvx(
2202         char fact,
2203         char uplo,
2204         Slice!(T*, 2, Canonical) a,
2205         Slice!(T*, 2, Canonical) af,
2206         char equed,
2207         Slice!(T*) s,
2208         Slice!(T*) b,
2209         Slice!(T*) x,
2210         out T rcond,
2211         out T ferr,
2212         out T berr,
2213         Slice!(T*) work,
2214         Slice!(lapackint*) iwork,
2215     )
2216     in {
2217         assert(fact == 'F' || fact == 'N' || fact == 'E');
2218         assert(uplo == 'U' || uplo == 'L');
2219         auto n = a.length!0;
2220         assert(a.length!1 == n);
2221         assert(af.length!0 == n);
2222         assert(af.length!1 == n);
2223         assert(x.length == n);
2224         assert(b.length == n);
2225         assert(work.length == n * 3);
2226         assert(iwork.length == n);
2227     }
2228     do {
2229         import mir.ndslice.topology: canonical;
2230         return posvx(fact, uplo, a, af, equed, s, b.sliced(1, b.length).canonical, x.sliced(1, x.length).canonical, rcond, sliced(&ferr, 1), sliced(&berr, 1), work, iwork);
2231     }
2232 }
2233 
2234 version(none)
2235 unittest
2236 {
2237     alias s = posvx!float;
2238     alias d = posvx!double;
2239 }
2240 
2241 ///
2242 size_t sytrf_wk(T)(
2243     char uplo,
2244     Slice!(T*, 2, Canonical) a,
2245     )
2246 in
2247 {
2248     assert(a.length!0 == a.length!1, "sytrf_wk: 'a' must be a square matrix.");
2249 }
2250 do
2251 {
2252     lapackint n = cast(lapackint) a.length;
2253     lapackint lda = cast(lapackint) a._stride.max(1);
2254     lapackint lwork = -1;
2255     lapackint info;
2256     T work;
2257     lapackint ipiv;
2258 
2259     lapack.sytrf_(uplo, n, a.iterator, lda, &ipiv, &work, lwork, info);
2260 
2261     return cast(size_t) work.re;
2262 }
2263 
2264 unittest
2265 {
2266     alias s = sytrf_wk!float;
2267     alias d = sytrf_wk!double;
2268 }
2269 
2270 ///
2271 template posv(T)
2272     if (is(T == double) || is(T == float))
2273 {
2274     @trusted
2275     size_t posv(
2276         char uplo,
2277         Slice!(T*, 2, Canonical) a,
2278         Slice!(T*, 2, Canonical) b
2279     )
2280     in {
2281         assert(uplo == 'U' || uplo == 'L');
2282         auto n = a.length!0;
2283         auto nrhs = b.length!0;
2284         assert(a.length!1 == n);
2285         assert(b.length!1 == n);
2286         assert(b.length!0 == nrhs);
2287     }
2288     do {
2289         lapackint n = cast(lapackint) a.length!0;
2290         lapackint nrhs = cast(lapackint) b.length!0;
2291         lapackint lda = cast(lapackint) a._stride.max(1);
2292         lapackint ldb = cast(lapackint) b._stride.max(1);
2293         lapackint info;
2294         lapack.posv_(uplo, n, nrhs, a._iterator, lda, b._iterator, ldb, info);
2295         assert(info >= 0);
2296         return info;
2297     }
2298 
2299     @trusted
2300     size_t posv(
2301         char uplo,
2302         Slice!(T*, 2, Canonical) a,
2303         Slice!(T*) b
2304     )
2305     in {
2306         assert(uplo == 'U' || uplo == 'L');
2307         assert(a.length!0 == a.length!1);
2308         assert(b.length == a.length!0);
2309     }
2310     do {
2311         import mir.ndslice.topology: canonical;
2312         return posv(uplo, a, b.sliced(1, b.length).canonical);
2313     }
2314 }
2315 
2316 version(none)
2317 unittest
2318 {
2319     alias s = posv!float;
2320     alias d = posv!double;
2321 }