dlasv2.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright ©2015 The Gonum Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gonum
  5. import "math"
  6. // Dlasv2 computes the singular value decomposition of a 2×2 matrix.
  7. // [ csl snl] [f g] [csr -snr] = [ssmax 0]
  8. // [-snl csl] [0 h] [snr csr] = [ 0 ssmin]
  9. // ssmax is the larger absolute singular value, and ssmin is the smaller absolute
  10. // singular value. [cls, snl] and [csr, snr] are the left and right singular vectors.
  11. //
  12. // Dlasv2 is an internal routine. It is exported for testing purposes.
  13. func (impl Implementation) Dlasv2(f, g, h float64) (ssmin, ssmax, snr, csr, snl, csl float64) {
  14. ft := f
  15. fa := math.Abs(ft)
  16. ht := h
  17. ha := math.Abs(h)
  18. // pmax points to the largest element of the matrix in terms of absolute value.
  19. // 1 if F, 2 if G, 3 if H.
  20. pmax := 1
  21. swap := ha > fa
  22. if swap {
  23. pmax = 3
  24. ft, ht = ht, ft
  25. fa, ha = ha, fa
  26. }
  27. gt := g
  28. ga := math.Abs(gt)
  29. var clt, crt, slt, srt float64
  30. if ga == 0 {
  31. ssmin = ha
  32. ssmax = fa
  33. clt = 1
  34. crt = 1
  35. slt = 0
  36. srt = 0
  37. } else {
  38. gasmall := true
  39. if ga > fa {
  40. pmax = 2
  41. if (fa / ga) < dlamchE {
  42. gasmall = false
  43. ssmax = ga
  44. if ha > 1 {
  45. ssmin = fa / (ga / ha)
  46. } else {
  47. ssmin = (fa / ga) * ha
  48. }
  49. clt = 1
  50. slt = ht / gt
  51. srt = 1
  52. crt = ft / gt
  53. }
  54. }
  55. if gasmall {
  56. d := fa - ha
  57. l := d / fa
  58. if d == fa { // deal with inf
  59. l = 1
  60. }
  61. m := gt / ft
  62. t := 2 - l
  63. s := math.Hypot(t, m)
  64. var r float64
  65. if l == 0 {
  66. r = math.Abs(m)
  67. } else {
  68. r = math.Hypot(l, m)
  69. }
  70. a := 0.5 * (s + r)
  71. ssmin = ha / a
  72. ssmax = fa * a
  73. if m == 0 {
  74. if l == 0 {
  75. t = math.Copysign(2, ft) * math.Copysign(1, gt)
  76. } else {
  77. t = gt/math.Copysign(d, ft) + m/t
  78. }
  79. } else {
  80. t = (m/(s+t) + m/(r+l)) * (1 + a)
  81. }
  82. l = math.Hypot(t, 2)
  83. crt = 2 / l
  84. srt = t / l
  85. clt = (crt + srt*m) / a
  86. slt = (ht / ft) * srt / a
  87. }
  88. }
  89. if swap {
  90. csl = srt
  91. snl = crt
  92. csr = slt
  93. snr = clt
  94. } else {
  95. csl = clt
  96. snl = slt
  97. csr = crt
  98. snr = srt
  99. }
  100. var tsign float64
  101. switch pmax {
  102. case 1:
  103. tsign = math.Copysign(1, csr) * math.Copysign(1, csl) * math.Copysign(1, f)
  104. case 2:
  105. tsign = math.Copysign(1, snr) * math.Copysign(1, csl) * math.Copysign(1, g)
  106. case 3:
  107. tsign = math.Copysign(1, snr) * math.Copysign(1, snl) * math.Copysign(1, h)
  108. }
  109. ssmax = math.Copysign(ssmax, tsign)
  110. ssmin = math.Copysign(ssmin, tsign*math.Copysign(1, f)*math.Copysign(1, h))
  111. return ssmin, ssmax, snr, csr, snl, csl
  112. }