github.com/wzzhu/tensor@v0.9.24/genlib2/generic_reduce.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"text/template"
     7  )
     8  
     9  const reflectBasedReduceRaw = `func ReduceRef(f reflect.Value, fnT reflect.Type, def reflect.Value, l *Dense) interface{} {
    10  	retVal := def
    11  	if l.len() == 0 {
    12  		return retVal.Interface()
    13  	}
    14  
    15  	args := make([]reflect.Value, 0, fnT.NumIn())
    16  	for i := 0; i < l.len(); i++ {
    17  		v := reflect.ValueOf(l.Get(i))
    18  		args = append(args, retVal)
    19  		args = append(args, v)
    20  		retVal = f.Call(args)[0]
    21  		args = args[:0]
    22  	}
    23  	return retVal.Interface()
    24  }
    25  
    26  `
    27  const genericReduceRaw = `func Reduce{{short .}}(f func(a, b {{asType .}}) {{asType .}}, def {{asType .}}, l ...{{asType .}}) (retVal {{asType .}}){
    28  	retVal = def
    29  	if len(l) == 0 {
    30  		return 
    31  	}
    32  
    33  	for _, v := range l {
    34  		retVal = f(retVal, v)
    35  	}
    36  	return
    37  }
    38  
    39  `
    40  
    41  const genericSumRaw = `func Sum{{short .}}(a []{{asType .}}) {{asType .}}{ 
    42  	var retVal {{asType .}}
    43  	a = a[:len(a)]
    44  	for _, v := range a {
    45  		retVal += v
    46  	}
    47  	return retVal
    48  }
    49  `
    50  
    51  const genericProdRaw = `func Prod{{short .}}(a []{{asType .}}) {{asType .}} { 
    52  	if len(a) == 0 {
    53  		return 0
    54  	}
    55  	var retVal {{asType .}} = 1
    56  	a = a[:len(a)]
    57  	for _, v := range a {
    58  		retVal *= v
    59  	}
    60  	return retVal
    61  }
    62  `
    63  
    64  const genericSliceMinMaxRaw = `func SliceMin{{short .}}(a []{{asType .}}) {{asType .}}{
    65  	if len(a) < 1 {
    66  		panic("Max of empty slice is meaningless")
    67  	}
    68  	return Reduce{{short .}}(Min{{short .}}, a[0], a[1:]...)
    69  }
    70  
    71  func SliceMax{{short .}}(a []{{asType .}}) {{asType .}}{
    72  	if len(a) < 1 {
    73  		panic("Max of empty slice is meaningless")
    74  	}
    75  	return Reduce{{short .}}(Max{{short .}}, a[0], a[1:]...)
    76  }
    77  
    78  `
    79  
    80  const genericReduce0Raw = `func reduceFirst{{short .}}(data, retVal []{{asType .}}, split, size int, fn func(a, b []{{asType .}})) {
    81  	start := split
    82  	copy(retVal[0:split], data[0:split])
    83  	for i := 0; i < size - 1; i++ {
    84  		fn(retVal, data[start:start+split])
    85  		start += split
    86  	}
    87  }
    88  
    89  func genericReduceFirst{{short .}}(data, retVal []{{asType .}}, split, size int, fn func(a, b {{asType .}}){{asType .}} ){
    90  	start := split
    91  	copy(retVal[0:split], data[0:split])
    92  	for i := 0; i < size - 1; i++ {
    93  		for j := 0; j < split; j++ {
    94  			retVal[j] = fn(retVal[j], data[j+start])
    95  		}
    96  		start += split
    97  	}
    98  }
    99  `
   100  
   101  const genericReduce0ParRaw = `func reduceFirst{{short .}}(data, retVal []{{asType .}}, split, size int, fn func(a, b {{asType .}}){{asType .}}) {
   102  	start := split
   103  	var wg sync.Waitgroup
   104  	for i := 0; i < size - 1; i++ {
   105  		wg.Add(1)
   106  		go func(sp, st int) {
   107  			for j := 0; j < sp; j++ {
   108  				retVal[j] = fn(retVal[j], data[j+start])
   109  			}
   110  		}(split, start, &wg)
   111  		start += split
   112  	}
   113  }
   114  
   115  `
   116  
   117  const genericReduceLastRaw = `func reduceLast{{short .}}(a, retVal []{{asType .}}, dimSize int, defaultValue {{asType .}}, fn func(a []{{asType .}}){{asType .}}) {
   118  	var at int
   119  	for start := 0; start <= len(a) - dimSize; start += dimSize {
   120  		r := fn(a[start:start+dimSize])
   121  		retVal[at] = r
   122  		at++
   123  	}
   124  }
   125  
   126  func genericReduceLast{{short .}}(a, retVal []{{asType .}}, dimSize int, defaultValue {{asType .}}, fn func({{asType .}}, {{asType .}}){{asType .}}) {
   127  	var at int 
   128  	for start := 0; start <= len(a) - dimSize; start += dimSize {
   129  		r := Reduce{{short .}}(fn, defaultValue, a[start:start+dimSize]...)
   130  		retVal[at] = r
   131  		at++
   132  	}
   133  }
   134  
   135  `
   136  
   137  const genericReduceDefaultRaw = `func reduceDefault{{short .}}(data, retVal []{{asType .}}, dim0, dimSize, outerStride, stride, expected int, fn func(a,b {{asType .}}){{asType .}}) {
   138  	for i := 0; i < dim0; i++ {
   139  		start := i * outerStride
   140  		sliced := data[start : start+outerStride]
   141  		var innerStart, strideTrack int 
   142  		for j := 0; j < expected; j++ {
   143  			writeTo := i * expected + j
   144  			retVal[writeTo] = sliced[innerStart]
   145  			for k := 1; k < dimSize; k++ {
   146  				readFrom := innerStart + k * stride
   147  				retVal[writeTo] = fn(retVal[writeTo], sliced[readFrom])
   148  			}
   149  			strideTrack++
   150  			if strideTrack >= stride {
   151  				strideTrack = 0
   152  				innerStart += stride
   153  			}
   154  			innerStart++
   155  		}
   156  	}
   157  }
   158  
   159  `
   160  
   161  var (
   162  	genericReduce      *template.Template
   163  	genericSum         *template.Template
   164  	genericProd        *template.Template
   165  	genericSliceMinMax *template.Template
   166  
   167  	genericReduce0       *template.Template
   168  	genericReduceLast    *template.Template
   169  	genericReduceDefault *template.Template
   170  )
   171  
   172  func init() {
   173  	genericReduce = template.Must(template.New("genericReduce").Funcs(funcs).Parse(genericReduceRaw))
   174  	genericSum = template.Must(template.New("genericSum").Funcs(funcs).Parse(genericSumRaw))
   175  	genericProd = template.Must(template.New("genericProd").Funcs(funcs).Parse(genericProdRaw))
   176  	genericSliceMinMax = template.Must(template.New("genericSliceMinMax").Funcs(funcs).Parse(genericSliceMinMaxRaw))
   177  	genericReduce0 = template.Must(template.New("genericReduce0").Funcs(funcs).Parse(genericReduce0Raw))
   178  	genericReduceLast = template.Must(template.New("genericReduceLast").Funcs(funcs).Parse(genericReduceLastRaw))
   179  	genericReduceDefault = template.Must(template.New("genericReduceDefault").Funcs(funcs).Parse(genericReduceDefaultRaw))
   180  }
   181  
   182  func generateGenericReduce(f io.Writer, generic Kinds) {
   183  	// fmt.Fprintln(f, reflectBasedReduceRaw)
   184  	for _, k := range generic.Kinds {
   185  		if !isParameterized(k) {
   186  			genericReduce.Execute(f, k)
   187  		}
   188  	}
   189  
   190  	for _, k := range filter(generic.Kinds, isNumber) {
   191  		genericSum.Execute(f, k)
   192  
   193  	}
   194  	for _, k := range filter(generic.Kinds, isNumber) {
   195  		genericProd.Execute(f, k)
   196  	}
   197  	fmt.Fprintf(f, "\n")
   198  
   199  	for _, k := range filter(generic.Kinds, isOrd) {
   200  		if isNumber(k) {
   201  			genericSliceMinMax.Execute(f, k)
   202  		}
   203  	}
   204  
   205  	for _, k := range filter(generic.Kinds, isNotParameterized) {
   206  		genericReduce0.Execute(f, k)
   207  	}
   208  
   209  	for _, k := range filter(generic.Kinds, isNotParameterized) {
   210  		genericReduceLast.Execute(f, k)
   211  	}
   212  
   213  	for _, k := range filter(generic.Kinds, isNotParameterized) {
   214  		genericReduceDefault.Execute(f, k)
   215  	}
   216  }