@@ -227,6 +227,179 @@ impl EigWorkImpl for EigWork<c64> {
227
227
}
228
228
}
229
229
230
+ impl EigWorkImpl for EigWork < f64 > {
231
+ type Elem = f64 ;
232
+
233
+ fn new ( calc_v : bool , l : MatrixLayout ) -> Result < Self > {
234
+ let ( n, _) = l. size ( ) ;
235
+ let ( jobvl, jobvr) = if calc_v {
236
+ match l {
237
+ MatrixLayout :: C { .. } => ( JobEv :: All , JobEv :: None ) ,
238
+ MatrixLayout :: F { .. } => ( JobEv :: None , JobEv :: All ) ,
239
+ }
240
+ } else {
241
+ ( JobEv :: None , JobEv :: None )
242
+ } ;
243
+ let mut eigs_re: Vec < MaybeUninit < f64 > > = vec_uninit ( n as usize ) ;
244
+ let mut eigs_im: Vec < MaybeUninit < f64 > > = vec_uninit ( n as usize ) ;
245
+
246
+ let mut vr_l: Option < Vec < MaybeUninit < f64 > > > = jobvl. then ( || vec_uninit ( ( n * n) as usize ) ) ;
247
+ let mut vr_r: Option < Vec < MaybeUninit < f64 > > > = jobvr. then ( || vec_uninit ( ( n * n) as usize ) ) ;
248
+ let vc_l: Option < Vec < MaybeUninit < c64 > > > = jobvl. then ( || vec_uninit ( ( n * n) as usize ) ) ;
249
+ let vc_r: Option < Vec < MaybeUninit < c64 > > > = jobvr. then ( || vec_uninit ( ( n * n) as usize ) ) ;
250
+
251
+ // calc work size
252
+ let mut info = 0 ;
253
+ let mut work_size: [ f64 ; 1 ] = [ 0.0 ] ;
254
+ unsafe {
255
+ lapack_sys:: dgeev_ (
256
+ jobvl. as_ptr ( ) ,
257
+ jobvr. as_ptr ( ) ,
258
+ & n,
259
+ std:: ptr:: null_mut ( ) ,
260
+ & n,
261
+ AsPtr :: as_mut_ptr ( & mut eigs_re) ,
262
+ AsPtr :: as_mut_ptr ( & mut eigs_im) ,
263
+ AsPtr :: as_mut_ptr ( vr_l. as_deref_mut ( ) . unwrap_or ( & mut [ ] ) ) ,
264
+ & n,
265
+ AsPtr :: as_mut_ptr ( vr_r. as_deref_mut ( ) . unwrap_or ( & mut [ ] ) ) ,
266
+ & n,
267
+ AsPtr :: as_mut_ptr ( & mut work_size) ,
268
+ & ( -1 ) ,
269
+ & mut info,
270
+ )
271
+ } ;
272
+ info. as_lapack_result ( ) ?;
273
+
274
+ // actual ev
275
+ let lwork = work_size[ 0 ] . to_usize ( ) . unwrap ( ) ;
276
+ let work: Vec < MaybeUninit < f64 > > = vec_uninit ( lwork) ;
277
+
278
+ Ok ( Self {
279
+ n,
280
+ jobvr,
281
+ jobvl,
282
+ eigs : vec_uninit ( n as usize ) ,
283
+ eigs_re : Some ( eigs_re) ,
284
+ eigs_im : Some ( eigs_im) ,
285
+ rwork : None ,
286
+ vr_l,
287
+ vr_r,
288
+ vc_l,
289
+ vc_r,
290
+ work,
291
+ } )
292
+ }
293
+
294
+ fn calc < ' work > ( & ' work mut self , a : & mut [ f64 ] ) -> Result < EigRef < ' work , f64 > > {
295
+ let lwork = self . work . len ( ) . to_i32 ( ) . unwrap ( ) ;
296
+ let mut info = 0 ;
297
+ unsafe {
298
+ lapack_sys:: dgeev_ (
299
+ self . jobvl . as_ptr ( ) ,
300
+ self . jobvr . as_ptr ( ) ,
301
+ & self . n ,
302
+ AsPtr :: as_mut_ptr ( a) ,
303
+ & self . n ,
304
+ AsPtr :: as_mut_ptr ( self . eigs_re . as_mut ( ) . unwrap ( ) ) ,
305
+ AsPtr :: as_mut_ptr ( self . eigs_im . as_mut ( ) . unwrap ( ) ) ,
306
+ AsPtr :: as_mut_ptr ( self . vr_l . as_deref_mut ( ) . unwrap_or ( & mut [ ] ) ) ,
307
+ & self . n ,
308
+ AsPtr :: as_mut_ptr ( self . vr_r . as_deref_mut ( ) . unwrap_or ( & mut [ ] ) ) ,
309
+ & self . n ,
310
+ AsPtr :: as_mut_ptr ( & mut self . work ) ,
311
+ & lwork,
312
+ & mut info,
313
+ )
314
+ } ;
315
+ info. as_lapack_result ( ) ?;
316
+
317
+ let eigs_re: & [ f64 ] = self
318
+ . eigs_re
319
+ . as_ref ( )
320
+ . map ( |e| unsafe { e. slice_assume_init_ref ( ) } )
321
+ . unwrap ( ) ;
322
+ let eigs_im: & [ f64 ] = self
323
+ . eigs_im
324
+ . as_ref ( )
325
+ . map ( |e| unsafe { e. slice_assume_init_ref ( ) } )
326
+ . unwrap ( ) ;
327
+ reconstruct_eigs ( eigs_re, eigs_im, & mut self . eigs ) ;
328
+
329
+ if let Some ( v) = self . vr_l . as_ref ( ) {
330
+ let v = unsafe { v. slice_assume_init_ref ( ) } ;
331
+ reconstruct_eigenvectors ( false , eigs_im, v, self . vc_l . as_mut ( ) . unwrap ( ) ) ;
332
+ }
333
+ if let Some ( v) = self . vr_r . as_ref ( ) {
334
+ let v = unsafe { v. slice_assume_init_ref ( ) } ;
335
+ reconstruct_eigenvectors ( false , eigs_im, v, self . vc_l . as_mut ( ) . unwrap ( ) ) ;
336
+ }
337
+
338
+ Ok ( EigRef {
339
+ eigs : unsafe { self . eigs . slice_assume_init_ref ( ) } ,
340
+ vl : self
341
+ . vc_l
342
+ . as_ref ( )
343
+ . map ( |v| unsafe { v. slice_assume_init_ref ( ) } ) ,
344
+ vr : self
345
+ . vc_r
346
+ . as_ref ( )
347
+ . map ( |v| unsafe { v. slice_assume_init_ref ( ) } ) ,
348
+ } )
349
+ }
350
+
351
+ fn eval ( mut self , a : & mut [ f64 ] ) -> Result < Eig < f64 > > {
352
+ let lwork = self . work . len ( ) . to_i32 ( ) . unwrap ( ) ;
353
+ let mut info = 0 ;
354
+ unsafe {
355
+ lapack_sys:: dgeev_ (
356
+ self . jobvl . as_ptr ( ) ,
357
+ self . jobvr . as_ptr ( ) ,
358
+ & self . n ,
359
+ AsPtr :: as_mut_ptr ( a) ,
360
+ & self . n ,
361
+ AsPtr :: as_mut_ptr ( self . eigs_re . as_mut ( ) . unwrap ( ) ) ,
362
+ AsPtr :: as_mut_ptr ( self . eigs_im . as_mut ( ) . unwrap ( ) ) ,
363
+ AsPtr :: as_mut_ptr ( self . vr_l . as_deref_mut ( ) . unwrap_or ( & mut [ ] ) ) ,
364
+ & self . n ,
365
+ AsPtr :: as_mut_ptr ( self . vr_r . as_deref_mut ( ) . unwrap_or ( & mut [ ] ) ) ,
366
+ & self . n ,
367
+ AsPtr :: as_mut_ptr ( & mut self . work ) ,
368
+ & lwork,
369
+ & mut info,
370
+ )
371
+ } ;
372
+ info. as_lapack_result ( ) ?;
373
+
374
+ let eigs_re: & [ f64 ] = self
375
+ . eigs_re
376
+ . as_ref ( )
377
+ . map ( |e| unsafe { e. slice_assume_init_ref ( ) } )
378
+ . unwrap ( ) ;
379
+ let eigs_im: & [ f64 ] = self
380
+ . eigs_im
381
+ . as_ref ( )
382
+ . map ( |e| unsafe { e. slice_assume_init_ref ( ) } )
383
+ . unwrap ( ) ;
384
+ reconstruct_eigs ( eigs_re, eigs_im, & mut self . eigs ) ;
385
+
386
+ if let Some ( v) = self . vr_l . as_ref ( ) {
387
+ let v = unsafe { v. slice_assume_init_ref ( ) } ;
388
+ reconstruct_eigenvectors ( false , eigs_im, v, self . vc_l . as_mut ( ) . unwrap ( ) ) ;
389
+ }
390
+ if let Some ( v) = self . vr_r . as_ref ( ) {
391
+ let v = unsafe { v. slice_assume_init_ref ( ) } ;
392
+ reconstruct_eigenvectors ( false , eigs_im, v, self . vc_l . as_mut ( ) . unwrap ( ) ) ;
393
+ }
394
+
395
+ Ok ( Eig {
396
+ eigs : unsafe { self . eigs . assume_init ( ) } ,
397
+ vl : self . vc_l . map ( |v| unsafe { v. assume_init ( ) } ) ,
398
+ vr : self . vc_r . map ( |v| unsafe { v. assume_init ( ) } ) ,
399
+ } )
400
+ }
401
+ }
402
+
230
403
macro_rules! impl_eig_complex {
231
404
( $scalar: ty, $ev: path) => {
232
405
impl Eig_ for $scalar {
@@ -429,59 +602,81 @@ macro_rules! impl_eig_real {
429
602
. map( |( & re, & im) | Self :: complex( re, im) )
430
603
. collect( ) ;
431
604
432
- if !calc_v {
433
- return Ok ( ( eigs, Vec :: new( ) ) ) ;
434
- }
435
-
436
- // Reconstruct eigenvectors into complex-array
437
- // --------------------------------------------
438
- //
439
- // From LAPACK API https://software.intel.com/en-us/node/469230
440
- //
441
- // - If the j-th eigenvalue is real,
442
- // - v(j) = VR(:,j), the j-th column of VR.
443
- //
444
- // - If the j-th and (j+1)-st eigenvalues form a complex conjugate pair,
445
- // - v(j) = VR(:,j) + i*VR(:,j+1)
446
- // - v(j+1) = VR(:,j) - i*VR(:,j+1).
447
- //
448
- // In the C-layout case, we need the conjugates of the left
449
- // eigenvectors, so the signs should be reversed.
450
-
451
- let n = n as usize ;
452
- let v = vr. or( vl) . unwrap( ) ;
453
- let mut eigvecs: Vec <MaybeUninit <Self :: Complex >> = vec_uninit( n * n) ;
454
- let mut col = 0 ;
455
- while col < n {
456
- if eig_im[ col] == 0. {
457
- // The corresponding eigenvalue is real.
458
- for row in 0 ..n {
459
- let re = v[ row + col * n] ;
460
- eigvecs[ row + col * n] . write( Self :: complex( re, 0. ) ) ;
461
- }
462
- col += 1 ;
463
- } else {
464
- // This is a complex conjugate pair.
465
- assert!( col + 1 < n) ;
466
- for row in 0 ..n {
467
- let re = v[ row + col * n] ;
468
- let mut im = v[ row + ( col + 1 ) * n] ;
469
- if jobvl. is_calc( ) {
470
- im = -im;
471
- }
472
- eigvecs[ row + col * n] . write( Self :: complex( re, im) ) ;
473
- eigvecs[ row + ( col + 1 ) * n] . write( Self :: complex( re, -im) ) ;
474
- }
475
- col += 2 ;
476
- }
605
+ if calc_v {
606
+ let mut eigvecs = vec_uninit( ( n * n) as usize ) ;
607
+ reconstruct_eigenvectors(
608
+ jobvl. is_calc( ) ,
609
+ & eig_im,
610
+ & vr. or( vl) . unwrap( ) ,
611
+ & mut eigvecs,
612
+ ) ;
613
+ Ok ( ( eigs, unsafe { eigvecs. assume_init( ) } ) )
614
+ } else {
615
+ Ok ( ( eigs, Vec :: new( ) ) )
477
616
}
478
- let eigvecs = unsafe { eigvecs. assume_init( ) } ;
479
-
480
- Ok ( ( eigs, eigvecs) )
481
617
}
482
618
}
483
619
} ;
484
620
}
485
621
486
622
impl_eig_real ! ( f64 , lapack_sys:: dgeev_) ;
487
623
impl_eig_real ! ( f32 , lapack_sys:: sgeev_) ;
624
+
625
+ /// Reconstruct eigenvectors into complex-array
626
+ ///
627
+ /// From LAPACK API https://software.intel.com/en-us/node/469230
628
+ ///
629
+ /// - If the j-th eigenvalue is real,
630
+ /// - v(j) = VR(:,j), the j-th column of VR.
631
+ ///
632
+ /// - If the j-th and (j+1)-st eigenvalues form a complex conjugate pair,
633
+ /// - v(j) = VR(:,j) + i*VR(:,j+1)
634
+ /// - v(j+1) = VR(:,j) - i*VR(:,j+1).
635
+ ///
636
+ /// In the C-layout case, we need the conjugates of the left
637
+ /// eigenvectors, so the signs should be reversed.
638
+ fn reconstruct_eigenvectors < T : Scalar > (
639
+ take_hermite_conjugate : bool ,
640
+ eig_im : & [ T ] ,
641
+ vr : & [ T ] ,
642
+ vc : & mut [ MaybeUninit < T :: Complex > ] ,
643
+ ) {
644
+ let n = eig_im. len ( ) ;
645
+ assert_eq ! ( vr. len( ) , n * n) ;
646
+ assert_eq ! ( vc. len( ) , n * n) ;
647
+
648
+ let mut col = 0 ;
649
+ while col < n {
650
+ if eig_im[ col] . is_zero ( ) {
651
+ // The corresponding eigenvalue is real.
652
+ for row in 0 ..n {
653
+ let re = vr[ row + col * n] ;
654
+ vc[ row + col * n] . write ( T :: complex ( re, T :: zero ( ) ) ) ;
655
+ }
656
+ col += 1 ;
657
+ } else {
658
+ // This is a complex conjugate pair.
659
+ assert ! ( col + 1 < n) ;
660
+ for row in 0 ..n {
661
+ let re = vr[ row + col * n] ;
662
+ let mut im = vr[ row + ( col + 1 ) * n] ;
663
+ if take_hermite_conjugate {
664
+ im = -im;
665
+ }
666
+ vc[ row + col * n] . write ( T :: complex ( re, im) ) ;
667
+ vc[ row + ( col + 1 ) * n] . write ( T :: complex ( re, -im) ) ;
668
+ }
669
+ col += 2 ;
670
+ }
671
+ }
672
+ }
673
+
674
+ /// Create complex eigenvalues from real and imaginary parts.
675
+ fn reconstruct_eigs < T : Scalar > ( re : & [ T ] , im : & [ T ] , eigs : & mut [ MaybeUninit < T :: Complex > ] ) {
676
+ let n = eigs. len ( ) ;
677
+ assert_eq ! ( re. len( ) , n) ;
678
+ assert_eq ! ( im. len( ) , n) ;
679
+ for i in 0 ..n {
680
+ eigs[ i] . write ( T :: complex ( re[ i] , im[ i] ) ) ;
681
+ }
682
+ }
0 commit comments