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  }