github.com/flyinox/gosm@v0.0.0-20171117061539-16768cb62077/src/math/big/hilbert_test.go (about)

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