github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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) binomials(n int) {
   197  	g.p(`// Binomials
   198  const (
   199  `)
   200  	for j := 0; j <= n; j++ {
   201  		if j > 0 {
   202  			g.p("\n")
   203  		}
   204  		for k := 0; k <= j; k++ {
   205  			g.p("\tb%d_%d = f%d / (f%d*f%d)\n", j, k, j, k, j-k)
   206  		}
   207  	}
   208  	g.p(")\n\n")
   209  }
   210  
   211  func (g *gen) factorials(n int) {
   212  	g.p(`// Factorials
   213  const (
   214  	f0 = 1
   215  	f1 = 1
   216  `)
   217  	for i := 2; i <= n; i++ {
   218  		g.p("\tf%d = f%d * %d\n", i, i-1, i)
   219  	}
   220  	g.p(")\n\n")
   221  }