github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/go/types/hilbert_test.go (about) 1 // Copyright 2013 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 package types_test 6 7 import ( 8 "bytes" 9 "flag" 10 "fmt" 11 "go/ast" 12 "go/importer" 13 "go/parser" 14 "go/token" 15 "io/ioutil" 16 "testing" 17 18 . "go/types" 19 ) 20 21 var ( 22 H = flag.Int("H", 5, "Hilbert matrix size") 23 out = flag.String("out", "", "write generated program to out") 24 ) 25 26 func TestHilbert(t *testing.T) { 27 // generate source 28 src := program(*H, *out) 29 if *out != "" { 30 ioutil.WriteFile(*out, src, 0666) 31 return 32 } 33 34 // parse source 35 fset := token.NewFileSet() 36 f, err := parser.ParseFile(fset, "hilbert.go", src, 0) 37 if err != nil { 38 t.Fatal(err) 39 } 40 41 // type-check file 42 DefPredeclaredTestFuncs() // define assert built-in 43 conf := Config{Importer: importer.Default()} 44 _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) 45 if err != nil { 46 t.Fatal(err) 47 } 48 } 49 50 func program(n int, out string) []byte { 51 var g gen 52 53 g.p(`// Code generated by: go test -run=Hilbert -H=%d -out=%q. DO NOT EDIT. 54 55 // This program tests arbitrary precision constant arithmetic 56 // by generating the constant elements of a Hilbert matrix H, 57 // its inverse I, and the product P = H*I. The product should 58 // be the identity matrix. 59 package main 60 61 func main() { 62 if !ok { 63 printProduct() 64 return 65 } 66 println("PASS") 67 } 68 69 `, n, out) 70 g.hilbert(n) 71 g.inverse(n) 72 g.product(n) 73 g.verify(n) 74 g.printProduct(n) 75 g.binomials(2*n - 1) 76 g.factorials(2*n - 1) 77 78 return g.Bytes() 79 } 80 81 type gen struct { 82 bytes.Buffer 83 } 84 85 func (g *gen) p(format string, args ...interface{}) { 86 fmt.Fprintf(&g.Buffer, format, args...) 87 } 88 89 func (g *gen) hilbert(n int) { 90 g.p(`// Hilbert matrix, n = %d 91 const ( 92 `, n) 93 for i := 0; i < n; i++ { 94 g.p("\t") 95 for j := 0; j < n; j++ { 96 if j > 0 { 97 g.p(", ") 98 } 99 g.p("h%d_%d", i, j) 100 } 101 if i == 0 { 102 g.p(" = ") 103 for j := 0; j < n; j++ { 104 if j > 0 { 105 g.p(", ") 106 } 107 g.p("1.0/(iota + %d)", j+1) 108 } 109 } 110 g.p("\n") 111 } 112 g.p(")\n\n") 113 } 114 115 func (g *gen) inverse(n int) { 116 g.p(`// Inverse Hilbert matrix 117 const ( 118 `) 119 for i := 0; i < n; i++ { 120 for j := 0; j < n; j++ { 121 s := "+" 122 if (i+j)&1 != 0 { 123 s = "-" 124 } 125 g.p("\ti%d_%d = %s%d * b%d_%d * b%d_%d * b%d_%d * b%d_%d\n", 126 i, j, s, i+j+1, n+i, n-j-1, n+j, n-i-1, i+j, i, i+j, i) 127 } 128 g.p("\n") 129 } 130 g.p(")\n\n") 131 } 132 133 func (g *gen) product(n int) { 134 g.p(`// Product matrix 135 const ( 136 `) 137 for i := 0; i < n; i++ { 138 for j := 0; j < n; j++ { 139 g.p("\tp%d_%d = ", i, j) 140 for k := 0; k < n; k++ { 141 if k > 0 { 142 g.p(" + ") 143 } 144 g.p("h%d_%d*i%d_%d", i, k, k, j) 145 } 146 g.p("\n") 147 } 148 g.p("\n") 149 } 150 g.p(")\n\n") 151 } 152 153 func (g *gen) verify(n int) { 154 g.p(`// Verify that product is the identity matrix 155 const ok = 156 `) 157 for i := 0; i < n; i++ { 158 for j := 0; j < n; j++ { 159 if j == 0 { 160 g.p("\t") 161 } else { 162 g.p(" && ") 163 } 164 v := 0 165 if i == j { 166 v = 1 167 } 168 g.p("p%d_%d == %d", i, j, v) 169 } 170 g.p(" &&\n") 171 } 172 g.p("\ttrue\n\n") 173 174 // verify ok at type-check time 175 if *out == "" { 176 g.p("const _ = assert(ok)\n\n") 177 } 178 } 179 180 func (g *gen) printProduct(n int) { 181 g.p("func printProduct() {\n") 182 for i := 0; i < n; i++ { 183 g.p("\tprintln(") 184 for j := 0; j < n; j++ { 185 if j > 0 { 186 g.p(", ") 187 } 188 g.p("p%d_%d", i, j) 189 } 190 g.p(")\n") 191 } 192 g.p("}\n\n") 193 } 194 195 func (g *gen) binomials(n int) { 196 g.p(`// Binomials 197 const ( 198 `) 199 for j := 0; j <= n; j++ { 200 if j > 0 { 201 g.p("\n") 202 } 203 for k := 0; k <= j; k++ { 204 g.p("\tb%d_%d = f%d / (f%d*f%d)\n", j, k, j, k, j-k) 205 } 206 } 207 g.p(")\n\n") 208 } 209 210 func (g *gen) factorials(n int) { 211 g.p(`// Factorials 212 const ( 213 f0 = 1 214 f1 = 1 215 `) 216 for i := 2; i <= n; i++ { 217 g.p("\tf%d = f%d * %d\n", i, i-1, i) 218 } 219 g.p(")\n\n") 220 }