hilbert_test.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright 2009 The Go 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. // A little test program and benchmark for rational arithmetics.
  5. // Computes a Hilbert matrix, its inverse, multiplies them
  6. // and verifies that the product is the identity matrix.
  7. package big
  8. import (
  9. "fmt"
  10. "testing"
  11. )
  12. type matrix struct {
  13. n, m int
  14. a []*Rat
  15. }
  16. func (a *matrix) at(i, j int) *Rat {
  17. if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
  18. panic("index out of range")
  19. }
  20. return a.a[i*a.m+j]
  21. }
  22. func (a *matrix) set(i, j int, x *Rat) {
  23. if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
  24. panic("index out of range")
  25. }
  26. a.a[i*a.m+j] = x
  27. }
  28. func newMatrix(n, m int) *matrix {
  29. if !(0 <= n && 0 <= m) {
  30. panic("illegal matrix")
  31. }
  32. a := new(matrix)
  33. a.n = n
  34. a.m = m
  35. a.a = make([]*Rat, n*m)
  36. return a
  37. }
  38. func newUnit(n int) *matrix {
  39. a := newMatrix(n, n)
  40. for i := 0; i < n; i++ {
  41. for j := 0; j < n; j++ {
  42. x := NewRat(0, 1)
  43. if i == j {
  44. x.SetInt64(1)
  45. }
  46. a.set(i, j, x)
  47. }
  48. }
  49. return a
  50. }
  51. func newHilbert(n int) *matrix {
  52. a := newMatrix(n, n)
  53. for i := 0; i < n; i++ {
  54. for j := 0; j < n; j++ {
  55. a.set(i, j, NewRat(1, int64(i+j+1)))
  56. }
  57. }
  58. return a
  59. }
  60. func newInverseHilbert(n int) *matrix {
  61. a := newMatrix(n, n)
  62. for i := 0; i < n; i++ {
  63. for j := 0; j < n; j++ {
  64. x1 := new(Rat).SetInt64(int64(i + j + 1))
  65. x2 := new(Rat).SetInt(new(Int).Binomial(int64(n+i), int64(n-j-1)))
  66. x3 := new(Rat).SetInt(new(Int).Binomial(int64(n+j), int64(n-i-1)))
  67. x4 := new(Rat).SetInt(new(Int).Binomial(int64(i+j), int64(i)))
  68. x1.Mul(x1, x2)
  69. x1.Mul(x1, x3)
  70. x1.Mul(x1, x4)
  71. x1.Mul(x1, x4)
  72. if (i+j)&1 != 0 {
  73. x1.Neg(x1)
  74. }
  75. a.set(i, j, x1)
  76. }
  77. }
  78. return a
  79. }
  80. func (a *matrix) mul(b *matrix) *matrix {
  81. if a.m != b.n {
  82. panic("illegal matrix multiply")
  83. }
  84. c := newMatrix(a.n, b.m)
  85. for i := 0; i < c.n; i++ {
  86. for j := 0; j < c.m; j++ {
  87. x := NewRat(0, 1)
  88. for k := 0; k < a.m; k++ {
  89. x.Add(x, new(Rat).Mul(a.at(i, k), b.at(k, j)))
  90. }
  91. c.set(i, j, x)
  92. }
  93. }
  94. return c
  95. }
  96. func (a *matrix) eql(b *matrix) bool {
  97. if a.n != b.n || a.m != b.m {
  98. return false
  99. }
  100. for i := 0; i < a.n; i++ {
  101. for j := 0; j < a.m; j++ {
  102. if a.at(i, j).Cmp(b.at(i, j)) != 0 {
  103. return false
  104. }
  105. }
  106. }
  107. return true
  108. }
  109. func (a *matrix) String() string {
  110. s := ""
  111. for i := 0; i < a.n; i++ {
  112. for j := 0; j < a.m; j++ {
  113. s += fmt.Sprintf("\t%s", a.at(i, j))
  114. }
  115. s += "\n"
  116. }
  117. return s
  118. }
  119. func doHilbert(t *testing.T, n int) {
  120. a := newHilbert(n)
  121. b := newInverseHilbert(n)
  122. I := newUnit(n)
  123. ab := a.mul(b)
  124. if !ab.eql(I) {
  125. if t == nil {
  126. panic("Hilbert failed")
  127. }
  128. t.Errorf("a = %s\n", a)
  129. t.Errorf("b = %s\n", b)
  130. t.Errorf("a*b = %s\n", ab)
  131. t.Errorf("I = %s\n", I)
  132. }
  133. }
  134. func TestHilbert(t *testing.T) {
  135. doHilbert(t, 10)
  136. }
  137. func BenchmarkHilbert(b *testing.B) {
  138. for i := 0; i < b.N; i++ {
  139. doHilbert(nil, 10)
  140. }
  141. }