github.com/aloncn/graphics-go@v0.0.1/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(`// WARNING: GENERATED FILE - DO NOT MODIFY MANUALLY! 54 // (To generate, in go/types directory: go test -run=Hilbert -H=%d -out=%q) 55 56 // This program tests arbitrary precision constant arithmetic 57 // by generating the constant elements of a Hilbert matrix H, 58 // its inverse I, and the product P = H*I. The product should 59 // be the identity matrix. 60 package main 61 62 func main() { 63 if !ok { 64 printProduct() 65 return 66 } 67 println("PASS") 68 } 69 70 `, n, out) 71 g.hilbert(n) 72 g.inverse(n) 73 g.product(n) 74 g.verify(n) 75 g.printProduct(n) 76 g.binomials(2*n - 1) 77 g.factorials(2*n - 1) 78 79 return g.Bytes() 80 } 81 82 type gen struct { 83 bytes.Buffer 84 } 85 86 func (g *gen) p(format string, args ...interface{}) { 87 fmt.Fprintf(&g.Buffer, format, args...) 88 } 89 90 func (g *gen) hilbert(n int) { 91 g.p(`// Hilbert matrix, n = %d 92 const ( 93 `, n) 94 for i := 0; i < n; i++ { 95 g.p("\t") 96 for j := 0; j < n; j++ { 97 if j > 0 { 98 g.p(", ") 99 } 100 g.p("h%d_%d", i, j) 101 } 102 if i == 0 { 103 g.p(" = ") 104 for j := 0; j < n; j++ { 105 if j > 0 { 106 g.p(", ") 107 } 108 g.p("1.0/(iota + %d)", j+1) 109 } 110 } 111 g.p("\n") 112 } 113 g.p(")\n\n") 114 } 115 116 func (g *gen) inverse(n int) { 117 g.p(`// Inverse Hilbert matrix 118 const ( 119 `) 120 for i := 0; i < n; i++ { 121 for j := 0; j < n; j++ { 122 s := "+" 123 if (i+j)&1 != 0 { 124 s = "-" 125 } 126 g.p("\ti%d_%d = %s%d * b%d_%d * b%d_%d * b%d_%d * b%d_%d\n", 127 i, j, s, i+j+1, n+i, n-j-1, n+j, n-i-1, i+j, i, i+j, i) 128 } 129 g.p("\n") 130 } 131 g.p(")\n\n") 132 } 133 134 func (g *gen) product(n int) { 135 g.p(`// Product matrix 136 const ( 137 `) 138 for i := 0; i < n; i++ { 139 for j := 0; j < n; j++ { 140 g.p("\tp%d_%d = ", i, j) 141 for k := 0; k < n; k++ { 142 if k > 0 { 143 g.p(" + ") 144 } 145 g.p("h%d_%d*i%d_%d", i, k, k, j) 146 } 147 g.p("\n") 148 } 149 g.p("\n") 150 } 151 g.p(")\n\n") 152 } 153 154 func (g *gen) verify(n int) { 155 g.p(`// Verify that product is the identity matrix 156 const ok = 157 `) 158 for i := 0; i < n; i++ { 159 for j := 0; j < n; j++ { 160 if j == 0 { 161 g.p("\t") 162 } else { 163 g.p(" && ") 164 } 165 v := 0 166 if i == j { 167 v = 1 168 } 169 g.p("p%d_%d == %d", i, j, v) 170 } 171 g.p(" &&\n") 172 } 173 g.p("\ttrue\n\n") 174 175 // verify ok at type-check time 176 if *out == "" { 177 g.p("const _ = assert(ok)\n\n") 178 } 179 } 180 181 func (g *gen) printProduct(n int) { 182 g.p("func printProduct() {\n") 183 for i := 0; i < n; i++ { 184 g.p("\tprintln(") 185 for j := 0; j < n; j++ { 186 if j > 0 { 187 g.p(", ") 188 } 189 g.p("p%d_%d", i, j) 190 } 191 g.p(")\n") 192 } 193 g.p("}\n\n") 194 } 195 196 func (g *gen) mulRange(a, b int) { 197 if a > b { 198 g.p("1") 199 return 200 } 201 for i := a; i <= b; i++ { 202 if i > a { 203 g.p("*") 204 } 205 g.p("%d", i) 206 } 207 } 208 209 func (g *gen) binomials(n int) { 210 g.p(`// Binomials 211 const ( 212 `) 213 for j := 0; j <= n; j++ { 214 if j > 0 { 215 g.p("\n") 216 } 217 for k := 0; k <= j; k++ { 218 g.p("\tb%d_%d = f%d / (f%d*f%d)\n", j, k, j, k, j-k) 219 } 220 } 221 g.p(")\n\n") 222 } 223 224 func (g *gen) factorials(n int) { 225 g.p(`// Factorials 226 const ( 227 f0 = 1 228 f1 = 1 229 `) 230 for i := 2; i <= n; i++ { 231 g.p("\tf%d = f%d * %d\n", i, i-1, i) 232 } 233 g.p(")\n\n") 234 }