| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | // $G $D/$F.go && $L $F.$A && ./$A.out | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Copyright 2009 The Go Authors. All rights reserved. | 
					
						
							|  |  |  | // Use of this source code is governed by a BSD-style | 
					
						
							|  |  |  | // license that can be found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A little test program for rational arithmetics. | 
					
						
							|  |  |  | // Computes a Hilbert matrix, its inverse, multiplies them | 
					
						
							|  |  |  | // and verifies that the product is the identity matrix. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import Big "bignum" | 
					
						
							|  |  |  | import Fmt "fmt" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func assert(p bool) { | 
					
						
							|  |  |  | 	if !p { | 
					
						
							|  |  |  | 		panic("assert failed"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 	Zero = Big.Rat(0, 1); | 
					
						
							|  |  |  | 	One = Big.Rat(1, 1); | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | type Matrix struct { | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 	n, m int; | 
					
						
							| 
									
										
										
										
											2008-12-18 22:37:22 -08:00
										 |  |  | 	a []*Big.Rational; | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (a *Matrix) at(i, j int) *Big.Rational { | 
					
						
							|  |  |  | 	assert(0 <= i && i < a.n && 0 <= j && j < a.m); | 
					
						
							|  |  |  | 	return a.a[i*a.m + j]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (a *Matrix) set(i, j int, x *Big.Rational) { | 
					
						
							|  |  |  | 	assert(0 <= i && i < a.n && 0 <= j && j < a.m); | 
					
						
							|  |  |  | 	a.a[i*a.m + j] = x; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | func NewMatrix(n, m int) *Matrix { | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 	assert(0 <= n && 0 <= m); | 
					
						
							| 
									
										
										
										
											2009-01-06 15:19:02 -08:00
										 |  |  | 	a := new(Matrix); | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 	a.n = n; | 
					
						
							|  |  |  | 	a.m = m; | 
					
						
							| 
									
										
										
										
											2009-01-06 15:19:02 -08:00
										 |  |  | 	a.a = make([]*Big.Rational, n*m); | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 	return a; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | func NewUnit(n int) *Matrix { | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 	a := NewMatrix(n, n); | 
					
						
							|  |  |  | 	for i := 0; i < n; i++ { | 
					
						
							|  |  |  | 		for j := 0; j < n; j++ { | 
					
						
							|  |  |  | 			x := Zero; | 
					
						
							|  |  |  | 			if i == j { | 
					
						
							|  |  |  | 				x = One; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			a.set(i, j, x); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return a; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | func NewHilbert(n int) *Matrix { | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 	a := NewMatrix(n, n); | 
					
						
							|  |  |  | 	for i := 0; i < n; i++ { | 
					
						
							|  |  |  | 		for j := 0; j < n; j++ { | 
					
						
							|  |  |  | 			x := Big.Rat(1, i + j + 1); | 
					
						
							|  |  |  | 			a.set(i, j, x); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return a; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | func MakeRat(x Big.Natural) *Big.Rational { | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 	return Big.MakeRat(Big.MakeInt(false, x), Big.Nat(1)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-20 14:40:40 -08:00
										 |  |  | func NewInverseHilbert(n int) *Matrix { | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 	a := NewMatrix(n, n); | 
					
						
							|  |  |  | 	for i := 0; i < n; i++ { | 
					
						
							|  |  |  | 		for j := 0; j < n; j++ { | 
					
						
							|  |  |  | 			x0 := One; | 
					
						
							|  |  |  | 			if (i+j)&1 != 0 { | 
					
						
							|  |  |  | 				x0 = x0.Neg(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			x1 := Big.Rat(i + j + 1, 1); | 
					
						
							|  |  |  | 			x2 := MakeRat(Big.Binomial(uint(n+i), uint(n-j-1))); | 
					
						
							|  |  |  | 			x3 := MakeRat(Big.Binomial(uint(n+j), uint(n-i-1))); | 
					
						
							|  |  |  | 			x4 := MakeRat(Big.Binomial(uint(i+j), uint(i))); | 
					
						
							|  |  |  | 			x4 = x4.Mul(x4); | 
					
						
							| 
									
										
										
										
											2008-12-30 14:02:20 -08:00
										 |  |  | 			a.set(i, j, x0.Mul(x1).Mul(x2).Mul(x3).Mul(x4)); | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return a; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (a *Matrix) Mul(b *Matrix) *Matrix { | 
					
						
							|  |  |  | 	assert(a.m == b.n); | 
					
						
							|  |  |  | 	c := NewMatrix(a.n, b.m); | 
					
						
							|  |  |  | 	for i := 0; i < c.n; i++ { | 
					
						
							|  |  |  | 		for j := 0; j < c.m; j++ { | 
					
						
							|  |  |  | 			x := Zero; | 
					
						
							|  |  |  | 			for k := 0; k < a.m; k++ { | 
					
						
							| 
									
										
										
										
											2008-12-30 14:02:20 -08:00
										 |  |  | 				x = x.Add(a.at(i, k).Mul(b.at(k, j))); | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			c.set(i, j, x); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return c; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (a *Matrix) Eql(b *Matrix) bool { | 
					
						
							|  |  |  | 	if a.n != b.n || a.m != b.m { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for i := 0; i < a.n; i++ { | 
					
						
							|  |  |  | 		for j := 0; j < a.m; j++ { | 
					
						
							| 
									
										
										
										
											2008-12-30 14:02:20 -08:00
										 |  |  | 			if a.at(i, j).Cmp(b.at(i,j)) != 0 { | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 				return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (a *Matrix) String() string { | 
					
						
							|  |  |  | 	s := ""; | 
					
						
							|  |  |  | 	for i := 0; i < a.n; i++ { | 
					
						
							|  |  |  | 		for j := 0; j < a.m; j++ { | 
					
						
							| 
									
										
										
										
											2009-01-15 13:48:11 -08:00
										 |  |  | 			s += Fmt.Sprintf("\t%s", a.at(i, j)); | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		s += "\n"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func main() { | 
					
						
							|  |  |  | 	n := 10; | 
					
						
							|  |  |  | 	a := NewHilbert(n); | 
					
						
							|  |  |  | 	b := NewInverseHilbert(n); | 
					
						
							|  |  |  | 	I := NewUnit(n); | 
					
						
							|  |  |  | 	ab := a.Mul(b); | 
					
						
							|  |  |  | 	if !ab.Eql(I) { | 
					
						
							| 
									
										
										
										
											2009-01-15 13:48:11 -08:00
										 |  |  | 		Fmt.Println("a =", a); | 
					
						
							|  |  |  | 		Fmt.Println("b =", b); | 
					
						
							|  |  |  | 		Fmt.Println("a*b =", ab); | 
					
						
							|  |  |  | 		Fmt.Println("I =", I); | 
					
						
							| 
									
										
										
										
											2008-11-06 14:23:49 -08:00
										 |  |  | 		panic("FAILED"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |