File Coverage

blib/lib/PDL/LinearAlgebra.pm
Criterion Covered Total %
statement 25 27 92.5
branch n/a
condition n/a
subroutine 9 9 100.0
pod n/a
total 34 36 94.4


line stmt bran cond sub pod time code
1             package PDL::LinearAlgebra;
2 1     1   156405 use PDL::Ops;
  1         3  
  1         11  
3 1     1   183 use PDL::Core;
  1         2  
  1         8  
4 1     1   379 use PDL::Basic qw/sequence/;
  1         8  
  1         7  
5 1     1   89 use PDL::Primitive qw/which which_both/;
  1         2  
  1         7  
6 1     1   90 use PDL::Ufunc qw/sumover/;
  1         1  
  1         8  
7 1     1   81 use PDL::NiceSlice;
  1         2  
  1         11  
8 1     1   207260 use PDL::Slices;
  1         3  
  1         14  
9 1     1   1113 use PDL::Complex;
  1         7320  
  1         14  
10 1     1   1855 use PDL::LinearAlgebra::Real;
  0            
  0            
11             use PDL::LinearAlgebra::Complex;
12             use PDL::LinearAlgebra::Special qw//;
13             use PDL::Exporter;
14             no warnings 'uninitialized';
15             use constant{
16             NO => 0,
17             WARN => 1,
18             BARF => 2,
19             };
20              
21             use strict;
22              
23             our $VERSION = '0.11';
24             $VERSION = eval $VERSION;
25              
26             @PDL::LinearAlgebra::ISA = qw/PDL::Exporter/;
27             @PDL::LinearAlgebra::EXPORT_OK = qw/t diag issym minv mtriinv msyminv mposinv mdet mposdet mrcond positivise
28             mdsvd msvd mgsvd mlu mhessen mchol mqr mql mlq mrq meigen meigenx
29             mgeigen mgeigenx msymeigen msymeigenx msymgeigen msymgeigenx
30             msolve mtrisolve msymsolve mpossolve msolvex msymsolvex mpossolvex
31             mrank mlls mllsy mllss mglm mlse tritosym mnorm mgschur mgschurx
32             mcrossprod mcond morth mschur mschurx posinf neginf nan
33             NO WARN BARF setlaerror getlaerorr laerror/;
34             %PDL::LinearAlgebra::EXPORT_TAGS = (Func=>[@PDL::LinearAlgebra::EXPORT_OK]);
35              
36             my $_laerror = BARF;
37              
38             my $nan;
39             BEGIN { $nan = 0/pdl(0) }
40             sub nan() { $nan->copy };
41             my $posinf;
42             BEGIN { $posinf = 1/pdl(0) }
43             sub posinf() { $posinf->copy };
44             my $neginf;
45             BEGIN { $neginf = -1/pdl(0) }
46             sub neginf() { $neginf->copy };
47              
48             {
49              
50             package PDL::Complex;
51              
52             use PDL::Types;
53              
54             use vars qw($sep $sep2);
55             our $floatformat = "%4.4g"; # Default print format for long numbers
56             our $doubleformat = "%6.6g";
57              
58              
59             *r2p = \&PDL::Complex::Cr2p;
60             *p2r = \&PDL::Complex::Cp2r;
61             *scale = \&PDL::Complex::Cscale;
62             *conj = \&PDL::Complex::Cconj;
63             *abs2 = \&PDL::Complex::Cabs2;
64             *arg = \&PDL::Complex::Carg;
65             *tan = \&PDL::Complex::Ctan;
66             *proj = \&PDL::Complex::Cproj;
67             *asin = \&PDL::Complex::Casin;
68             *acos = \&PDL::Complex::Cacos;
69             *atan = \&PDL::Complex::Catan;
70             *sinh = \&PDL::Complex::Csinh;
71             *cosh = \&PDL::Complex::Ccosh;
72             *tanh = \&PDL::Complex::Ctanh;
73             *asinh = \&PDL::Complex::Casinh;
74             *acosh = \&PDL::Complex::Cacosh;
75             *atanh = \&PDL::Complex::Catanh;
76             *prodover = \&PDL::Complex::Cprodover;
77              
78             sub ecplx {
79             my ($re, $im) = @_;
80             return $re if UNIVERSAL::isa($re,'PDL::Complex');
81             if (defined $im){
82             $re = pdl($re) unless (UNIVERSAL::isa($re,'PDL'));
83             $im = pdl($im) unless (UNIVERSAL::isa($im,'PDL'));
84             my $ret = PDL::new_from_specification('PDL::Complex', $re->type, 2, $re->dims);
85             $ret->slice('(0),') .= $re;
86             $ret->slice('(1),') .= $im;
87             return $ret;
88             }
89             croak "first dimsize must be 2" unless $re->dims > 0 && $re->dim(0) == 2;
90             bless $_[0]->slice('');
91             }
92              
93              
94             sub sumover {
95             my $c = shift;
96             return dims($c) > 1 ? PDL::Ufunc::sumover($c->xchg(0,1)) : $c;
97             }
98              
99              
100              
101             sub norm {
102             my ($m, $real, $trans) = @_;
103            
104             # If trans == true => transpose output matrice
105             # If real == true => rotate (complex as a vector)
106             # such that max abs will be real
107            
108             #require PDL::LinearAlgebra::Complex;
109             PDL::LinearAlgebra::Complex::cnrm2($m,1, my $ret = null);
110             if ($real){
111             my ($index, $scale);
112             $m = PDL::Complex::Cscale($m,1/$ret->dummy(0))->reshape(-1);
113             $index = $m->Cabs->maximum_ind;
114             $scale = $m->mv(0,-1)->index($index)->mv(-1,0);
115             $scale= $scale->Cconj/$scale->Cabs;
116             return $trans ? $m->xchg(1,2)*$scale->dummy(2) : $m*$scale->dummy(2)->xchg(1,2);
117             }
118             return $trans ? PDL::Complex::Cscale($m->xchg(1,2),1/$ret->dummy(0)->xchg(0,1))->reshape(-1) :
119             PDL::Complex::Cscale($m,1/$ret->dummy(0))->reshape(-1);
120             }
121              
122              
123             }
124             ########################################################################
125              
126             =encoding Latin-1
127              
128             =head1 NAME
129              
130             PDL::LinearAlgebra - Linear Algebra utils for PDL
131              
132             =head1 SYNOPSIS
133              
134             use PDL::LinearAlgebra;
135              
136             $a = random (100,100);
137             ($U, $s, $V) = mdsvd($a);
138              
139             =head1 DESCRIPTION
140              
141             This module provides a convenient interface to L
142             and L. Its primary purpose is educational.
143             You have to know that routines defined here are not optimized, particularly in term of memory. Since
144             Blas and Lapack use a column major ordering scheme some routines here need to transpose matrices before
145             calling fortran routines and transpose back (see the documentation of each routine). If you need
146             optimized code use directly L and
147             L. It's planned to "port" this module to PDL::Matrix such
148             that transpositions will not be necessary, the major problem is that two new modules need to be created PDL::Matrix::Real
149             and PDL::Matrix::Complex.
150              
151              
152             =cut
153              
154              
155             =head1 FUNCTIONS
156              
157             =head2 setlaerror
158              
159             =for ref
160              
161             Sets action type when an error is encountered, returns previous type. Available values are NO, WARN and BARF (predefined constants).
162             If, for example, in computation of the inverse, singularity is detected,
163             the routine can silently return values from computation (see manuals),
164             warn about singularity or barf. BARF is the default value.
165              
166             =for example
167              
168             # h : x -> g(f(x))
169              
170             $a = sequence(5,5);
171             $err = setlaerror(NO);
172             ($b, $info)= f($a);
173             setlaerror($err);
174             $info ? barf "can't compute h" : return g($b);
175              
176              
177             =cut
178              
179             sub setlaerror($){
180             my $err = $_laerror;
181             $_laerror = shift;
182             $err;
183             }
184              
185             =head2 getlaerror
186              
187             =for ref
188              
189             Gets action type when an error is encountered.
190            
191             0 => NO,
192             1 => WARN,
193             2 => BARF
194              
195             =cut
196              
197             sub getlaerror{
198             $_laerror;
199             }
200              
201             sub laerror{
202             return unless $_laerror;
203             if ($_laerror < 2){
204             warn "$_[0]\n";
205             }
206             else{
207             barf "$_[0]\n";
208             }
209             }
210              
211             =head2 t
212              
213             =for usage
214              
215             PDL = t(PDL, SCALAR(conj))
216             conj : Conjugate Transpose = 1 | Transpose = 0, default = 1;
217              
218             =for ref
219              
220             Convenient function for transposing real or complex 2D array(s).
221             For PDL::Complex, if conj is true returns conjugate transposed array(s) and doesn't support dataflow.
222             Supports threading.
223              
224             =cut
225              
226             sub t{
227             my $m = shift;
228             $m->t(@_);
229             }
230              
231             sub PDL::t {
232             $_[0]->xchg(0,1);
233             }
234             sub PDL::Complex::t {
235             my ($m, $conj) = @_;
236             $conj = 1 unless defined($conj);
237             $conj ? PDL::Complex::Cconj($m->xchg(1,2)) : $m->xchg(1,2);
238             }
239              
240             =head2 issym
241              
242             =for usage
243              
244             PDL = issym(PDL, SCALAR|PDL(tol),SCALAR(hermitian))
245             tol : tolerance value, default: 1e-8 for double else 1e-5
246             hermitian : Hermitian = 1 | Symmetric = 0, default = 1;
247              
248             =for ref
249              
250             Checks symmetricity/Hermitianicity of matrix.
251             Supports threading.
252              
253             =cut
254              
255             sub issym{
256             my $m = shift;
257             $m->issym(@_);
258             }
259              
260             sub PDL::issym {
261             my ($m, $tol) = @_;
262             my @dims = $m->dims;
263              
264             barf("issym: Require square array(s)")
265             if( $dims[0] != $dims[1] );
266              
267             $tol = defined($tol) ? $tol : ($m->type == double) ? 1e-8 : 1e-5;
268              
269             my ($min,$max) = PDL::Ufunc::minmaximum($m - $m->xchg(0,1));
270             $min = $min->minimum;
271             $max = $max->maximum;
272             return (((abs($max) > $tol) + (abs($min) > $tol)) == 0);
273             }
274              
275             sub PDL::Complex::issym {
276             my ($m, $tol, $conj) = @_;
277             my @dims = $m->dims;
278              
279             barf("issym: Require square array(s)")
280             if( $dims[1] != $dims[2] );
281              
282             $conj = 1 unless defined($conj);
283             $tol = defined($tol) ? $tol : ($m->type == double) ? 1e-8 : 1e-5;
284              
285             my ($min, $max, $mini, $maxi);
286             if ($conj){
287             ($min,$max) = PDL::Ufunc::minmaximum(PDL::clump($m - $m->t(1),2));
288             }
289             else{
290             ($min,$max) = PDL::Ufunc::minmaximum(PDL::clump($m - $m->xchg(1,2),2));
291             }
292             $min->minimum($mini = null);
293             $max->maximum($maxi = null);
294             return (((abs($maxi) > $tol) + (abs($mini) > $tol)) == 0);
295              
296             }
297              
298              
299             =head2 diag
300              
301             =for ref
302              
303             Returns i-th diagonal if matrix in entry or matrix with i-th diagonal
304             with entry. I-th diagonal returned flows data back&forth.
305             Can be used as lvalue subs if your perl supports it.
306             Supports threading.
307              
308             =for usage
309              
310             PDL = diag(PDL, SCALAR(i), SCALAR(vector)))
311             i : i-th diagonal, default = 0
312             vector : create diagonal matrices by threading over row vectors, default = 0
313            
314              
315             =for example
316              
317             my $a = random(5,5);
318             my $diag = diag($a,2);
319             # If your perl support lvaluable subroutines.
320             $a->diag(-2) .= pdl(1,2,3);
321             # Construct a (5,5,5) PDL (5 matrices) with
322             # diagonals from row vectors of $a
323             $a->diag(0,1)
324              
325             =cut
326              
327             sub diag{
328             my $m = shift;
329             $m->diag(@_);
330             }
331             sub PDL::diag{
332             my ($a,$i, $vec) = @_;
333             my ($diag, $dim, @dims, $z);
334             @dims = $a->dims;
335              
336             $diag = ($i < 0) ? -$i : $i ;
337              
338             if (@dims == 1 || $vec){
339             $dim = $dims[0];
340             my $zz = $dim + $diag;
341             $z= PDL::zeroes('PDL',$a->type,$zz, $zz,@dims[1..$#dims]);
342             if ($i){
343             ($i < 0) ? $z(:($dim-1),$diag:)->diagonal(0,1) .= $a : $z($diag:,:($dim-1))->diagonal(0,1).=$a;
344             }
345             else{ $z->diagonal(0,1) .= $a; }
346             }
347             elsif($i < 0){
348             $z = $a(:-$diag-1 , $diag:)->diagonal(0,1);
349             }
350             elsif($i){
351             $z = $a($diag:, :-$diag-1)->diagonal(0,1);
352             }
353             else{$z = $a->diagonal(0,1);}
354             $z;
355             }
356              
357             sub PDL::Complex::diag{
358             my ($a,$i, $vec) = @_;
359             my ($diag, $dim, @dims, $z);
360             @dims = $a->dims;
361              
362             $diag = ($i < 0) ? -$i : $i ;
363              
364              
365             if (@dims == 2 || $vec){
366             $dim = $dims[1];
367             my $zz = $dim + $diag;
368             $z= PDL::zeroes('PDL::Complex',$a->type, 2, $zz, $zz,@dims[2..$#dims]);
369             if ($i){
370             ($i < 0) ? $z(,:($dim-1),$diag:)->diagonal(1,2) .= $a : $z(,$diag:,:($dim-1))->diagonal(1,2).=$a;
371             }
372             else{ $z->diagonal(1,2) .= $a; }
373             }
374             elsif($i < 0){
375             $z = $a(,:-$diag-1 , $diag:)->diagonal(1,2);
376             }
377             elsif($i){
378             $z = $a(,$diag:, :-$diag-1 )->diagonal(1,2);
379             }
380             else{
381             $z = $a->diagonal(1,2);
382             }
383             $z;
384             }
385              
386             if ($^V and $^V ge v5.6.0){
387             use attributes 'PDL', \&PDL::diag, 'lvalue';
388             use attributes 'PDL', \&PDL::Complex::diag, 'lvalue';
389             }
390              
391             =head2 tritosym
392              
393             =for ref
394              
395             Returns symmetric or Hermitian matrix from lower or upper triangular matrix.
396             Supports inplace and threading.
397             Uses L or L from Lapack.
398              
399             =for usage
400              
401             PDL = tritosym(PDL, SCALAR(uplo), SCALAR(conj))
402             uplo : UPPER = 0 | LOWER = 1, default = 0
403             conj : Hermitian = 1 | Symmetric = 0, default = 1;
404              
405             =for example
406              
407             # Assume $a is symmetric triangular
408             my $a = random(10,10);
409             my $b = tritosym($a);
410              
411             =cut
412              
413             sub tritosym{
414             my $m = shift;
415             $m->tritosym(@_);
416             }
417              
418             sub PDL::tritosym {
419             my ($m, $upper) = @_;
420             my @dims = $m->dims;
421              
422             barf("tritosym: Require square array(s)")
423             unless( $dims[0] == $dims[1] );
424              
425             my $b = $m->is_inplace ? $m : PDL::new_from_specification(ref($m),$m->type,@dims);
426             $m->tricpy($upper, $b) unless $m->is_inplace(0);
427             $m->tricpy($upper, $b->xchg(0,1));
428             $b;
429              
430             }
431              
432             sub PDL::Complex::tritosym {
433             my ($m, $upper, $conj) = @_;
434             my @dims = $m->dims;
435              
436             barf("tritosym: Require square array(s)")
437             if( $dims[1] != $dims[2] );
438              
439             my $b = $m->is_inplace ? $m : PDL::new_from_specification(ref($m),$m->type,@dims);
440             $conj = 1 unless defined($conj);
441             $conj ? PDL::Complex::Cconj($m)->ctricpy($upper, $b->xchg(1,2)) :
442             $m->ctricpy($upper, $b->xchg(1,2));
443             # ...
444             $m->ctricpy($upper, $b) unless (!$conj && $m->is_inplace(0));
445             $b((1),)->diagonal(0,1) .= 0 if $conj;
446             $b;
447              
448             }
449              
450              
451             =head2 positivise
452              
453             =for ref
454              
455             Returns entry pdl with changed sign by row so that average of positive sign > 0.
456             In other words threads among dimension 1 and row = -row if sum(sign(row)) < 0.
457             Works inplace.
458              
459             =for example
460              
461             my $a = random(10,10);
462             $a -= 0.5;
463             $a->xchg(0,1)->inplace->positivise;
464              
465             =cut
466              
467             *positivise = \&PDL::positivise;
468             sub PDL::positivise{
469             my $m = shift;
470             my $tmp;
471             $m = $m->copy unless $m->is_inplace(0);
472             $tmp = $m->dice('X', which(( $m->lt(0,0)->sumover > ($m->dim(0)/2))>0));
473             $tmp->inplace->mult(-1,0);# .= -$tmp;
474             $m;
475             }
476              
477              
478              
479              
480             =head2 mcrossprod
481              
482             =for ref
483              
484             Computes the cross-product of two matrix: A' x B.
485             If only one matrix is given, takes B to be the same as A.
486             Supports threading.
487             Uses L or L.
488              
489             =for usage
490              
491             PDL = mcrossprod(PDL(A), (PDL(B))
492              
493             =for example
494              
495             my $a = random(10,10);
496             my $crossproduct = mcrossprod($a);
497              
498             =cut
499              
500             sub mcrossprod{
501             my $m = shift;
502             $m->mcrossprod(@_);
503             }
504              
505             sub PDL::mcrossprod {
506             my($a, $b) = @_;
507             my(@dims) = $a->dims;
508              
509             barf("mcrossprod: Require 2D array(s)")
510             unless( @dims >= 2 );
511            
512             $b = $a unless defined $b;
513             $a->crossprod($b);
514             }
515              
516             sub PDL::Complex::mcrossprod {
517             my($a, $b) = @_;
518             my(@dims) = $a->dims;
519              
520             barf("mcrossprod: Require 2D array(s)")
521             unless( @dims >= 3);
522            
523             $b = $a unless defined $b;
524             $a->ccrossprod($b);
525             }
526              
527              
528             =head2 mrank
529              
530             =for ref
531              
532             Computes the rank of a matrix, using a singular value decomposition.
533             from Lapack.
534              
535             =for usage
536              
537             SCALAR = mrank(PDL, SCALAR(TOL))
538             TOL: tolerance value, default : mnorm(dims(PDL),'inf') * mnorm(PDL) * EPS
539              
540             =for example
541              
542             my $a = random(10,10);
543             my $b = mrank($a, 1e-5);
544              
545             =cut
546              
547             *mrank = \&PDL::mrank;
548              
549             sub PDL::mrank {
550             my($m, $tol) = @_;
551             my(@dims) = $m->dims;
552              
553             barf("mrank: Require a 2D matrix")
554             unless( @dims == 2 or @dims == 3 );
555              
556             my ($sv, $info, $err);
557              
558             $err = setlaerror(NO);
559             # Sometimes mdsvd bugs for float (SGEBRD)
560             # ($sv, $info) = $m->msvd(0, 0);
561             ($sv, $info) = $m->mdsvd(0);
562             setlaerror($err);
563             barf("mrank: SVD algorithm did not converge\n") if $info;
564              
565             unless (defined $tol){
566             $tol = ($dims[-1] > $dims[-2] ? $dims[-1] : $dims[-2]) * $sv((0)) * lamch(pdl($m->type,3));
567             }
568             (which($sv > $tol))->dim(0);
569             }
570              
571             =head2 mnorm
572              
573             =for ref
574              
575             Computes norm of real or complex matrix
576             Supports threading.
577              
578             =for usage
579              
580             PDL(norm) = mnorm(PDL, SCALAR(ord));
581             ord :
582             0|'inf' : Infinity norm
583             1|'one' : One norm
584             2|'two' : norm 2 (default)
585             3|'fro' : frobenius norm
586              
587             =for example
588              
589             my $a = random(10,10);
590             my $norm = mnorm($a);
591              
592             =cut
593              
594             sub mnorm {
595             my $m =shift;
596             $m->mnorm(@_);
597             }
598              
599              
600             sub PDL::mnorm {
601             my ($m, $ord) = @_;
602             $ord = 2 unless (defined $ord);
603              
604             if ($ord eq 'inf'){
605             $ord = 0;
606             }
607             elsif ($ord eq 'one'){
608             $ord = 1;
609             }
610             elsif($ord eq 'two'){
611             $ord = 2;
612             }
613             elsif($ord eq 'fro'){
614             $ord = 3;
615             }
616              
617             if ($ord == 0){
618             $m->lange(1);
619             }
620             elsif($ord == 1){
621             $m->lange(2);
622             }
623             elsif($ord == 3){
624             $m->lange(3);
625             }
626             else{
627             my ($sv, $info, $err);
628             $err = setlaerror(NO);
629             ($sv, $info) = $m->msvd(0, 0);
630             setlaerror($err);
631             if($info->max > 0 && $_laerror) {
632             my ($index,@list);
633             $index = which($info > 0)+1;
634             @list = $index->list;
635             laerror("mnorm: SVD algorithm did not converge for matrix (PDL(s) @list): \$info = $info");
636             }
637             $sv->slice('(0)')->reshape(-1)->sever;
638             }
639            
640             }
641              
642              
643             sub PDL::Complex::mnorm {
644             my ($m, $ord) = @_;
645             $ord = 2 unless (defined $ord);
646              
647             if ($ord eq 'inf'){
648             $ord = 0;
649             }
650             elsif ($ord eq 'one'){
651             $ord = 1;
652             }
653             elsif($ord eq 'two'){
654             $ord = 2;
655             }
656             elsif($ord eq 'fro'){
657             $ord = 3;
658             }
659              
660             if ($ord == 0){
661             return bless $m->clange(1),'PDL';
662             }
663             elsif($ord == 1){
664             return bless $m->clange(2),'PDL';
665             }
666             elsif($ord == 3){
667             return bless $m->clange(3),'PDL';
668             }
669             else{
670             my ($sv, $info, $err) ;
671             $err = setlaerror(NO);
672             ($sv, $info) = $m->msvd(0, 0);
673             setlaerror($err);
674             if($info->max > 0 && $_laerror) {
675             my ($index,@list);
676             $index = which($info > 0)+1;
677             @list = $index->list;
678             laerror("mnorm: SVD algorithm did not converge for matrix (PDL(s) @list): \$info = $info");
679             }
680             $sv->slice('(0)')->reshape(-1)->sever;
681             }
682            
683             }
684              
685              
686              
687             =head2 mdet
688              
689             =for ref
690              
691             Computes determinant of a general square matrix using LU factorization.
692             Supports threading.
693             Uses L or L
694             from Lapack.
695              
696             =for usage
697              
698             PDL(determinant) = mdet(PDL);
699              
700             =for example
701              
702             my $a = random(10,10);
703             my $det = mdet($a);
704              
705             =cut
706              
707             sub mdet{
708             my $m =shift;
709             $m->mdet;
710             }
711              
712              
713             sub PDL::mdet {
714             my $m = shift;
715             my @dims = $m->dims;
716              
717             barf("mdet: Require square array(s)")
718             unless( $dims[0] == $dims[1] && @dims >= 2);
719              
720             my ($info, $ipiv);
721             $m = $m->copy();
722             $info = null;
723             $ipiv = null;
724              
725             $m->getrf($ipiv, $info);
726             $m = $m->diagonal(0,1)->prodover;
727              
728             $m = $m * ((PDL::Ufunc::sumover(sequence($ipiv->dim(0))->plus(1,0) != $ipiv)%2)*(-2)+1) ;
729             $info = $m->flat->index(which($info != 0 ));
730             $info .= 0 unless $info->isempty;
731             $m;
732             }
733              
734              
735             sub PDL::Complex::mdet {
736             my $m = shift;
737             my @dims = $m->dims;
738              
739             barf("mdet: Require square array(s)")
740             unless( @dims >= 3 && $dims[1] == $dims[2] );
741              
742             my ($info, $ipiv);
743             $m = $m->copy();
744             $info = null;
745             $ipiv = null;
746              
747             $m->cgetrf($ipiv, $info);
748             $m = PDL::Complex::Cprodover($m->diagonal(1,2));
749             $m = $m * ((PDL::Ufunc::sumover(sequence($ipiv->dim(0))->plus(1,0) != $ipiv)%2)*(-2)+1) ;
750            
751             $info = which($info != 0 );
752             unless ($info->isempty){
753             $m->re->flat->index($info) .= 0;
754             $m->im->flat->index($info) .= 0;
755             }
756             $m;
757              
758             }
759              
760              
761             =head2 mposdet
762              
763             =for ref
764              
765             Compute determinant of a symmetric or Hermitian positive definite square matrix using Cholesky factorization.
766             Supports threading.
767             Uses L or L from Lapack.
768              
769             =for usage
770              
771             (PDL, PDL) = mposdet(PDL, SCALAR)
772             SCALAR : UPPER = 0 | LOWER = 1, default = 0
773              
774             =for example
775              
776             my $a = random(10,10);
777             my $det = mposdet($a);
778              
779             =cut
780              
781             sub mposdet{
782             my $m =shift;
783             $m->mposdet(@_);
784             }
785              
786             sub PDL::mposdet {
787             my ($m, $upper) = @_;
788             my @dims = $m->dims;
789              
790             barf("mposdet: Require square array(s)")
791             unless( @dims >= 2 && $dims[0] == $dims[1] );
792              
793             $m = $m->copy();
794            
795             $m->potrf($upper, (my $info=null));
796             if($info->max > 0 && $_laerror) {
797             my ($index,@list);
798             $index = which($info > 0)+1;
799             @list = $index->list;
800             laerror("mposdet: Matrix (PDL(s) @list) is/are not positive definite(s) (after potrf factorization): \$info = $info");
801             }
802             $m = $m->diagonal(0,1)->prodover->pow(2);
803             return wantarray ? ($m, $info) : $m;
804             }
805              
806             sub PDL::Complex::mposdet {
807             my ($m, $upper) = @_;
808             my @dims = $m->dims;
809              
810             barf("mposdet: Require square array(s)")
811             unless( @dims >= 3 && $dims[1] == $dims[2] );
812              
813             $m = $m->copy();
814            
815             $m->cpotrf($upper, (my $info=null));
816             if($info->max > 0 && $_laerror) {
817             my ($index,@list);
818             $index = which($info > 0)+1;
819             @list = $index->list;
820             laerror("mposdet: Matrix (PDL(s) @list) is/are not positive definite(s) (after cpotrf factorization): \$info = $info");
821             }
822              
823             $m = PDL::Complex::re($m)->diagonal(0,1)->prodover->pow(2);
824             return wantarray ? ($m, $info) : $m;
825             }
826              
827              
828             =head2 mcond
829              
830             =for ref
831              
832             Computes the condition number (two-norm) of a general matrix.
833              
834             The condition number in two-n is defined:
835              
836             norm (a) * norm (inv (a)).
837              
838             Uses a singular value decomposition.
839             Supports threading.
840              
841             =for usage
842              
843             PDL = mcond(PDL)
844              
845             =for example
846              
847             my $a = random(10,10);
848             my $cond = mcond($a);
849              
850             =cut
851              
852             sub mcond{
853             my $m =shift;
854             $m->mcond(@_);
855             }
856              
857             sub PDL::mcond {
858             my $m = shift;
859             my @dims = $m->dims;
860              
861             barf("mcond: Require 2D array(s)")
862             unless( @dims >= 2 );
863              
864             my ($sv, $info, $err, $ret, $temp);
865             $err = setlaerror(NO);
866             ($sv, $info) = $m->msvd(0, 0);
867             setlaerror($err);
868             if($info->max > 0) {
869             my ($index,@list);
870             $index = which($info > 0)+1;
871             @list = $index->list;
872             barf("mcond: Algorithm did not converge for matrix (PDL(s) @list): \$info = $info");
873             }
874            
875             $temp = $sv->slice('(0)');
876             $ret = $temp/$sv->((-1));
877            
878             $info = $ret->flat->index(which($temp == 0));
879             $info .= posinf unless $info->isempty;
880             return $ret;
881            
882             }
883              
884             sub PDL::Complex::mcond {
885             my $m = shift;
886             my @dims = $m->dims;
887              
888             barf("mcond: Require 2D array(s)")
889             unless( @dims >= 3);
890              
891             my ($sv, $info, $err, $ret, $temp) ;
892             $err = setlaerror(NO);
893             ($sv, $info) = $m->msvd(0, 0);
894             setlaerror($err);
895             if($info->max > 0 && $_laerror) {
896             my ($index,@list);
897             $index = which($info > 0)+1;
898             @list = $index->list;
899             laerror("mcond: Algorithm did not converge for matrix (PDL(s) @list): \$info = $info");
900             }
901              
902             $temp = $sv->slice('(0)');
903             $ret = $temp/$sv->((-1));
904            
905             $info = $ret->flat->index(which($temp == 0));
906             $info .= posinf unless $info->isempty;
907             return $ret;
908             }
909              
910              
911              
912             =head2 mrcond
913              
914             =for ref
915              
916             Estimates the reciprocal condition number of a
917             general square matrix using LU factorization
918             in either the 1-norm or the infinity-norm.
919              
920             The reciprocal condition number is defined:
921              
922             1/(norm (a) * norm (inv (a)))
923              
924             Supports threading.
925             Works on transposed array(s)
926              
927             =for usage
928              
929             PDL = mrcond(PDL, SCALAR(ord))
930             ord :
931             0 : Infinity norm (default)
932             1 : One norm
933              
934             =for example
935              
936             my $a = random(10,10);
937             my $rcond = mrcond($a,1);
938              
939             =cut
940              
941             sub mrcond{
942             my $m =shift;
943             $m->mcond(@_);
944             }
945              
946             sub PDL::mrcond {
947             my ($m,$anorm) = @_;
948             $anorm = 0 unless defined $anorm;
949             my @dims = $m->dims;
950              
951             barf("mrcond: Require square array")
952             unless ( $dims[0] == $dims[1] );
953              
954             my ($ipiv, $info,$rcond,$norm);
955             $norm = $m->mnorm($anorm);
956             $m = $m->xchg(0,1)->copy();
957             $ipiv = PDL->null;
958             $info = PDL->null;
959             $rcond = PDL->null;
960              
961             $m->getrf($ipiv, $info);
962             if($info->max > 0 && $_laerror) {
963             my ($index,@list);
964             $index = which($info > 0)+1;
965             @list = $index->list;
966             laerror("mrcond: Factor(s) U (PDL(s) @list) is/are singular(s) (after getrf factorization): \$info = $info");
967             }
968             else{
969             $m->gecon($anorm,$norm,$rcond,$info);
970             }
971             return wantarray ? ($rcond, $info) : $rcond;
972              
973            
974             }
975              
976             sub PDL::Complex::mrcond {
977             my ($m, $anorm) = @_;
978             $anorm = 0 unless defined $anorm;
979             my @dims = $m->dims;
980              
981             barf("mrcond: Require square array(s)")
982             unless ( $dims[1] == $dims[2] );
983              
984             my ($ipiv, $info,$rcond,$norm);
985             $norm = $m->mnorm($anorm);
986             $m = $m->xchg(1,2)->copy();
987             $ipiv = PDL->null;
988             $info = PDL->null;
989             $rcond = PDL->null;
990            
991             $m->cgetrf($ipiv, $info);
992             if($info->max > 0 && $_laerror) {
993             my ($index,@list);
994             $index = which($info > 0)+1;
995             @list = $index->list;
996             laerror("mrcond: Factor(s) U (PDL(s) @list) is/are singular(s) (after cgetrf factorization) : \$info = $info");
997             }
998             else{
999             $m->cgecon($anorm,$norm,$rcond,$info);
1000             }
1001             return wantarray ? ($rcond, $info) : $rcond;
1002              
1003             }
1004              
1005              
1006              
1007              
1008              
1009             =head2 morth
1010              
1011             =for ref
1012              
1013             Returns an orthonormal basis of the range space of matrix A.
1014              
1015             =for usage
1016              
1017             PDL = morth(PDL(A), SCALAR(tol))
1018             tol : tolerance for determining rank, default: 1e-8 for double else 1e-5
1019              
1020             =for example
1021              
1022             my $a = sequence(10,10);
1023             my $ortho = morth($a, 1e-8);
1024              
1025             =cut
1026              
1027             *morth = \&PDL::morth;
1028              
1029             sub PDL::morth {
1030             my ($m, $tol) = @_;
1031             my @dims = $m->dims;
1032             barf("morth: Require a matrix")
1033             unless( (@dims == 2) || (@dims == 3));
1034              
1035             my ($u, $s, $rank, $info, $err);
1036             $tol = (defined $tol) ? $tol : ($m->type == double) ? 1e-8 : 1e-5;
1037              
1038             $err = setlaerror(NO);
1039             ($u, $s, undef, $info) = $m->mdsvd;
1040             setlaerror($err);
1041             barf("morth: SVD algorithm did not converge\n") if $info;
1042              
1043             $rank = (which($s > $tol))->dim(0) - 1;
1044             if(@dims == 3){
1045             return $rank < 0 ? PDL::Complex->null : $u(,:$rank,)->sever;
1046             }
1047             else{
1048             return $rank < 0 ? null : $u(:$rank,)->sever;
1049             }
1050             }
1051              
1052             =head2 mnull
1053              
1054             =for ref
1055              
1056             Returns an orthonormal basis of the null space of matrix A.
1057             Works on transposed array.
1058              
1059             =for usage
1060              
1061             PDL = mnull(PDL(A), SCALAR(tol))
1062             tol : tolerance for determining rank, default: 1e-8 for double else 1e-5
1063              
1064             =for example
1065              
1066             my $a = sequence(10,10);
1067             my $null = mnull($a, 1e-8);
1068              
1069             =cut
1070              
1071             *mnull = \&PDL::mnull;
1072              
1073             sub PDL::mnull {
1074             my ($m, $tol) = @_;
1075             my @dims = $m->dims;
1076             barf("mnull: Require a matrix")
1077             unless( (@dims == 2) || (@dims == 3));
1078              
1079             my ($v, $s, $rank, $info, $err);
1080             $tol = (defined $tol) ? $tol : ($m->type == double) ? 1e-8 : 1e-5;
1081              
1082             $err = setlaerror(NO);
1083             (undef, $s, $v, $info) = $m->mdsvd;
1084             setlaerror($err);
1085             barf("mnull: SVD algorithm did not converge\n") if $info;
1086              
1087             #TODO: USE TRANSPOSED A
1088             $rank = (which($s > $tol))->dim(0);
1089             if (@dims == 3){
1090             return $rank < $dims[1] ? $v->(,,$rank:)->t : PDL::Complex->null;
1091             }
1092             else{
1093             return $rank < $dims[1] ? $v->xchg(0,1)->($rank:,)->sever : null;
1094             }
1095             }
1096              
1097              
1098              
1099             =head2 minv
1100              
1101             =for ref
1102              
1103             Computes inverse of a general square matrix using LU factorization. Supports inplace and threading.
1104             Uses L and L
1105             or L and L
1106             from Lapack and returns C in array context.
1107              
1108             =for usage
1109              
1110             PDL(inv) = minv(PDL)
1111              
1112             =for example
1113              
1114             my $a = random(10,10);
1115             my $inv = minv($a);
1116              
1117             =cut
1118              
1119             sub minv($) {
1120             $_[0]->minv;
1121             }
1122             sub PDL::minv {
1123             my $m = shift;
1124             my @dims = $m->dims;
1125             my ($ipiv, $info);
1126              
1127             barf("minv: Require square array(s)")
1128             if( $dims[0] != $dims[1] );
1129              
1130             $m = $m->copy() unless $m->is_inplace(0);
1131             $ipiv = PDL->null;
1132             $info = PDL->null;
1133              
1134             $m->getrf($ipiv, $info);
1135             if($info->max > 0 && $_laerror) {
1136             my ($index,@list);
1137             $index = which($info > 0)+1;
1138             @list = $index->list;
1139             laerror("minv: Factor(s) U (PDL(s) @list) is/are singular(s) (after getrf factorization): \$info = $info");
1140             }
1141             $m->getri($ipiv,$info);
1142             return wantarray ? ($m, $info) : $m;
1143             }
1144             sub PDL::Complex::minv {
1145             my $m = shift;
1146             my @dims = $m->dims;
1147             my ($ipiv, $info);
1148              
1149             barf("minv: Require square array(s)")
1150             if( $dims[1] != $dims[2] );
1151              
1152             $m = $m->copy() unless $m->is_inplace(0);
1153             $ipiv = PDL->null;
1154             $info = PDL->null;
1155              
1156             $m->cgetrf($ipiv, $info);
1157             if($info->max > 0 && $_laerror) {
1158             my ($index,@list);
1159             $index = which($info > 0)+1;
1160             @list = $index->list;
1161             laerror("minv: Factor(s) U (PDL(s) @list) is/are singular(s) (after cgetrf factorization) : \$info = $info");
1162             }
1163             else{
1164             $m->cgetri($ipiv,$info);
1165             }
1166             return wantarray ? ($m, $info) : $m;
1167             }
1168              
1169             =head2 mtriinv
1170              
1171             =for ref
1172              
1173             Computes inverse of a triangular matrix. Supports inplace and threading.
1174             Uses L or L from Lapack.
1175             Returns C in array context.
1176              
1177             =for usage
1178              
1179             (PDL, PDL(info))) = mtriinv(PDL, SCALAR(uplo), SCALAR|PDL(diag))
1180             uplo : UPPER = 0 | LOWER = 1, default = 0
1181             diag : UNITARY DIAGONAL = 1, default = 0
1182              
1183             =for example
1184              
1185             # Assume $a is upper triangular
1186             my $a = random(10,10);
1187             my $inv = mtriinv($a);
1188              
1189             =cut
1190              
1191              
1192             sub mtriinv{
1193             my $m = shift;
1194             $m->mtriinv(@_);
1195             }
1196              
1197             sub PDL::mtriinv{
1198             my $m = shift;
1199             my $upper = @_ ? (1 - shift) : pdl (long,1);
1200             my $diag = shift;
1201              
1202             my(@dims) = $m->dims;
1203              
1204             barf("mtriinv: Require square array(s)")
1205             if( $dims[0] != $dims[1] );
1206              
1207             $m = $m->copy() unless $m->is_inplace(0);
1208             my $info = PDL->null;
1209             $m->trtri($upper, $diag, $info);
1210             if($info->max > 0 && $_laerror) {
1211             my ($index,@list);
1212             $index = which($info > 0)+1;
1213             @list = $index->list;
1214             laerror("mtriinv: Matrix (PDL(s) @list) is/are singular(s): \$info = $info");
1215             }
1216             return wantarray ? ($m, $info) : $m;
1217             }
1218              
1219             sub PDL::Complex::mtriinv{
1220             my $m = shift;
1221             my $upper = @_ ? (1 - shift) : pdl (long,1);
1222             my $diag = shift;
1223              
1224             my(@dims) = $m->dims;
1225              
1226             barf("mtriinv: Require square array(s)")
1227             if( $dims[1] != $dims[2] );
1228              
1229             $m = $m->copy() unless $m->is_inplace(0);
1230             my $info = PDL->null;
1231             $m->ctrtri($upper, $diag, $info);
1232             if($info->max > 0 && $_laerror) {
1233             my ($index,@list);
1234             $index = which($info > 0)+1;
1235             @list = $index->list;
1236             laerror("mtriinv: Matrix (PDL(s) @list) is/are singular(s): \$info = $info");
1237             }
1238             return wantarray ? ($m, $info) : $m;
1239             }
1240              
1241             =head2 msyminv
1242              
1243             =for ref
1244              
1245             Computes inverse of a symmetric square matrix using the Bunch-Kaufman diagonal pivoting method.
1246             Supports inplace and threading.
1247             Uses L and L or
1248             L and L
1249             from Lapack and returns C in array context.
1250              
1251             =for usage
1252              
1253             (PDL, (PDL(info))) = msyminv(PDL, SCALAR|PDL(uplo))
1254             uplo : UPPER = 0 | LOWER = 1, default = 0
1255              
1256             =for example
1257              
1258             # Assume $a is symmetric
1259             my $a = random(10,10);
1260             my $inv = msyminv($a);
1261              
1262             =cut
1263              
1264             sub msyminv {
1265             my $m = shift;
1266             $m->msyminv(@_);
1267             }
1268              
1269             sub PDL::msyminv {
1270             my $m = shift;
1271             my $upper = @_ ? (1 - shift) : pdl (long,1);
1272             my ($ipiv , $info);
1273             my(@dims) = $m->dims;
1274              
1275             barf("msyminv: Require square array(s)")
1276             if( $dims[0] != $dims[1] );
1277              
1278             $m = $m->copy() unless $m->is_inplace(0);
1279              
1280             $ipiv = zeroes(long, @dims[1..$#dims]);
1281             @dims = @dims[2..$#dims];
1282             $info = @dims ? zeroes(long,@dims) : pdl(long,0);
1283              
1284             $m->sytrf($upper, $ipiv, $info);
1285             if($info->max > 0 && $_laerror) {
1286             my ($index,@list);
1287             $index = which($info > 0)+1;
1288             @list = $index->list;
1289             laerror("msyminv: Block diagonal matrix D (PDL(s) @list) is/are singular(s) (after sytrf factorization): \$info = $info");
1290             }
1291             else{
1292             $m->sytri($upper,$ipiv,$info);
1293             $m = $m->t->tritosym($upper);
1294             }
1295             return wantarray ? ($m, $info) : $m;
1296             }
1297              
1298             sub PDL::Complex::msyminv {
1299             my $m = shift;
1300             my $upper = @_ ? (1 - shift) : pdl (long,1);
1301             my ($ipiv , $info);
1302             my(@dims) = $m->dims;
1303              
1304             barf("msyminv: Require square array(s)")
1305             if( $dims[1] != $dims[2] );
1306              
1307             $m = $m->copy() unless $m->is_inplace(0);
1308              
1309             $ipiv = zeroes(long, @dims[2..$#dims]);
1310             @dims = @dims[3..$#dims];
1311             $info = @dims ? zeroes(long,@dims) : pdl(long,0);
1312              
1313             $m->csytrf($upper, $ipiv, $info);
1314             if($info->max > 0 && $_laerror) {
1315             my ($index,@list);
1316             $index = which($info > 0)+1;
1317             @list = $index->list;
1318             laerror("msyminv: Block diagonal matrix D (PDL(s) @list) is/are singular(s) (after csytrf factorization): \$info = $info");
1319             }
1320             else{
1321             $m->csytri($upper,$ipiv,$info);
1322             $m = $m->xchg(1,2)->tritosym($upper, 0);
1323             }
1324             return wantarray ? ($m, $info) : $m;
1325             }
1326              
1327             =head2 mposinv
1328              
1329             =for ref
1330              
1331             Computes inverse of a symmetric positive definite square matrix using Cholesky factorization.
1332             Supports inplace and threading.
1333             Uses L and L or
1334             L and L
1335             from Lapack and returns C in array context.
1336              
1337             =for usage
1338              
1339             (PDL, (PDL(info))) = mposinv(PDL, SCALAR|PDL(uplo))
1340             uplo : UPPER = 0 | LOWER = 1, default = 0
1341              
1342             =for example
1343              
1344             # Assume $a is symmetric positive definite
1345             my $a = random(10,10);
1346             $a = $a->crossprod($a);
1347             my $inv = mposinv($a);
1348              
1349             =cut
1350              
1351             sub mposinv {
1352             my $m = shift;
1353             $m->mposinv(@_);
1354             }
1355              
1356             sub PDL::mposinv {
1357             my $m = shift;
1358             my $upper = @_ ? (1 - shift) : pdl (long,1);
1359             my(@dims) = $m->dims;
1360              
1361             barf("mposinv: Require square array(s)")
1362             unless( $dims[0] == $dims[1] );
1363              
1364             $m = $m->copy() unless $m->is_inplace(0);
1365             @dims = @dims[2..$#dims];
1366             my $info = @dims ? zeroes(long,@dims) : pdl(long,0);
1367              
1368             $m->potrf($upper, $info);
1369             if($info->max > 0 && $_laerror) {
1370             my ($index,@list);
1371             $index = which($info > 0)+1;
1372             @list = $index->list;
1373             laerror("mposinv: matrix (PDL(s) @list) is/are not positive definite(s) (after potrf factorization): \$info = $info");
1374             }
1375             else{
1376             $m->potri($upper, $info);
1377             }
1378             return wantarray ? ($m, $info) : $m;
1379             }
1380              
1381             sub PDL::Complex::mposinv {
1382             my $m = shift;
1383             my $upper = @_ ? (1 - shift) : pdl (long,1);
1384             my(@dims) = $m->dims;
1385              
1386              
1387             barf("mposinv: Require square array(s)")
1388             unless( $dims[1] == $dims[2] );
1389              
1390             $m = $m->copy() unless $m->is_inplace(0);
1391             @dims = @dims[3..$#dims];
1392             my $info = @dims ? zeroes(long,@dims) : pdl(long,0);
1393              
1394             $m->cpotrf($upper, $info);
1395             if($info->max > 0 && $_laerror) {
1396             my ($index,@list);
1397             $index = which($info > 0)+1;
1398             @list = $index->list;
1399             laerror("mposinv: matrix (PDL(s) @list) is/are not positive definite(s) (after cpotrf factorization): \$info = $info");
1400             }
1401             else{
1402             $m->cpotri($upper, $info);
1403             }
1404             return wantarray ? ($m, $info) : $m;
1405             }
1406              
1407             =head2 mpinv
1408              
1409             =for ref
1410              
1411             Computes pseudo-inverse (Moore-Penrose) of a general matrix.
1412             Works on transposed array.
1413              
1414             =for usage
1415              
1416             PDL(pseudo-inv) = mpinv(PDL, SCALAR(tol))
1417             TOL: tolerance value, default : mnorm(dims(PDL),'inf') * mnorm(PDL) * EPS
1418              
1419             =for example
1420              
1421             my $a = random(5,10);
1422             my $inv = mpinv($a);
1423              
1424             =cut
1425              
1426             *mpinv = \&PDL::mpinv;
1427              
1428             sub PDL::mpinv{
1429             my ($m, $tol) = @_;
1430             my @dims = $m->dims;
1431             barf("mpinv: Require a matrix")
1432             unless( @dims == 2 or @dims == 3 );
1433            
1434             my ($ind, $cind, $u, $s, $v, $info, $err);
1435              
1436             $err = setlaerror(NO);
1437             #TODO: don't transpose
1438             ($u, $s, $v, $info) = $m->mdsvd(2);
1439             setlaerror($err);
1440             laerror("mpinv: SVD algorithm did not converge\n") if $info;
1441              
1442             unless (defined $tol){
1443             $tol = ($dims[-1] > $dims[-2] ? $dims[-1] : $dims[-2]) * $s((0)) * lamch(pdl($m->type,3));
1444             }
1445              
1446              
1447             ($ind, $cind) = which_both( $s > $tol );
1448             $s->index($cind) .= 0 if defined $cind;
1449             $s->index($ind) .= 1/$s->index($ind) ;
1450              
1451             $ind = (@dims == 3) ? ($v->t * $s->r2C ) x $u->t :
1452             ($v->xchg(0,1) * $s ) x $u->xchg(0,1);
1453             return wantarray ? ($ind, $info) : $ind;
1454              
1455             }
1456              
1457              
1458              
1459             =head2 mlu
1460              
1461             =for ref
1462              
1463             Computes LU factorization.
1464             Uses L or L
1465             from Lapack and returns L, U, pivot and info.
1466             Works on transposed array.
1467              
1468             =for usage
1469              
1470             (PDL(l), PDL(u), PDL(pivot), PDL(info)) = mlu(PDL)
1471              
1472             =for example
1473              
1474             my $a = random(10,10);
1475             ($l, $u, $pivot, $info) = mlu($a);
1476              
1477             =cut
1478              
1479             *mlu = \&PDL::mlu;
1480              
1481             sub PDL::mlu {
1482             my $m = shift;
1483             my(@dims) = $m->dims;
1484             barf("mlu: Require a matrix")
1485             unless((@dims == 2) || (@dims == 3));
1486             my ($ipiv, $info, $l, $u);
1487              
1488             $m = $m->copy;
1489             $info = pdl(long ,0);
1490             $ipiv = zeroes(long, ($dims[-2] > $dims[-1] ? $dims[-1]: $dims[-2]));
1491              
1492             if (@dims == 3){
1493             $m->t->cgetrf($ipiv,$info);
1494             if($info > 0) {
1495             $info--;
1496             laerror("mlu: Factor U is singular: U($info,$info) = 0 (after cgetrf factorization)");
1497             $u = $l = $m;
1498             }
1499             else{
1500             $u = $m->mtri;
1501             $l = $m->mtri(1);
1502             if ($dims[-1] > $dims[-2]){
1503             $u = $u(,,:($dims[0]-1));
1504             $l((0), :($dims[0]-1), :($dims[0]-1))->diagonal(0,1) .= 1;
1505             $l((1), :($dims[0]-1), :($dims[0]-1))->diagonal(0,1) .= 0;
1506             }
1507             elsif($dims[-1] < $dims[-2]){
1508             $l = $l(,:($dims[1]-1),);
1509             $l((0),,)->diagonal(0,1).=1;
1510             $l((1),,)->diagonal(0,1).=0;
1511             }
1512             else{
1513             $l((0),,)->diagonal(0,1).=1;
1514             $l((1),,)->diagonal(0,1).=0;
1515             }
1516             }
1517             }
1518             else{
1519             $m->t->getrf($ipiv,$info);
1520             if($info > 0) {
1521             $info--;
1522             laerror("mlu: Factor U is singular: U($info,$info) = 0 (after getrf factorization)");
1523             $u = $l = $m;
1524             }
1525             else{
1526             $u = $m->mtri;
1527             $l = $m->mtri(1);
1528             if ($dims[1] > $dims[0]){
1529             $u = $u(,:($dims[0]-1))->sever;
1530             $l( :($dims[0]-1), :($dims[0]-1))->diagonal(0,1) .= 1;
1531             }
1532             elsif($dims[1] < $dims[0]){
1533             $l = $l(:($dims[1]-1),)->sever;
1534             $l->diagonal(0,1) .= 1;
1535             }
1536             else{
1537             $l->diagonal(0,1).=1;
1538             }
1539             }
1540             }
1541             $l, $u, $ipiv, $info;
1542             }
1543              
1544             =head2 mchol
1545              
1546             =for ref
1547              
1548             Computes Cholesky decomposition of a symmetric matrix also knows as symmetric square root.
1549             If inplace flag is set, overwrite the leading upper or lower triangular part of A else returns
1550             triangular matrix. Returns C in array context.
1551             Supports threading.
1552             Uses L or L from Lapack.
1553              
1554             =for usage
1555              
1556             PDL(Cholesky) = mchol(PDL, SCALAR)
1557             SCALAR : UPPER = 0 | LOWER = 1, default = 0
1558              
1559             =for example
1560              
1561             my $a = random(10,10);
1562             $a = crossprod($a, $a);
1563             my $u = mchol($a);
1564              
1565             =cut
1566              
1567             sub mchol {
1568             my $m = shift;
1569             $m->mchol(@_);
1570             }
1571              
1572             sub PDL::mchol {
1573             my($m, $upper) = @_;
1574             my(@dims) = $m->dims;
1575             barf("mchol: Require square array(s)")
1576             if ( $dims[0] != $dims[1] );
1577              
1578             my ($uplo, $info);
1579              
1580             $m = $m->mtri($upper) unless $m->is_inplace(0);
1581             @dims = @dims[2..$#dims];
1582             $info = @dims ? zeroes(long,@dims) : pdl(long,0);
1583             $uplo = 1 - $upper;
1584             $m->potrf($uplo,$info);
1585              
1586             if($info->max > 0 && $_laerror) {
1587             my ($index,@list);
1588             $index = which($info > 0)+1;
1589             @list = $index->list;
1590             laerror("mchol: matrix (PDL(s) @list) is/are not positive definite(s) (after potrf factorization): \$info = $info");
1591             }
1592             return wantarray ? ($m, $info) : $m;
1593            
1594             }
1595              
1596             sub PDL::Complex::mchol {
1597             my($m, $upper) = @_;
1598             my(@dims) = $m->dims;
1599             barf("mchol: Require square array(s)")
1600             if ( $dims[1] != $dims[2] );
1601              
1602             my ($uplo, $info);
1603              
1604             $m = $m->mtri($upper) unless $m->is_inplace(0);
1605             @dims = @dims[3..$#dims];
1606             $info = @dims ? zeroes(long,@dims) : pdl(long,0);
1607             $uplo = 1 - $upper;
1608             $m->cpotrf($uplo,$info);
1609              
1610             if($info->max > 0 && $_laerror) {
1611             my ($index,@list);
1612             $index = which($info > 0)+1;
1613             @list = $index->list;
1614             laerror("mchol: matrix (PDL(s) @list) is/are not positive definite(s) (after cpotrf factorization): \$info = $info");
1615             }
1616             return wantarray ? ($m, $info) : $m;
1617            
1618             }
1619              
1620             =head2 mhessen
1621              
1622             =for ref
1623              
1624             Reduces a square matrix to Hessenberg form H and orthogonal matrix Q.
1625              
1626             It reduces a general matrix A to upper Hessenberg form H by an orthogonal
1627             similarity transformation:
1628              
1629             Q' x A x Q = H
1630              
1631             or
1632              
1633             A = Q x H x Q'
1634              
1635             Uses L and L or
1636             L and L
1637             from Lapack and returns C in scalar context else C and C.
1638             Works on transposed array.
1639              
1640             =for usage
1641              
1642             (PDL(h), (PDL(q))) = mhessen(PDL)
1643              
1644             =for example
1645              
1646             my $a = random(10,10);
1647             ($h, $q) = mhessen($a);
1648              
1649             =cut
1650              
1651             *mhessen = \&PDL::mhessen;
1652              
1653             sub PDL::mhessen {
1654             my $m = shift;
1655             my(@dims) = $m->dims;
1656             barf("mhessen: Require a square matrix")
1657             unless( ((@dims == 2) || (@dims == 3)) && $dims[-1] == $dims[-2] );
1658              
1659             my ($info, $tau, $h, $q);
1660            
1661             $m = $m->t->copy;
1662             $info = pdl(long, 0);
1663             if(@dims == 3){
1664             $tau = zeroes($m->type, 2, ($dims[-2]-1));
1665             $m->cgehrd(1,$dims[-2],$tau,$info);
1666             if (wantarray){
1667             $q = $m->copy;
1668             $q->cunghr(1, $dims[-2], $tau, $info);
1669             }
1670             $m = $m->xchg(1,2);
1671             $h = $m->mtri;
1672             $h((0),:-2, 1:)->diagonal(0,1) .= $m((0),:-2, 1:)->diagonal(0,1);
1673             $h((1),:-2, 1:)->diagonal(0,1) .= $m((1),:-2, 1:)->diagonal(0,1);
1674             }
1675             else{
1676             $tau = zeroes($m->type, ($dims[0]-1));
1677             $m->gehrd(1,$dims[0],$tau,$info);
1678             if (wantarray){
1679             $q = $m->copy;
1680             $q->orghr(1, $dims[0], $tau, $info);
1681             }
1682             $m = $m->xchg(0,1);
1683             $h = $m->mtri;
1684             $h(:-2, 1:)->diagonal(0,1) .= $m(:-2, 1:)->diagonal(0,1);
1685             }
1686             wantarray ? return ($h, $q->xchg(-2,-1)->sever) : $h;
1687             }
1688              
1689              
1690             =head2 mschur
1691              
1692             =for ref
1693              
1694             Computes Schur form, works inplace.
1695              
1696             A = Z x T x Z'
1697              
1698             Supports threading for unordered eigenvalues.
1699             Uses L or L
1700             from Lapack and returns schur(T) in scalar context.
1701             Works on tranposed array(s).
1702              
1703             =for usage
1704              
1705             ( PDL(schur), (PDL(eigenvalues), (PDL(left schur vectors), PDL(right schur vectors), $sdim), $info) ) = mschur(PDL(A), SCALAR(schur vector),SCALAR(left eigenvector), SCALAR(right eigenvector),SCALAR(select_func), SCALAR(backtransform), SCALAR(norm))
1706             schur vector : Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0
1707             left eigenvector : Left eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0
1708             right eigenvector : Right eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0
1709             select_func : Select_func is used to select eigenvalues to sort
1710             to the top left of the Schur form.
1711             An eigenvalue is selected if PerlInt select_func(PDL::Complex(w)) is true;
1712             Note that a selected complex eigenvalue may no longer
1713             satisfy select_func(PDL::Complex(w)) = 1 after ordering, since
1714             ordering may change the value of complex eigenvalues
1715             (especially if the eigenvalue is ill-conditioned).
1716             All eigenvalues/vectors are selected if select_func is undefined.
1717             backtransform : Whether or not backtransforms eigenvectors to those of A.
1718             Only supported if schur vectors are computed, default = 1.
1719             norm : Whether or not computed eigenvectors are normalized to have Euclidean norm equal to
1720             1 and largest component real, default = 1
1721              
1722             Returned values :
1723             Schur form T (SCALAR CONTEXT),
1724             eigenvalues,
1725             Schur vectors (Z) if requested,
1726             left eigenvectors if requested
1727             right eigenvectors if requested
1728             sdim: Number of eigenvalues selected if select_func is defined.
1729             info: Info output from gees/cgees.
1730              
1731             =for example
1732              
1733             my $a = random(10,10);
1734             my $schur = mschur($a);
1735             sub select{
1736             my $m = shift;
1737             # select "discrete time" eigenspace
1738             return $m->Cabs < 1 ? 1 : 0;
1739             }
1740             my ($schur,$eigen, $svectors,$evectors) = mschur($a,1,1,0,\&select);
1741              
1742             =cut
1743              
1744              
1745             sub mschur{
1746             my $m = shift;
1747             $m->mschur(@_);
1748              
1749             }
1750              
1751             sub PDL::mschur{
1752             my ($m, $jobv, $jobvl, $jobvr, $select_func, $mult,$norm) = @_;
1753             my(@dims) = $m->dims;
1754              
1755             barf("mschur: Require square array(s)")
1756             unless($dims[0] == $dims[1]);
1757             barf("mschur: thread doesn't supported for selected vectors")
1758             if ($select_func && @dims > 2 && ($jobv == 2 || $jobvl == 2 || $jobvr == 2));
1759              
1760             my ($w, $v, $info, $type, $select,$sdim, $vr,$vl, $mm, @ret, $select_f, $wi, $wtmp);
1761              
1762             $mult = 1 unless defined($mult);
1763             $norm = 1 unless defined($norm);
1764             $jobv = $jobvl = $jobvr = 0 unless wantarray;
1765             $type = $m->type;
1766             $select = $select_func ? pdl(long,1) : pdl(long,0);
1767              
1768             $info = null;
1769             $sdim = null;
1770             $wtmp = null;
1771             $wi = null;
1772              
1773             $mm = $m->is_inplace ? $m->xchg(0,1) : $m->xchg(0,1)->copy;
1774             if ($select_func){
1775             $select_f= sub{
1776             &$select_func(PDL::Complex::complex(pdl($type,@_[0..1])));
1777             };
1778             }
1779             $v = $jobv ? PDL::new_from_specification('PDL', $type, $dims[1], $dims[1],@dims[2..$#dims]) :
1780             pdl($type,0);
1781             $mm->gees( $jobv, $select, $wtmp, $wi, $v, $sdim,$info, $select_f);
1782              
1783             if ($info->max > 0 && $_laerror){
1784             my ($index, @list);
1785             $index = which((($info > 0)+($info <=$dims[0]))==2);
1786             unless ($index->isempty){
1787             @list = $index->list;
1788             laerror("mschur: The QR algorithm failed to converge for matrix (PDL(s) @list): \$info = $info");
1789             print ("Returning converged eigenvalues\n");
1790             }
1791             if ($select_func){
1792             $index = which((($info > 0)+($info == ($dims[0]+1) ))==2);
1793             unless ($index->isempty){
1794             @list = $index->list;
1795             laerror("mschur: The eigenvalues could not be reordered because some\n".
1796             "eigenvalues were too close to separate (the problem".
1797             "is very ill-conditioned) for PDL(s) @list: \$info = $info");
1798             }
1799             $index = which((($info > 0)+($info > ($dims[0]+1) ))==2);
1800             unless ($index->isempty){
1801             @list = $index->list;
1802             warn("mschur: The Schur form no longer satisfy select_func = 1\n because of roundoff".
1803             "or underflow (PDL(s) @list)\n");
1804             }
1805             }
1806             }
1807             if ($select_func){
1808             if ($jobvl == 2){
1809             if(!$sdim){
1810             push @ret, PDL::Complex->null;
1811             $jobvl = 0;
1812             }
1813             }
1814             if ($jobvr == 2){
1815             if(!$sdim){
1816             push @ret, PDL::Complex->null;
1817             $jobvr = 0;
1818             }
1819             }
1820             push @ret, $sdim;
1821             }
1822             if ($jobvl || $jobvr){
1823             my ($sel, $job, $wtmpi, $wtmpr, $sdims);
1824             unless ($jobvr && $jobvl){
1825             $job = $jobvl ? 2 : 1;
1826             }
1827             if ($select_func){
1828             if ($jobvl == 1 || $jobvr == 1 || $mult){
1829             $sdims = null;
1830             if ($jobv){
1831             $vr = $v->copy if $jobvr;
1832             $vl = $v->copy if $jobvl;
1833             }
1834             else{
1835             $vr = PDL::new_from_specification('PDL', $type, $dims[1], $dims[1],@dims[2..$#dims]) if $jobvr;
1836             $vl = PDL::new_from_specification('PDL', $type, $dims[1], $dims[1],@dims[2..$#dims]) if $jobvl;
1837             $mult = 0;
1838             }
1839             $mm->trevc($job, $mult, $sel, $vl, $vr, $sdims, my $infos=null);
1840             if ($jobvr){
1841             if($norm){
1842             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr,1);
1843             bless $vr, 'PDL::Complex';
1844             unshift @ret, $jobvr == 2 ? $vr(,,:($sdim-1))->norm(1,1) : $vr->norm(1,1);
1845              
1846             }
1847             else{
1848             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr->xchg(0,1),0);
1849             bless $vr, 'PDL::Complex';
1850             unshift @ret, $jobvr == 2 ? $vr(,:($sdim-1))->sever : $vr;
1851             }
1852             }
1853             if ($jobvl){
1854             if($norm){
1855             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl,1);
1856             bless $vl, 'PDL::Complex';
1857             unshift @ret, $jobvl == 2 ? $vl(,,:($sdim-1))->norm(1,1) : $vl->norm(1,1);
1858             }
1859             else{
1860             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl->xchg(0,1),0);
1861             bless $vl, 'PDL::Complex';
1862             unshift @ret, $jobvl == 2 ? $vl(,:($sdim-1))->sever : $vl;
1863             }
1864             }
1865             }
1866             else{
1867             $vr = PDL::new_from_specification('PDL', $type, $dims[1], $sdim) if $jobvr;
1868             $vl = PDL::new_from_specification('PDL', $type, $dims[1], $sdim) if $jobvl;
1869             $sel = zeroes($dims[1]);
1870             $sel(:($sdim-1)) .= 1;
1871             $mm->trevc($job, 2, $sel, $vl, $vr, $sdim, my $infos = null);
1872             $wtmpr = $wtmp(:($sdim-1));
1873             $wtmpi = $wi(:($sdim-1));
1874             if ($jobvr){
1875             if ($norm){
1876             (undef,$vr) = $wtmpr->cplx_eigen($wtmpi,$vr,1);
1877             bless $vr, 'PDL::Complex';
1878             unshift @ret, $vr->norm(1,1);
1879             }
1880             else{
1881             (undef,$vr) = $wtmpr->cplx_eigen($wtmpi,$vr->xchg(0,1),0);
1882             bless $vr, 'PDL::Complex';
1883             unshift @ret,$vr;
1884             }
1885             }
1886             if ($jobvl){
1887             if ($norm){
1888             (undef,$vl) = $wtmpr->cplx_eigen($wtmpi,$vl,1);
1889             bless $vl, 'PDL::Complex';
1890             unshift @ret, $vl->norm(1,1);
1891              
1892             }
1893             else{
1894             (undef,$vl) = $wtmpr->cplx_eigen($wtmpi,$vl->xchg(0,1),0);
1895             bless $vl, 'PDL::Complex';
1896             unshift @ret, $vl;
1897             }
1898             }
1899             }
1900             }
1901             else{
1902             if ($jobv){
1903             $vr = $v->copy if $jobvr;
1904             $vl = $v->copy if $jobvl;
1905             }
1906             else{
1907             $vr = PDL::new_from_specification('PDL', $type, $dims[1], $dims[1],@dims[2..$#dims]) if $jobvr;
1908             $vl = PDL::new_from_specification('PDL', $type, $dims[1], $dims[1],@dims[2..$#dims]) if $jobvl;
1909             $mult = 0;
1910             }
1911             $mm->trevc($job, $mult, $sel, $vl, $vr, $sdim, my $infos=null);
1912             if ($jobvr){
1913             if ($norm){
1914             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr,1);
1915             bless $vr, 'PDL::Complex';
1916             unshift @ret, $vr->norm(1,1);
1917             }
1918             else{
1919             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr->xchg(0,1),0);
1920             bless $vr, 'PDL::Complex';
1921             unshift @ret, $vr;
1922             }
1923             }
1924             if ($jobvl){
1925             if ($norm){
1926             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl,1);
1927             bless $vl, 'PDL::Complex';
1928             unshift @ret, $vl->norm(1,1);
1929             }
1930             else{
1931             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl->xchg(0,1),0);
1932             bless $vl, 'PDL::Complex';
1933             unshift @ret, $vl;
1934             }
1935             }
1936             }
1937             }
1938             $w = PDL::Complex::ecplx ($wtmp, $wi);
1939              
1940             if ($jobv == 2 && $select_func) {
1941             $v = $sdim > 0 ? $v->xchg(0,1)->(:($sdim-1),)->sever : null;
1942             unshift @ret,$v;
1943             }
1944             elsif($jobv){
1945             $v = $v->xchg(0,1)->sever;
1946             unshift @ret,$v;
1947             }
1948             $m = $mm->xchg(0,1)->sever unless $m->is_inplace(0);
1949             return wantarray ? ($m, $w, @ret, $info) : $m;
1950            
1951             }
1952              
1953             sub PDL::Complex::mschur {
1954             my($m, $jobv, $jobvl, $jobvr, $select_func, $mult, $norm) = @_;
1955             my(@dims) = $m->dims;
1956              
1957             barf("mschur: Require square array(s)")
1958             unless($dims[1] == $dims[2]);
1959             barf("mschur: thread doesn't supported for selected vectors")
1960             if ($select_func && @dims > 3 && ($jobv == 2 || $jobvl == 2 || $jobvr == 2));
1961              
1962             my ($w, $v, $info, $type, $select,$sdim, $vr,$vl, $mm, @ret);
1963              
1964             $mult = 1 unless defined($mult);
1965             $norm = 1 unless defined($norm);
1966             $jobv = $jobvl = $jobvr = 0 unless wantarray;
1967             $type = $m->type;
1968             $select = $select_func ? pdl(long,1) : pdl(long,0);
1969              
1970             $info = null;
1971             $sdim = null;
1972              
1973             $mm = $m->is_inplace ? $m->xchg(1,2) : $m->xchg(1,2)->copy;
1974             $w = PDL::Complex->null;
1975             $v = $jobv ? PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1],@dims[3..$#dims]) :
1976             pdl($type,[0,0]);
1977              
1978             $mm->cgees( $jobv, $select, $w, $v, $sdim, $info, $select_func);
1979              
1980             if ($info->max > 0 && $_laerror){
1981             my ($index, @list);
1982             $index = which((($info > 0)+($info <=$dims[1]))==2);
1983             unless ($index->isempty){
1984             @list = $index->list;
1985             laerror("mschur: The QR algorithm failed to converge for matrix (PDL(s) @list): \$info = $info");
1986             print ("Returning converged eigenvalues\n");
1987             }
1988             if ($select_func){
1989             $index = which((($info > 0)+($info == ($dims[1]+1) ))==2);
1990             unless ($index->isempty){
1991             @list = $index->list;
1992             laerror("mschur: The eigenvalues could not be reordered because some\n".
1993             "eigenvalues were too close to separate (the problem".
1994             "is very ill-conditioned) for PDL(s) @list: \$info = $info");
1995             }
1996             $index = which((($info > 0)+($info > ($dims[1]+1) ))==2);
1997             unless ($index->isempty){
1998             @list = $index->list;
1999             warn("mschur: The Schur form no longer satisfy select_func = 1\n because of roundoff".
2000             "or underflow (PDL(s) @list)\n");
2001             }
2002             }
2003             }
2004              
2005             if ($select_func){
2006             if ($jobvl == 2){
2007             if (!$sdim){
2008             push @ret, PDL::Complex->null;
2009             $jobvl = 0;
2010             }
2011             }
2012             if ($jobvr == 2){
2013             if (!$sdim){
2014             push @ret, PDL::Complex->null;
2015             $jobvr = 0;
2016             }
2017             }
2018             push @ret, $sdim;
2019             }
2020             if ($jobvl || $jobvr){
2021             my ($sel, $job, $sdims);
2022             unless ($jobvr && $jobvl){
2023             $job = $jobvl ? 2 : 1;
2024             }
2025             if ($select_func){
2026             if ($jobvl == 1 || $jobvr == 1 || $mult){
2027             $sdims = null;
2028             if ($jobv){
2029             $vr = $v->copy if $jobvr;
2030             $vl = $v->copy if $jobvl;
2031             }
2032             else{
2033             $vr = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1],@dims[3..$#dims]) if $jobvr;
2034             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1],@dims[3..$#dims]) if $jobvl;
2035             $mult = 0;
2036             }
2037             $mm->ctrevc($job, $mult, $sel, $vl, $vr, $sdims, my $infos=null);
2038             if ($jobvr){
2039             if ($jobvr == 2){
2040             unshift @ret, $norm ? $vr(,,:($sdim-1))->norm(1,1) :
2041             $vr(,,:($sdim-1))->xchg(1,2)->sever;
2042             }
2043             else{
2044             unshift @ret, $norm ? $vr->norm(1,1) : $vr->xchg(1,2)->sever;
2045             }
2046             }
2047             if ($jobvl){
2048             if ($jobvl == 2){
2049             unshift @ret, $norm ? $vl(,,:($sdim-1))->norm(1,1) :
2050             $vl(,,:($sdim-1))->xchg(1,2)->sever;
2051             }
2052             else{
2053             unshift @ret, $norm ? $vl->norm(1,1) : $vl->xchg(1,2)->sever;
2054             }
2055             }
2056             }
2057             else{
2058             $vr = PDL::new_from_specification('PDL::Complex', $type, 2,$dims[1], $sdim) if $jobvr;
2059             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $sdim) if $jobvl;
2060             $sel = zeroes($dims[1]);
2061             $sel(:($sdim-1)) .= 1;
2062             $mm->ctrevc($job, 2, $sel, $vl, $vr, $sdim, my $infos=null);
2063             if ($jobvr){
2064             unshift @ret, $norm ? $vr->norm(1,1) : $vr->xchg(1,2)->sever;
2065             }
2066             if ($jobvl){
2067             unshift @ret, $norm ? $vl->norm(1,1) : $vl->xchg(1,2)->sever;
2068             }
2069             }
2070             }
2071             else{
2072             if ($jobv){
2073             $vr = $v->copy if $jobvr;
2074             $vl = $v->copy if $jobvl;
2075             }
2076             else{
2077             $vr = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1],@dims[3..$#dims]) if $jobvr;
2078             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1],@dims[3..$#dims]) if $jobvl;
2079             $mult = 0;
2080             }
2081             $mm->ctrevc($job, $mult, $sel, $vl, $vr, $sdim, my $infos=null);
2082             if ($jobvl){
2083             push @ret, $norm ? $vl->norm(1,1) : $vl->xchg(1,2)->sever;
2084             }
2085             if ($jobvr){
2086             push @ret, $norm ? $vr->norm(1,1) : $vr->xchg(1,2)->sever;
2087             }
2088             }
2089             }
2090             if ($jobv == 2 && $select_func) {
2091             $v = $sdim > 0 ? $v->xchg(1,2)->(,:($sdim-1),) ->sever : PDL::Complex->null;
2092             unshift @ret,$v;
2093             }
2094             elsif($jobv){
2095             $v = $v->xchg(1,2)->sever;
2096             unshift @ret,$v;
2097             }
2098             $m = $mm->xchg(1,2)->sever unless $m->is_inplace(0);
2099             return wantarray ? ($m, $w, @ret, $info) : $m;
2100            
2101             }
2102              
2103              
2104              
2105             =head2 mschurx
2106              
2107             =for ref
2108              
2109             Computes Schur form, works inplace.
2110             Uses L or L
2111             from Lapack and returns schur(T) in scalar context.
2112             Works on transposed array.
2113              
2114             =for usage
2115              
2116             ( PDL(schur) (,PDL(eigenvalues)) (, PDL(schur vectors), HASH(result)) ) = mschurx(PDL, SCALAR(schur vector), SCALAR(left eigenvector), SCALAR(right eigenvector),SCALAR(select_func), SCALAR(sense), SCALAR(backtransform), SCALAR(norm))
2117             schur vector : Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0
2118             left eigenvector : Left eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0
2119             right eigenvector : Right eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0
2120             select_func : Select_func is used to select eigenvalues to sort
2121             to the top left of the Schur form.
2122             An eigenvalue is selected if PerlInt select_func(PDL::Complex(w)) is true;
2123             Note that a selected complex eigenvalue may no longer
2124             satisfy select_func(PDL::Complex(w)) = 1 after ordering, since
2125             ordering may change the value of complex eigenvalues
2126             (especially if the eigenvalue is ill-conditioned).
2127             All eigenvalues/vectors are selected if select_func is undefined.
2128             sense : Determines which reciprocal condition numbers will be computed.
2129             0: None are computed
2130             1: Computed for average of selected eigenvalues only
2131             2: Computed for selected right invariant subspace only
2132             3: Computed for both
2133             If select_func is undefined, sense is not used.
2134             backtransform : Whether or not backtransforms eigenvectors to those of A.
2135             Only supported if schur vector are computed, default = 1
2136             norm : Whether or not computed eigenvectors are normalized to have Euclidean norm equal to
2137             1 and largest component real, default = 1
2138              
2139             Returned values :
2140             Schur form T (SCALAR CONTEXT),
2141             eigenvalues,
2142             Schur vectors if requested,
2143             HASH{VL}: left eigenvectors if requested
2144             HASH{VR}: right eigenvectors if requested
2145             HASH{info}: info output from gees/cgees.
2146             if select_func is defined:
2147             HASH{n}: number of eigenvalues selected,
2148             HASH{rconde}: reciprocal condition numbers for the average of
2149             the selected eigenvalues if requested,
2150             HASH{rcondv}: reciprocal condition numbers for the selected
2151             right invariant subspace if requested.
2152              
2153             =for example
2154              
2155             my $a = random(10,10);
2156             my $schur = mschurx($a);
2157             sub select{
2158             my $m = shift;
2159             # select "discrete time" eigenspace
2160             return $m->Cabs < 1 ? 1 : 0;
2161             }
2162             my ($schur,$eigen, $vectors,%ret) = mschurx($a,1,0,0,\&select);
2163              
2164             =cut
2165              
2166              
2167             *mschurx = \&PDL::mschurx;
2168              
2169             sub PDL::mschurx{
2170             my($m, $jobv, $jobvl, $jobvr, $select_func, $sense, $mult,$norm) = @_;
2171             my(@dims) = $m->dims;
2172              
2173             barf("mschur: Require a square matrix")
2174             unless( ( (@dims == 2)|| (@dims == 3) )&& $dims[-1] == $dims[-2]);
2175              
2176             my ($w, $v, $info, $type, $select, $sdim, $rconde, $rcondv, %ret, $mm, $vl, $vr);
2177              
2178             $mult = 1 unless defined($mult);
2179             $norm = 1 unless defined($norm);
2180             $jobv = $jobvl = $jobvr = 0 unless wantarray;
2181             $type = $m->type;
2182             if ($select_func){
2183             $select = pdl(long 1);
2184             }
2185             else{
2186             $select = pdl(long,0);
2187             $sense = pdl(long,0);
2188             }
2189              
2190             $info = null;
2191             $sdim = null;
2192             $rconde = null;
2193             $rcondv = null;
2194             $mm = $m->is_inplace ? $m->xchg(-1,-2) : $m->xchg(-1,-2)->copy;
2195              
2196             if (@dims == 3){
2197             $w = PDL::Complex->null;
2198             $v = $jobv ? PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1]) :
2199             pdl($type,[0,0]);
2200             $mm->cgeesx( $jobv, $select, $sense, $w, $v, $sdim, $rconde, $rcondv,$info, $select_func);
2201              
2202             if ($info){
2203             if ($info < $dims[1]){
2204             laerror("mschurx: The QR algorithm failed to converge");
2205             print ("Returning converged eigenvalues\n") if $_laerror;
2206             }
2207             laerror("mschurx: The eigenvalues could not be reordered because some\n".
2208             "eigenvalues were too close to separate (the problem".
2209             "is very ill-conditioned)")
2210             if $info == ($dims[1] + 1);
2211             warn("mschurx: The Schur form no longer satisfy select_func = 1\n because of roundoff or underflow\n")
2212             if ($info > ($dims[1] + 1) and $_laerror);
2213             }
2214              
2215             if ($select_func){
2216             if(!$sdim){
2217             if ($jobvl == 2){
2218             $ret{VL} = PDL::Complex->null;
2219             $jobvl = 0;
2220             }
2221             if ($jobvr == 2){
2222             $ret{VR} = PDL::Complex->null;
2223             $jobvr = 0;
2224             }
2225             }
2226             $ret{n} = $sdim;
2227             }
2228             if ($jobvl || $jobvr){
2229             my ($sel, $job, $sdims);
2230             unless ($jobvr && $jobvl){
2231             $job = $jobvl ? 2 : 1;
2232             }
2233             if ($select_func){
2234             if ($jobvl == 1 || $jobvr == 1 || $mult){
2235             $sdims = null;
2236             if ($jobv){
2237             $vr = $v->copy if $jobvr;
2238             $vl = $v->copy if $jobvl;
2239             }
2240             else{
2241             $vr = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1]) if $jobvr;
2242             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1]) if $jobvl;
2243             $mult = 0;
2244             }
2245             $mm->ctrevc($job, $mult, $sel, $vl, $vr, $sdims, my $infos=null);
2246             if ($jobvr){
2247             if ($jobvr == 2){
2248             $ret{VR} = $norm ? $vr(,,:($sdim-1))->norm(1,1) :
2249             $vr(,,:($sdim-1))->xchg(1,2)->sever;
2250             }
2251             else{
2252             $ret{VR} = $norm ? $vr->norm(1,1) : $vr->xchg(1,2)->sever;
2253             }
2254             }
2255             if ($jobvl){
2256             if ($jobvl == 2){
2257             $ret{VL} = $norm ? $vl(,,:($sdim-1))->norm(1,1) :
2258             $vl(,,:($sdim-1))->xchg(1,2)->sever;
2259             }
2260             else{
2261             $ret{VL} = $norm ? $vl->norm(1,1) : $vl->xchg(1,2)->sever;
2262             }
2263             }
2264             }
2265             else{
2266             $vr = PDL::new_from_specification('PDL::Complex', $type, 2,$dims[1], $sdim) if $jobvr;
2267             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $sdim) if $jobvl;
2268             $sel = zeroes($dims[1]);
2269             $sel(:($sdim-1)) .= 1;
2270             $mm->ctrevc($job, 2, $sel, $vl, $vr, $sdim, my $infos=null);
2271             if ($jobvr){
2272             $ret{VL} = $norm ? $vr->norm(1,1) : $vr->xchg(1,2)->sever;
2273             }
2274             if ($jobvl){
2275             $ret{VL} = $norm ? $vl->norm(1,1) : $vl->xchg(1,2)->sever;
2276             }
2277             }
2278             }
2279             else{
2280             if ($jobv){
2281             $vr = $v->copy if $jobvr;
2282             $vl = $v->copy if $jobvl;
2283             }
2284             else{
2285             $vr = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1]) if $jobvr;
2286             $vl = PDL::new_from_specification('PDL::Complex', $type, $dims[1], 2, $dims[1]) if $jobvl;
2287             $mult = 0;
2288             }
2289             $mm->ctrevc($job, $mult, $sel, $vl, $vr, $sdim, my $infos=null);
2290             if ($jobvl){
2291             $ret{VL} = $norm ? $vl->norm(1,1) : $vl->xchg(1,2)->sever;
2292             }
2293             if ($jobvr){
2294             $ret{VR} = $norm ? $vr->norm(1,1) : $vr->xchg(1,2)->sever;
2295             }
2296             }
2297             }
2298             if ($jobv == 2 && $select_func) {
2299             $v = $sdim > 0 ? $v->xchg(1,2)->(,:($sdim-1),) ->sever : PDL::Complex->null;
2300             }
2301             elsif($jobv){
2302             $v = $v->xchg(1,2)->sever;
2303             }
2304              
2305             }
2306             else{
2307             my ($select_f, $wi, $wtmp);
2308             if ($select_func){
2309             no strict 'refs';
2310             $select_f= sub{
2311             &$select_func(PDL::Complex::complex(pdl($type,$_[0],$_[1])));
2312             };
2313             }
2314             $wi = null;
2315             $wtmp = null;
2316             $v = $jobv ? PDL::new_from_specification('PDL', $type, $dims[1], $dims[1]) :
2317             pdl($type,0);
2318             $mm->geesx( $jobv, $select, $sense, $wtmp, $wi, $v, $sdim, $rconde, $rcondv,$info, $select_f);
2319             if ($info){
2320             if ($info < $dims[0]){
2321             laerror("mschurx: The QR algorithm failed to converge");
2322             print ("Returning converged eigenvalues\n") if $_laerror;
2323             }
2324             laerror("mschurx: The eigenvalues could not be reordered because some\n".
2325             "eigenvalues were too close to separate (the problem".
2326             "is very ill-conditioned)")
2327             if $info == ($dims[0] + 1);
2328             warn("mschurx: The Schur form no longer satisfy select_func = 1\n because of roundoff or underflow\n")
2329             if ($info > ($dims[0] + 1) and $_laerror);
2330             }
2331              
2332             if ($select_func){
2333             if(!$sdim){
2334             if ($jobvl == 2){
2335             $ret{VL} = null;
2336             $jobvl = 0;
2337             }
2338             if ($jobvr == 2){
2339             $ret{VR} = null;
2340             $jobvr = 0;
2341             }
2342             }
2343             $ret{n} = $sdim;
2344             }
2345             if ($jobvl || $jobvr){
2346             my ($sel, $job, $wtmpi, $wtmpr, $sdims);
2347             unless ($jobvr && $jobvl){
2348             $job = $jobvl ? 2 : 1;
2349             }
2350             if ($select_func){
2351             if ($jobvl == 1 || $jobvr == 1 || $mult){
2352             $sdims = null;
2353             if ($jobv){
2354             $vr = $v->copy if $jobvr;
2355             $vl = $v->copy if $jobvl;
2356             }
2357             else{
2358             $vr = PDL::new_from_specification('PDL', $type, $dims[1], $dims[1]) if $jobvr;
2359             $vl = PDL::new_from_specification('PDL', $type, $dims[1], $dims[1]) if $jobvl;
2360             $mult = 0;
2361             }
2362             $mm->trevc($job, $mult, $sel, $vl, $vr, $sdims, my $infos=null);
2363              
2364             if ($jobvr){
2365             if($norm){
2366             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr,1);
2367             bless $vr, 'PDL::Complex';
2368             $ret{VR} = $jobvr == 2 ? $vr(,,:($sdim-1))->norm(1,1) : $vr->norm(1,1);
2369             }
2370             else{
2371             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr->xchg(0,1),0);
2372             bless $vr, 'PDL::Complex';
2373             $ret{VR} = $jobvr == 2 ? $vr(,:($sdim-1))->sever : $vr;
2374             }
2375             }
2376             if ($jobvl){
2377             if($norm){
2378             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl,1);
2379             bless $vl, 'PDL::Complex';
2380             $ret{VL}= $jobvl == 2 ? $vl(,,:($sdim-1))->norm(1,1) : $vl->norm(1,1);
2381             }
2382             else{
2383             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl->xchg(0,1),0);
2384             bless $vl, 'PDL::Complex';
2385             $ret{VL}= $jobvl == 2 ? $vl(,:($sdim-1))->sever : $vl;
2386             }
2387             }
2388             }
2389             else{
2390             $vr = PDL::new_from_specification('PDL', $type, $dims[1], $sdim) if $jobvr;
2391             $vl = PDL::new_from_specification('PDL', $type, $dims[1], $sdim) if $jobvl;
2392             $sel = zeroes($dims[1]);
2393             $sel(:($sdim-1)) .= 1;
2394             $mm->trevc($job, 2, $sel, $vl, $vr, $sdim, my $infos = null);
2395             $wtmpr = $wtmp(:($sdim-1));
2396             $wtmpi = $wi(:($sdim-1));
2397              
2398             if ($jobvr){
2399             if ($norm){
2400             (undef,$vr) = $wtmpr->cplx_eigen($wtmpi,$vr,1);
2401             bless $vr, 'PDL::Complex';
2402             $ret{VR} = $vr->norm(1,1);
2403             }
2404             else{
2405             (undef,$vr) = $wtmpr->cplx_eigen($wtmpi,$vr->xchg(0,1),0);
2406             bless $vr, 'PDL::Complex';
2407             $ret{VR} = $vr;
2408             }
2409             }
2410             if ($jobvl){
2411             if ($norm){
2412             (undef,$vl) = $wtmpr->cplx_eigen($wtmpi,$vl,1);
2413             bless $vl, 'PDL::Complex';
2414             $ret{VL} = $vl->norm(1,1);
2415             }
2416             else{
2417             (undef,$vl) = $wtmpr->cplx_eigen($wtmpi,$vl->xchg(0,1),0);
2418             bless $vl, 'PDL::Complex';
2419             $ret{VL} = $vl;
2420             }
2421             }
2422             }
2423             }
2424             else{
2425             if ($jobv){
2426             $vr = $v->copy if $jobvr;
2427             $vl = $v->copy if $jobvl;
2428             }
2429             else{
2430             $vr = PDL::new_from_specification('PDL', $type, $dims[1], $dims[1]) if $jobvr;
2431             $vl = PDL::new_from_specification('PDL', $type, $dims[1], $dims[1]) if $jobvl;
2432             $mult = 0;
2433             }
2434             $mm->trevc($job, $mult, $sel, $vl, $vr, $sdim, my $infos=null);
2435             if ($jobvr){
2436             if ($norm){
2437             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr,1);
2438             bless $vr, 'PDL::Complex';
2439             $ret{VR} = $vr->norm(1,1);
2440             }
2441             else{
2442             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr->xchg(0,1),0);
2443             bless $vr, 'PDL::Complex';
2444             $ret{VR} = $vr;
2445             }
2446             }
2447             if ($jobvl){
2448             if ($norm){
2449             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl,1);
2450             bless $vl, 'PDL::Complex';
2451             $ret{VL} = $vl->norm(1,1);
2452             }
2453             else{
2454             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl->xchg(0,1),0);
2455             bless $vl, 'PDL::Complex';
2456             $ret{VL} = $vl;
2457             }
2458             }
2459             }
2460             }
2461             $w = PDL::Complex::ecplx ($wtmp, $wi);
2462              
2463             if ($jobv == 2 && $select_func) {
2464             $v = $sdim > 0 ? $v->xchg(0,1)->(:($sdim-1),) ->sever : null;
2465             }
2466             elsif($jobv){
2467             $v = $v->xchg(0,1)->sever;
2468             }
2469              
2470             }
2471              
2472            
2473             $ret{info} = $info;
2474             if ($sense){
2475             if ($sense == 3){
2476             $ret{rconde} = $rconde;
2477             $ret{rcondv} = $rcondv;
2478             }
2479             else{
2480             $ret{rconde} = $rconde if ($sense == 1);
2481             $ret{rcondv} = $rcondv if ($sense == 2);
2482             }
2483             }
2484             $m = $mm->xchg(-1,-2)->sever unless $m->is_inplace(0);
2485             return wantarray ? $jobv ? ($m, $w, $v, %ret) :
2486             ($m, $w, %ret) :
2487             $m;
2488             }
2489              
2490              
2491             # scale by max(abs(real)+abs(imag))
2492             sub magn_norm{
2493             my ($m, $trans) = @_;
2494            
2495             # If trans == true => transpose output matrice
2496            
2497            
2498             my $ret = PDL::abs($m);
2499             bless $ret,'PDL';
2500             $ret = PDL::sumover($ret)->maximum;
2501             return $trans ? PDL::Complex::Cscale($m->xchg(1,2),1/$ret->dummy(0)->xchg(0,1))->reshape(-1) :
2502             PDL::Complex::Cscale($m,1/$ret->dummy(0))->reshape(-1);
2503             }
2504              
2505              
2506              
2507              
2508             #TODO: inplace ?
2509              
2510             =head2 mgschur
2511              
2512             =for ref
2513              
2514             Computes generalized Schur decomposition of the pair (A,B).
2515              
2516             A = Q x S x Z'
2517             B = Q x T x Z'
2518              
2519             Uses L or L
2520             from Lapack.
2521             Works on transposed array.
2522              
2523             =for usage
2524              
2525             ( PDL(schur S), PDL(schur T), PDL(alpha), PDL(beta), HASH{result}) = mgschur(PDL(A), PDL(B), SCALAR(left schur vector),SCALAR(right schur vector),SCALAR(left eigenvector), SCALAR(right eigenvector), SCALAR(select_func), SCALAR(backtransform), SCALAR(scale))
2526             left schur vector : Left Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0
2527             right schur vector : Right Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0
2528             left eigenvector : Left eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0
2529             right eigenvector : Right eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0
2530             select_func : Select_func is used to select eigenvalues to sort.
2531             to the top left of the Schur form.
2532             An eigenvalue w = wr(j)+sqrt(-1)*wi(j) is selected if
2533             PerlInt select_func(PDL::Complex(alpha),PDL | PDL::Complex (beta)) is true;
2534             Note that a selected complex eigenvalue may no longer
2535             satisfy select_func = 1 after ordering, since
2536             ordering may change the value of complex eigenvalues
2537             (especially if the eigenvalue is ill-conditioned).
2538             All eigenvalues/vectors are selected if select_func is undefined.
2539             backtransform : Whether or not backtransforms eigenvectors to those of (A,B).
2540             Only supported if right and/or left schur vector are computed,
2541             scale : Whether or not computed eigenvectors are scaled so the largest component
2542             will have abs(real part) + abs(imag. part) = 1, default = 1
2543              
2544             Returned values :
2545             Schur form S,
2546             Schur form T,
2547             alpha,
2548             beta (eigenvalues = alpha/beta),
2549             HASH{info}: info output from gges/cgges.
2550             HASH{SL}: left Schur vectors if requested
2551             HASH{SR}: right Schur vectors if requested
2552             HASH{VL}: left eigenvectors if requested
2553             HASH{VR}: right eigenvectors if requested
2554             HASH{n} : Number of eigenvalues selected if select_func is defined.
2555              
2556             =for example
2557              
2558             my $a = random(10,10);
2559             my $b = random(10,10);
2560             my ($S,$T) = mgschur($a,$b);
2561             sub select{
2562             my ($alpha,$beta) = @_;
2563             return $alpha->Cabs < abs($beta) ? 1 : 0;
2564             }
2565             my ($S, $T, $alpha, $beta, %res) = mgschur( $a, $b, 1, 1, 1, 1,\&select);
2566              
2567             =cut
2568              
2569              
2570             sub mgschur{
2571             my $m = shift;
2572             $m->mgschur(@_);
2573             }
2574              
2575             sub PDL::mgschur{
2576             my($m, $p, $jobvsl, $jobvsr, $jobvl, $jobvr, $select_func, $mult, $norm) = @_;
2577             my @mdims = $m->dims;
2578             my @pdims = $p->dims;
2579              
2580             barf("mgschur: Require square matrices of same order")
2581             unless( $mdims[0] == $mdims[1] && $pdims[0] == $pdims[1] && $mdims[0] == $pdims[0]);
2582             barf("mgschur: thread doesn't supported for selected vectors")
2583             if ($select_func && ((@mdims > 2) || (@pdims > 2)) &&
2584             ($jobvsl == 2 || $jobvsr == 2 || $jobvl == 2 || $jobvr == 2));
2585              
2586              
2587             my ($w, $vsl, $vsr, $info, $type, $select,$sdim, $vr,$vl, $mm, $pp, %ret, $beta);
2588              
2589             $mult = 1 unless defined($mult);
2590             $norm = 1 unless defined($norm);
2591             $type = $m->type;
2592             $select = $select_func ? pdl(long,1) : pdl(long,0);
2593              
2594             $info = null;
2595             $sdim = null;
2596             $mm = $m->is_inplace ? $m->xchg(0,1) : $m->xchg(0,1)->copy;
2597             $pp = $p->is_inplace ? $p->xchg(0,1) : $p->xchg(0,1)->copy;
2598              
2599             my ($select_f, $wi, $wtmp, $betai);
2600             if ($select_func){
2601             $select_f= sub{
2602             &$select_func(PDL::Complex::complex(pdl($type,@_[0..1])),pdl($_[2]));
2603             };
2604             }
2605             $wtmp = null;
2606             $wi = null;
2607             $beta = null;
2608             # $vsl = $jobvsl ? PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1],@mdims[2..$#mdims]) :
2609             # pdl($type,[[0]]);
2610              
2611             # Lapack always write in VSL (g77 3.3) ???
2612             $vsl = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1],@mdims[2..$#mdims]);
2613             $vsr = $jobvsr ? PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1],@mdims[2..$#mdims]) :
2614             pdl($type,[[0]]);
2615             $mm->gges( $jobvsl, $jobvsr, $select, $pp, $wtmp, $wi, $beta, $vsl, $vsr, $sdim, $info, $select_f);
2616              
2617             if ($info->max > 0 && $_laerror){
2618             my ($index, @list);
2619             $index = which((($info > 0)+($info <=$mdims[0])) == 2);
2620             unless ($index->isempty){
2621             @list = $index->list;
2622             laerror("mgschur: The QZ algorithm failed to converge for matrix (PDL(s) @list): \$info = $info");
2623             print ("Returning converged eigenvalues\n");
2624             }
2625             $index = which((($info > 0)+($info <=($mdims[0]+1))) == 2);
2626             unless ($index->isempty){
2627             @list = $index->list;
2628             laerror("mgschur: Error in hgeqz for matrix (PDL(s) @list): \$info = $info");
2629             }
2630             if ($select_func){
2631             $index = which((($info > 0)+($info == ($mdims[0]+3))) == 2);
2632             unless ($index->isempty){
2633             laerror("mgschur: The eigenvalues could not be reordered because some\n".
2634             "eigenvalues were too close to separate (the problem".
2635             "is very ill-conditioned) for PDL(s) @list: \$info = $info");
2636             }
2637             }
2638             }
2639              
2640             if ($select_func){
2641             if ($jobvsl == 2 || $jobvsr == 2 || $jobvl == 2 || $jobvr == 2){
2642             if ($info == ($mdims[0] + 2)){
2643             warn("mgschur: The Schur form no longer satisfy select_func = 1\n because of roundoff or underflow\n") if $_laerror;
2644             #TODO : Check sdim and lapack
2645             $sdim+=1 if ($sdim < $mdims[0] && $wi($sdim) != 0 && $wi($sdim-1) == -$wi($sdim));
2646             }
2647             }
2648             elsif($_laerror){
2649             my $index = which((($info > 0)+($info == ($mdims[0]+2))) == 2);
2650             unless ($index->isempty){
2651             my @list = $index->list;
2652             warn("mgschur: The Schur form no longer satisfy select_func = 1\n because".
2653             "of roundoff or underflow for PDL(s) @list: \$info = $info\n");
2654             }
2655             }
2656             if ($jobvl == 2){
2657             if (!$sdim){
2658             $ret{VL} = PDL::Complex->null;
2659             $jobvl = 0;
2660             }
2661             }
2662             if ($jobvr == 2){
2663             if(!$sdim){
2664             $ret{VR} = PDL::Complex->null;
2665             $jobvr = 0;
2666             }
2667             }
2668             $ret{n} = $sdim;
2669             }
2670              
2671             if ($jobvl || $jobvr){
2672             my ($sel, $job, $wtmpi, $wtmpr, $sdims);
2673             unless ($jobvr && $jobvl){
2674             $job = $jobvl ? 2 : 1;
2675             }
2676             if ($select_func){
2677             if ($jobvl == 1 || $jobvr == 1 || $mult){
2678             $sdims = null;
2679             if ($jobvl){
2680             if ($jobvsl){
2681             $vl = $vsl->copy;
2682             }
2683             else{
2684             $vl = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1],@mdims[2..$#mdims]);
2685             $mult = 0;
2686             }
2687             }
2688             if ($jobvr){
2689             if ($jobvsr){
2690             $vr = $vsr->copy;
2691             }
2692             else{
2693             $vr = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1],@mdims[2..$#mdims]);
2694             $mult = 0;
2695             }
2696             }
2697              
2698             $mm->tgevc($job, $mult, $pp, $sel, $vl, $vr, $sdims, my $infos=null);
2699             if ($jobvr){
2700             if($norm){
2701             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr,1);
2702             bless $vr, 'PDL::Complex';
2703             $ret{VR} = $jobvr == 2 ? magn_norm($vr(,,:($sdim-1)),1) : magn_norm($vr,1);
2704              
2705             }
2706             else{
2707             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr->xchg(0,1),0);
2708             bless $vr, 'PDL::Complex';
2709             $ret{VR} = $jobvr == 2 ? $vr(,:($sdim-1))->sever : $vr;
2710             }
2711             }
2712             if ($jobvl){
2713             if ($norm){
2714             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl,1);
2715             bless $vl, 'PDL::Complex';
2716             $ret{VL} = $jobvl == 2 ? magn_norm($vl(,,:($sdim-1)),1) : magn_norm($vl,1);
2717            
2718             }
2719             else{
2720             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl->xchg(0,1),0);
2721             bless $vl, 'PDL::Complex';
2722             $ret{VL} = $jobvl == 2 ? $vl(,:($sdim-1))->sever : $vl;
2723             }
2724             }
2725             }
2726             else{
2727             $vr = PDL::new_from_specification('PDL', $type, $mdims[1], $sdim) if $jobvr;
2728             $vl = PDL::new_from_specification('PDL', $type, $mdims[1], $sdim) if $jobvl;
2729             $sel = zeroes($mdims[1]);
2730             $sel(:($sdim-1)) .= 1;
2731             $mm->tgevc($job, 2, $pp, $sel, $vl, $vr, $sdim, my $infos = null);
2732             $wtmpr = $wtmp(:($sdim-1));
2733             $wtmpi = $wi(:($sdim-1));
2734             if ($jobvr){
2735             if ($norm){
2736             (undef,$vr) = $wtmpr->cplx_eigen($wtmpi,$vr,1);
2737             bless $vr, 'PDL::Complex';
2738             $ret{VR} = magn_norm($vr,1);
2739             }
2740             else{
2741             (undef,$vr) = $wtmpr->cplx_eigen($wtmpi,$vr->xchg(0,1),0);
2742             bless $vr, 'PDL::Complex';
2743             $ret{VR} = $vr;
2744             }
2745             }
2746             if ($jobvl){
2747             if ($norm){
2748             (undef,$vl) = $wtmpr->cplx_eigen($wtmpi,$vl,1);
2749             bless $vl, 'PDL::Complex';
2750             $ret{VL} = magn_norm($vl,1);
2751            
2752             }
2753             else{
2754             (undef,$vl) = $wtmpr->cplx_eigen($wtmpi,$vl->xchg(0,1),0);
2755             bless $vl, 'PDL::Complex';
2756             $ret{VL} = $vl;
2757             }
2758             }
2759             }
2760             }
2761             else{
2762             if ($jobvl){
2763             if ($jobvsl){
2764             $vl = $vsl->copy;
2765             }
2766             else{
2767             $vl = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1],@mdims[2..$#mdims]);
2768             $mult = 0;
2769             }
2770             }
2771             if ($jobvr){
2772             if ($jobvsr){
2773             $vr = $vsr->copy;
2774             }
2775             else{
2776             $vr = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1],@mdims[2..$#mdims]);
2777             $mult = 0;
2778             }
2779             }
2780              
2781             $mm->tgevc($job, $mult, $pp, $sel, $vl, $vr, $sdim, my $infos=null);
2782             if ($jobvl){
2783             if ($norm){
2784             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl,1);
2785             bless $vl, 'PDL::Complex';
2786             $ret{VL} = magn_norm($vl,1);
2787             }
2788             else{
2789             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl->xchg(0,1),0);
2790             bless $vl, 'PDL::Complex';
2791             $ret{VL} = $vl;
2792             }
2793             }
2794             if ($jobvr){
2795             if ($norm){
2796             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr,1);
2797             bless $vr, 'PDL::Complex';
2798             $ret{VR} = magn_norm($vr,1);
2799             }
2800             else{
2801             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr->xchg(0,1),0);
2802             bless $vr, 'PDL::Complex';
2803             $ret{VR} = $vr;
2804             }
2805             }
2806             }
2807             }
2808             $w = PDL::Complex::ecplx ($wtmp, $wi);
2809              
2810             if ($jobvsr == 2 && $select_func) {
2811             $vsr = $sdim ? $vsr->xchg(0,1)->(:($sdim-1),) ->sever : null;
2812             $ret{SR} = $vsr;
2813             }
2814             elsif($jobvsr){
2815             $vsr = $vsr->xchg(0,1)->sever;
2816             $ret{SR} = $vsr;
2817             }
2818              
2819             if ($jobvsl == 2 && $select_func) {
2820             $vsl = $sdim ? $vsl->xchg(0,1)->(:($sdim-1),) ->sever : null;
2821             $ret{SL} = $vsl;
2822             }
2823             elsif($jobvsl){
2824             $vsl = $vsl->xchg(0,1)->sever;
2825             $ret{SL} = $vsl;
2826             }
2827             $ret{info} = $info;
2828             $m = $mm->xchg(0,1)->sever unless $m->is_inplace(0);
2829             $p = $pp->xchg(0,1)->sever unless $p->is_inplace(0);
2830             return ($m, $p, $w, $beta, %ret);
2831            
2832             }
2833              
2834              
2835             sub PDL::Complex::mgschur{
2836             my($m, $p, $jobvsl, $jobvsr, $jobvl, $jobvr, $select_func, $mult, $norm) = @_;
2837             my @mdims = $m->dims;
2838             my @pdims = $p->dims;
2839              
2840             barf("mgschur: Require square matrices of same order")
2841             unless( $mdims[2] == $mdims[1] && $pdims[2] == $pdims[1] && $mdims[1] == $pdims[1]);
2842             barf("mgschur: thread doesn't supported for selected vectors")
2843             if ($select_func && ((@mdims > 2) || (@pdims > 2)) &&
2844             ($jobvsl == 2 || $jobvsr == 2 || $jobvl == 2 || $jobvr == 2));
2845              
2846              
2847             my ($w, $vsl, $vsr, $info, $type, $select,$sdim, $vr,$vl, $mm, $pp, %ret, $beta);
2848              
2849             $mult = 1 unless defined($mult);
2850             $norm = 1 unless defined($norm);
2851             $type = $m->type;
2852             $select = $select_func ? pdl(long,1) : pdl(long,0);
2853              
2854             $info = null;
2855             $sdim = null;
2856             $mm = $m->is_inplace ? $m->xchg(1,2) : $m->xchg(1,2)->copy;
2857             $pp = $p->is_inplace ? $p->xchg(1,2) : $p->xchg(1,2)->copy;
2858              
2859             $w = PDL::Complex->null;
2860             $beta = PDL::Complex->null;
2861             $vsr = $jobvsr ? PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1],@mdims[3..$#mdims]) :
2862             pdl($type,[0,0]);
2863             # $vsl = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1]);
2864             $vsl = $jobvsl ? PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1],@mdims[3..$#mdims]) :
2865             pdl($type,[0,0]);
2866              
2867             $mm->cgges( $jobvsl, $jobvsr, $select, $pp, $w, $beta, $vsl, $vsr, $sdim, $info, $select_func);
2868             if ($info->max > 0 && $_laerror){
2869             my ($index, @list);
2870             $index = which((($info > 0)+($info <=$mdims[1])) == 2);
2871             unless ($index->isempty){
2872             @list = $index->list;
2873             laerror("mgschur: The QZ algorithm failed to converge for matrix (PDL(s) @list): \$info = $info");
2874             print ("Returning converged eigenvalues\n");
2875             }
2876             $index = which((($info > 0)+($info <=($mdims[1]+1))) == 2);
2877             unless ($index->isempty){
2878             @list = $index->list;
2879             laerror("mgschur: Error in hgeqz for matrix (PDL(s) @list): \$info = $info");
2880             }
2881             if ($select_func){
2882             $index = which((($info > 0)+($info == ($mdims[1]+3))) == 2);
2883             unless ($index->isempty){
2884             laerror("mgschur: The eigenvalues could not be reordered because some\n".
2885             "eigenvalues were too close to separate (the problem".
2886             "is very ill-conditioned) for PDL(s) @list: \$info = $info");
2887             }
2888             }
2889             }
2890              
2891             if ($select_func){
2892             if ($_laerror){
2893             if (($jobvsl == 2 || $jobvsr == 2 || $jobvl == 2 || $jobvr == 2) && $info == ($mdims[1] + 2)){
2894             warn("mgschur: The Schur form no longer satisfy select_func = 1\n because of roundoff or underflow\n");
2895             }
2896             else{
2897             my $index = which((($info > 0)+($info == ($mdims[1]+2))) == 2);
2898             unless ($index->isempty){
2899             my @list = $index->list;
2900             warn("mgschur: The Schur form no longer satisfy select_func = 1\n because".
2901             "of roundoff or underflow for PDL(s) @list: \$info = $info\n");
2902             }
2903             }
2904             }
2905             if ($jobvl == 2){
2906             if (!$sdim){
2907             $ret{VL} = PDL::Complex->null;
2908             $jobvl = 0;
2909             }
2910             }
2911             if ($jobvr == 2){
2912             if(!$sdim){
2913             $ret{VR} = PDL::Complex->null;
2914             $jobvr = 0;
2915             }
2916             }
2917             $ret{n} = $sdim;
2918             }
2919              
2920             if ($jobvl || $jobvr){
2921             my ($sel, $job, $sdims);
2922             unless ($jobvr && $jobvl){
2923             $job = $jobvl ? 2 : 1;
2924             }
2925             if ($select_func){
2926             if ($jobvl == 1 || $jobvr == 1 || $mult){
2927             $sdims = null;
2928             if ($jobvl){
2929             if ($jobvsl){
2930             $vl = $vsl->copy;
2931             }
2932             else{
2933             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1],@mdims[3..$#mdims]);
2934             $mult = 0;
2935             }
2936             }
2937             if ($jobvr){
2938             if ($jobvsr){
2939             $vr = $vsr->copy;
2940             }
2941             else{
2942             $vr = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1],@mdims[3..$#mdims]);
2943             $mult = 0;
2944             }
2945             }
2946             $mm->ctgevc($job, $mult, $pp, $sel, $vl, $vr, $sdims, my $infos=null);
2947             if ($jobvr){
2948             if ($norm){
2949             $ret{VR} = $jobvr == 2 ? magn_norm($vr(,,:($sdim-1)),1) : magn_norm($vr,1);
2950             }
2951             else{
2952             $ret{VR} = $jobvr == 2 ? $vr(,,:($sdim-1))->xchg(1,2)->sever : $vr->xchg(1,2)->sever;
2953             }
2954             }
2955             if ($jobvl){
2956             if ($norm){
2957             $ret{VL} = $jobvl == 2 ? magn_norm($vl(,,:($sdim-1)),1) : magn_norm($vl,1);
2958             }
2959             else{
2960             $ret{VL} = $jobvl == 2 ? $vl(,,:($sdim-1))->xchg(1,2)->sever : $vl->xchg(1,2)->sever;
2961             }
2962             }
2963             }
2964             else{
2965             $vr = PDL::new_from_specification('PDL::Complex', $type, 2,$mdims[1], $sdim) if $jobvr;;
2966             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $sdim) if $jobvl;;
2967             $sel = zeroes($mdims[1]);
2968             $sel(:($sdim-1)) .= 1;
2969             $mm->ctgevc($job, 2, $pp, $sel, $vl, $vr, $sdim, my $infos=null);
2970             if ($jobvl){
2971             $ret{VL} = $norm ? magn_norm($vl,1) : $vl->xchg(1,2)->sever;
2972             }
2973             if ($jobvr){
2974             $ret{VR} = $norm ? magn_norm($vr,1) : $vr->xchg(1,2)->sever;
2975             }
2976             }
2977             }
2978             else{
2979             if ($jobvl){
2980             if ($jobvsl){
2981             $vl = $vsl->copy;
2982             }
2983             else{
2984             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1],@mdims[3..$#mdims]);
2985             $mult = 0;
2986             }
2987             }
2988             if ($jobvr){
2989             if ($jobvsr){
2990             $vr = $vsr->copy;
2991             }
2992             else{
2993             $vr = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1],@mdims[3..$#mdims]);
2994             $mult = 0;
2995             }
2996             }
2997             $mm->ctgevc($job, $mult, $pp, $sel, $vl, $vr, $sdim, my $infos=null);
2998             if ($jobvl){
2999             $ret{VL} = $norm ? magn_norm($vl,1) : $vl->xchg(1,2)->sever;
3000             }
3001             if ($jobvr){
3002             $ret{VR} = $norm ? magn_norm($vr,1) : $vr->xchg(1,2)->sever;
3003             }
3004             }
3005             }
3006             if ($jobvsl == 2 && $select_func) {
3007             $vsl = $sdim ? $vsl->xchg(1,2)->(,:($sdim-1),) ->sever : PDL::Complex->null;
3008             $ret{SL} = $vsl;
3009             }
3010             elsif($jobvsl){
3011             $vsl = $vsl->xchg(1,2)->sever;
3012             $ret{SL} = $vsl;
3013             }
3014             if ($jobvsr == 2 && $select_func) {
3015             $vsr = $sdim ? $vsr->xchg(1,2)->(,:($sdim-1),) ->sever : PDL::Complex->null;
3016             $ret{SR} = $vsr;
3017             }
3018             elsif($jobvsr){
3019             $vsr = $vsr->xchg(1,2)->sever;
3020             $ret{SR} = $vsr;
3021             }
3022              
3023             $ret{info} = $info;
3024             $m = $mm->xchg(1,2)->sever unless $m->is_inplace(0);
3025             $p = $pp->xchg(1,2)->sever unless $p->is_inplace(0);
3026             return ($m, $p, $w, $beta, %ret);
3027            
3028             }
3029              
3030              
3031              
3032             =head2 mgschurx
3033              
3034             =for ref
3035              
3036             Computes generalized Schur decomposition of the pair (A,B).
3037              
3038             A = Q x S x Z'
3039             B = Q x T x Z'
3040              
3041             Uses L or L
3042             from Lapack. Works on transposed array.
3043              
3044             =for usage
3045              
3046             ( PDL(schur S), PDL(schur T), PDL(alpha), PDL(beta), HASH{result}) = mgschurx(PDL(A), PDL(B), SCALAR(left schur vector),SCALAR(right schur vector),SCALAR(left eigenvector), SCALAR(right eigenvector), SCALAR(select_func), SCALAR(sense), SCALAR(backtransform), SCALAR(scale))
3047             left schur vector : Left Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0
3048             right schur vector : Right Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0
3049             left eigenvector : Left eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0
3050             right eigenvector : Right eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0
3051             select_func : Select_func is used to select eigenvalues to sort.
3052             to the top left of the Schur form.
3053             An eigenvalue w = wr(j)+sqrt(-1)*wi(j) is selected if
3054             PerlInt select_func(PDL::Complex(alpha),PDL | PDL::Complex (beta)) is true;
3055             Note that a selected complex eigenvalue may no longer
3056             satisfy select_func = 1 after ordering, since
3057             ordering may change the value of complex eigenvalues
3058             (especially if the eigenvalue is ill-conditioned).
3059             All eigenvalues/vectors are selected if select_func is undefined.
3060             sense : Determines which reciprocal condition numbers will be computed.
3061             0: None are computed
3062             1: Computed for average of selected eigenvalues only
3063             2: Computed for selected deflating subspaces only
3064             3: Computed for both
3065             If select_func is undefined, sense is not used.
3066              
3067             backtransform : Whether or not backtransforms eigenvectors to those of (A,B).
3068             Only supported if right and/or left schur vector are computed, default = 1
3069             scale : Whether or not computed eigenvectors are scaled so the largest component
3070             will have abs(real part) + abs(imag. part) = 1, default = 1
3071              
3072             Returned values :
3073             Schur form S,
3074             Schur form T,
3075             alpha,
3076             beta (eigenvalues = alpha/beta),
3077             HASH{info}: info output from gges/cgges.
3078             HASH{SL}: left Schur vectors if requested
3079             HASH{SR}: right Schur vectors if requested
3080             HASH{VL}: left eigenvectors if requested
3081             HASH{VR}: right eigenvectors if requested
3082             HASH{rconde}: reciprocal condition numbers for average of selected eigenvalues if requested
3083             HASH{rcondv}: reciprocal condition numbers for selected deflating subspaces if requested
3084             HASH{n} : Number of eigenvalues selected if select_func is defined.
3085              
3086             =for example
3087              
3088             my $a = random(10,10);
3089             my $b = random(10,10);
3090             my ($S,$T) = mgschurx($a,$b);
3091             sub select{
3092             my ($alpha,$beta) = @_;
3093             return $alpha->Cabs < abs($beta) ? 1 : 0;
3094             }
3095             my ($S, $T, $alpha, $beta, %res) = mgschurx( $a, $b, 1, 1, 1, 1,\&select,3);
3096              
3097              
3098              
3099             =cut
3100              
3101             *mgschurx = \&PDL::mgschurx;
3102              
3103             sub PDL::mgschurx{
3104             my($m, $p, $jobvsl, $jobvsr, $jobvl, $jobvr, $select_func, $sense, $mult, $norm) = @_;
3105             my (@mdims) = $m->dims;
3106             my (@pdims) = $p->dims;
3107              
3108             barf("mgschurx: Require square matrices of same order")
3109             unless( ( (@mdims == 2) || (@mdims == 3) )&& $mdims[-1] == $mdims[-2] && @mdims == @pdims &&
3110             $pdims[-1] == $pdims[-2] && $mdims[1] == $pdims[1]);
3111              
3112             my ($w, $vsl, $vsr, $info, $type, $select, $sdim, $rconde, $rcondv, %ret, $mm, $vl, $vr, $beta, $pp);
3113              
3114             $mult = 1 unless defined($mult);
3115             $norm = 1 unless defined($norm);
3116             $type = $m->type;
3117             if ($select_func){
3118             $select = pdl(long 1);
3119             $rconde = pdl($type,[0,0]);
3120             $rcondv = pdl($type,[0,0]);
3121             }
3122             else{
3123             $select = pdl(long,0);
3124             $sense = pdl(long,0);
3125             $rconde = pdl($type,0);
3126             $rcondv = pdl($type,0);
3127             }
3128              
3129             $info = pdl(long,0);
3130             $sdim = pdl(long,0);
3131              
3132              
3133             $mm = $m->is_inplace ? $m->xchg(-1,-2) : $m->xchg(-1,-2)->copy;
3134             $pp = $p->is_inplace ? $p->xchg(-1,-2) : $p->xchg(-1,-2)->copy;
3135              
3136             if (@mdims == 3){
3137             $w = PDL::Complex->null;
3138             $beta = PDL::Complex->null;
3139             # $vsl = $jobvsl ? PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1]) :
3140             # pdl($type,[0,0]);
3141             $vsl = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1]);
3142             $vsr = $jobvsr ? PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1]) :
3143             pdl($type,[0,0]);
3144             $mm->cggesx( $jobvsl, $jobvsr, $select, $sense, $pp, $w, $beta, $vsl, $vsr, $sdim, $rconde, $rcondv,$info, $select_func);
3145             if ($info){
3146             if ($info < $mdims[1]){
3147             laerror("mgschurx: The QZ algorithm failed to converge");
3148             print ("Returning converged eigenvalues\n") if $_laerror;
3149             }
3150             laerror("mgschurx: The eigenvalues could not be reordered because some\n".
3151             "eigenvalues were too close to separate (the problem".
3152             "is very ill-conditioned)")
3153             if $info == ($mdims[1] + 3);
3154             laerror("mgschurx: Error in hgeqz\n")
3155             if $info == ($mdims[1] + 1);
3156              
3157             warn("mgschurx: The Schur form no longer satisfy select_func = 1\n because of roundoff or underflow\n")
3158             if ($info == ($mdims[1] + 2) and $_laerror);
3159              
3160             }
3161              
3162             if ($select_func){
3163             if(!$sdim){
3164             if ($jobvl == 2){
3165             $ret{VL} = PDL::Complex->null;
3166             $jobvl = 0;
3167             }
3168             if ($jobvr == 2){
3169             $ret{VR} = PDL::Complex->null;
3170             $jobvr = 0;
3171             }
3172             }
3173             $ret{n} = $sdim;
3174             }
3175             if ($jobvl || $jobvr){
3176             my ($sel, $job, $sdims);
3177             unless ($jobvr && $jobvl){
3178             $job = $jobvl ? 2 : 1;
3179             }
3180             if ($select_func){
3181             if ($jobvl == 1 || $jobvr == 1 || $mult){
3182             $sdims = null;
3183             if ($jobvl){
3184             if ($jobvsl){
3185             $vl = $vsl->copy;
3186             }
3187             else{
3188             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1]);
3189             $mult = 0;
3190             }
3191             }
3192             if ($jobvr){
3193             if ($jobvsr){
3194             $vr = $vsr->copy;
3195             }
3196             else{
3197             $vr = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1]);
3198             $mult = 0;
3199             }
3200             }
3201             $mm->ctgevc($job, $mult, $pp, $sel, $vl, $vr, $sdims, my $infos=null);
3202             if ($jobvr){
3203             if ($norm){
3204             $ret{VR} = $jobvr == 2 ? magn_norm($vr(,,:($sdim-1)),1) : magn_norm($vr,1);
3205             }
3206             else{
3207             $ret{VR} = $jobvr == 2 ? $vr(,,:($sdim-1))->xchg(1,2)->sever : $vr->xchg(1,2)->sever;
3208             }
3209             }
3210             if ($jobvl){
3211             if ($norm){
3212             $ret{VL} = $jobvl == 2 ? magn_norm($vl(,,:($sdim-1)),1) : magn_norm($vl,1);
3213             }
3214             else{
3215             $ret{VL} = $jobvl == 2 ? $vl(,,:($sdim-1))->xchg(1,2)->sever : $vl->xchg(1,2)->sever;
3216             }
3217             }
3218             }
3219             else{
3220             $vr = PDL::new_from_specification('PDL::Complex', $type, 2,$mdims[1], $sdim) if $jobvr;
3221             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $sdim) if $jobvl;
3222             $sel = zeroes($mdims[1]);
3223             $sel(:($sdim-1)) .= 1;
3224             $mm->ctgevc($job, 2, $pp, $sel, $vl, $vr, $sdim, my $infos=null);
3225             if ($jobvl){
3226             $ret{VL} = $norm ? magn_norm($vl,1) : $vl->xchg(1,2)->sever;
3227             }
3228             if ($jobvr){
3229             $ret{VR} = $norm ? magn_norm($vr,1) : $vr->xchg(1,2)->sever;
3230             }
3231             }
3232             }
3233             else{
3234             if ($jobvl){
3235             if ($jobvsl){
3236             $vl = $vsl->copy;
3237             }
3238             else{
3239             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1]);
3240             $mult = 0;
3241             }
3242             }
3243             if ($jobvr){
3244             if ($jobvsr){
3245             $vr = $vsr->copy;
3246             }
3247             else{
3248             $vr = PDL::new_from_specification('PDL::Complex', $type, 2, $mdims[1], $mdims[1]);
3249             $mult = 0;
3250             }
3251             }
3252             $mm->ctgevc($job, $mult, $pp,$sel, $vl, $vr, $sdim, my $infos=null);
3253             if ($jobvl){
3254             $ret{VL} = $norm ? magn_norm($vl,1) : $vl->xchg(1,2)->sever;
3255             }
3256             if ($jobvr){
3257             $ret{VR} = $norm ? magn_norm($vr,1) : $vr->xchg(1,2)->sever;
3258             }
3259             }
3260             }
3261             if ($jobvsl == 2 && $select_func) {
3262             $vsl = $sdim > 0 ? $vsl->xchg(1,2)->(,:($sdim-1),) ->sever : PDL::Complex->null;
3263             $ret{SL} = $vsl;
3264             }
3265             elsif($jobvsl){
3266             $vsl = $vsl->xchg(1,2)->sever;
3267             $ret{SL} = $vsl;
3268             }
3269             if ($jobvsr == 2 && $select_func) {
3270             $vsr = $sdim > 0 ? $vsr->xchg(1,2)->(,:($sdim-1),) ->sever : PDL::Complex->null;
3271             $ret{SR} = $vsr;
3272             }
3273             elsif($jobvsr){
3274             $vsr = $vsr->xchg(1,2)->sever;
3275             $ret{SR} = $vsr;
3276             }
3277             }
3278             else{
3279             my ($select_f, $wi, $wtmp);
3280             if ($select_func){
3281             no strict 'refs';
3282             $select_f= sub{
3283             &$select_func(PDL::Complex::complex(pdl($type,$_[0],$_[1])), $_[2]);
3284             };
3285             }
3286             $wi = null;
3287             $wtmp = null;
3288             $beta = null;
3289             #$vsl = $jobvsl ? PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1]) :
3290             # pdl($type,[[0]]);
3291             $vsl = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1]);
3292             $vsr = $jobvsr ? PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1]) :
3293             pdl($type,[[0]]);
3294             $mm->ggesx( $jobvsl, $jobvsr, $select, $sense, $pp, $wtmp, $wi, $beta, $vsl, $vsr, $sdim, $rconde, $rcondv,$info, $select_f);
3295             if ($info){
3296             if ($info < $mdims[0]){
3297             laerror("mgschurx: The QZ algorithm failed to converge");
3298             print ("Returning converged eigenvalues\n") if $_laerror;
3299             }
3300             laerror("mgschurx: The eigenvalues could not be reordered because some\n".
3301             "eigenvalues were too close to separate (the problem".
3302             "is very ill-conditioned)")
3303             if $info == ($mdims[0] + 3);
3304             laerror("mgschurx: Error in hgeqz\n")
3305             if $info == ($mdims[0] + 1);
3306              
3307             if ($info == ($mdims[0] + 2)){
3308             warn("mgschur: The Schur form no longer satisfy select_func = 1\n because of roundoff or underflow\n") if $_laerror;
3309             $sdim+=1 if ($sdim < $mdims[0] && $wi($sdim) != 0 && $wi($sdim-1) == -$wi($sdim));
3310             }
3311             }
3312              
3313             if ($select_func){
3314             if(!$sdim){
3315             if ($jobvl == 2){
3316             $ret{VL} = null;
3317             $jobvl = 0;
3318             }
3319             if ($jobvr == 2){
3320             $ret{VR} = null;
3321             $jobvr = 0;
3322             }
3323             }
3324             $ret{n} = $sdim;
3325             }
3326              
3327             if ($jobvl || $jobvr){
3328             my ($sel, $job, $wtmpi, $wtmpr, $sdims);
3329             unless ($jobvr && $jobvl){
3330             $job = $jobvl ? 2 : 1;
3331             }
3332             if ($select_func){
3333             $sdims = null;
3334             if ($jobvl == 1 || $jobvr == 1 || $mult){
3335             if ($jobvl){
3336             if ($jobvsl){
3337             $vl = $vsl->copy;
3338             }
3339             else{
3340             $vl = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1]);
3341             $mult = 0;
3342             }
3343             }
3344             if ($jobvr){
3345             if ($jobvsr){
3346             $vr = $vsr->copy;
3347             }
3348             else{
3349             $vr = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1]);
3350             $mult = 0;
3351             }
3352             }
3353              
3354             $mm->tgevc($job, $mult, $pp, $sel, $vl, $vr, $sdims, my $infos=null);
3355             if ($jobvr){
3356             if($norm){
3357             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr,1);
3358             bless $vr, 'PDL::Complex';
3359             $ret{VR} = $jobvr == 2 ? magn_norm($vr(,,:($sdim-1)),1) : magn_norm($vr,1);
3360             }
3361             else{
3362             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr->xchg(0,1),0);
3363             bless $vr, 'PDL::Complex';
3364             $ret{VR} = $jobvr == 2 ? $vr(,:($sdim-1))->sever : $vr;
3365             }
3366             }
3367             if ($jobvl){
3368             if ($norm){
3369             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl,1);
3370             bless $vl, 'PDL::Complex';
3371             $ret{VL} = $jobvl == 2 ? magn_norm($vl(,,:($sdim-1)),1) : magn_norm($vl,1);
3372             }
3373             else{
3374             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl->xchg(0,1),0);
3375             bless $vl, 'PDL::Complex';
3376             $ret{VL} = $jobvl == 2 ? $vl(,:($sdim-1))->sever : $vl;
3377             }
3378             }
3379             }
3380             else{
3381             $vr = PDL::new_from_specification('PDL', $type, $mdims[1], $sdim) if $jobvr;
3382             $vl = PDL::new_from_specification('PDL', $type, $mdims[1], $sdim) if $jobvl;
3383             $sel = zeroes($mdims[1]);
3384             $sel(:($sdim-1)) .= 1;
3385             $mm->tgevc($job, 2, $pp, $sel, $vl, $vr, $sdim, my $infos = null);
3386             $wtmpr = $wtmp(:($sdim-1));
3387             $wtmpi = $wi(:($sdim-1));
3388             if ($jobvr){
3389             if ($norm){
3390             (undef,$vr) = $wtmpr->cplx_eigen($wtmpi,$vr,1);
3391             bless $vr, 'PDL::Complex';
3392             $ret{VR} = magn_norm($vr,1);
3393             }
3394             else{
3395             (undef,$vr) = $wtmpr->cplx_eigen($wtmpi,$vr->xchg(0,1),0);
3396             bless $vr, 'PDL::Complex';
3397             $ret{VR} = $vr;
3398             }
3399             }
3400             if ($jobvl){
3401             if ($norm){
3402             (undef,$vl) = $wtmpr->cplx_eigen($wtmpi,$vl,1);
3403             bless $vl, 'PDL::Complex';
3404             $ret{VL} = magn_norm($vl,1);
3405             }
3406             else{
3407             (undef,$vl) = $wtmpr->cplx_eigen($wtmpi,$vl->xchg(0,1),0);
3408             bless $vl, 'PDL::Complex';
3409             $ret{VL} = $vl;
3410             }
3411             }
3412             }
3413             }
3414             else{
3415             if ($jobvl){
3416             if ($jobvsl){
3417             $vl = $vsl->copy;
3418             }
3419             else{
3420             $vl = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1]);
3421             $mult = 0;
3422             }
3423             }
3424             if ($jobvr){
3425             if ($jobvsr){
3426             $vr = $vsr->copy;
3427             }
3428             else{
3429             $vr = PDL::new_from_specification('PDL', $type, $mdims[1], $mdims[1]);
3430             $mult = 0;
3431             }
3432             }
3433              
3434             $mm->tgevc($job, $mult, $pp, $sel, $vl, $vr, $sdim, my $infos=null);
3435             if ($jobvl){
3436             if ($norm){
3437             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl,1);
3438             bless $vl, 'PDL::Complex';
3439             $ret{VL} = magn_norm($vl,1);
3440             }
3441             else{
3442             (undef,$vl) = $wtmp->cplx_eigen($wi,$vl->xchg(0,1),0);
3443             bless $vl, 'PDL::Complex';
3444             $ret{VL} = $vl;
3445             }
3446             }
3447             if ($jobvr){
3448             if ($norm){
3449             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr,1);
3450             bless $vr, 'PDL::Complex';
3451             $ret{VR} = magn_norm($vr,1);
3452             }
3453             else{
3454             (undef,$vr) = $wtmp->cplx_eigen($wi,$vr->xchg(0,1),0);
3455             bless $vr, 'PDL::Complex';
3456             $ret{VR} = $vr;
3457             }
3458             }
3459             }
3460             }
3461             $w = PDL::Complex::ecplx ($wtmp, $wi);
3462              
3463             if ($jobvsr == 2 && $select_func) {
3464             $vsr = $sdim > 0 ? $vsr->xchg(0,1)->(:($sdim-1),) ->sever : null;
3465             $ret{SR} = $vsr;
3466             }
3467             elsif($jobvsr){
3468             $vsr = $vsr->xchg(0,1)->sever;
3469             $ret{SR} = $vsr;
3470             }
3471              
3472             if ($jobvsl == 2 && $select_func) {
3473             $vsl = $sdim > 0 ? $vsl->xchg(0,1)->(:($sdim-1),) ->sever : null;
3474             $ret{SL} = $vsl;
3475             }
3476             elsif($jobvsl){
3477             $vsl = $vsl->xchg(0,1)->sever;
3478             $ret{SL} = $vsl;
3479             }
3480              
3481             }
3482              
3483            
3484             $ret{info} = $info;
3485             if ($sense){
3486             if ($sense == 3){
3487             $ret{rconde} = $rconde;
3488             $ret{rcondv} = $rcondv;
3489             }
3490             else{
3491             $ret{rconde} = $rconde if ($sense == 1);
3492             $ret{rcondv} = $rcondv if ($sense == 2);
3493             }
3494             }
3495             $m = $mm->xchg(-1,-2)->sever unless $m->is_inplace(0);
3496             $p = $pp->xchg(-1,-2)->sever unless $p->is_inplace(0);
3497             return ($m, $p, $w, $beta, %ret);
3498             }
3499              
3500              
3501             =head2 mqr
3502              
3503             =for ref
3504              
3505             Computes QR decomposition.
3506             For complex number needs object of type PDL::Complex.
3507             Uses L and L
3508             or L and L
3509             from Lapack and returns C in scalar context. Works on transposed array.
3510              
3511             =for usage
3512              
3513             (PDL(Q), PDL(R), PDL(info)) = mqr(PDL, SCALAR)
3514             SCALAR : ECONOMIC = 0 | FULL = 1, default = 0
3515              
3516             =for example
3517              
3518             my $a = random(10,10);
3519             my ( $q, $r ) = mqr($a);
3520             # Can compute full decomposition if nrow > ncol
3521             $a = random(5,7);
3522             ( $q, $r ) = $a->mqr(1);
3523              
3524             =cut
3525              
3526             sub mqr{
3527             my $m = shift;
3528             $m->mqr(@_);
3529             }
3530              
3531             sub PDL::mqr {
3532             my($m, $full) = @_;
3533             my(@dims) = $m->dims;
3534             my ($q, $r);
3535             barf("mqr: Require a matrix") unless @dims == 2;
3536              
3537             $m = $m->xchg(0,1)->copy;
3538             my $min = $dims[0] < $dims[1] ? $dims[0] : $dims[1];
3539            
3540             my $tau = zeroes($m->type, $min);
3541             $m->geqrf($tau, (my $info = pdl(long,0)));
3542             if ($info){
3543             laerror("mqr: Error $info in geqrf\n");
3544             $q = $r = $m;
3545             }
3546             else{
3547             $q = $dims[0] > $dims[1] ? $m(:,:($min-1))->copy : $m->copy;
3548             $q->reshape($dims[1], $dims[1]) if $full && $dims[0] < $dims[1];
3549              
3550             $q->orgqr($tau, $info);
3551             return $q->xchg(0,1)->sever unless wantarray;
3552              
3553             if ($dims[0] < $dims[1] && !$full){
3554             $r = zeroes($m->type, $min, $min);
3555             $m->xchg(0,1)->(,:($min-1))->tricpy(0,$r);
3556             }
3557             else{
3558             $r = zeroes($m->type, $dims[0],$dims[1]);
3559             $m->xchg(0,1)->tricpy(0,$r);
3560             }
3561             }
3562             return ($q->xchg(0,1)->sever, $r, $info);
3563             }
3564              
3565             sub PDL::Complex::mqr {
3566             my($m, $full) = @_;
3567             my(@dims) = $m->dims;
3568             my ($q, $r);
3569             barf("mqr: Require a matrix") unless @dims == 3;
3570              
3571             $m = $m->xchg(1,2)->copy;
3572             my $min = $dims[1] < $dims[2] ? $dims[1] : $dims[2];
3573            
3574             my $tau = zeroes($m->type, 2, $min);
3575             $m->cgeqrf($tau, (my $info = pdl(long,0)));
3576             if ($info){
3577             laerror("mqr: Error $info in cgeqrf\n");
3578             $q = $r = $m;
3579             }
3580             else{
3581             $q = $dims[1] > $dims[2] ? $m(,:,:($min-1))->copy : $m->copy;
3582             $q->reshape(2,$dims[2], $dims[2]) if $full && $dims[1] < $dims[2];
3583              
3584             $q->cungqr($tau, $info);
3585             return $q->xchg(1,2)->sever unless wantarray;
3586              
3587             if ($dims[1] < $dims[2] && !$full){
3588             $r = PDL::new_from_specification('PDL::Complex',$m->type, 2, $min, $min);
3589             $r .= 0;
3590             $m->xchg(1,2)->(,,:($min-1))->ctricpy(0,$r);
3591             }
3592             else{
3593             $r = PDL::new_from_specification('PDL::Complex', $m->type, 2, $dims[1],$dims[2]);
3594             $r .= 0;
3595             $m->xchg(1,2)->ctricpy(0,$r);
3596             }
3597             }
3598             return ($q->xchg(1,2)->sever, $r, $info);
3599             }
3600              
3601             =head2 mrq
3602              
3603             =for ref
3604              
3605             Computes RQ decomposition.
3606             For complex number needs object of type PDL::Complex.
3607             Uses L and L
3608             or L and L
3609             from Lapack and returns C in scalar context. Works on transposed array.
3610              
3611             =for usage
3612              
3613             (PDL(R), PDL(Q), PDL(info)) = mrq(PDL, SCALAR)
3614             SCALAR : ECONOMIC = 0 | FULL = 1, default = 0
3615              
3616             =for example
3617              
3618             my $a = random(10,10);
3619             my ( $r, $q ) = mrq($a);
3620             # Can compute full decomposition if nrow < ncol
3621             $a = random(5,7);
3622             ( $r, $q ) = $a->mrq(1);
3623              
3624             =cut
3625              
3626             sub mrq{
3627             my $m = shift;
3628             $m->mrq(@_);
3629             }
3630              
3631             sub PDL::mrq {
3632             my($m, $full) = @_;
3633             my(@dims) = $m->dims;
3634             my ($q, $r);
3635              
3636              
3637             barf("mrq: Require a matrix") unless @dims == 2;
3638             $m = $m->xchg(0,1)->copy;
3639             my $min = $dims[0] < $dims[1] ? $dims[0] : $dims[1];
3640            
3641             my $tau = zeroes($m->type, $min);
3642             $m->gerqf($tau, (my $info = pdl(long,0)));
3643             if ($info){
3644             laerror ("mrq: Error $info in gerqf\n");
3645             $r = $q = $m;
3646             }
3647             else{
3648             if ($dims[0] > $dims[1] && $full){
3649             $q = zeroes($m->type, $dims[0],$dims[0]);
3650             $q(($dims[0] - $dims[1]):,:) .= $m;
3651             }
3652             elsif ($dims[0] < $dims[1]){
3653             $q = $m(($dims[1] - $dims[0]):,:)->copy;
3654             }
3655             else{
3656             $q = $m->copy;
3657             }
3658            
3659             $q->orgrq($tau, $info);
3660             return $q->xchg(0,1)->sever unless wantarray;
3661              
3662             if ($dims[0] > $dims[1] && $full){
3663             $r = zeroes ($m->type,$dims[0],$dims[1]);
3664             $m->xchg(0,1)->tricpy(0,$r);
3665             $r(:($min-1),:($min-1))->diagonal(0,1) .= 0;
3666             }
3667             elsif ($dims[0] < $dims[1]){
3668             my $temp = zeroes($m->type,$dims[1],$dims[1]);
3669             $temp(-$min:, :) .= $m->xchg(0,1)->sever;
3670             $r = PDL::zeroes($temp);
3671             $temp->tricpy(0,$r);
3672             $r = $r(-$min:, :);
3673             }
3674             else{
3675             $r = zeroes($m->type, $min, $min);
3676             $m->xchg(0,1)->(($dims[0] - $dims[1]):, :)->tricpy(0,$r);
3677             }
3678             }
3679             return ($r, $q->xchg(0,1)->sever, $info);
3680              
3681             }
3682              
3683             sub PDL::Complex::mrq {
3684             my($m, $full) = @_;
3685             my(@dims) = $m->dims;
3686             my ($q, $r);
3687              
3688              
3689             barf("mrq: Require a matrix") unless @dims == 3;
3690             $m = $m->xchg(1,2)->copy;
3691             my $min = $dims[1] < $dims[2] ? $dims[1] : $dims[2];
3692            
3693             my $tau = zeroes($m->type, 2, $min);
3694             $m->cgerqf($tau, (my $info = pdl(long,0)));
3695             if ($info){
3696             laerror ("mrq: Error $info in cgerqf\n");
3697             $r = $q = $m;
3698             }
3699             else{
3700             if ($dims[1] > $dims[2] && $full){
3701             $q = PDL::new_from_specification('PDL::Complex',$m->type, 2, $dims[1],$dims[1]);
3702             $q .= 0;
3703             $q(,($dims[1] - $dims[2]):,:) .= $m;
3704             }
3705             elsif ($dims[1] < $dims[2]){
3706             $q = $m(,($dims[2] - $dims[1]):,:)->copy;
3707             }
3708             else{
3709             $q = $m->copy;
3710             }
3711            
3712             $q->cungrq($tau, $info);
3713             return $q->xchg(1,2)->sever unless wantarray;
3714              
3715             if ($dims[1] > $dims[2] && $full){
3716             $r = PDL::new_from_specification('PDL::Complex',$m->type,2,$dims[1],$dims[2]);
3717             $r .= 0;
3718             $m->xchg(1,2)->ctricpy(0,$r);
3719             $r(,:($min-1),:($min-1))->diagonal(1,2) .= 0;
3720             }
3721             elsif ($dims[1] < $dims[2]){
3722             my $temp = PDL::new_from_specification('PDL::Complex',$m->type,2,$dims[2],$dims[2]);
3723             $temp .= 0;
3724             $temp(,-$min:, :) .= $m->xchg(1,2);
3725             $r = PDL::zeroes($temp);
3726             $temp->ctricpy(0,$r);
3727             $r = $r(,-$min:, :)->sever;
3728             }
3729             else{
3730             $r = PDL::new_from_specification('PDL::Complex',$m->type, 2,$min, $min);
3731             $r .= 0;
3732             $m->xchg(1,2)->(,($dims[1] - $dims[2]):, :)->ctricpy(0,$r);
3733             }
3734             }
3735             return ($r, $q->xchg(1,2)->sever, $info);
3736              
3737             }
3738              
3739             =head2 mql
3740              
3741             =for ref
3742              
3743             Computes QL decomposition.
3744             For complex number needs object of type PDL::Complex.
3745             Uses L and L
3746             or L and L
3747             from Lapack and returns C in scalar context. Works on transposed array.
3748              
3749             =for usage
3750              
3751             (PDL(Q), PDL(L), PDL(info)) = mql(PDL, SCALAR)
3752             SCALAR : ECONOMIC = 0 | FULL = 1, default = 0
3753              
3754             =for example
3755              
3756             my $a = random(10,10);
3757             my ( $q, $l ) = mql($a);
3758             # Can compute full decomposition if nrow > ncol
3759             $a = random(5,7);
3760             ( $q, $l ) = $a->mql(1);
3761              
3762             =cut
3763              
3764             sub mql{
3765             my $m = shift;
3766             $m->mql(@_);
3767             }
3768              
3769             sub PDL::mql {
3770             my($m, $full) = @_;
3771             my(@dims) = $m->dims;
3772             my ($q, $l);
3773              
3774              
3775             barf("mql: Require a matrix") unless @dims == 2;
3776             $m = $m->xchg(0,1)->copy;
3777             my $min = $dims[0] < $dims[1] ? $dims[0] : $dims[1];
3778            
3779             my $tau = zeroes($m->type, $min);
3780             $m->geqlf($tau, (my $info = pdl(long,0)));
3781             if ($info){
3782             laerror("mql: Error $info in geqlf\n");
3783             $q = $l = $m;
3784             }
3785             else{
3786             if ($dims[0] < $dims[1] && $full){
3787             $q = zeroes($m->type, $dims[1],$dims[1]);
3788             $q(:, -$dims[0]:) .= $m;
3789             }
3790             elsif ($dims[0] > $dims[1]){
3791             $q = $m(:,-$min:)->copy;
3792             }
3793             else{
3794             $q = $m->copy;
3795             }
3796            
3797             $q->orgql($tau, $info);
3798             return $q->xchg(0,1)->sever unless wantarray;
3799              
3800             if ($dims[0] < $dims[1] && $full){
3801             $l = zeroes ($m->type,$dims[0],$dims[1]);
3802             $m->xchg(0,1)->tricpy(1,$l);
3803             $l(:($min-1),:($min-1))->diagonal(0,1) .= 0;
3804             }
3805             elsif ($dims[0] > $dims[1]){
3806             my $temp = zeroes($m->type,$dims[0],$dims[0]);
3807             $temp(:, -$dims[1]:) .= $m->xchg(0,1);
3808             $l = PDL::zeroes($temp);
3809             $temp->tricpy(1,$l);
3810             $l = $l(:, -$dims[1]:)->sever;
3811             }
3812             else{
3813             $l = zeroes($m->type, $min, $min);
3814             $m->xchg(0,1)->(:,($dims[1]-$min):)->tricpy(1,$l);
3815             }
3816             }
3817             return ($q->xchg(0,1)->sever, $l, $info);
3818              
3819             }
3820              
3821             sub PDL::Complex::mql{
3822             my($m, $full) = @_;
3823             my(@dims) = $m->dims;
3824             my ($q, $l);
3825              
3826              
3827             barf("mql: Require a matrix") unless @dims == 3;
3828             $m = $m->xchg(1,2)->copy;
3829             my $min = $dims[1] < $dims[2] ? $dims[1] : $dims[2];
3830            
3831             my $tau = zeroes($m->type, 2, $min);
3832             $m->cgeqlf($tau, (my $info = pdl(long,0)));
3833             if ($info){
3834             laerror("mql: Error $info in cgeqlf\n");
3835             $q = $l = $m;
3836             }
3837             else{
3838             if ($dims[1] < $dims[2] && $full){
3839             $q = PDL::new_from_specification('PDL::Complex', $m->type, 2, $dims[2],$dims[2]);
3840             $q .= 0;
3841             $q(,:, -$dims[1]:) .= $m;
3842             }
3843             elsif ($dims[1] > $dims[2]){
3844             $q = $m(,:,-$min:)->copy;
3845             }
3846             else{
3847             $q = $m->copy;
3848             }
3849            
3850             $q->cungql($tau, $info);
3851             return $q->xchg(1,2)->sever unless wantarray;
3852              
3853             if ($dims[1] < $dims[2] && $full){
3854             $l = PDL::new_from_specification('PDL::Complex', $m->type, 2, $dims[1], $dims[2]);
3855             $l .= 0;
3856             $m->xchg(1,2)->ctricpy(1,$l);
3857             $l(,:($min-1),:($min-1))->diagonal(1,2) .= 0;
3858             }
3859             elsif ($dims[1] > $dims[2]){
3860             my $temp = PDL::new_from_specification('PDL::Complex',$m->type,2,$dims[1],$dims[1]);
3861             $temp .= 0;
3862             $temp(,, -$dims[2]:) .= $m->xchg(1,2);
3863             $l = PDL::zeroes($temp);
3864             $temp->ctricpy(1,$l);
3865             $l = $l(,, -$dims[2]:)->sever;
3866             }
3867             else{
3868             $l = PDL::new_from_specification('PDL::Complex',$m->type, 2, $min, $min);
3869             $l .= 0;
3870             $m->xchg(1,2)->(,,($dims[2]-$min):)->ctricpy(1,$l);
3871             }
3872             }
3873             return ($q->xchg(1,2)->sever, $l, $info);
3874              
3875             }
3876              
3877             =head2 mlq
3878              
3879             =for ref
3880              
3881             Computes LQ decomposition.
3882             For complex number needs object of type PDL::Complex.
3883             Uses L and L
3884             or L and L
3885             from Lapack and returns C in scalar context. Works on transposed array.
3886              
3887             =for usage
3888              
3889             ( PDL(L), PDL(Q), PDL(info) ) = mlq(PDL, SCALAR)
3890             SCALAR : ECONOMIC = 0 | FULL = 1, default = 0
3891              
3892             =for example
3893              
3894             my $a = random(10,10);
3895             my ( $l, $q ) = mlq($a);
3896             # Can compute full decomposition if nrow < ncol
3897             $a = random(5,7);
3898             ( $l, $q ) = $a->mlq(1);
3899              
3900             =cut
3901              
3902             sub mlq{
3903             my $m = shift;
3904             $m->mlq(@_);
3905             }
3906              
3907             sub PDL::mlq {
3908             my($m, $full) = @_;
3909             my(@dims) = $m->dims;
3910             my ($q, $l);
3911              
3912             barf("mlq: Require a matrix") unless @dims == 2;
3913             $m = $m->xchg(0,1)->copy;
3914             my $min = $dims[0] < $dims[1] ? $dims[0] : $dims[1];
3915            
3916             my $tau = zeroes($m->type, $min);
3917             $m->gelqf($tau, (my $info = pdl(long,0)));
3918             if ($info){
3919             laerror("mlq: Error $info in gelqf\n");
3920             $q = $l = $m;
3921             }
3922             else{
3923             if ($dims[0] > $dims[1] && $full){
3924             $q = zeroes($m->type, $dims[0],$dims[0]);
3925             $q(:($min -1),:) .= $m;
3926             }
3927             elsif ($dims[0] < $dims[1]){
3928             $q = $m(:($min-1),)->copy;
3929             }
3930             else{
3931             $q = $m->copy;
3932             }
3933            
3934             $q->orglq($tau, $info);
3935             return $q->xchg(0,1)->sever unless wantarray;
3936            
3937             if ($dims[0] > $dims[1] && !$full){
3938             $l = zeroes($m->type, $dims[1], $dims[1]);
3939             $m->xchg(0,1)->(:($min-1))->tricpy(1,$l);
3940             }
3941             else{
3942             $l = zeroes($m->type, $dims[0], $dims[1]);
3943             $m->xchg(0,1)->tricpy(1,$l);
3944             }
3945             }
3946             return ($l, $q->xchg(0,1)->sever, $info);
3947              
3948             }
3949              
3950             sub PDL::Complex::mlq{
3951             my($m, $full) = @_;
3952             my(@dims) = $m->dims;
3953             my ($q, $l);
3954              
3955             barf("mlq: Require a matrix") unless @dims == 3;
3956             $m = $m->xchg(1,2)->copy;
3957             my $min = $dims[1] < $dims[2] ? $dims[1] : $dims[2];
3958            
3959             my $tau = zeroes($m->type, 2, $min);
3960             $m->cgelqf($tau, (my $info = pdl(long,0)));
3961             if ($info){
3962             laerror("mlq: Error $info in cgelqf\n");
3963             $q = $l = $m;
3964             }
3965             else{
3966             if ($dims[1] > $dims[2] && $full){
3967             $q = PDL::new_from_specification('PDL::Complex',$m->type, 2, $dims[1],$dims[1]);
3968             $q .= 0;
3969             $q(,:($min -1),:) .= $m;
3970             }
3971             elsif ($dims[1] < $dims[2]){
3972             $q = $m(,:($min-1),)->copy;
3973             }
3974             else{
3975             $q = $m->copy;
3976             }
3977            
3978             $q->cunglq($tau, $info);
3979             return $q->xchg(1,2)->sever unless wantarray;
3980            
3981             if ($dims[1] > $dims[2] && !$full){
3982             $l = PDL::new_from_specification('PDL::Complex',$m->type, 2, $dims[2], $dims[2]);
3983             $l .= 0;
3984             $m->xchg(1,2)->(,:($min-1))->ctricpy(1,$l);
3985             }
3986             else{
3987             $l = PDL::new_from_specification('PDL::Complex',$m->type, 2, $dims[1], $dims[2]);
3988             $l .= 0;
3989             $m->xchg(1,2)->ctricpy(1,$l);
3990             }
3991             }
3992             return ($l, $q->xchg(1,2)->sever, $info);
3993              
3994             }
3995              
3996             =head2 msolve
3997              
3998             =for ref
3999              
4000             Solves linear system of equations using LU decomposition.
4001            
4002             A * X = B
4003              
4004             Returns X in scalar context else X, LU, pivot vector and info.
4005             B is overwritten by X if its inplace flag is set.
4006             Supports threading.
4007             Uses L or L from Lapack.
4008             Works on transposed arrays.
4009              
4010             =for usage
4011              
4012             (PDL(X), (PDL(LU), PDL(pivot), PDL(info))) = msolve(PDL(A), PDL(B) )
4013              
4014             =for example
4015              
4016             my $a = random(5,5);
4017             my $b = random(10,5);
4018             my $X = msolve($a, $b);
4019              
4020             =cut
4021              
4022              
4023             sub msolve{
4024             my $m = shift;
4025             $m->msolve(@_);
4026             }
4027              
4028             sub PDL::msolve {
4029             my($a, $b) = @_;
4030             my(@adims) = $a->dims;
4031             my(@bdims) = $b->dims;
4032             my ($ipiv, $info, $c);
4033              
4034             barf("msolve: Require square coefficient array(s)")
4035             unless( (@adims >= 2) && $adims[0] == $adims[1] );
4036             barf("msolve: Require right hand side array(s) B with number".
4037             " of row equal to number of columns of A")
4038             unless( (@bdims >= 2) && $bdims[1] == $adims[0]);
4039             barf("msolve: Require arrays with equal number of dimensions")
4040             if( @adims != @bdims);
4041            
4042             $a = $a->xchg(0,1)->copy;
4043             $c = $b->is_inplace ? $b->xchg(0,1) : $b->xchg(0,1)->copy;
4044             $ipiv = zeroes(long, @adims[1..$#adims]);
4045             @adims = @adims[2..$#adims];
4046             $info = @adims ? zeroes(long,@adims) : pdl(long,0);
4047             $a->gesv($c, $ipiv, $info);
4048              
4049             if($info->max > 0 && $_laerror) {
4050             my ($index,@list);
4051             $index = which($info > 0)+1;
4052             @list = $index->list;
4053             laerror("msolve: Can't solve system of linear equations (after getrf factorization): matrix (PDL(s) @list) is/are singular(s): \$info = $info");
4054             }
4055             return wantarray ? $b->is_inplace(0) ? ($b, $a->xchg(0,1)->sever, $ipiv, $info) : ($c->xchg(0,1)->sever , $a->xchg(0,1)->sever, $ipiv, $info) :
4056             $b->is_inplace(0) ? $b : $c->xchg(0,1)->sever;
4057              
4058             }
4059              
4060             sub PDL::Complex::msolve {
4061             my($a, $b) = @_;
4062             my(@adims) = $a->dims;
4063             my(@bdims) = $b->dims;
4064             my ($ipiv, $info, $c);
4065              
4066             barf("msolve: Require square coefficient array(s)")
4067             unless( (@adims >= 3) && $adims[1] == $adims[2] );
4068             barf("msolve: Require right hand side array(s) B with number".
4069             " of row equal to order of A")
4070             unless( (@bdims >= 3) && $bdims[2] == $adims[1]);
4071             barf("msolve: Require arrays with equal number of dimensions")
4072             if( @adims != @bdims);
4073            
4074             $a = $a->xchg(1,2)->copy;
4075             $c = $b->is_inplace ? $b->xchg(1,2) : $b->xchg(1,2)->copy;
4076             $ipiv = zeroes(long, @adims[2..$#adims]);
4077             @adims = @adims[3..$#adims];
4078             $info = @adims ? zeroes(long,@adims) : pdl(long,0);
4079             $a->cgesv($c, $ipiv, $info);
4080              
4081             if($info->max > 0 && $_laerror) {
4082             my ($index,@list);
4083             $index = which($info > 0)+1;
4084             @list = $index->list;
4085             laerror("msolve: Can't solve system of linear equations (after cgetrf factorization): matrix (PDL(s) @list) is/are singular(s): \$info = $info");
4086             }
4087             return wantarray ? $b->is_inplace(0) ? ($b, $a->xchg(1,2)->sever, $ipiv, $info) : ($c->xchg(1,2)->sever , $a->xchg(1,2)->sever, $ipiv, $info):
4088             $b->is_inplace(0) ? $b : $c->xchg(1,2)->sever;
4089              
4090             }
4091              
4092             =head2 msolvex
4093              
4094             =for ref
4095              
4096             Solves linear system of equations using LU decomposition.
4097            
4098             A * X = B
4099              
4100             Can optionnally equilibrate the matrix.
4101             Uses L or L from Lapack.
4102             Works on transposed arrays.
4103              
4104             =for usage
4105              
4106             (PDL, (HASH(result))) = msolvex(PDL(A), PDL(B), HASH(options))
4107             where options are:
4108             transpose: solves A' * X = B
4109             0: false
4110             1: true
4111             equilibrate: equilibrates A if necessary.
4112             form equilibration is returned in HASH{'equilibration'}:
4113             0: no equilibration
4114             1: row equilibration
4115             2: column equilibration
4116             row scale factors are returned in HASH{'row'}
4117             column scale factors are returned in HASH{'column'}
4118             0: false
4119             1: true
4120             LU: returns lu decomposition in HASH{LU}
4121             0: false
4122             1: true
4123             A: returns scaled A if equilibration was done in HASH{A}
4124             0: false
4125             1: true
4126             B: returns scaled B if equilibration was done in HASH{B}
4127             0: false
4128             1: true
4129             Returned values:
4130             X (SCALAR CONTEXT),
4131             HASH{'pivot'}:
4132             Pivot indice from LU factorization
4133             HASH{'rcondition'}:
4134             Reciprocal condition of the matrix
4135             HASH{'ferror'}:
4136             Forward error bound
4137             HASH{'berror'}:
4138             Componentwise relative backward error
4139             HASH{'rpvgrw'}:
4140             Reciprocal pivot growth factor
4141             HASH{'info'}:
4142             Info: output from gesvx
4143              
4144             =for example
4145              
4146             my $a = random(10,10);
4147             my $b = random(5,10);
4148             my %options = (
4149             LU=>1,
4150             equilibrate => 1,
4151             );
4152             my( $X, %result) = msolvex($a,$b,%options);
4153              
4154             =cut
4155              
4156              
4157             *msolvex = \&PDL::msolvex;
4158              
4159             sub PDL::msolvex {
4160             my($a, $b, %opt) = @_;
4161             my(@adims) = $a->dims;
4162             my(@bdims) = $b->dims;
4163             my ( $af, $x, $ipiv, $info, $equilibrate, $berr, $ferr, $rcond, $equed, %result, $r, $c ,$rpvgrw);
4164              
4165             barf("msolvex: Require a square coefficient matrix")
4166             unless( ((@adims == 2) || (@adims == 3)) && $adims[-1] == $adims[-2] );
4167             barf("msolvex: Require a right hand side matrix B with number".
4168             " of row equal to order of A")
4169             unless( ((@bdims == 2) || (@bdims == 3))&& $bdims[-1] == $adims[-2]);
4170              
4171            
4172             $equilibrate = $opt{'equilibrate'} ? pdl(long, 2): pdl(long,1);
4173             $a = $a->t->copy;
4174             $b = $b->t->copy;
4175             $x = PDL::zeroes $b;
4176             $af = PDL::zeroes $a;
4177             $info = pdl(long, 0);
4178             $rcond = null;
4179             $rpvgrw = null;
4180             $equed = pdl(long, 0);
4181              
4182             $c = zeroes($a->type, $adims[-2]);
4183             $r = zeroes($a->type, $adims[-2]);
4184             $ipiv = zeroes(long, $adims[-2]);
4185             $ferr = zeroes($b->type, $bdims[-2]);
4186             $berr = zeroes($b->type, $bdims[-2]);
4187            
4188             ( @adims == 3 ) ? $a->cgesvx($opt{'transpose'}, $equilibrate, $b, $af, $ipiv, $equed, $r, $c, $x, $rcond, $ferr, $berr, $rpvgrw,$info) :
4189             $a->gesvx($opt{'transpose'}, $equilibrate, $b, $af, $ipiv, $equed, $r, $c, $x, $rcond, $ferr, $berr, $rpvgrw,$info);
4190             if( $info < $adims[-2] && $info > 0){
4191             $info--;
4192             laerror("msolvex: Can't solve system of linear equations:\nfactor U($info,$info)".
4193             " of coefficient matrix is exactly 0");
4194             }
4195             elsif ($info != 0 and $_laerror){
4196             warn ("msolvex: The matrix is singular to working precision");
4197             }
4198              
4199             return $x->xchg(-1,-2)->sever unless wantarray;
4200              
4201             $result{rcondition} = $rcond;
4202             $result{ferror} = $ferr;
4203             $result{berror} = $berr;
4204             if ($opt{equilibrate}){
4205             $result{equilibration} = $equed;
4206             $result{row} = $r if $equed == 1 || $equed == 3;
4207             $result{column} = $c if $equed == 2 || $equed == 3;
4208             if ($equed){
4209             $result{A} = $a->xchg(-2,-1)->sever if $opt{A};
4210             $result{B} = $b->xchg(-2,-1)->sever if $opt{B};
4211             }
4212             }
4213             $result{pivot} = $ipiv;
4214             $result{rpvgrw} = $rpvgrw;
4215             $result{info} = $info;
4216             $result{LU} = $af->xchg(-2,-1)->sever if $opt{LU};
4217            
4218             return ($x->xchg(-2,-1)->sever, %result);
4219              
4220             }
4221              
4222             =head2 mtrisolve
4223              
4224             =for ref
4225              
4226             Solves linear system of equations with triangular matrix A.
4227            
4228             A * X = B or A' * X = B
4229              
4230             B is overwritten by X if its inplace flag is set.
4231             Supports threading.
4232             Uses L or L from Lapack.
4233             Work on transposed array(s).
4234              
4235             =for usage
4236              
4237             (PDL(X), (PDL(info)) = mtrisolve(PDL(A), SCALAR(uplo), PDL(B), SCALAR(trans), SCALAR(diag))
4238             uplo : UPPER = 0 | LOWER = 1
4239             trans : NOTRANSPOSE = 0 | TRANSPOSE = 1, default = 0
4240             uplo : UNITARY DIAGONAL = 1, default = 0
4241              
4242             =for example
4243              
4244             # Assume $a is upper triagonal
4245             my $a = random(5,5);
4246             my $b = random(5,10);
4247             my $X = mtrisolve($a, 0, $b);
4248              
4249             =cut
4250              
4251              
4252             sub mtrisolve{
4253             my $m = shift;
4254             $m->mtrisolve(@_);
4255             }
4256              
4257             sub PDL::mtrisolve{
4258             my($a, $uplo, $b, $trans, $diag) = @_;
4259             my(@adims) = $a->dims;
4260             my(@bdims) = $b->dims;
4261             my ($info, $c);
4262              
4263             barf("mtrisolve: Require square coefficient array(s)")
4264             unless( (@adims >= 2) && $adims[0] == $adims[1] );
4265             barf("mtrisolve: Require 2D right hand side array(s) B with number".
4266             " of row equal to order of A")
4267             unless( (@bdims >= 2) && $bdims[1] == $adims[0]);
4268             barf("mtrisolve: Require arrays with equal number of dimensions")
4269             if( @adims != @bdims);
4270              
4271             $uplo = 1 - $uplo;
4272             $trans = 1 - $trans;
4273             $c = $b->is_inplace ? $b->xchg(0,1) : $b->xchg(0,1)->copy;
4274             @adims = @adims[2..$#adims];
4275             $info = @adims ? zeroes(long,@adims) : pdl(long,0);
4276             $a->trtrs($uplo, $trans, $diag, $c, $info);
4277              
4278             if($info->max > 0 && $_laerror) {
4279             my ($index,@list);
4280             $index = which($info > 0)+1;
4281             @list = $index->list;
4282             laerror("mtrisolve: Can't solve system of linear equations: matrix (PDL(s) @list) is/are singular(s): \$info = $info");
4283             }
4284             return wantarray ? $b->is_inplace(0) ? ($b, $info) : ($c->xchg(0,1)->sever, $info) :
4285             $b->is_inplace(0) ? $b : $c->xchg(0,1)->sever;
4286             }
4287              
4288             sub PDL::Complex::mtrisolve{
4289             my($a, $uplo, $b, $trans, $diag) = @_;
4290             my(@adims) = $a->dims;
4291             my(@bdims) = $b->dims;
4292             my ($info, $c);
4293              
4294             barf("mtrisolve: Require square coefficient array(s)")
4295             unless( (@adims >= 3) && $adims[1] == $adims[2] );
4296             barf("mtrisolve: Require 2D right hand side array(s) B with number".
4297             " of row equal to order of A")
4298             unless( (@bdims >= 3) && $bdims[2] == $adims[1]);
4299             barf("mtrisolve: Require arrays with equal number of dimensions")
4300             if( @adims != @bdims);
4301              
4302             $uplo = 1 - $uplo;
4303             $trans = 1 - $trans;
4304             $c = $b->is_inplace ? $b->xchg(1,2) : $b->xchg(1,2)->copy;
4305             @adims = @adims[3..$#adims];
4306             $info = @adims ? zeroes(long,@adims) : pdl(long,0);
4307             $a->ctrtrs($uplo, $trans, $diag, $c, $info);
4308              
4309             if($info->max > 0 && $_laerror) {
4310             my ($index,@list);
4311             $index = which($info > 0)+1;
4312             @list = $index->list;
4313             laerror("mtrisolve: Can't solve system of linear equations: matrix (PDL(s) @list) is/are singular(s): \$info = $info");
4314             }
4315             return wantarray ? $b->is_inplace(0) ? ($b, $info) : ($c->xchg(1,2)->sever, $info) :
4316             $b->is_inplace(0) ? $b : $c->xchg(1,2)->sever;
4317             }
4318              
4319             =head2 msymsolve
4320              
4321             =for ref
4322              
4323             Solves linear system of equations using diagonal pivoting method with symmetric matrix A.
4324            
4325             A * X = B
4326              
4327             Returns X in scalar context else X, block diagonal matrix D (and the
4328             multipliers), pivot vector an info. B is overwritten by X if its inplace flag is set.
4329             Supports threading.
4330             Uses L or L from Lapack.
4331             Works on transposed array(s).
4332              
4333             =for usage
4334              
4335             (PDL(X), ( PDL(D), PDL(pivot), PDL(info) ) ) = msymsolve(PDL(A), SCALAR(uplo), PDL(B) )
4336             uplo : UPPER = 0 | LOWER = 1, default = 0
4337              
4338             =for example
4339              
4340             # Assume $a is symmetric
4341             my $a = random(5,5);
4342             my $b = random(5,10);
4343             my $X = msymsolve($a, 0, $b);
4344              
4345             =cut
4346              
4347             sub msymsolve{
4348             my $m = shift;
4349             $m->msymsolve(@_);
4350             }
4351              
4352             sub PDL::msymsolve {
4353             my($a, $uplo, $b) = @_;
4354             my(@adims) = $a->dims;
4355             my(@bdims) = $b->dims;
4356             my ($ipiv, $info, $c);
4357              
4358             barf("msymsolve: Require square coefficient array(s)")
4359             unless( (@adims >= 2) && $adims[0] == $adims[1] );
4360             barf("msymsolve: Require 2D right hand side array(s) B with number".
4361             " of row equal to order of A")
4362             unless( (@bdims >= 2)&& $bdims[1] == $adims[0]);
4363             barf("msymsolve: Require array(s) with equal number of dimensions")
4364             if( @adims != @bdims);
4365              
4366             $uplo = 1 - $uplo;
4367             $a = $a->copy;
4368             $c = $b->is_inplace ? $b->xchg(0,1) : $b->xchg(0,1)->copy;
4369             $ipiv = zeroes(long, @adims[1..$#adims]);
4370             @adims = @adims[2..$#adims];
4371             $info = @adims ? zeroes(long,@adims) : pdl(long,0);
4372              
4373             $a->sysv($uplo, $c, $ipiv, $info);
4374             if($info->max > 0 && $_laerror) {
4375             my ($index,@list);
4376             $index = which($info > 0)+1;
4377             @list = $index->list;
4378             laerror("msymsolve: Can't solve system of linear equations (after sytrf factorization): matrix (PDL(s) @list) is/are singular(s): \$info = $info");
4379             }
4380              
4381            
4382             wantarray ? ( ( $b->is_inplace(0) ? $b : $c->xchg(0,1)->sever ), $a, $ipiv, $info):
4383             $b->is_inplace(0) ? $b : $c->xchg(0,1)->sever;
4384              
4385             }
4386              
4387             sub PDL::Complex::msymsolve {
4388             my($a, $uplo, $b) = @_;
4389             my(@adims) = $a->dims;
4390             my(@bdims) = $b->dims;
4391             my ($ipiv, $info, $c);
4392              
4393             barf("msymsolve: Require square coefficient array(s)")
4394             unless( (@adims >= 3) && $adims[1] == $adims[2] );
4395             barf("msymsolve: Require 2D right hand side array(s) B with number".
4396             " of row equal to order of A")
4397             unless( (@bdims >= 3)&& $bdims[2] == $adims[1]);
4398             barf("msymsolve: Require arrays with equal number of dimensions")
4399             if( @adims != @bdims);
4400              
4401             $uplo = 1 - $uplo;
4402             $a = $a->copy;
4403             $c = $b->is_inplace ? $b->xchg(1,2) : $b->xchg(1,2)->copy;
4404             $ipiv = zeroes(long, @adims[2..$#adims]);
4405             @adims = @adims[3..$#adims];
4406             $info = @adims ? zeroes(long,@adims) : pdl(long,0);
4407              
4408             $a->csysv($uplo, $c, $ipiv, $info);
4409             if($info->max > 0 && $_laerror) {
4410             my ($index,@list);
4411             $index = which($info > 0)+1;
4412             @list = $index->list;
4413             laerror("msymsolve: Can't solve system of linear equations (after csytrf factorization): matrix (PDL(s) @list) is/are singular(s): \$info = $info");
4414             }
4415              
4416            
4417             wantarray ? ( ( $b->is_inplace(0) ? $b : $c->xchg(1,2)->sever ), $a, $ipiv, $info):
4418             $b->is_inplace(0) ? $b : $c->xchg(1,2)->sever;
4419              
4420             }
4421              
4422             =head2 msymsolvex
4423              
4424             =for ref
4425              
4426             Solves linear system of equations using diagonal pivoting method with symmetric matrix A.
4427            
4428             A * X = B
4429              
4430             Uses L or L
4431             from Lapack. Works on transposed array.
4432              
4433             =for usage
4434              
4435             (PDL, (HASH(result))) = msymsolvex(PDL(A), SCALAR (uplo), PDL(B), SCALAR(d))
4436             uplo : UPPER = 0 | LOWER = 1, default = 0
4437             d : whether return diagonal matrix d and pivot vector
4438             FALSE = 0 | TRUE = 1, default = 0
4439             Returned values:
4440             X (SCALAR CONTEXT),
4441             HASH{'D'}:
4442             Block diagonal matrix D (and the multipliers) (if requested)
4443             HASH{'pivot'}:
4444             Pivot indice from LU factorization (if requested)
4445             HASH{'rcondition'}:
4446             Reciprocal condition of the matrix
4447             HASH{'ferror'}:
4448             Forward error bound
4449             HASH{'berror'}:
4450             Componentwise relative backward error
4451             HASH{'info'}:
4452             Info: output from sysvx
4453              
4454             =for example
4455              
4456             # Assume $a is symmetric
4457             my $a = random(10,10);
4458             my $b = random(5,10);
4459             my ($X, %result) = msolvex($a, 0, $b);
4460              
4461              
4462             =cut
4463              
4464              
4465             *msymsolvex = \&PDL::msymsolvex;
4466              
4467             sub PDL::msymsolvex {
4468             my($a, $uplo, $b, $d) = @_;
4469             my(@adims) = $a->dims;
4470             my(@bdims) = $b->dims;
4471             my ( $af, $x, $ipiv, $info, $berr, $ferr, $rcond, %result);
4472              
4473             barf("msymsolvex: Require a square coefficient matrix")
4474             unless( ((@adims == 2) || (@adims == 3)) && $adims[-1] == $adims[-2] );
4475             barf("msymsolvex: Require a right hand side matrix B with number".
4476             " of row equal to order of A")
4477             unless( ((@bdims == 2) || (@bdims == 3))&& $bdims[-1] == $adims[-2]);
4478              
4479            
4480             $uplo = 1 - $uplo;
4481             $b = $b->t;
4482             $x = PDL::zeroes $b;
4483             $af = PDL::zeroes $a;
4484             $info = pdl(long, 0);
4485             $rcond = null;
4486              
4487             $ipiv = zeroes(long, $adims[-2]);
4488             $ferr = zeroes($b->type, $bdims[-2]);
4489             $berr = zeroes($b->type, $bdims[-2]);
4490            
4491             (@adims == 3) ? $a->csysvx($uplo, (pdl(long, 0)), $b, $af, $ipiv, $x, $rcond, $ferr, $berr, $info) :
4492             $a->sysvx($uplo, (pdl(long, 0)), $b, $af, $ipiv, $x, $rcond, $ferr, $berr, $info);
4493             if( $info < $adims[-2] && $info > 0){
4494             $info--;
4495             laerror("msymsolvex: Can't solve system of linear equations:\nfactor D($info,$info)".
4496             " of coefficient matrix is exactly 0");
4497             }
4498             elsif ($info != 0 and $_laerror){
4499             warn("msymsolvex: The matrix is singular to working precision");
4500             }
4501             $result{rcondition} = $rcond;
4502             $result{ferror} = $ferr;
4503             $result{berror} = $berr;
4504             $result{info} = $info;
4505             if ($d){
4506             $result{D} = $af;
4507             $result{pivot} = $ipiv;
4508             }
4509            
4510             wantarray ? ($x->xchg(-2,-1)->sever, %result): $x->xchg(-2,-1)->sever;
4511              
4512             }
4513              
4514             =head2 mpossolve
4515              
4516             =for ref
4517              
4518             Solves linear system of equations using Cholesky decomposition with
4519             symmetric positive definite matrix A.
4520            
4521             A * X = B
4522              
4523             Returns X in scalar context else X, U or L and info.
4524             B is overwritten by X if its inplace flag is set.
4525             Supports threading.
4526             Uses L or L from Lapack.
4527             Works on transposed array(s).
4528              
4529             =for usage
4530              
4531             (PDL, (PDL, PDL, PDL)) = mpossolve(PDL(A), SCALAR(uplo), PDL(B) )
4532             uplo : UPPER = 0 | LOWER = 1, default = 0
4533              
4534             =for example
4535              
4536             # asume $a is symmetric positive definite
4537             my $a = random(5,5);
4538             my $b = random(5,10);
4539             my $X = mpossolve($a, 0, $b);
4540              
4541             =cut
4542              
4543              
4544             sub mpossolve{
4545             my $m = shift;
4546             $m->mpossolve(@_);
4547             }
4548              
4549             sub PDL::mpossolve {
4550             my($a, $uplo, $b) = @_;
4551             my(@adims) = $a->dims;
4552             my(@bdims) = $b->dims;
4553             my ($info, $c);
4554              
4555             barf("mpossolve: Require square coefficient array(s)")
4556             unless( (@adims >= 2) && $adims[0] == $adims[1] );
4557             barf("mpossolve: Require right hand side array(s) B with number".
4558             " of row equal to order of A")
4559             unless( (@bdims >= 2)&& $bdims[1] == $adims[0]);
4560             barf("mpossolve: Require arrays with equal number of dimensions")
4561             if( @adims != @bdims);
4562              
4563             $uplo = 1 - $uplo;
4564             $a = $a->copy;
4565             $c = $b->is_inplace ? $b->xchg(0,1) : $b->xchg(0,1)->copy;
4566             @adims = @adims[2..$#adims];
4567             $info = @adims ? zeroes(long,@adims) : pdl(long,0);
4568             $a->posv($uplo, $c, $info);
4569             if($info->max > 0 && $_laerror) {
4570             my ($index,@list);
4571             $index = which($info > 0)+1;
4572             @list = $index->list;
4573             laerror("mpossolve: Can't solve system of linear equations: matrix (PDL(s) @list) is/are not positive definite(s): \$info = $info");
4574             }
4575             wantarray ? $b->is_inplace(0) ? ($b, $a,$info) : ($c->xchg(0,1)->sever , $a,$info) : $b->is_inplace(0) ? $b : $c->xchg(0,1)->sever;
4576             }
4577              
4578             sub PDL::Complex::mpossolve {
4579             my($a, $uplo, $b) = @_;
4580             my(@adims) = $a->dims;
4581             my(@bdims) = $b->dims;
4582             my ($info, $c);
4583              
4584             barf("mpossolve: Require square coefficient array(s)")
4585             unless( (@adims >= 3) && $adims[1] == $adims[2] );
4586             barf("mpossolve: Require right hand side array(s) B with number".
4587             " of row equal to order of A")
4588             unless( (@bdims >= 3)&& $bdims[2] == $adims[1]);
4589             barf("mpossolve: Require arrays with equal number of dimensions")
4590             if( @adims != @bdims);
4591              
4592             $uplo = 1 - $uplo;
4593             $a = $a->copy;
4594             $c = $b->is_inplace ? $b->xchg(1,2) : $b->xchg(1,2)->copy;
4595             @adims = @adims[3..$#adims];
4596             $info = @adims ? zeroes(long,@adims) : pdl(long,0);
4597             $a->cposv($uplo, $c, $info);
4598             if($info->max > 0 && $_laerror) {
4599             my ($index,@list);
4600             $index = which($info > 0)+1;
4601             @list = $index->list;
4602             laerror("mpossolve: Can't solve system of linear equations: matrix (PDL(s) @list) is/are not positive definite(s): \$info = $info");
4603             }
4604             wantarray ? $b->is_inplace(0) ? ($b, $a,$info) : ($c->xchg(1,2)->sever , $a,$info) : $b->is_inplace(0) ? $b : $c->xchg(1,2)->sever;
4605             }
4606              
4607             =head2 mpossolvex
4608              
4609             =for ref
4610              
4611             Solves linear system of equations using Cholesky decomposition with
4612             symmetric positive definite matrix A
4613            
4614             A * X = B
4615              
4616             Can optionnally equilibrate the matrix.
4617             Uses L or
4618             L from Lapack.
4619             Works on transposed array(s).
4620              
4621             =for usage
4622              
4623             (PDL, (HASH(result))) = mpossolvex(PDL(A), SCARA(uplo), PDL(B), HASH(options))
4624             uplo : UPPER = 0 | LOWER = 1, default = 0
4625             where options are:
4626             equilibrate: equilibrates A if necessary.
4627             form equilibration is returned in HASH{'equilibration'}:
4628             0: no equilibration
4629             1: equilibration
4630             scale factors are returned in HASH{'scale'}
4631             0: false
4632             1: true
4633             U|L: returns Cholesky factorization in HASH{U} or HASH{L}
4634             0: false
4635             1: true
4636             A: returns scaled A if equilibration was done in HASH{A}
4637             0: false
4638             1: true
4639             B: returns scaled B if equilibration was done in HASH{B}
4640             0: false
4641             1: true
4642             Returned values:
4643             X (SCALAR CONTEXT),
4644             HASH{'rcondition'}:
4645             Reciprocal condition of the matrix
4646             HASH{'ferror'}:
4647             Forward error bound
4648             HASH{'berror'}:
4649             Componentwise relative backward error
4650             HASH{'info'}:
4651             Info: output from gesvx
4652              
4653             =for example
4654              
4655             # Assume $a is symmetric positive definite
4656             my $a = random(10,10);
4657             my $b = random(5,10);
4658             my %options = (U=>1,
4659             equilibrate => 1,
4660             );
4661             my ($X, %result) = msolvex($a, 0, $b,%opt);
4662              
4663             =cut
4664              
4665              
4666             *mpossolvex = \&PDL::mpossolvex;
4667              
4668             sub PDL::mpossolvex {
4669             my($a, $uplo, $b, %opt) = @_;
4670             my(@adims) = $a->dims;
4671             my(@bdims) = $b->dims;
4672             my ( $af, $x, $info, $equilibrate, $berr, $ferr, $rcond, $equed, %result, $s);
4673              
4674             barf("mpossolvex: Require a square coefficient matrix")
4675             unless( ((@adims == 2) || (@adims == 3)) && $adims[-1] == $adims[-2] );
4676             barf("mpossolvex: Require a 2D right hand side matrix B with number".
4677             " of row equal to order of A")
4678             unless( ((@bdims == 2) || (@bdims == 3))&& $bdims[-1] == $adims[-2]);
4679              
4680            
4681             $uplo = $uplo ? pdl(long, 0): pdl(long, 1);
4682             $equilibrate = $opt{'equilibrate'} ? pdl(long, 2): pdl(long,1);
4683             $a = $a->copy;
4684             $b = $b->t->copy;
4685             $x = PDL::zeroes $b;
4686             $af = PDL::zeroes $a;
4687             $info = pdl(long, 0);
4688             $rcond = null;
4689             $equed = pdl(long, 0);
4690              
4691             $s = zeroes($a->type, $adims[-2]);
4692             $ferr = zeroes($b->type, $bdims[-2]);
4693             $berr = zeroes($b->type, $bdims[-2]);
4694            
4695             (@adims == 3) ? $a->cposvx($uplo, $equilibrate, $b, $af, $equed, $s, $x, $rcond, $ferr, $berr, $info) :
4696             $a->posvx($uplo, $equilibrate, $b, $af, $equed, $s, $x, $rcond, $ferr, $berr, $info);
4697             if( $info < $adims[-2] && $info > 0){
4698             $info--;
4699             barf("mpossolvex: Can't solve system of linear equations:\n".
4700             "the leading minor of order $info of A is".
4701             " not positive definite");
4702             return;
4703             }
4704             elsif ( $info and $_laerror){
4705             warn("mpossolvex: The matrix is singular to working precision");
4706             }
4707             $result{rcondition} = $rcond;
4708             $result{ferror} = $ferr;
4709             $result{berror} = $berr;
4710             if ($opt{equilibrate}){
4711             $result{equilibration} = $equed;
4712             if ($equed){
4713             $result{scale} = $s if $equed;
4714             $result{A} = $a if $opt{A};
4715             $result{B} = $b->xchg(-2,-1)->sever if $opt{B};
4716             }
4717             }
4718             $result{info} = $info;
4719             $result{L} = $af if $opt{L};
4720             $result{U} = $af if $opt{U};
4721              
4722             wantarray ? ($x->xchg(-2,-1)->sever, %result): $x->xchg(-2,-1)->sever;
4723              
4724             }
4725              
4726             =head2 mlls
4727              
4728             =for ref
4729              
4730             Solves overdetermined or underdetermined real linear systems using QR or LQ factorization.
4731              
4732             If M > N in the M-by-N matrix A, returns the residual sum of squares too.
4733             Uses L or L from Lapack.
4734             Works on transposed arrays.
4735              
4736             =for usage
4737              
4738             PDL(X) = mlls(PDL(A), PDL(B), SCALAR(trans))
4739             trans : NOTRANSPOSE = 0 | TRANSPOSE/CONJUGATE = 1, default = 0
4740              
4741             =for example
4742              
4743             $a = random(4,5);
4744             $b = random(3,5);
4745             ($x, $res) = mlls($a, $b);
4746              
4747             =cut
4748              
4749             *mlls = \&PDL::mlls;
4750              
4751             sub PDL::mlls {
4752             my($a, $b, $trans) = @_;
4753             my(@adims) = $a->dims;
4754             my(@bdims) = $b->dims;
4755             my ($info, $x, $type);
4756              
4757             barf("mlls: Require a matrix")
4758             unless( @adims == 2 || @adims == 3);
4759             barf("mlls: Require a 2D right hand side matrix B with number".
4760             " of rows equal to number of rows of A")
4761             unless( (@bdims == 2 || @bdims == 3)&& $bdims[-1] == $adims[-1]);
4762              
4763             $a = $a->copy;
4764             $type = $a->type;
4765             if ( $adims[-1] < $adims[-2]){
4766             if (@adims == 3){
4767             $x = PDL::new_from_specification('PDL::Complex', $type, 2,$adims[1], $bdims[1]);
4768             $x(, :($bdims[2]-1), :($bdims[1]-1)) .= $b->xchg(1,2);
4769             }
4770             else{
4771             $x = PDL::new_from_specification('PDL', $type, $adims[0], $bdims[0]);
4772             $x(:($bdims[1]-1), :($bdims[0]-1)) .= $b->xchg(0,1);
4773             }
4774             }
4775             else{
4776             $x = $b->xchg(-2,-1)->copy;
4777             }
4778             $info = pdl(long,0);
4779              
4780             if (@adims == 3){
4781             $trans ? $a->xchg(1,2)->cgels(1, $x, $info) : $a->xchg(1,2)->cgels(0, $x, $info);
4782             }
4783             else{
4784             $trans ? $a->gels(0, $x, $info) : $a->gels(1, $x, $info);
4785             }
4786              
4787             $x = $x->xchg(-2,-1);
4788             if ( $adims[-1] <= $adims[-2]){
4789             return $x->sever;
4790             }
4791              
4792            
4793             if(@adims == 2){
4794             wantarray ? return($x(, :($adims[0]-1))->sever, $x(, $adims[0]:)->xchg(0,1)->pow(2)->sumover) :
4795             return $x(, :($adims[0]-1))->sever;
4796             }
4797             else{
4798             wantarray ? return($x(,, :($adims[1]-1))->sever, PDL::Ufunc::sumover(PDL::Complex::Cpow($x(,, $adims[1]:),pdl($type,2,0))->reorder(2,0,1))) :
4799             return $x(,, :($adims[1]-1))->sever;
4800             }
4801             }
4802              
4803             =head2 mllsy
4804              
4805             =for ref
4806              
4807             Computes the minimum-norm solution to a real linear least squares problem
4808             using a complete orthogonal factorization.
4809              
4810             Uses L or L
4811             from Lapack. Works on tranposed arrays.
4812              
4813             =for usage
4814              
4815             ( PDL(X), ( HASH(result) ) ) = mllsy(PDL(A), PDL(B))
4816             Returned values:
4817             X (SCALAR CONTEXT),
4818             HASH{'A'}:
4819             complete orthogonal factorization of A
4820             HASH{'jpvt'}:
4821             details of columns interchanges
4822             HASH{'rank'}:
4823             effective rank of A
4824              
4825             =for example
4826              
4827             my $a = random(10,10);
4828             my $b = random(10,10);
4829             $X = mllsy($a, $b);
4830              
4831             =cut
4832              
4833             *mllsy = \&PDL::mllsy;
4834              
4835             sub PDL::mllsy {
4836             my($a, $b) = @_;
4837             my(@adims) = $a->dims;
4838             my(@bdims) = $b->dims;
4839             my ($info, $x, $rcond, $rank, $jpvt, $type);
4840              
4841             barf("mllsy: Require a matrix")
4842             unless( @adims == 2 || @adims == 3);
4843             barf("mllsy: Require a 2D right hand side matrix B with number".
4844             " of rows equal to number of rows of A")
4845             unless( (@bdims == 2 || @bdims == 3)&& $bdims[-1] == $adims[-1]);
4846              
4847             $type = $a->type;
4848             $rcond = lamch(pdl($type,0));
4849             $rcond = $rcond->sqrt - ($rcond->sqrt - $rcond) / 2;
4850              
4851             $a = $a->xchg(-2,-1)->copy;
4852              
4853             if ( $adims[1] < $adims[0]){
4854             if (@adims == 3){
4855             $x = PDL::new_from_specification('PDL::Complex', $type, 2, $adims[1], $bdims[1]);
4856             $x(, :($bdims[2]-1), :($bdims[1]-1)) .= $b->xchg(1,2);
4857             }
4858             else{
4859             $x = PDL::new_from_specification('PDL', $type, $adims[0], $bdims[0]);
4860             $x(:($bdims[1]-1), :($bdims[0]-1)) .= $b->xchg(0,1);
4861             }
4862              
4863             }
4864             else{
4865             $x = $b->xchg(-2,-1)->copy;
4866             }
4867             $info = pdl(long,0);
4868             $rank = null;
4869             $jpvt = zeroes(long, $adims[-2]);
4870              
4871             (@adims == 3) ? $a->cgelsy($x, $rcond, $jpvt, $rank, $info) :
4872             $a->gelsy($x, $rcond, $jpvt, $rank, $info);
4873            
4874             if ( $adims[-1] <= $adims[-2]){
4875             wantarray ? return ($x->xchg(-2,-1)->sever, ('A'=> $a->xchg(-2,-1)->sever, 'rank' => $rank, 'jpvt'=>$jpvt)) :
4876             return $x->xchg(-2,-1)->sever;
4877             }
4878             if (@adims == 3){
4879             wantarray ? return ($x->xchg(1,2)->(,, :($adims[1]-1))->sever, ('A'=> $a->xchg(1,2)->sever, 'rank' => $rank, 'jpvt'=>$jpvt)) :
4880             $x->xchg(1,2)->(, :($adims[1]-1))->sever;
4881             }
4882             else{
4883             wantarray ? return ($x->xchg(0,1)->(, :($adims[0]-1))->sever, ('A'=> $a->xchg(0,1)->sever, 'rank' => $rank, 'jpvt'=>$jpvt)) :
4884             $x->xchg(0,1)->(, :($adims[0]-1))->sever;
4885             }
4886             }
4887              
4888             =head2 mllss
4889              
4890             =for ref
4891              
4892             Computes the minimum-norm solution to a real linear least squares problem
4893             using a singular value decomposition.
4894              
4895             Uses L or L from Lapack.
4896             Works on transposed arrays.
4897              
4898             =for usage
4899              
4900             ( PDL(X), ( HASH(result) ) )= mllss(PDL(A), PDL(B), SCALAR(method))
4901             method: specifie which method to use (see Lapack for further details)
4902             '(c)gelss' or '(c)gelsd', default = '(c)gelsd'
4903             Returned values:
4904             X (SCALAR CONTEXT),
4905             HASH{'V'}:
4906             if method = (c)gelss, the right singular vectors, stored columnwise
4907             HASH{'s'}:
4908             singular values from SVD
4909             HASH{'res'}:
4910             if A has full rank the residual sum-of-squares for the solution
4911             HASH{'rank'}:
4912             effective rank of A
4913             HASH{'info'}:
4914             info output from method
4915              
4916             =for example
4917              
4918             my $a = random(10,10);
4919             my $b = random(10,10);
4920             $X = mllss($a, $b);
4921              
4922             =cut
4923              
4924             *mllss = \&PDL::mllss;
4925              
4926             sub PDL::mllss {
4927             my($a, $b, $method) = @_;
4928             my(@adims) = $a->dims;
4929             my(@bdims) = $b->dims;
4930             my ($info, $x, $rcond, $rank, $s, $min, $type);
4931              
4932             barf("mllss: Require a matrix")
4933             unless( @adims == 2 || @adims == 3);
4934             barf("mllss: Require a 2D right hand side matrix B with number".
4935             " of rows equal to number of rows of A")
4936             unless( (@bdims == 2 || @bdims == 3)&& $bdims[-1] == $adims[-1]);
4937              
4938              
4939             $type = $a->type;
4940             #TODO: Add this in option
4941             $rcond = lamch(pdl($type,0));
4942             $rcond = $rcond->sqrt - ($rcond->sqrt - $rcond) / 2;
4943              
4944             $a = $a->xchg(-2,-1)->copy;
4945              
4946             if ($adims[1] < $adims[0]){
4947             if (@adims == 3){
4948             $x = PDL::new_from_specification('PDL::Complex', $type, 2, $adims[1], $bdims[1]);
4949             $x(, :($bdims[2]-1), :($bdims[1]-1)) .= $b->xchg(1,2);
4950             }
4951             else{
4952             $x = PDL::new_from_specification('PDL', $type, $adims[0], $bdims[0]);
4953             $x(:($bdims[1]-1), :($bdims[0]-1)) .= $b->xchg(0,1);
4954             }
4955              
4956             }
4957             else{
4958             $x = $b->xchg(-2,-1)->copy;
4959             }
4960              
4961             $info = pdl(long,0);
4962             $rank = null;
4963             $min = ($adims[-2] > $adims[-1]) ? $adims[-1] : $adims[-2];
4964             $s = zeroes($a->type, $min);
4965            
4966             unless ($method) {
4967             $method = (@adims == 3) ? 'cgelsd' : 'gelsd';
4968             }
4969              
4970             $a->$method($x, $rcond, $s, $rank, $info);
4971             laerror("mllss: The algorithm for computing the SVD failed to converge\n") if $info;
4972              
4973             $x = $x->xchg(-2,-1);
4974              
4975             if ( $adims[-1] <= $adims[-2]){
4976             if (wantarray){
4977             $method =~ /gelsd/ ? return ($x->sever, ('rank' => $rank, 's'=>$s, 'info'=>$info)):
4978             (return ($x, ('V'=> $a, 'rank' => $rank, 's'=>$s, 'info'=>$info)) );
4979             }
4980             else{return $x;}
4981             }
4982             elsif (wantarray){
4983             if ($rank == $min){
4984             if (@adims == 3){
4985             my $res = PDL::Ufunc::sumover(PDL::Complex::Cpow($x(,, $adims[1]:),pdl($type,2,0))->reorder(2,0,1));
4986             if ($method =~ /gelsd/){
4987            
4988             return ($x(,, :($adims[1]-1))->sever,
4989             ('res' => $res, 'rank' => $rank, 's'=>$s, 'info'=>$info));
4990             }
4991             else{
4992             return ($x(,, :($adims[1]-1))->sever,
4993             ('res' => $res, 'V'=> $a, 'rank' => $rank, 's'=>$s, 'info'=>$info));
4994             }
4995             }
4996             else{
4997             my $res = $x(, $adims[0]:)->xchg(0,1)->pow(2)->sumover;
4998             if ($method =~ /gelsd/){
4999            
5000             return ($x(, :($adims[0]-1))->sever,
5001             ('res' => $res, 'rank' => $rank, 's'=>$s, 'info'=>$info));
5002             }
5003             else{
5004             return ($x(, :($adims[0]-1))->sever,
5005             ('res' => $res, 'V'=> $a, 'rank' => $rank, 's'=>$s, 'info'=>$info));
5006             }
5007             }
5008             }
5009             else {
5010             if (@adims == 3){
5011             $method =~ /gelsd/ ? return ($x(,, :($adims[1]-1))->sever, ('rank' => $rank, 's'=>$s, 'info'=>$info))
5012             : ($x(,, :($adims[1]-1))->sever, ('v'=> $a, 'rank' => $rank, 's'=>$s, 'info'=>$info));
5013             }
5014             else{
5015             $method =~ /gelsd/ ? return ($x(, :($adims[0]-1))->sever, ('rank' => $rank, 's'=>$s, 'info'=>$info))
5016             : ($x(, :($adims[0]-1))->sever, ('v'=> $a, 'rank' => $rank, 's'=>$s, 'info'=>$info));
5017             }
5018             }
5019              
5020             }
5021             else{return (@adims == 3) ? $x(,, :($adims[1]-1))->sever : $x(, :($adims[0]-1))->sever;}
5022             }
5023              
5024             =head2 mglm
5025              
5026             =for ref
5027              
5028             Solves a general Gauss-Markov Linear Model (GLM) problem.
5029             Supports threading.
5030             Uses L or L
5031             from Lapack. Works on transposed arrays.
5032              
5033             =for usage
5034              
5035             (PDL(x), PDL(y)) = mglm(PDL(a), PDL(b), PDL(d))
5036             where d is the left hand side of the GLM equation
5037              
5038             =for example
5039              
5040             my $a = random(8,10);
5041             my $b = random(7,10);
5042             my $d = random(10);
5043             my ($x, $y) = mglm($a, $b, $d);
5044              
5045             =cut
5046              
5047             sub mglm{
5048             my $m = shift;
5049             $m->mglm(@_);
5050             }
5051              
5052             sub PDL::mglm{
5053             my($a, $b, $d) = @_;
5054             my(@adims) = $a->dims;
5055             my(@bdims) = $b->dims;
5056             my(@ddims) = $d->dims;
5057             my($x, $y, $info);
5058              
5059             barf("mglm: Require arrays with equal number of rows")
5060             unless( @adims >= 2 && @bdims >= 2 && $adims[1] == $bdims[1]);
5061            
5062             barf "mglm: Require that column(A) <= row(A) <= column(A) + column(B)" unless
5063             ( ($adims[0] <= $adims[1] ) && ($adims[1] <= ($adims[0] + $bdims[0])) );
5064              
5065             barf("mglm: Require vector(s) with size equal to number of rows of A")
5066             unless( @ddims >= 1 && $adims[1] == $ddims[0]);
5067              
5068             $a = $a->xchg(0,1)->copy;
5069             $b = $b->xchg(0,1)->copy;
5070             $d = $d->copy;
5071              
5072             ($x, $y, $info) = $a->ggglm($b, $d);
5073             $x, $y;
5074              
5075             }
5076              
5077             sub PDL::Complex::mglm {
5078             my($a, $b, $d) = @_;
5079             my(@adims) = $a->dims;
5080             my(@bdims) = $b->dims;
5081             my(@ddims) = $d->dims;
5082             my($x, $y, $info);
5083              
5084             barf("mglm: Require arrays with equal number of rows")
5085             unless( @adims >= 3 && @bdims >= 3 && $adims[2] == $bdims[2]);
5086            
5087             barf "mglm: Require that column(A) <= row(A) <= column(A) + column(B)" unless
5088             ( ($adims[2] <= $adims[2] ) && ($adims[2] <= ($adims[1] + $bdims[1])) );
5089              
5090             barf("mglm: Require vector(s) with size equal to number of rows of A")
5091             unless( @ddims >= 2 && $adims[2] == $ddims[1]);
5092              
5093              
5094             $a = $a->xchg(1,2)->copy;
5095             $b = $b->xchg(1,2)->copy;
5096             $d = $d->copy;
5097              
5098             ($x, $y, $info) = $a->cggglm($b, $d);
5099             $x, $y;
5100              
5101             }
5102              
5103              
5104             =head2 mlse
5105              
5106             =for ref
5107              
5108             Solves a linear equality-constrained least squares (LSE) problem.
5109             Uses L or L
5110             from Lapack. Works on transposed arrays.
5111              
5112             =for usage
5113              
5114             (PDL(x), PDL(res2)) = mlse(PDL(a), PDL(b), PDL(c), PDL(d))
5115             where
5116             c : The right hand side vector for the
5117             least squares part of the LSE problem.
5118             d : The right hand side vector for the
5119             constrained equation.
5120             x : The solution of the LSE problem.
5121             res2 : The residual sum of squares for the solution
5122             (returned only in array context)
5123              
5124              
5125             =for example
5126              
5127             my $a = random(5,4);
5128             my $b = random(5,3);
5129             my $c = random(4);
5130             my $d = random(3);
5131             my ($x, $res2) = mlse($a, $b, $c, $d);
5132              
5133             =cut
5134              
5135             *mlse = \&PDL::mlse;
5136              
5137             sub PDL::mlse {
5138             my($a, $b, $c, $d) = @_;
5139             my(@adims) = $a->dims;
5140             my(@bdims) = $b->dims;
5141             my(@cdims) = $c->dims;
5142             my(@ddims) = $d->dims;
5143              
5144             my($x, $info);
5145              
5146             barf("mlse: Require 2 matrices with equal number of columns")
5147             unless( ((@adims == 2 && @bdims == 2)||(@adims == 3 && @bdims == 3)) &&
5148             $adims[-2] == $bdims[-2]);
5149            
5150             barf("mlse: Require 1D vector C with size equal to number of A rows")
5151             unless( (@cdims == 1 || @cdims == 2)&& $adims[-1] == $cdims[-1]);
5152              
5153             barf("mlse: Require 1D vector D with size equal to number of B rows")
5154             unless( (@ddims == 1 || @ddims == 2)&& $bdims[-1] == $ddims[-1]);
5155              
5156             barf "mlse: Require that row(B) <= column(A) <= row(A) + row(B)" unless
5157             ( ($bdims[-1] <= $adims[-2] ) && ($adims[-2] <= ($adims[-1]+ $bdims[-1])) );
5158              
5159              
5160              
5161             $a = $a->xchg(-2,-1)->copy;
5162             $b = $b->xchg(-2,-1)->copy;
5163             $c = $c->copy;
5164             $d = $d->copy;
5165             ($x , $info) = (@adims == 3) ? $a->cgglse($b, $c, $d) : $a->gglse($b, $c, $d);
5166              
5167             if (@adims == 3){
5168             wantarray ? ($x, PDL::Ufunc::sumover(PDL::Complex::Cpow($c(,($adims[1]-$bdims[2]):($adims[2]-1)),pdl($a->type,2,0))->xchg(0,1))) : $x;
5169             }
5170             else{
5171             wantarray ? ($x, $c(($adims[0]-$bdims[1]):($adims[1]-1))->pow(2)->sumover) : $x;
5172             }
5173              
5174             }
5175              
5176             =head2 meigen
5177              
5178             =for ref
5179              
5180             Computes eigenvalues and, optionally, the left and/or right eigenvectors of a general square matrix
5181             (spectral decomposition).
5182             Eigenvectors are normalized (Euclidean norm = 1) and largest component real.
5183             The eigenvalues and eigenvectors returned are object of type PDL::Complex.
5184             If only eigenvalues are requested, info is returned in array context.
5185             Supports threading.
5186             Uses L or L from Lapack.
5187             Works on transposed arrays.
5188              
5189             =for usage
5190              
5191             (PDL(values), (PDL(LV), (PDL(RV)), (PDL(info))) = meigen(PDL, SCALAR(left vector), SCALAR(right vector))
5192             left vector : FALSE = 0 | TRUE = 1, default = 0
5193             right vector : FALSE = 0 | TRUE = 1, default = 0
5194              
5195             =for example
5196              
5197             my $a = random(10,10);
5198             my ( $eigenvalues, $left_eigenvectors, $right_eigenvectors ) = meigen($a,1,1);
5199              
5200             =cut
5201              
5202             sub meigen{
5203             my $m = shift;
5204             $m->meigen(@_);
5205             }
5206              
5207              
5208             sub PDL::meigen {
5209             my($m,$jobvl,$jobvr) = @_;
5210             my(@dims) = $m->dims;
5211              
5212             barf("meigen: Require square array(s)")
5213             unless( @dims >= 2 && $dims[0] == $dims[1]);
5214              
5215             my ($w, $vl, $vr, $info, $type, $wr, $wi);
5216             $type = $m->type;
5217              
5218             $info = null;
5219             $wr = null;
5220             $wi = null;
5221              
5222             $vl = $jobvl ? PDL::new_from_specification('PDL', $type, @dims) :
5223             pdl($type,0);
5224             $vr = $jobvr ? PDL::new_from_specification('PDL', $type, @dims) :
5225             pdl($type,0);
5226             $m->xchg(0,1)->geev( $jobvl,$jobvr, $wr, $wi, $vl, $vr, $info);
5227             if ($jobvl){
5228             ($w, $vl) = cplx_eigen((bless $wr, 'PDL::Complex'), $wi, $vl, 1);
5229             }
5230             if ($jobvr){
5231             ($w, $vr) = cplx_eigen((bless $wr, 'PDL::Complex'), $wi, $vr, 1);
5232             }
5233             $w = PDL::Complex::ecplx( $wr, $wi ) unless $jobvr || $jobvl;
5234              
5235             if($info->max > 0 && $_laerror) {
5236             my ($index,@list);
5237             $index = which($info > 0)+1;
5238             @list = $index->list;
5239             laerror("meigen: The QR algorithm failed to converge for PDL(s) @list: \$info = $info");
5240             print ("Returning converged eigenvalues\n");
5241             }
5242              
5243             $jobvl? $jobvr ? ($w, $vl->xchg(1,2)->sever, $vr->xchg(1,2)->sever, $info):($w, $vl->xchg(1,2)->sever, $info) :
5244             $jobvr? ($w, $vr->xchg(1,2)->sever, $info) : wantarray ? ($w, $info) : $w;
5245            
5246             }
5247              
5248             sub PDL::Complex::meigen {
5249             my($m,$jobvl,$jobvr) = @_;
5250             my(@dims) = $m->dims;
5251              
5252             barf("meigen: Require square array(s)")
5253             unless( @dims >= 3 && $dims[1] == $dims[2]);
5254              
5255             my ($w, $vl, $vr, $info, $type);
5256             $type = $m->type;
5257              
5258             $info = null;
5259            
5260             $w = PDL::Complex->null;
5261             #PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1]);
5262             $vl = $jobvl ? PDL::new_from_specification('PDL::Complex', $type, @dims) :
5263             pdl($type,[0,0]);
5264             $vr = $jobvr ? PDL::new_from_specification('PDL::Complex', $type, @dims) :
5265             pdl($type,[0,0]);
5266             $m->xchg(1,2)->cgeev( $jobvl,$jobvr, $w, $vl, $vr, $info);
5267              
5268             if($info->max > 0 && $_laerror) {
5269             my ($index,@list);
5270             $index = which($info > 0)+1;
5271             @list = $index->list;
5272             laerror("meigen: The QR algorithm failed to converge for PDL(s) @list: \$info = $info");
5273             print ("Returning converged eigenvalues\n");
5274             }
5275              
5276             $jobvl? $jobvr ? ($w, $vl->xchg(1,2)->sever, $vr->xchg(1,2)->sever, $info):($w, $vl->xchg(1,2)->sever, $info) :
5277             $jobvr? ($w, $vr->xchg(1,2)->sever, $info) : wantarray ? ($w, $info) : $w;
5278            
5279             }
5280              
5281              
5282             =head2 meigenx
5283              
5284             =for ref
5285              
5286             Computes eigenvalues, one-norm and, optionally, the left and/or right eigenvectors of a general square matrix
5287             (spectral decomposition).
5288             Eigenvectors are normalized (Euclidean norm = 1) and largest component real.
5289             The eigenvalues and eigenvectors returned are object of type PDL::Complex.
5290             Uses L or
5291             L from Lapack.
5292             Works on transposed arrays.
5293              
5294             =for usage
5295              
5296             (PDL(value), (PDL(lv), (PDL(rv)), HASH(result)), HASH(result)) = meigenx(PDL, HASH(options))
5297             where options are:
5298             vector: eigenvectors to compute
5299             'left': computes left eigenvectors
5300             'right': computes right eigenvectors
5301             'all': computes left and right eigenvectors
5302             0: doesn't compute (default)
5303             rcondition: reciprocal condition numbers to compute (returned in HASH{'rconde'} for eigenvalues and HASH{'rcondv'} for eigenvectors)
5304             'value': computes reciprocal condition numbers for eigenvalues
5305             'vector': computes reciprocal condition numbers for eigenvectors
5306             'all': computes reciprocal condition numbers for eigenvalues and eigenvectors
5307             0: doesn't compute (default)
5308             error: specifie whether or not it computes the error bounds (returned in HASH{'eerror'} and HASH{'verror'})
5309             error bound = EPS * One-norm / rcond(e|v)
5310             (reciprocal condition numbers for eigenvalues or eigenvectors must be computed).
5311             1: returns error bounds
5312             0: not computed
5313             scale: specifie whether or not it diagonaly scales the entry matrix
5314             (scale details returned in HASH : 'scale')
5315             1: scales
5316             0: Doesn't scale (default)
5317             permute: specifie whether or not it permutes row and columns
5318             (permute details returned in HASH{'balance'})
5319             1: permutes
5320             0: Doesn't permute (default)
5321             schur: specifie whether or not it returns the Schur form (returned in HASH{'schur'})
5322             1: returns Schur form
5323             0: not returned
5324             Returned values:
5325             eigenvalues (SCALAR CONTEXT),
5326             left eigenvectors if requested,
5327             right eigenvectors if requested,
5328             HASH{'norm'}:
5329             One-norm of the matrix
5330             HASH{'info'}:
5331             Info: if > 0, the QR algorithm failed to compute all the eigenvalues
5332             (see syevx for further details)
5333              
5334              
5335             =for example
5336              
5337             my $a = random(10,10);
5338             my %options = ( rcondition => 'all',
5339             vector => 'all',
5340             error => 1,
5341             scale => 1,
5342             permute=>1,
5343             shur => 1
5344             );
5345             my ( $eigenvalues, $left_eigenvectors, $right_eigenvectors, %result) = meigenx($a,%options);
5346             print "Error bounds for eigenvalues:\n $eigenvalues\n are:\n". transpose($result{'eerror'}) unless $info;
5347              
5348             =cut
5349              
5350              
5351             *meigenx = \&PDL::meigenx;
5352              
5353             sub PDL::meigenx {
5354             my($m, %opt) = @_;
5355             my(@dims) = $m->dims;
5356             barf("meigenx: Require a square matrix")
5357             unless( ( (@dims == 2)|| (@dims == 3) )&& $dims[-1] == $dims[-2]);
5358            
5359              
5360             my (%result, $jobvl, $jobvr, $sense, $balanc, $vr, $vl, $rconde, $rcondv,
5361             $w, $info, $ilo, $ihi, $scale, $abnrm, $type);
5362              
5363             $type = $m->type;
5364             $info = null;
5365             $ilo = null;
5366             $ihi = null;
5367             $abnrm = null;
5368             $balanc = ($opt{'permute'} && $opt{'scale'} ) ? 3 : $opt{'permute'} ? 1 : $opt{'scale'} ? 2:0;
5369              
5370             if (@dims == 3){
5371             $m = $m->copy;
5372             $w = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1]);
5373             $scale = PDL::new_from_specification('PDL', $type, $dims[1]);
5374            
5375             if ($opt{'vector'} eq 'left' ||
5376             $opt{'vector'} eq 'all' ||
5377             $opt{'rcondition'} ){
5378             $jobvl = 1;
5379             $vl = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1]);
5380             }
5381             else{
5382             $jobvl = 0;
5383             $vl = pdl($type,[0,0]);
5384             }
5385            
5386             if ($opt{'vector'} eq 'right' ||
5387             $opt{'vector'} eq 'all' ||
5388             $opt{'rcondition'} ){
5389             $jobvr = 1;
5390             $vr = PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1]);
5391             }
5392             else{
5393             $jobvr = 0;
5394             $vr = pdl($type,[0,0]);
5395             }
5396            
5397             if ( $opt{'rcondition'} eq 'value'){
5398             $sense = 1;
5399             $rconde = PDL::new_from_specification('PDL', $type, $dims[1]);
5400             $rcondv = pdl($type,0);
5401             }
5402             elsif( $opt{'rcondition'} eq 'vector'){
5403             $sense = 2;
5404             $rcondv = PDL::new_from_specification('PDL', $type, $dims[1]);
5405             $rconde = pdl($type,0);
5406             }
5407             elsif( $opt{'rcondition'} eq 'all' ){
5408             $sense = 3;
5409             $rcondv = PDL::new_from_specification('PDL', $type, $dims[1]);
5410             $rconde = PDL::new_from_specification('PDL', $type, $dims[1]);
5411             }
5412             else{
5413             $sense = 0;
5414             $rconde = pdl($type,0);
5415             $rcondv = pdl($type,0);
5416             }
5417             $m->xchg(1,2)->cgeevx( $jobvl, $jobvr, $balanc,$sense,$w, $vl, $vr, $ilo, $ihi, $scale, $abnrm, $rconde, $rcondv, $info);
5418              
5419             }
5420             else{
5421             my ($wr, $wi);
5422             $m = $m->copy;
5423             $wr = PDL::new_from_specification('PDL', $type, $dims[0]);
5424             $wi = PDL::new_from_specification('PDL', $type, $dims[0]);
5425             $scale = PDL::new_from_specification('PDL', $type, $dims[0]);
5426            
5427             if ($opt{'vector'} eq 'left' ||
5428             $opt{'vector'} eq 'all' ||
5429             $opt{'rcondition'} ){
5430             $jobvl = 1;
5431             $vl = PDL::new_from_specification('PDL', $type, $dims[0], $dims[0]);
5432             }
5433             else{
5434             $jobvl = 0;
5435             $vl = pdl($type, 0);
5436             }
5437            
5438             if ($opt{'vector'} eq 'right' ||
5439             $opt{'vector'} eq 'all' ||
5440             $opt{'rcondition'} ){
5441             $jobvr = 1;
5442             $vr = PDL::new_from_specification('PDL', $type, $dims[0], $dims[0]);
5443             }
5444             else{
5445             $jobvr = 0;
5446             $vr = pdl($type,0);
5447             }
5448            
5449             if ( $opt{'rcondition'} eq 'value'){
5450             $sense = 1;
5451             $rconde = PDL::new_from_specification('PDL', $type, $dims[0]);
5452             $rcondv = pdl($type, 0);
5453             }
5454             elsif( $opt{'rcondition'} eq 'vector'){
5455             $sense = 2;
5456             $rcondv = PDL::new_from_specification('PDL', $type, $dims[0]);
5457             $rconde = pdl($type, 0);
5458             }
5459             elsif( $opt{'rcondition'} eq 'all' ){
5460             $sense = 3;
5461             $rcondv = PDL::new_from_specification('PDL', $type, $dims[0]);
5462             $rconde = PDL::new_from_specification('PDL', $type, $dims[0]);
5463             }
5464             else{
5465             $sense = 0;
5466             $rconde = pdl($type, 0);
5467             $rcondv = pdl($type, 0);
5468             }
5469             $m->xchg(0,1)->geevx( $jobvl, $jobvr, $balanc,$sense,$wr, $wi, $vl, $vr, $ilo, $ihi, $scale, $abnrm, $rconde, $rcondv, $info);
5470             if ($jobvl){
5471             ($w, $vl) = cplx_eigen((bless $wr, 'PDL::Complex'), $wi, $vl, 1);
5472             }
5473             if ($jobvr){
5474             ($w, $vr) = cplx_eigen((bless $wr, 'PDL::Complex'), $wi, $vr, 1);
5475             }
5476             $w = PDL::Complex::complex t(cat $wr, $wi) unless $jobvr || $jobvl;
5477             }
5478              
5479             if ($info){
5480             laerror("meigenx: The QR algorithm failed to converge");
5481             print "Returning converged eigenvalues\n" if $_laerror;
5482             }
5483            
5484            
5485             $result{'schur'} = $m if $opt{'schur'};
5486              
5487             if ($opt{'permute'}){
5488             my $balance = cat $ilo, $ihi;
5489             $result{'balance'} = $balance;
5490             }
5491            
5492             $result{'info'} = $info;
5493             $result{'scale'} = $scale if $opt{'scale'};
5494             $result{'norm'} = $abnrm;
5495              
5496             if ( $opt{'rcondition'} eq 'vector' || $opt{'rcondition'} eq "all"){
5497             $result{'rcondv'} = $rcondv;
5498             $result{'verror'} = (lamch(pdl($type,0))* $abnrm /$rcondv ) if $opt{'error'};
5499             }
5500             if ( $opt{'rcondition'} eq 'value' || $opt{'rcondition'} eq "all"){
5501             $result{'rconde'} = $rconde;
5502             $result{'eerror'} = (lamch(pdl($type,0))* $abnrm /$rconde ) if $opt{'error'};
5503             }
5504            
5505             if ($opt{'vector'} eq "left"){
5506             return ($w, $vl->xchg(-2,-1)->sever, %result);
5507             }
5508             elsif ($opt{'vector'} eq "right"){
5509             return ($w, $vr->xchg(-2,-1)->sever, %result);
5510             }
5511             elsif ($opt{'vector'} eq "all"){
5512             $w, $vl->xchg(-2,-1)->sever, $vr->xchg(-2,-1)->sever, %result;
5513             }
5514             else{
5515             return ($w, %result);
5516             }
5517              
5518             }
5519              
5520             =head2 mgeigen
5521              
5522             =for ref
5523              
5524             Computes generalized eigenvalues and, optionally, the left and/or right generalized eigenvectors
5525             for a pair of N-by-N real nonsymmetric matrices (A,B) .
5526             The alpha from ratio alpha/beta is object of type PDL::Complex.
5527             Supports threading. Uses L or
5528             L from Lapack.
5529             Works on transposed arrays.
5530              
5531             =for usage
5532              
5533             ( PDL(alpha), PDL(beta), ( PDL(LV), (PDL(RV) ), PDL(info)) = mgeigen(PDL(A),PDL(B) SCALAR(left vector), SCALAR(right vector))
5534             left vector : FALSE = 0 | TRUE = 1, default = 0
5535             right vector : FALSE = 0 | TRUE = 1, default = 0
5536              
5537             =for example
5538              
5539             my $a = random(10,10);
5540             my $b = random(10,10);
5541             my ( $alpha, $beta, $left_eigenvectors, $right_eigenvectors ) = mgeigen($a, $b,1, 1);
5542              
5543             =cut
5544              
5545              
5546             sub mgeigen{
5547             my $m = shift;
5548             $m->mgeigen(@_);
5549             }
5550              
5551             sub PDL::mgeigen {
5552             my($a, $b,$jobvl,$jobvr) = @_;
5553             my(@adims) = $a->dims;
5554             my(@bdims) = $b->dims;
5555              
5556              
5557             barf("mgeigen: Require 2 square matrices of same order")
5558             unless( @adims >= 2 && $adims[0] == $adims[1] &&
5559             @bdims >= 2 && $bdims[0] == $bdims[1] && $adims[0] == $bdims[0]);
5560             barf("mgeigen: Require matrices with equal number of dimensions")
5561             if( @adims != @bdims);
5562              
5563              
5564             my ($vl, $vr, $info, $beta, $type, $wtmp);
5565             $type = $a->type;
5566              
5567             my ($w,$wi);
5568             $b = $b->xchg(0,1);
5569             $wtmp = null;
5570             $wi = null;
5571             $beta = null;
5572             $vl = $jobvl ? PDL::zeroes $a : pdl($type,0);
5573             $vr = $jobvr ? PDL::zeroes $a : pdl($type,0);
5574             $info = null;
5575              
5576             $a->xchg(0,1)->ggev($jobvl,$jobvr, $b, $wtmp, $wi, $beta, $vl, $vr, $info);
5577              
5578             if($info->max > 0 && $_laerror) {
5579             my ($index,@list);
5580             $index = which($info > 0)+1;
5581             @list = $index->list;
5582             laerror("mgeigen: Can't compute eigenvalues/vectors for PDL(s) @list: \$info = $info");
5583             }
5584              
5585              
5586             $w = PDL::Complex::ecplx ($wtmp, $wi);
5587             if ($jobvl){
5588             (undef, $vl) = cplx_eigen((bless $wtmp, 'PDL::Complex'), $wi, $vl, 1);
5589             }
5590             if ($jobvr){
5591             (undef, $vr) = cplx_eigen((bless $wtmp, 'PDL::Complex'), $wi, $vr, 1);
5592             }
5593              
5594              
5595              
5596             $jobvl? $jobvr? ($w, $beta, $vl->xchg(1,2)->sever, $vr->xchg(1,2)->sever, $info):($w, $beta, $vl->xchg(1,2)->sever, $info) :
5597             $jobvr? ($w, $beta, $vr->xchg(1,2)->sever, $info): ($w, $beta, $info);
5598            
5599             }
5600              
5601             sub PDL::Complex::mgeigen {
5602             my($a, $b,$jobvl,$jobvr) = @_;
5603             my(@adims) = $a->dims;
5604             my(@bdims) = $b->dims;
5605              
5606             my ($vl, $vr, $info, $beta, $type, $eigens);
5607              
5608             $type = $a->type;
5609              
5610             barf("mgeigen: Require 2 square matrices of same order")
5611             unless( @adims >= 3 && $adims[1] == $adims[2] &&
5612             @bdims >= 3 && $bdims[1] == $bdims[2] && $adims[1] == $bdims[1]);
5613             barf("mgeigen: Require matrices with equal number of dimensions")
5614             if( @adims != @bdims);
5615              
5616              
5617             $b = $b->xchg(1,2);
5618             $eigens = PDL::Complex->null;
5619             $beta = PDL::Complex->null;
5620             $vl = $jobvl ? PDL::zeroes $a : pdl($type,[0,0]);
5621             $vr = $jobvr ? PDL::zeroes $a : pdl($type,[0,0]);
5622             $info = null;
5623              
5624             $a->xchg(1,2)->cggev($jobvl,$jobvr, $b, $eigens, $beta, $vl, $vr, $info);
5625              
5626             if($info->max > 0 && $_laerror) {
5627             my ($index,@list);
5628             $index = which($info > 0)+1;
5629             @list = $index->list;
5630             laerror("mgeigen: Can't compute eigenvalues/vectors for PDL(s) @list: \$info = $info");
5631             }
5632              
5633             $jobvl? $jobvr? ($eigens, $beta, $vl->xchg(1,2)->sever, $vr->xchg(1,2)->sever, $info):($eigens, $beta, $vl->xchg(1,2)->sever, $info) :
5634             $jobvr? ($eigens, $beta, $vr->xchg(1,2)->sever, $info): ($eigens, $beta, $info);
5635            
5636             }
5637              
5638              
5639             =head2 mgeigenx
5640              
5641             =for ref
5642              
5643             Computes generalized eigenvalues, one-norms and, optionally, the left and/or right generalized
5644             eigenvectors for a pair of N-by-N real nonsymmetric matrices (A,B).
5645             The alpha from ratio alpha/beta is object of type PDL::Complex.
5646             Uses L or
5647             L from Lapack.
5648             Works on transposed arrays.
5649              
5650             =for usage
5651              
5652             (PDL(alpha), PDL(beta), PDL(lv), PDL(rv), HASH(result) ) = mgeigenx(PDL(a), PDL(b), HASH(options))
5653             where options are:
5654             vector: eigenvectors to compute
5655             'left': computes left eigenvectors
5656             'right': computes right eigenvectors
5657             'all': computes left and right eigenvectors
5658             0: doesn't compute (default)
5659             rcondition: reciprocal condition numbers to compute (returned in HASH{'rconde'} for eigenvalues and HASH{'rcondv'} for eigenvectors)
5660             'value': computes reciprocal condition numbers for eigenvalues
5661             'vector': computes reciprocal condition numbers for eigenvectors
5662             'all': computes reciprocal condition numbers for eigenvalues and eigenvectors
5663             0: doesn't compute (default)
5664             error: specifie whether or not it computes the error bounds (returned in HASH{'eerror'} and HASH{'verror'})
5665             error bound = EPS * sqrt(one-norm(a)**2 + one-norm(b)**2) / rcond(e|v)
5666             (reciprocal condition numbers for eigenvalues or eigenvectors must be computed).
5667             1: returns error bounds
5668             0: not computed
5669             scale: specifie whether or not it diagonaly scales the entry matrix
5670             (scale details returned in HASH : 'lscale' and 'rscale')
5671             1: scales
5672             0: doesn't scale (default)
5673             permute: specifie whether or not it permutes row and columns
5674             (permute details returned in HASH{'balance'})
5675             1: permutes
5676             0: Doesn't permute (default)
5677             schur: specifie whether or not it returns the Schur forms (returned in HASH{'aschur'} and HASH{'bschur'})
5678             (right or left eigenvectors must be computed).
5679             1: returns Schur forms
5680             0: not returned
5681             Returned values:
5682             alpha,
5683             beta,
5684             left eigenvectors if requested,
5685             right eigenvectors if requested,
5686             HASH{'anorm'}, HASH{'bnorm'}:
5687             One-norm of the matrix A and B
5688             HASH{'info'}:
5689             Info: if > 0, the QR algorithm failed to compute all the eigenvalues
5690             (see syevx for further details)
5691              
5692             =for example
5693              
5694             $a = random(10,10);
5695             $b = random(10,10);
5696             %options = (rcondition => 'all',
5697             vector => 'all',
5698             error => 1,
5699             scale => 1,
5700             permute=>1,
5701             shur => 1
5702             );
5703             ($alpha, $beta, $left_eigenvectors, $right_eigenvectors, %result) = mgeigenx($a, $b,%options);
5704             print "Error bounds for eigenvalues:\n $eigenvalues\n are:\n". transpose($result{'eerror'}) unless $info;
5705              
5706             =cut
5707              
5708              
5709             *mgeigenx = \&PDL::mgeigenx;
5710              
5711             sub PDL::mgeigenx {
5712             my($a, $b,%opt) = @_;
5713             my(@adims) = $a->dims;
5714             my(@bdims) = $b->dims;
5715             my (%result, $jobvl, $jobvr, $sense, $balanc, $vr, $vl, $rconde, $rcondv,
5716             $wr, $wi, $beta, $info, $ilo, $ihi, $rscale, $lscale, $abnrm, $bbnrm, $type, $eigens);
5717            
5718             if (@adims ==3){
5719             barf("mgeigenx: Require 2 square matrices of same order")
5720             unless( @adims == 3 && $adims[1] == $adims[2] &&
5721             @bdims == 3 && $bdims[1] == $bdims[2] && $adims[1] == $bdims[1]);
5722              
5723             $a = $a->copy;
5724             $b = $b->xchg(-1,-2)->copy;
5725              
5726             $eigens = PDL::Complex->null;
5727             $beta = PDL::Complex->null;
5728              
5729             }
5730             else{
5731             barf("mgeigenx: Require 2 square matrices of same order")
5732             unless( @adims == 2 && $adims[0] == $adims[1] &&
5733             @bdims == 2 && $bdims[0] == $bdims[1] && $adims[0] == $bdims[0]);
5734              
5735             $a = $a->copy;
5736             $b = $b->xchg(0,1)->copy;
5737              
5738             $wr = null;
5739             $wi = null;
5740             $beta= null;
5741              
5742             }
5743              
5744             $type = $a->type;
5745             $info = null;
5746             $ilo = null;
5747             $ihi = null;
5748              
5749             $rscale = zeroes($type, $adims[-1]);
5750             $lscale = zeroes($type, $adims[-1]);
5751             $abnrm = null;
5752             $bbnrm = null;
5753            
5754             if ($opt{'vector'} eq 'left' ||
5755             $opt{'vector'} eq 'all' ||
5756             $opt{'rcondition'} ){
5757             $jobvl = pdl(long,1);
5758             $vl = PDL::zeroes $a;
5759             }
5760             else{
5761             $jobvl = pdl(long,0);
5762             $vl = pdl($type,0);
5763             }
5764              
5765             if ($opt{'vector'} eq 'right' ||
5766             $opt{'vector'} eq 'all' ||
5767             $opt{'rcondition'} ){
5768             $jobvr = pdl(long,1);
5769             $vr = PDL::zeroes $a;
5770             }
5771             else{
5772             $jobvr = pdl(long,0);
5773             $vr = pdl($type,0);
5774             }
5775              
5776              
5777             if ( $opt{'rcondition'} eq 'value'){
5778             $sense = pdl(long,1);
5779             $rconde = zeroes($type, $adims[-1]);
5780             $rcondv = pdl($type,0);
5781             }
5782             elsif( $opt{'rcondition'} eq 'vector'){
5783             $sense = pdl(long,2);
5784             $rcondv = zeroes($type, $adims[-1]);
5785             $rconde = pdl($type,0);
5786             }
5787             elsif( $opt{'rcondition'} eq 'all' ){
5788             $sense = pdl(long,3);
5789             $rcondv = zeroes($type, $adims[-1]);
5790             $rconde = zeroes($type, $adims[-1]);
5791             }
5792             else{
5793             $sense = pdl(long,0);
5794             $rconde = pdl($type,0);
5795             $rcondv = pdl($type,0);
5796             }
5797              
5798              
5799             $balanc = ($opt{'permute'} && $opt{'scale'} ) ? pdl(long,3) : $opt{'permute'} ? pdl(long,1) : $opt{'scale'} ? pdl(long,2) : pdl(long,0);
5800              
5801              
5802             if (@adims == 2){
5803             $a->xchg(0,1)->ggevx($balanc, $jobvl, $jobvr, $sense, $b, $wr, $wi, $beta, $vl, $vr, $ilo, $ihi, $lscale, $rscale,
5804             $abnrm, $bbnrm, $rconde, $rcondv, $info);
5805             $eigens = PDL::Complex::complex t(cat $wr, $wi);
5806             }
5807             else{
5808             $a->xchg(1,2)->cggevx($balanc, $jobvl, $jobvr, $sense, $b, $eigens, $beta, $vl, $vr, $ilo, $ihi, $lscale, $rscale,
5809             $abnrm, $bbnrm, $rconde, $rcondv, $info);
5810             }
5811              
5812              
5813              
5814              
5815             if ( ($info > 0) && ($info < $adims[-1])){
5816             laerror("mgeigenx: The QZ algorithm failed to converge");
5817             print ("Returning converged eigenvalues\n") if $_laerror;
5818             }
5819             elsif($info){
5820             laerror("mgeigenx: Error from hgeqz or tgevc");
5821             }
5822              
5823              
5824             $result{'aschur'} = $a if $opt{'schur'};
5825             $result{'bschur'} = $b->xchg(-1,-2)->sever if $opt{'schur'};
5826              
5827             if ($opt{'permute'}){
5828             my $balance = cat $ilo, $ihi;
5829             $result{'balance'} = $balance;
5830             }
5831            
5832             $result{'info'} = $info;
5833             $result{'rscale'} = $rscale if $opt{'scale'};
5834             $result{'lscale'} = $lscale if $opt{'scale'};
5835              
5836             $result{'anorm'} = $abnrm;
5837             $result{'bnorm'} = $bbnrm;
5838              
5839             # Doesn't use lacpy2 =(sqrt **2 , **2) without unnecessary overflow
5840             if ( $opt{'rcondition'} eq 'vector' || $opt{'rcondition'} eq "all"){
5841             $result{'rcondv'} = $rcondv;
5842             if ($opt{'error'}){
5843             $abnrm = sqrt ($abnrm->pow(2) + $bbnrm->pow(2));
5844             $result{'verror'} = (lamch(pdl($type,0))* $abnrm /$rcondv );
5845             }
5846             }
5847             if ( $opt{'rcondition'} eq 'value' || $opt{'rcondition'} eq "all"){
5848             $result{'rconde'} = $rconde;
5849             if ($opt{'error'}){
5850             $abnrm = sqrt ($abnrm->pow(2) + $bbnrm->pow(2));
5851             $result{'eerror'} = (lamch(pdl($type,0))* $abnrm /$rconde );
5852             }
5853             }
5854            
5855             if ($opt{'vector'} eq 'left'){
5856             return ($eigens, $beta, $vl->xchg(-1,-2)->sever, %result);
5857             }
5858             elsif ($opt{'vector'} eq 'right'){
5859             return ($eigens, $beta, $vr->xchg(-1,-2)->sever, %result);
5860             }
5861             elsif ($opt{'vector'} eq 'all'){
5862             return ($eigens, $beta, $vl->xchg(-1,-2)->sever, $vr->xchg(-1,-2)->sever, %result);
5863             }
5864             else{
5865             return ($eigens, $beta, %result);
5866             }
5867              
5868             }
5869              
5870              
5871             =head2 msymeigen
5872              
5873             =for ref
5874              
5875             Computes eigenvalues and, optionally eigenvectors of a real symmetric square or
5876             complex Hermitian matrix (spectral decomposition).
5877             The eigenvalues are computed from lower or upper triangular matrix.
5878             If only eigenvalues are requested, info is returned in array context.
5879             Supports threading and works inplace if eigenvectors are requested.
5880             From Lapack, uses L or L for real
5881             and L or L for complex.
5882             Works on transposed array(s).
5883              
5884             =for usage
5885              
5886             (PDL(values), (PDL(VECTORS)), PDL(info)) = msymeigen(PDL, SCALAR(uplo), SCALAR(vector), SCALAR(method))
5887             uplo : UPPER = 0 | LOWER = 1, default = 0
5888             vector : FALSE = 0 | TRUE = 1, default = 0
5889             method : 'syev' | 'syevd' | 'cheev' | 'cheevd', default = 'syevd'|'cheevd'
5890              
5891             =for example
5892              
5893             # Assume $a is symmetric
5894             my $a = random(10,10);
5895             my ( $eigenvalues, $eigenvectors ) = msymeigen($a,0,1, 'syev');
5896              
5897             =cut
5898              
5899             sub msymeigen{
5900             my $m = shift;
5901             $m->msymeigen(@_);
5902             }
5903              
5904             sub PDL::msymeigen {
5905             my($m, $upper, $jobv, $method) = @_;
5906             my(@dims) = $m->dims;
5907              
5908             barf("msymeigen: Require square array(s)")
5909             unless( @dims >= 2 && $dims[0] == $dims[1]);
5910              
5911             my ($w, $v, $info);
5912             $info = null;
5913             $w = null;
5914             $method = 'syevd' unless defined $method;
5915             $m = $m->copy unless ($m->is_inplace(0) and $jobv);
5916              
5917             $m->xchg(0,1)->$method($jobv, $upper, $w, $info);
5918            
5919             if($info->max > 0 && $_laerror) {
5920             my ($index,@list);
5921             $index = which($info > 0)+1;
5922             @list = $index->list;
5923             laerror("msymeigen: The algorithm failed to converge for PDL(s) @list: \$info = $info");
5924             }
5925              
5926             $jobv ? wantarray ? ($w , $m, $info) : $w : wantarray ? ($w, $info) : $w;
5927             }
5928              
5929             sub PDL::Complex::msymeigen {
5930             my($m, $upper, $jobv, $method) = @_;
5931             my(@dims) = $m->dims;
5932              
5933             barf("msymeigen: Require square array(s)")
5934             unless( @dims >= 3 && $dims[1] == $dims[2]);
5935              
5936             my ($w, $v, $info);
5937             $info = null;
5938             $w = null; #PDL::new_from_specification('PDL', $m->type, $dims[1]);
5939             $m = $m->copy unless ($m->is_inplace(0) and $jobv);
5940              
5941             $method = 'cheevd' unless defined $method;
5942             $m->xchg(1,2)->$method($jobv, $upper, $w, $info);
5943            
5944             if($info->max > 0 && $_laerror) {
5945             my ($index,@list);
5946             $index = which($info > 0)+1;
5947             @list = $index->list;
5948             laerror("msymeigen: The algorithm failed to converge for PDL(s) @list: \$info = $info");
5949             }
5950              
5951             $jobv ? wantarray ? ($w , $m, $info) : $w : wantarray ? ($w, $info) : $w;
5952             }
5953              
5954              
5955             =head2 msymeigenx
5956              
5957             =for ref
5958              
5959             Computes eigenvalues and, optionally eigenvectors of a symmetric square matrix (spectral decomposition).
5960             The eigenvalues are computed from lower or upper triangular matrix and can be selected by specifying a
5961             range. From Lapack, uses L or
5962             L for real and L
5963             or L for complex. Works on transposed arrays.
5964              
5965             =for usage
5966              
5967             (PDL(value), (PDL(vector)), PDL(n), PDL(info), (PDL(support)) ) = msymeigenx(PDL, SCALAR(uplo), SCALAR(vector), HASH(options))
5968             uplo : UPPER = 0 | LOWER = 1, default = 0
5969             vector : FALSE = 0 | TRUE = 1, default = 0
5970             where options are:
5971             range_type: method for selecting eigenvalues
5972             indice: range of indices
5973             interval: range of values
5974             0: find all eigenvalues and optionally all vectors
5975             range: PDL(2), lower and upper bounds interval or smallest and largest indices
5976             1<=range<=N for indice
5977             abstol: specifie error tolerance for eigenvalues
5978             method: specifie which method to use (see Lapack for further details)
5979             'syevx' (default)
5980             'syevr'
5981             'cheevx' (default)
5982             'cheevr'
5983             Returned values:
5984             eigenvalues (SCALAR CONTEXT),
5985             eigenvectors if requested,
5986             total number of eigenvalues found (n),
5987             info
5988             issupz or ifail (support) according to method used and returned info,
5989             for (sy|che)evx returns support only if info != 0
5990            
5991              
5992             =for example
5993              
5994             # Assume $a is symmetric
5995             my $a = random(10,10);
5996             my $overflow = lamch(9);
5997             my $range = cat pdl(0),$overflow;
5998             my $abstol = pdl(1.e-5);
5999             my %options = (range_type=>'interval',
6000             range => $range,
6001             abstol => $abstol,
6002             method=>'syevd');
6003             my ( $eigenvalues, $eigenvectors, $n, $isuppz ) = msymeigenx($a,0,1, %options);
6004              
6005             =cut
6006              
6007             *msymeigenx = \&PDL::msymeigenx;
6008              
6009             sub PDL::msymeigenx {
6010             my($m, $upper, $jobv, %opt) = @_;
6011             my(@dims) = $m->dims;
6012              
6013             barf("msymeigenx: Require a square matrix")
6014             unless( ( (@dims == 2)|| (@dims == 3) )&& $dims[-1] == $dims[-2]);
6015              
6016             my ($w, $v, $info, $n, $support, $z, $range, $method, $type);
6017              
6018             $type = $m->type;
6019              
6020             $range = ($opt{'range_type'} eq 'interval') ? pdl(long, 1) :
6021             ($opt{'range_type'} eq 'indice')? pdl(long, 2) : pdl(long, 0);
6022              
6023             if ((ref $opt{range}) ne 'PDL'){
6024             $opt{range} = pdl($type,[0,0]);
6025             $range = pdl(long, 0);
6026              
6027             }
6028             elsif ($range == 2){
6029             barf "msymeigenx: Indices must be > 0" unless $opt{range}->(0) > 0;
6030             barf "msymeigenx: Indices must be <= $dims[1]" unless $opt{range}->(1) <= $dims[1];
6031             }
6032             elsif ($range == 1){
6033             barf "msymeigenx: Interval limits must be differents" unless ($opt{range}->(0) != $opt{range}->(1));
6034             }
6035             $w = PDL::new_from_specification('PDL', $type, $dims[1]);
6036             $n = null;
6037             $info = pdl(long,0);
6038              
6039             if (!defined $opt{'abstol'})
6040             {
6041             my ( $unfl, $ovfl );
6042             $unfl = lamch(pdl($type,1));
6043             $ovfl = lamch(pdl($type,9));
6044             $unfl->labad($ovfl);
6045             $opt{'abstol'} = $unfl + $unfl;
6046             }
6047              
6048             $method = $opt{'method'} ? $opt{'method'} : (@dims == 3) ? 'PDL::LinearAlgebra::Complex::cheevx' : 'PDL::LinearAlgebra::Real::syevx';
6049              
6050             if ( $method =~ 'evx' && $jobv){
6051             $support = zeroes(long, $dims[1]);
6052             }
6053             elsif ($method =~ 'evr' && $jobv){
6054             $support = zeroes(long, (2*$dims[1]));
6055             }
6056              
6057             if (@dims == 3){
6058             $upper = $upper ? pdl(long,1) : pdl(long,0);
6059             $m = $m->xchg(1,2)->copy;
6060             $z = $jobv ? PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1], $dims[1]) :
6061             pdl($type,[0,0]);
6062             $m->$method($jobv, $range, $upper, $opt{range}->(0), $opt{range}->(1),$opt{range}->(0),$opt{range}->(1),
6063             $opt{'abstol'}, $n, $w, $z , $support, $info);
6064             }
6065             else{
6066             $upper = $upper ? pdl(long,0) : pdl(long,1);
6067             $m = $m->copy;
6068             $z = $jobv ? PDL::new_from_specification('PDL', $type, $dims[1], $dims[1]) :
6069             pdl($type,0);
6070             $m->$method($jobv, $range, $upper, $opt{range}->(0), $opt{range}->(1),$opt{range}->(0),$opt{range}->(1),
6071             $opt{'abstol'}, $n, $w, $z ,$support, $info);
6072             }
6073              
6074             if ($info){
6075             laerror("msymeigenx: The algorithm failed to converge.");
6076             print ("See support for details.\n") if $_laerror;
6077             }
6078              
6079              
6080             if ($jobv){
6081             if ($info){
6082             return ($w , $z->xchg(-2,-1)->sever, $n, $info, $support);
6083             }
6084             elsif ($method =~ 'evr'){
6085             return (undef,undef,$n,$info,$support) if $n == 0;
6086             return (@dims == 3) ? ($w(:$n-1)->sever , $z->xchg(1,2)->(,:$n-1,)->sever, $n, $info, $support) :
6087             ($w(:$n-1)->sever , $z->xchg(0,1)->(:$n-1,)->sever, $n, $info, $support);
6088             }
6089             else{
6090             return (undef,undef,$n, $info) if $n == 0;
6091             return (@dims == 3) ? ($w(:$n-1)->sever , $z->xchg(1,2)->(,:$n-1,)->sever, $n, $info) :
6092             ($w(:$n-1)->sever , $z->xchg(0,1)->(:$n-1,)->sever, $n, $info);
6093             }
6094             }
6095             else{
6096             if ($info){
6097             wantarray ? ($w, $n, $info, $support) : $w;
6098             }
6099             elsif ($method =~ 'evr'){
6100             wantarray ? ($w(:$n-1)->sever, $n, $info, $support) : $w;
6101             }
6102             else{
6103             wantarray ? ($w(:$n-1)->sever, $n, $info) : $w;
6104             }
6105             }
6106             }
6107              
6108             =head2 msymgeigen
6109              
6110             =for ref
6111              
6112             Computes eigenvalues and, optionally eigenvectors of a real generalized
6113             symmetric-definite or Hermitian-definite eigenproblem.
6114             The eigenvalues are computed from lower or upper triangular matrix
6115             If only eigenvalues are requested, info is returned in array context.
6116             Supports threading. From Lapack, uses L or L for real
6117             or L or L for complex.
6118             Works on transposed array(s).
6119              
6120             =for usage
6121              
6122             (PDL(values), (PDL(vectors)), PDL(info)) = msymgeigen(PDL(a), PDL(b),SCALAR(uplo), SCALAR(vector), SCALAR(type), SCALAR(method))
6123             uplo : UPPER = 0 | LOWER = 1, default = 0
6124             vector : FALSE = 0 | TRUE = 1, default = 0
6125             type :
6126             1: A * x = (lambda) * B * x
6127             2: A * B * x = (lambda) * x
6128             3: B * A * x = (lambda) * x
6129             default = 1
6130             method : 'sygv' | 'sygvd' for real or ,'chegv' | 'chegvd' for complex, default = 'sygvd' | 'chegvd'
6131              
6132             =for example
6133              
6134             # Assume $a is symmetric
6135             my $a = random(10,10);
6136             my $b = random(10,10);
6137             $b = $b->crossprod($b);
6138             my ( $eigenvalues, $eigenvectors ) = msymgeigen($a, $b, 0, 1, 1, 'sygv');
6139              
6140             =cut
6141              
6142              
6143             sub msymgeigen{
6144             my $a = shift;
6145             $a->msymgeigen(@_);
6146             }
6147              
6148             sub PDL::msymgeigen {
6149             my($a, $b, $upper, $jobv, $type, $method) = @_;
6150             my(@adims) = $a->dims;
6151             my(@bdims) = $b->dims;
6152              
6153             barf("msymgeigen: Require square matrices of same order")
6154             unless( @adims >= 2 && @bdims >= 2 && $adims[0] == $adims[1] &&
6155             $bdims[0] == $bdims[1] && $adims[0] == $bdims[0]);
6156             barf("msymgeigen: Require matrices with equal number of dimensions")
6157             if( @adims != @bdims);
6158              
6159             $type = 1 unless $type;
6160             my ($w, $v, $info);
6161             $method = 'PDL::LinearAlgebra::Real::sygvd' unless defined $method;
6162              
6163              
6164             $upper = 1-$upper;
6165             $a = $a->copy;
6166             $b = $b->copy;
6167             $w = null;
6168             $info = null;
6169            
6170             $a->$method($type, $jobv, $upper, $b, $w, $info);
6171              
6172             if($info->max > 0 && $_laerror) {
6173             my ($index,@list);
6174             $index = which($info > 0)+1;
6175             @list = $index->list;
6176             laerror("msymgeigen: Can't compute eigenvalues/vectors: matrix (PDL(s) @list) is/are not positive definite(s) or the algorithm failed to converge: \$info = $info");
6177             }
6178              
6179             return $jobv ? ($w , $a->xchg(0,1)->sever, $info) : wantarray ? ($w, $info) : $w;
6180             }
6181              
6182             sub PDL::Complex::msymgeigen {
6183             my($a, $b, $upper, $jobv, $type, $method) = @_;
6184             my(@adims) = $a->dims;
6185             my(@bdims) = $b->dims;
6186              
6187             barf("msymgeigen: Require 2 square matrices of same order")
6188             unless( @adims >= 3 && @bdims >= 3 && $adims[1] == $adims[2] &&
6189             $bdims[1] == $bdims[2] && $adims[1] == $bdims[1]);
6190             barf("msymgeigen: Require matrices with equal number of dimensions")
6191             if( @adims != @bdims);
6192              
6193              
6194             $type = 1 unless $type;
6195             my ($w, $v, $info);
6196             $method = 'PDL::LinearAlgebra::Complex::chegvd' unless defined $method;
6197              
6198              
6199             $a = $a->xchg(1,2)->copy;
6200             $b = $b->xchg(1,2)->copy;
6201             $w = null;
6202             $info = null;
6203            
6204             # TODO bug in chegv ???
6205             $a->$method($type, $jobv, $upper, $b, $w, $info);
6206              
6207             if($info->max > 0 && $_laerror) {
6208             my ($index,@list);
6209             $index = which($info > 0)+1;
6210             @list = $index->list;
6211             laerror("msymgeigen: Can't compute eigenvalues/vectors: matrix (PDL(s) @list) is/are not positive definite(s) or the algorithm failed to converge: \$info = $info");
6212             }
6213              
6214             return $jobv ? ($w , $a->xchg(1,2)->sever, $info) : wantarray ? ($w, $info) : $w;
6215             }
6216              
6217              
6218              
6219             =head2 msymgeigenx
6220              
6221             =for ref
6222              
6223             Computes eigenvalues and, optionally eigenvectors of a real generalized
6224             symmetric-definite or Hermitian eigenproblem.
6225             The eigenvalues are computed from lower or upper triangular matrix and can be selected by specifying a
6226             range. Uses L or L
6227             from Lapack. Works on transposed arrays.
6228              
6229             =for usage
6230              
6231             (PDL(value), (PDL(vector)), PDL(info), PDL(n), (PDL(support)) ) = msymeigenx(PDL(a), PDL(b), SCALAR(uplo), SCALAR(vector), HASH(options))
6232             uplo : UPPER = 0 | LOWER = 1, default = 0
6233             vector : FALSE = 0 | TRUE = 1, default = 0
6234             where options are:
6235             type : Specifies the problem type to be solved
6236             1: A * x = (lambda) * B * x
6237             2: A * B * x = (lambda) * x
6238             3: B * A * x = (lambda) * x
6239             default = 1
6240             range_type: method for selecting eigenvalues
6241             indice: range of indices
6242             interval: range of values
6243             0: find all eigenvalues and optionally all vectors
6244             range: PDL(2), lower and upper bounds interval or smallest and largest indices
6245             1<=range<=N for indice
6246             abstol: specifie error tolerance for eigenvalues
6247             Returned values:
6248             eigenvalues (SCALAR CONTEXT),
6249             eigenvectors if requested,
6250             total number of eigenvalues found (n),
6251             info
6252             ifail according to returned info (support).
6253              
6254             =for example
6255              
6256             # Assume $a is symmetric
6257             my $a = random(10,10);
6258             my $b = random(10,10);
6259             $b = $b->crossprod($b);
6260             my $overflow = lamch(9);
6261             my $range = cat pdl(0),$overflow;
6262             my $abstol = pdl(1.e-5);
6263             my %options = (range_type=>'interval',
6264             range => $range,
6265             abstol => $abstol,
6266             type => 1);
6267             my ( $eigenvalues, $eigenvectors, $n, $isuppz ) = msymgeigenx($a, $b, 0,1, %options);
6268              
6269             =cut
6270              
6271             *msymgeigenx = \&PDL::msymgeigenx;
6272              
6273             sub PDL::msymgeigenx {
6274             my($a, $b, $upper, $jobv, %opt) = @_;
6275             my(@adims) = $a->dims;
6276             my(@bdims) = $b->dims;
6277              
6278             if(@adims == 3){
6279             barf("msymgeigenx: Require 2 square matrices of same order")
6280             unless( @bdims == 3 && $adims[1] == $adims[2] &&
6281             $bdims[1] == $bdims[2] && $adims[1] == $bdims[1]);
6282             }
6283             else{
6284             barf("msymgeigenx: Require 2 square matrices of same order")
6285             unless( @adims == 2 && @bdims == 2 && $adims[0] == $adims[1] &&
6286             $bdims[0] == $bdims[1] && $adims[0] == $bdims[0]);
6287             }
6288            
6289             my ($w, $info, $n, $support, $z, $range, $type);
6290              
6291             $type = $a->type;
6292              
6293             $range = ($opt{'range_type'} eq 'interval') ? pdl(long, 1) :
6294             ($opt{'range_type'} eq 'indice')? pdl(long, 2) : pdl(long, 0);
6295              
6296             if (UNIVERSAL::isa($opt{range},'PDL')){
6297             $opt{range} = pdl($type,[0,0]);
6298             $range = pdl(long, 0);
6299              
6300             }
6301             $opt{type} = 1 unless (defined $opt{type});
6302             $w = PDL::new_from_specification('PDL', $type, $adims[1]);
6303             $n = pdl(long,0);
6304             $info = pdl(long,0);
6305              
6306             if (!defined $opt{'abstol'}){
6307             my ( $unfl, $ovfl );
6308             $unfl = lamch(pdl($type,1));
6309             $ovfl = lamch(pdl($type,9));
6310             $unfl->labad($ovfl);
6311             $opt{'abstol'} = $unfl + $unfl;
6312             }
6313             $support = zeroes(long, $adims[1]) if $jobv;
6314             $w = PDL::new_from_specification('PDL', $type, $adims[1]);
6315             $z = PDL::zeroes $a;
6316             if (@adims ==3){
6317             $upper = $upper ? pdl(long,1) : pdl(long,0);
6318             $a = $a->xchg(-1,-2)->copy;
6319             $b = $b->xchg(-1,-2)->copy;
6320             $a->chegvx($opt{type}, $jobv, $range, $upper, $b, $opt{range}->(0), $opt{range}->(1),$opt{range}->(0),$opt{range}->(1),
6321             $opt{'abstol'}, $n, $w, $z ,$support, $info);
6322             }
6323             else{
6324             $upper = $upper ? pdl(long,0) : pdl(long,1);
6325             $a = $a->copy;
6326             $b = $b->copy;
6327             $a->sygvx($opt{type}, $jobv, $range, $upper, $b, $opt{range}->(0), $opt{range}->(1),$opt{range}->(0),$opt{range}->(1),
6328             $opt{'abstol'}, $n, $w, $z ,$support, $info);
6329             }
6330             if ( ($info > 0) && ($info < $adims[-1])){
6331             laerror("msymgeigenx: The algorithm failed to converge");
6332             print("see support for details\n") if $_laerror;
6333             }
6334             elsif($info){
6335             $info = $info - $adims[-1] - 1;
6336             barf("msymgeigenx: The leading minor of order $info of B is not positive definite\n");
6337             }
6338              
6339             if ($jobv){
6340             if ($info){
6341             return ($w , $z->xchg(-1,-2)->sever, $n, $info, $support) ;
6342             }
6343             else{
6344             return ($w , $z->xchg(-1,-2)->sever, $n, $info);
6345             }
6346             }
6347             else{
6348             if ($info){
6349             wantarray ? ($w, $n, $info, $support) : $w;
6350             }
6351             else{
6352             wantarray ? ($w, $n, $info) : $w;
6353             }
6354             }
6355             }
6356              
6357              
6358             =head2 mdsvd
6359              
6360             =for ref
6361              
6362             Computes SVD using Coppen's divide and conquer algorithm.
6363             Return singular values in scalar context else left (U),
6364             singular values, right (V' (hermitian for complex)) singular vectors and info.
6365             Supports threading.
6366             If only singulars values are requested, info is only returned in array context.
6367             Uses L or L from Lapack.
6368              
6369             =for usage
6370              
6371             (PDL(U), (PDL(s), PDL(V)), PDL(info)) = mdsvd(PDL, SCALAR(job))
6372             job : 0 = computes only singular values
6373             1 = computes full SVD (square U and V)
6374             2 = computes SVD (singular values, right and left singular vectors)
6375             default = 1
6376              
6377             =for example
6378              
6379             my $a = random(5,10);
6380             my ($u, $s, $v) = mdsvd($a);
6381              
6382             =cut
6383              
6384              
6385             sub mdsvd{
6386             my $a = shift;
6387             $a->mdsvd(@_);
6388             }
6389              
6390              
6391             sub PDL::mdsvd {
6392             my($m, $job) = @_;
6393             my(@dims) = $m->dims;
6394              
6395             my ($u, $s, $v, $min, $info, $type);
6396             $type = $m->type;
6397             if (wantarray){
6398             $job = 1 unless defined($job);
6399             }
6400             else{
6401             $job = 0;
6402             }
6403             $min = $dims[0] > $dims[1] ? $dims[1]: $dims[0];
6404             $info = null;
6405             $s = null;
6406             $m = $m->copy;
6407              
6408             if ($job){
6409             if ($job == 2){
6410             $u = PDL::new_from_specification('PDL', $type, $min, $dims[1],@dims[2..$#dims]);
6411             $v = PDL::new_from_specification('PDL', $type, $dims[0],$min,@dims[2..$#dims]);
6412             }
6413             else{
6414             $u = PDL::new_from_specification('PDL', $type, $dims[1],$dims[1],@dims[2..$#dims]);
6415             $v = PDL::new_from_specification('PDL', $type, $dims[0],$dims[0],@dims[2..$#dims]);
6416             }
6417             }else{
6418             $u = PDL::new_from_specification('PDL', $type, 1,1);
6419             $v = PDL::new_from_specification('PDL', $type, 1,1);
6420             }
6421             $m->gesdd($job, $s, $v, $u, $info);
6422             if($info->max > 0 && $_laerror) {
6423             my ($index,@list);
6424             $index = which($info > 0)+1;
6425             @list = $index->list;
6426             laerror("mdsvd: Matrix (PDL(s) @list) is/are singular(s): \$info = $info");
6427             }
6428              
6429             if ($job){
6430             return ($u, $s, $v, $info);
6431             }else{ return wantarray ? ($s, $info) : $s; }
6432             }
6433              
6434             #Humm... $a= cplx random(2,4,5)
6435             sub PDL::Complex::mdsvd {
6436             my($m, $job) = @_;
6437             my(@dims) = $m->dims;
6438              
6439             my ($u, $s, $v, $min, $info, $type);
6440             $type = $m->type;
6441             if (wantarray){
6442             $job = 1 unless defined($job);
6443             }
6444             else{
6445             $job = 0;
6446             }
6447             $min = $dims[-2] > $dims[-1] ? $dims[-1]: $dims[-2];
6448             $info=null;
6449             $s = null;
6450             $m = $m->copy;
6451              
6452             if ($job){
6453             if ($job == 2){
6454             $u = PDL::new_from_specification('PDL::Complex', $type, 2,$min, $dims[2],@dims[3..$#dims]);
6455             $v = PDL::new_from_specification('PDL::Complex', $type, 2,$dims[1],$min,@dims[3..$#dims]);
6456             }
6457             else{
6458             $u = PDL::new_from_specification('PDL::Complex', $type, 2,$dims[2],$dims[2],@dims[3..$#dims]);
6459             $v = PDL::new_from_specification('PDL::Complex', $type, 2,$dims[1],$dims[1],@dims[3..$#dims]);
6460             }
6461             }else{
6462             $u = PDL::new_from_specification('PDL', $type, 2,1,1);
6463             $v = PDL::new_from_specification('PDL', $type, 2,1,1);
6464             }
6465             $m->cgesdd($job, $s, $v, $u, $info);
6466             if($info->max > 0 && $_laerror) {
6467             my ($index,@list);
6468             $index = which($info > 0)+1;
6469             @list = $index->list;
6470             laerror("mdsvd: Matrix (PDL(s) @list) is/are singular(s): \$info = $info");
6471             }
6472              
6473             if ($job){
6474             return ($u, $s, $v, $info);
6475             }else{ return wantarray ? ($s, $info) : $s; }
6476             }
6477              
6478              
6479              
6480             =head2 msvd
6481              
6482             =for ref
6483              
6484             Computes SVD.
6485             Can compute singular values, either U or V or neither.
6486             Return singulars values in scalar context else left (U),
6487             singular values, right (V' (hermitian for complex) singulars vector and info.
6488             Supports threading.
6489             If only singulars values are requested, info is returned in array context.
6490             Uses L or L from Lapack.
6491              
6492             =for usage
6493              
6494             ( (PDL(U)), PDL(s), (PDL(V), PDL(info)) = msvd(PDL, SCALAR(jobu), SCALAR(jobv))
6495             jobu : 0 = Doesn't compute U
6496             1 = computes full SVD (square U)
6497             2 = computes right singular vectors
6498             default = 1
6499             jobv : 0 = Doesn't compute V
6500             1 = computes full SVD (square V)
6501             2 = computes left singular vectors
6502             default = 1
6503              
6504             =for example
6505              
6506             my $a = random(10,10);
6507             my ($u, $s, $v) = msvd($a);
6508              
6509             =cut
6510              
6511             sub msvd{
6512             my $a = shift;
6513             $a->msvd(@_);
6514             }
6515              
6516              
6517             sub PDL::msvd {
6518             my($m, $jobu, $jobv) = @_;
6519             my(@dims) = $m->dims;
6520              
6521             my ($u, $s, $v, $min, $info, $type);
6522             $type = $m->type;
6523             if (wantarray){
6524             $jobu = 1 unless defined $jobu;
6525             $jobv = 1 unless defined $jobv;
6526             }
6527             else{
6528             $jobu = 0;
6529             $jobv = 0;
6530             }
6531             $m = $m->copy;
6532             $min = $dims[-2] > $dims[-1] ? $dims[-1]: $dims[-2];
6533             $s = null;
6534             $info = null;
6535              
6536             if ($jobv){
6537             $v = ($jobv == 1) ? PDL::new_from_specification('PDL', $type, $dims[0],$dims[0],@dims[2..$#dims]):
6538             PDL::new_from_specification('PDL', $type, $dims[0],$min,@dims[2..$#dims]);
6539             }else {$v = PDL::new_from_specification('PDL', $type, 1,1);}
6540             if ($jobu){
6541             $u = ($jobu == 1) ? PDL::new_from_specification('PDL', $type, $dims[1],$dims[1],@dims[2..$#dims]):
6542             PDL::new_from_specification('PDL', $type, $min, $dims[1],@dims[2..$#dims]);
6543            
6544             }else {$u = PDL::new_from_specification('PDL', $type, 1,1);}
6545             $m->gesvd($jobv, $jobu,$s, $v, $u, $info);
6546              
6547             if($info->max > 0 && $_laerror) {
6548             my ($index,@list);
6549             $index = which($info > 0)+1;
6550             @list = $index->list;
6551             laerror("msvd: Matrix (PDL(s) @list) is/are singular(s): \$info = $info");
6552             }
6553              
6554             if ($jobu){
6555             if ($jobv){
6556             return ($u, $s, $v, $info);
6557             }
6558             return ($u, $s, $info);
6559             }
6560             elsif($jobv){
6561             return ($s, $v, $info);
6562             }
6563             else{return wantarray ? ($s, $info) : $s;}
6564             }
6565              
6566             sub PDL::Complex::msvd{
6567             my($m, $jobu, $jobv) = @_;
6568             my(@dims) = $m->dims;
6569              
6570             my ($u, $s, $v, $min, $info, $type);
6571             $type = $m->type;
6572             if (wantarray){
6573             $jobu = 1 unless defined $jobu;
6574             $jobv = 1 unless defined $jobv;
6575             }
6576             else{
6577             $jobu = 0;
6578             $jobv = 0;
6579             }
6580             $m = $m->copy;
6581             $min = $dims[-2] > $dims[-1] ? $dims[-1]: $dims[-2];
6582             $s = null;
6583             $info = null;
6584              
6585             if ($jobv){
6586             $v = ($jobv == 1) ? PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1],$dims[1],@dims[3..$#dims]):
6587             PDL::new_from_specification('PDL::Complex', $type, 2, $dims[1],$min,@dims[3..$#dims]);
6588             }else {$v = PDL::new_from_specification('PDL', $type, 2,1,1);}
6589             if ($jobu){
6590             $u = ($jobu == 1) ? PDL::new_from_specification('PDL::Complex', $type, 2, $dims[2],$dims[2],@dims[3..$#dims]):
6591             PDL::new_from_specification('PDL::Complex', $type, 2, $min, $dims[2],@dims[3..$#dims]);
6592            
6593             }else {$u = PDL::new_from_specification('PDL', $type, 2,1,1);}
6594             $m->cgesvd($jobv, $jobu,$s, $v, $u, $info);
6595              
6596             if($info->max > 0 && $_laerror) {
6597             my ($index,@list);
6598             $index = which($info > 0)+1;
6599             @list = $index->list;
6600             laerror("msvd: Matrix (PDL(s) @list) is/are singular(s): \$info = $info");
6601             }
6602              
6603             if ($jobu){
6604             if ($jobv){
6605             return ($u, $s, $v, $info);
6606             }
6607             return ($u, $s, $info);
6608             }
6609             elsif($jobv){
6610             return ($s, $v, $info);
6611             }
6612             else{return wantarray ? ($s, $info) : $s;}
6613             }
6614              
6615              
6616             =head2 mgsvd
6617              
6618             =for ref
6619              
6620             Computes generalized (or quotient) singular value decomposition.
6621             If the effective rank of (A',B')' is 0 return only unitary V, U, Q.
6622             For complex number, needs object of type PDL::Complex.
6623             Uses L or
6624             L from Lapack. Works on transposed arrays.
6625              
6626             =for usage
6627              
6628             (PDL(sa), PDL(sb), %ret) = mgsvd(PDL(a), PDL(b), %HASH(options))
6629             where options are:
6630             V: whether or not computes V (boolean, returned in HASH{'V'})
6631             U: whether or not computes U (boolean, returned in HASH{'U'})
6632             Q: whether or not computes Q (boolean, returned in HASH{'Q'})
6633             D1: whether or not computes D1 (boolean, returned in HASH{'D1'})
6634             D2: whether or not computes D2 (boolean, returned in HASH{'D2'})
6635             0R: whether or not computes 0R (boolean, returned in HASH{'0R'})
6636             R: whether or not computes R (boolean, returned in HASH{'R'})
6637             X: whether or not computes X (boolean, returned in HASH{'X'})
6638             all: whether or not computes all the above.
6639             Returned value:
6640             sa,sb : singular value pairs of A and B (generalized singular values = sa/sb)
6641             $ret{'rank'} : effective numerical rank of (A',B')'
6642             $ret{'info'} : info from (c)ggsvd
6643              
6644             =for example
6645              
6646             my $a = random(5,5);
6647             my $b = random(5,7);
6648             my ($c, $s, %ret) = mgsvd($a, $b, X => 1);
6649              
6650             =cut
6651              
6652             sub mgsvd{
6653             my $m =shift;
6654             $m->mgsvd(@_);
6655             }
6656              
6657             sub PDL::mgsvd {
6658             my($a, $b, %opt) = @_;
6659             my(@adims) = $a->dims;
6660             my(@bdims) = $b->dims;
6661             barf("mgsvd: Require matrices with equal number of columns")
6662             unless( @adims == 2 && @bdims == 2 && $adims[0] == $bdims[0] );
6663              
6664             my ($U, $V, $Q, $alpha, $beta, $k, $l, $iwork, $info, $D2, $D1, $work, %ret, $X, $jobqx, $type);
6665             if ($opt{all}){
6666             $opt{'V'} = 1;
6667             $opt{'U'} = 1;
6668             $opt{'Q'} = 1;
6669             $opt{'D1'} = 1;
6670             $opt{'D2'} = 1;
6671             $opt{'0R'} = 1;
6672             $opt{'R'} = 1;
6673             $opt{'X'} = 1;
6674             }
6675             $type = $a->type;
6676             $jobqx = ($opt{Q} || $opt{X}) ? 1 : 0;
6677             $a = $a->copy;
6678             $b = $b->xchg(0,1)->copy;
6679             $k = null;
6680             $l = null;
6681             $alpha = zeroes($type, $adims[0]);
6682             $beta = zeroes($type, $adims[0]);
6683            
6684             $U = $opt{U} ? zeroes($type, $adims[1], $adims[1]) : zeroes($type,1,1);
6685             $V = $opt{V} ? zeroes($b->type, $bdims[1], $bdims[1]) : zeroes($b->type,1,1);
6686             $Q = $jobqx ? zeroes($type, $adims[0], $adims[0]) : zeroes($type,1,1);
6687             $iwork = zeroes(long, $adims[0]);
6688             $info = pdl(long, 0);
6689             $a->xchg(0,1)->ggsvd($opt{U}, $opt{V}, $jobqx, $b, $k, $l, $alpha, $beta, $U, $V, $Q, $iwork, $info);
6690             laerror("mgsvd: The Jacobi procedure fails to converge") if $info;
6691              
6692             $ret{rank} = $k + $l;
6693             warn "mgsvd: Effective rank of 0 in mgsvd" if (!$ret{rank} and $_laerror);
6694             $ret{'info'} = $info;
6695              
6696             if (%opt){
6697             $Q = $Q->xchg(0,1)->sever if $jobqx;
6698            
6699             if (($adims[1] - $k - $l) < 0 && $ret{rank}){
6700            
6701             if ( $opt{'0R'} || $opt{R} || $opt{X}){
6702             $a->reshape($adims[0], ($k + $l));
6703             # Slice $a ??? => always square ??
6704             $a ( ($adims[0] - (($k+$l) - $adims[1])) : , $adims[1]:) .=
6705             $b(($adims[1]-$k):($l-1),($adims[0]+$adims[1]-$k - $l):($adims[0]-1))->xchg(0,1);
6706             $ret{'0R'} = $a if $opt{'0R'};
6707             }
6708            
6709             if ($opt{'D1'}){
6710             $D1 = zeroes($type, $adims[1], $adims[1]);
6711             $D1->diagonal(0,1) .= $alpha(:($adims[1]-1));
6712             $D1 = $D1->xchg(0,1)->reshape($adims[1] , ($k+$l))->xchg(0,1)->sever;
6713             $ret{'D1'} = $D1;
6714             }
6715             }
6716             elsif ($ret{rank}){
6717             if ( $opt{'0R'} || $opt{R} || $opt{X}){
6718             $a->reshape($adims[0], ($k + $l));
6719             $ret{'0R'} = $a if $opt{'0R'};
6720             }
6721            
6722             if ($opt{'D1'}){
6723             $D1 = zeroes($type, ($k + $l), ($k + $l));
6724             $D1->diagonal(0,1) .= $alpha(:($k+$l-1));
6725             $D1->reshape(($k + $l), $adims[1]);
6726             $ret{'D1'} = $D1;
6727             }
6728             }
6729            
6730             if ($opt{'D2'} && $ret{rank}){
6731             $work = zeroes($b->type, $l, $l);
6732             $work->diagonal(0,1) .= $beta($k:($k+$l-1));
6733             $D2 = zeroes($b->type, ($k + $l), $bdims[1]);
6734             $D2( $k:, :($l-1) ) .= $work;
6735             $ret{'D2'} = $D2;
6736             }
6737            
6738             if ( $ret{rank} && ($opt{X} || $opt{R}) ){
6739             $work = $a( -($k + $l):,);
6740             $ret{R} = $work if $opt{R};
6741             if ($opt{X}){
6742             $X = zeroes($type, $adims[0], $adims[0]);
6743             $X->diagonal(0,1) .= 1 if ($adims[0] > ($k + $l));
6744             $X ( -($k + $l): , -($k + $l): ) .= mtriinv($work);
6745             $ret{X} = $Q x $X;
6746             }
6747            
6748             }
6749            
6750             $ret{U} = $U->xchg(0,1)->sever if $opt{U};
6751             $ret{V} = $V->xchg(0,1)->sever if $opt{V};
6752             $ret{Q} = $Q if $opt{Q};
6753             }
6754             $ret{rank} ? return ($alpha($k:($k+$l-1))->sever, $beta($k:($k+$l-1))->sever, %ret ) : (undef, undef, %ret);
6755             }
6756              
6757             sub PDL::Complex::mgsvd {
6758             my($a, $b, %opt) = @_;
6759             my(@adims) = $a->dims;
6760             my(@bdims) = $b->dims;
6761             barf("mgsvd: Require matrices with equal number of columns")
6762             unless( @adims == 3 && @bdims == 3 && $adims[1] == $bdims[1] );
6763              
6764             my ($U, $V, $Q, $alpha, $beta, $k, $l, $iwork, $info, $D2, $D1, $work, %ret, $X, $jobqx, $type);
6765             if ($opt{all}){
6766             $opt{'V'} = 1;
6767             $opt{'U'} = 1;
6768             $opt{'Q'} = 1;
6769             $opt{'D1'} = 1;
6770             $opt{'D2'} = 1;
6771             $opt{'0R'} = 1;
6772             $opt{'R'} = 1;
6773             $opt{'X'} = 1;
6774             }
6775             $type = $a->type;
6776             $jobqx = ($opt{Q} || $opt{X}) ? 1 : 0;
6777             $a = $a->copy;
6778             $b = $b->xchg(1,2)->copy;
6779             $k = null;
6780             $l = null;
6781             $alpha = zeroes($type, $adims[1]);
6782             $beta = zeroes($type, $adims[1]);
6783            
6784             $U = $opt{U} ? PDL::new_from_specification('PDL::Complex', $type, 2,$adims[2], $adims[2]) : zeroes($type,1,1);
6785             $V = $opt{V} ? PDL::new_from_specification('PDL::Complex', $b->type, 2,$bdims[2], $bdims[2]) : zeroes($b->type,1,1);
6786             $Q = $jobqx ? PDL::new_from_specification('PDL::Complex', $type, 2,$adims[1], $adims[1]) : zeroes($type,1,1);
6787             $iwork = zeroes(long, $adims[1]);
6788             $info = null;
6789             $a->xchg(1,2)->cggsvd($opt{U}, $opt{V}, $jobqx, $b, $k, $l, $alpha, $beta, $U, $V, $Q, $iwork, $info);
6790             $k = $k->sclr;
6791             $l = $l->sclr;
6792             laerror("mgsvd: The Jacobi procedure fails to converge") if $info;
6793              
6794             $ret{rank} = $k + $l;
6795             warn "mgsvd: Effective rank of 0 in mgsvd" if (!$ret{rank} and $_laerror);
6796             $ret{'info'} = $info;
6797              
6798             if (%opt){
6799             $Q = $Q->xchg(1,2)->sever if $jobqx;
6800            
6801             if (($adims[2] - $k - $l) < 0 && $ret{rank}){
6802             if ( $opt{'0R'} || $opt{R} || $opt{X}){
6803             $a->reshape(2,$adims[1], ($k + $l));
6804             # Slice $a ??? => always square ??
6805             $a (, ($adims[1] - (($k+$l) - $adims[2])) : , $adims[2]:) .=
6806             $b(,($adims[2]-$k):($l-1),($adims[1]+$adims[2]-$k - $l):($adims[1]-1))->xchg(1,2);
6807             $ret{'0R'} = $a if $opt{'0R'};
6808            
6809             }
6810             if ($opt{'D1'}){
6811             $D1 = zeroes($type, $adims[2], $adims[2]);
6812             $D1->diagonal(0,1) .= $alpha(:($adims[2]-1));
6813             $D1 = $D1->xchg(0,1)->reshape($adims[2] , ($k+$l))->xchg(0,1)->sever;
6814             $ret{'D1'} = $D1;
6815             }
6816             }
6817             elsif ($ret{rank}){
6818             if ( $opt{'0R'} || $opt{R} || $opt{X}){
6819             $a->reshape(2, $adims[1], ($k + $l));
6820             $ret{'0R'} = $a if $opt{'0R'};
6821             }
6822            
6823             if ($opt{'D1'}){
6824             $D1 = zeroes($type, ($k + $l), ($k + $l));
6825             $D1->diagonal(0,1) .= $alpha(:($k+$l-1));
6826             $D1->reshape(($k + $l), $adims[2]);
6827             $ret{'D1'} = $D1;
6828             }
6829             }
6830            
6831             if ($opt{'D2'} && $ret{rank}){
6832             $work = zeroes($b->type, $l, $l);
6833             $work->diagonal(0,1) .= $beta($k:($k+$l-1));
6834             $D2 = zeroes($b->type, ($k + $l), $bdims[2]);
6835             $D2( $k:, :($l-1) ) .= $work;
6836             $ret{'D2'} = $D2;
6837             }
6838            
6839             if ( $ret{rank} && ($opt{X} || $opt{R}) ){
6840             $work = $a( , -($k + $l):,);
6841             $ret{R} = $work if $opt{R};
6842             if ($opt{X}){
6843             # $X = #zeroes($type, 2, $adims[1], $adims[1]);
6844             $X = PDL::new_from_specification('PDL::Complex', $type, 2, $adims[1], $adims[1]);
6845             $X .= 0;
6846             $X->diagonal(1,2)->(0,) .= 1 if ($adims[1] > ($k + $l));
6847             $X ( ,-($k + $l): , -($k + $l): ) .= mtriinv($work);
6848             $ret{X} = $Q x $X;
6849             }
6850            
6851             }
6852            
6853             $ret{U} = $U->xchg(1,2)->sever if $opt{U};
6854             $ret{V} = $V->xchg(1,2)->sever if $opt{V};
6855             $ret{Q} = $Q if $opt{Q};
6856             }
6857             $ret{rank} ? return ($alpha($k:($k+$l-1))->sever, $beta($k:($k+$l-1))->sever, %ret ) : (undef, undef, %ret);
6858             }
6859              
6860              
6861              
6862             #TODO
6863              
6864             # Others things
6865              
6866             # rectangular diag
6867             # usage
6868             # is_inplace and function which modify entry matrix
6869             # avoid xchg
6870             # threading support
6871             # automatically create PDL
6872             # inplace operation and memory
6873             #d check s after he/she/it and matrix(s)
6874             # PDL type, verify float/double
6875             # eig_det qr_det
6876             # (g)schur(x):
6877             # if conjugate pair
6878             # non generalized pb: $seldim ?? (cf: generalized)
6879             # return conjugate pair if only selected?
6880             # port to PDL::Matrix
6881              
6882             =head1 AUTHOR
6883              
6884             Copyright (C) Grégory Vanuxem 2005-2007.
6885              
6886             This library is free software; you can redistribute it and/or modify
6887             it under the terms of the artistic license as specified in the Artistic
6888             file.
6889              
6890             =cut
6891              
6892             1;