numo-linalg-alt 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/ext/numo/linalg/blas/dot.c +59 -59
  4. data/ext/numo/linalg/blas/dot_sub.c +58 -58
  5. data/ext/numo/linalg/blas/gemm.c +157 -148
  6. data/ext/numo/linalg/blas/gemv.c +131 -127
  7. data/ext/numo/linalg/blas/nrm2.c +50 -50
  8. data/ext/numo/linalg/lapack/gees.c +239 -220
  9. data/ext/numo/linalg/lapack/geev.c +127 -110
  10. data/ext/numo/linalg/lapack/gelsd.c +81 -70
  11. data/ext/numo/linalg/lapack/geqrf.c +52 -51
  12. data/ext/numo/linalg/lapack/gerqf.c +70 -0
  13. data/ext/numo/linalg/lapack/gerqf.h +15 -0
  14. data/ext/numo/linalg/lapack/gesdd.c +96 -86
  15. data/ext/numo/linalg/lapack/gesv.c +80 -78
  16. data/ext/numo/linalg/lapack/gesvd.c +140 -129
  17. data/ext/numo/linalg/lapack/getrf.c +51 -50
  18. data/ext/numo/linalg/lapack/getri.c +64 -63
  19. data/ext/numo/linalg/lapack/getrs.c +92 -88
  20. data/ext/numo/linalg/lapack/gges.c +214 -0
  21. data/ext/numo/linalg/lapack/gges.h +15 -0
  22. data/ext/numo/linalg/lapack/heev.c +54 -52
  23. data/ext/numo/linalg/lapack/heevd.c +54 -52
  24. data/ext/numo/linalg/lapack/heevr.c +109 -98
  25. data/ext/numo/linalg/lapack/hegv.c +77 -74
  26. data/ext/numo/linalg/lapack/hegvd.c +77 -74
  27. data/ext/numo/linalg/lapack/hegvx.c +132 -120
  28. data/ext/numo/linalg/lapack/hetrf.c +54 -50
  29. data/ext/numo/linalg/lapack/lange.c +45 -44
  30. data/ext/numo/linalg/lapack/orgqr.c +63 -62
  31. data/ext/numo/linalg/lapack/orgrq.c +78 -0
  32. data/ext/numo/linalg/lapack/orgrq.h +15 -0
  33. data/ext/numo/linalg/lapack/potrf.c +49 -48
  34. data/ext/numo/linalg/lapack/potri.c +49 -48
  35. data/ext/numo/linalg/lapack/potrs.c +74 -72
  36. data/ext/numo/linalg/lapack/syev.c +54 -52
  37. data/ext/numo/linalg/lapack/syevd.c +54 -52
  38. data/ext/numo/linalg/lapack/syevr.c +107 -98
  39. data/ext/numo/linalg/lapack/sygv.c +77 -73
  40. data/ext/numo/linalg/lapack/sygvd.c +77 -73
  41. data/ext/numo/linalg/lapack/sygvx.c +132 -120
  42. data/ext/numo/linalg/lapack/sytrf.c +54 -50
  43. data/ext/numo/linalg/lapack/trtrs.c +79 -75
  44. data/ext/numo/linalg/lapack/ungqr.c +63 -62
  45. data/ext/numo/linalg/lapack/ungrq.c +78 -0
  46. data/ext/numo/linalg/lapack/ungrq.h +15 -0
  47. data/ext/numo/linalg/linalg.c +20 -10
  48. data/ext/numo/linalg/linalg.h +4 -0
  49. data/ext/numo/linalg/util.c +8 -0
  50. data/ext/numo/linalg/util.h +1 -0
  51. data/lib/numo/linalg/version.rb +1 -1
  52. data/lib/numo/linalg.rb +139 -3
  53. metadata +10 -2
data/lib/numo/linalg.rb CHANGED
@@ -560,6 +560,127 @@ module Numo
560
560
  [q, r]
561
561
  end
562
562
 
563
+ # Computes the RQ decomposition of a matrix.
564
+ #
565
+ # @example
566
+ # require 'numo/linalg'
567
+ #
568
+ # a = Numo::DFloat.new(2, 3).rand
569
+ # r, q = Numo::Linalg.rq(a)
570
+ # pp r
571
+ # # =>
572
+ # # Numo::DFloat#shape=[2,3]
573
+ # # [[0, -0.381748, -0.79309],
574
+ # # [0, 0, -0.41502]]
575
+ # pp q
576
+ # # =>
577
+ # # Numo::DFloat#shape=[3,3]
578
+ # # [[0.227957, 0.874475, -0.428169],
579
+ # # [0.844617, -0.396377, -0.359872],
580
+ # # [-0.484416, -0.279603, -0.828953]]
581
+ # puts (a - r.dot(q)).abs.max
582
+ # # => 5.551115123125783e-17
583
+ #
584
+ # r, q = Numo::Linalg.rq(a, mode: 'economic')
585
+ # pp r
586
+ # # =>
587
+ # # Numo::DFloat#shape=[2,2]
588
+ # # [[-0.381748, -0.79309],
589
+ # # [0, -0.41502]]
590
+ # pp q
591
+ # # =>
592
+ # # Numo::DFloat#shape=[2,3]
593
+ # # [[0.844617, -0.396377, -0.359872],
594
+ # # [-0.484416, -0.279603, -0.828953]]
595
+ # puts (a - r.dot(q)).abs.max
596
+ # # => 5.551115123125783e-17
597
+ #
598
+ # @param a [Numo::NArray] The m-by-n matrix to be decomposed.
599
+ # @param mode [String] The mode of decomposition.
600
+ # - "full" -- returns both R [m, n] and Q [n, n],
601
+ # - "r" -- returns only R,
602
+ # - "economic" -- returns both R [m, k] and Q [k, n], where k = min(m, n).
603
+ # @return [Array<Numo::NArray>/Numo::NArray]
604
+ # if mode='full' or 'economic', returns [R, Q].
605
+ # if mode='r', returns R.
606
+ def rq(a, mode: 'full') # rubocop:disable Metrics/AbcSize
607
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
608
+ raise ArgumentError, "invalid mode: #{mode}" unless %w[full r economic].include?(mode)
609
+
610
+ bchr = blas_char(a)
611
+ raise ArgumentError, "invalid array type: #{a.class}" if bchr == 'n'
612
+
613
+ fnc = :"#{bchr}gerqf"
614
+ rq, tau, info = Numo::Linalg::Lapack.send(fnc, a.dup)
615
+ raise "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
616
+
617
+ m, n = rq.shape
618
+ r = rq.triu(n - m).dup
619
+ r = r[true, (n - m)...n].dup if mode == 'economic' && n > m
620
+
621
+ return r if mode == 'r'
622
+
623
+ fnc = %w[d s].include?(bchr) ? :"#{bchr}orgrq" : :"#{bchr}ungrq"
624
+ tmp = if n < m
625
+ rq[(m - n)...m, 0...n].dup
626
+ elsif mode == 'economic'
627
+ rq.dup
628
+ else
629
+ rq.class.zeros(n, n).tap { |mat| mat[(n - m)...n, true] = rq }
630
+ end
631
+
632
+ q, info = Numo::Linalg::Lapack.send(fnc, tmp, tau)
633
+ raise "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
634
+
635
+ [r, q]
636
+ end
637
+
638
+ # Computes the QZ decomposition (generalized Schur decomposition) of a pair of square matrices.
639
+ #
640
+ # The QZ decomposition is given by `A = Q * AA * Z^H` and `B = Q * BB * Z^H`,
641
+ # where `A` and `B` are the input matrices, `Q` and `Z` are unitary matrices,
642
+ # and `AA` and `BB` are upper triangular matrices (or quasi-upper triangular matrices in real case).
643
+ #
644
+ # @example
645
+ # require 'numo/linalg'
646
+ #
647
+ # a = Numo::DFloat.new(5, 5).rand
648
+ # b = Numo::DFloat.new(5, 5).rand
649
+ #
650
+ # aa, bb, q, z = Numo::Linalg.qz(a, b)
651
+ #
652
+ # pp (a - q.dot(aa).dot(z.transpose)).abs.max
653
+ # # => 1.7763568394002505e-15
654
+ # pp (b - q.dot(bb).dot(z.transpose)).abs.max
655
+ # # => 1.1102230246251565e-15
656
+ #
657
+ # @param a [Numo::NArray] The n-by-n square matrix.
658
+ # @param b [Numo::NArray] The n-by-n square matrix.
659
+ # @return [Array<Numo::NArray, Numo::NArray, Numo::NArray, Numo::NArray>]
660
+ # The matrices `AA`, `BB`, `Q`, and `Z` such that `A = Q * AA * Z^H` and `B = Q * BB * Z^H`.
661
+ def qz(a, b) # rubocop:disable Metrics/AbcSize
662
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
663
+ raise Numo::NArray::ShapeError, 'input array b must be 2-dimensional' if b.ndim != 2
664
+ raise Numo::NArray::ShapeError, 'input array a must be square' if a.shape[0] != a.shape[1]
665
+ raise Numo::NArray::ShapeError, 'input array b must be square' if b.shape[0] != b.shape[1]
666
+ raise Numo::NArray::ShapeError, "incompatible dimensions: a.shape = #{a.shape} != b.shape = #{b.shape}" if a.shape != b.shape
667
+
668
+ bchr = blas_char(a, b)
669
+ raise ArgumentError, "invalid array type: #{a.class}, #{b.class}" if bchr == 'n'
670
+
671
+ fnc = :"#{bchr}gges"
672
+ if %w[d s].include?(bchr)
673
+ aa, bb, _ar, _ai, _beta, q, z, _sdim, info = Numo::Linalg::Lapack.send(fnc, a.dup, b.dup)
674
+ else
675
+ aa, bb, _alpha, _beta, q, z, _sdim, info = Numo::Linalg::Lapack.send(fnc, a.dup, b.dup)
676
+ end
677
+
678
+ raise "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
679
+ raise 'the QZ algorithm failed.' if info.positive?
680
+
681
+ [aa, bb, q, z]
682
+ end
683
+
563
684
  # Computes the Schur decomposition of a square matrix.
564
685
  # The Schur decomposition is given by `A = Z * T * Z^H`,
565
686
  # where `A` is the input matrix, `Z` is a unitary matrix,
@@ -604,11 +725,10 @@ module Numo
604
725
  raise ArgumentError, "invalid array type: #{a.class}" if bchr == 'n'
605
726
 
606
727
  fnc = :"#{bchr}gees"
607
- b = a.dup
608
728
  if %w[d s].include?(bchr)
609
- _wr, _wi, v, sdim, info = Numo::Linalg::Lapack.send(fnc, b, jobvs: 'V', sort: sort)
729
+ b, _wr, _wi, v, sdim, info = Numo::Linalg::Lapack.send(fnc, a.dup, jobvs: 'V', sort: sort)
610
730
  else
611
- _w, v, sdim, info = Numo::Linalg::Lapack.send(fnc, b, jobvs: 'V', sort: sort)
731
+ b, _w, v, sdim, info = Numo::Linalg::Lapack.send(fnc, a.dup, jobvs: 'V', sort: sort)
612
732
  end
613
733
 
614
734
  n = a.shape[0]
@@ -1381,6 +1501,22 @@ module Numo
1381
1501
  end
1382
1502
  end
1383
1503
 
1504
+ # Computes the matrix tangent.
1505
+ #
1506
+ # @param a [Numo::NArray] The n-by-n square matrix.
1507
+ # @return [Numo::NArray] The matrix tangent of `a`.
1508
+ def tanm(a)
1509
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
1510
+ raise Numo::NArray::ShapeError, 'input array a must be square' if a.shape[0] != a.shape[1]
1511
+
1512
+ bchr = blas_char(a)
1513
+ raise ArgumentError, "invalid array type: #{a.class}" if bchr == 'n'
1514
+
1515
+ a_sin = sinm(a)
1516
+ a_cos = cosm(a)
1517
+ a_sin.dot(Numo::Linalg.inv(a_cos))
1518
+ end
1519
+
1384
1520
  # Computes the inverse of a matrix using its LU decomposition.
1385
1521
  #
1386
1522
  # @param lu [Numo::NArray] The LU decomposition of the n-by-n matrix `A`.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: numo-linalg-alt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yoshoku
@@ -58,6 +58,8 @@ files:
58
58
  - ext/numo/linalg/lapack/gelsd.h
59
59
  - ext/numo/linalg/lapack/geqrf.c
60
60
  - ext/numo/linalg/lapack/geqrf.h
61
+ - ext/numo/linalg/lapack/gerqf.c
62
+ - ext/numo/linalg/lapack/gerqf.h
61
63
  - ext/numo/linalg/lapack/gesdd.c
62
64
  - ext/numo/linalg/lapack/gesdd.h
63
65
  - ext/numo/linalg/lapack/gesv.c
@@ -70,6 +72,8 @@ files:
70
72
  - ext/numo/linalg/lapack/getri.h
71
73
  - ext/numo/linalg/lapack/getrs.c
72
74
  - ext/numo/linalg/lapack/getrs.h
75
+ - ext/numo/linalg/lapack/gges.c
76
+ - ext/numo/linalg/lapack/gges.h
73
77
  - ext/numo/linalg/lapack/heev.c
74
78
  - ext/numo/linalg/lapack/heev.h
75
79
  - ext/numo/linalg/lapack/heevd.c
@@ -88,6 +92,8 @@ files:
88
92
  - ext/numo/linalg/lapack/lange.h
89
93
  - ext/numo/linalg/lapack/orgqr.c
90
94
  - ext/numo/linalg/lapack/orgqr.h
95
+ - ext/numo/linalg/lapack/orgrq.c
96
+ - ext/numo/linalg/lapack/orgrq.h
91
97
  - ext/numo/linalg/lapack/potrf.c
92
98
  - ext/numo/linalg/lapack/potrf.h
93
99
  - ext/numo/linalg/lapack/potri.c
@@ -112,6 +118,8 @@ files:
112
118
  - ext/numo/linalg/lapack/trtrs.h
113
119
  - ext/numo/linalg/lapack/ungqr.c
114
120
  - ext/numo/linalg/lapack/ungqr.h
121
+ - ext/numo/linalg/lapack/ungrq.c
122
+ - ext/numo/linalg/lapack/ungrq.h
115
123
  - ext/numo/linalg/linalg.c
116
124
  - ext/numo/linalg/linalg.h
117
125
  - ext/numo/linalg/util.c
@@ -126,7 +134,7 @@ metadata:
126
134
  homepage_uri: https://github.com/yoshoku/numo-linalg-alt
127
135
  source_code_uri: https://github.com/yoshoku/numo-linalg-alt
128
136
  changelog_uri: https://github.com/yoshoku/numo-linalg-alt/blob/main/CHANGELOG.md
129
- documentation_uri: https://gemdocs.org/gems/numo-linalg-alt/0.3.0/
137
+ documentation_uri: https://gemdocs.org/gems/numo-linalg-alt/0.4.0/
130
138
  rubygems_mfa_required: 'true'
131
139
  rdoc_options: []
132
140
  require_paths: