diff --git a/fermi b/fermi index c43d74c..bc9a06f 100755 Binary files a/fermi and b/fermi differ diff --git a/main/errors.go b/main/errors.go new file mode 100644 index 0000000..834cc21 --- /dev/null +++ b/main/errors.go @@ -0,0 +1,10 @@ +package main + +type MyError struct { + Code string + Msg string +} + +func (me MyError) Error() string { + return me.Msg +} diff --git a/fermi.go b/main/fermi.go similarity index 80% rename from fermi.go rename to main/fermi.go index a391888..6e67f3b 100644 --- a/fermi.go +++ b/main/fermi.go @@ -5,11 +5,9 @@ import ( "errors" "flag" "fmt" - "git.nunosempere.com/NunoSempere/fermi/pretty" "git.nunosempere.com/NunoSempere/fermi/sample" "math" "os" - "sort" "strings" ) @@ -46,11 +44,11 @@ func (p Scalar) Sampler(i int, r sample.State) float64 { } func (ln Lognormal) Sampler(i int, r sample.State) float64 { - return sample.Sample_to(ln.low, ln.high, r) + return sample.To(ln.low, ln.high, r) } func (beta Beta) Sampler(i int, r sample.State) float64 { - return sample.Sample_beta(beta.a, beta.b, r) + return sample.Beta(beta.a, beta.b, r) } func (fs FilledSamples) Sampler(i int, r sample.State) float64 { @@ -112,94 +110,12 @@ const INIT_DIST Scalar = Scalar(1) var N_SAMPLES = 100_000 -/* Printers */ -func prettyPrintDist(dist Dist) { - switch v := dist.(type) { - case Lognormal: - fmt.Printf("=> ") - pretty.PrettyPrint2Floats(v.low, v.high) - fmt.Println() - case Beta: - fmt.Printf("=> beta ") - pretty.PrettyPrint2Floats(v.a, v.b) - fmt.Println() - case Scalar: - fmt.Printf("=> scalar ") - w := float64(v) - pretty.PrettyPrintFloat(w) - fmt.Println() - case FilledSamples: - n := len(v.xs) - sorted_xs := make([]float64, n) - copy(sorted_xs, v.xs) - sort.Slice(sorted_xs, func(i, j int) bool { - return sorted_xs[i] < sorted_xs[j] - }) - - low := sorted_xs[int(math.Round(float64(n)*0.05))] - high := sorted_xs[int(math.Round(float64(n)*0.95))] - fmt.Printf("=> ") - pretty.PrettyPrint2Floats(low, high) - - fmt.Printf(" (") - pretty.PrettyPrintInt(N_SAMPLES) - fmt.Printf(" samples)") - fmt.Println() - default: - fmt.Printf("%v\n", v) - } -} - -func printAndReturnErr(err_msg string) error { - fmt.Println(err_msg) - fmt.Println("Type \"help\" (without quotes) to see a pseudogrammar and examples") - return errors.New(err_msg) -} - -func prettyPrintStats(dist Dist) { - xs := sample.Sample_serially(dist.Sampler, N_SAMPLES) - n := len(xs) - - mean := 0.0 - for i := 0; i < n; i++ { - mean += xs[i] - } - mean /= float64(n) - fmt.Printf("Mean: %f\n", mean) - - stdev := 0.0 - for i := 0; i < n; i++ { - stdev += math.Pow(xs[i]-mean, 2) - } - stdev = math.Sqrt(stdev / float64(n)) - fmt.Printf("Stdev: %f\n", stdev) - - sorted_xs := make([]float64, n) - copy(sorted_xs, xs) - sort.Slice(sorted_xs, func(i, j int) bool { - return sorted_xs[i] < sorted_xs[j] - }) - print_ci := func(ci float64, prefix string) { - x := sorted_xs[int(math.Round(float64(n)*ci))] - fmt.Printf("%s%f\n", prefix, x) - } - print_ci(0.01, "ci 1%: ") - print_ci(0.05, "ci 5%: ") - print_ci(0.10, "ci 10%: ") - print_ci(0.25, "ci 25%: ") - print_ci(0.50, "ci 50%: ") - print_ci(0.75, "ci 75%: ") - print_ci(0.90, "ci 90%: ") - print_ci(0.95, "ci 95%: ") - print_ci(0.99, "ci 99%: ") -} - /* Operations */ // Generic operations with samples func operateDistsAsSamples(dist1 Dist, dist2 Dist, op string) (Dist, error) { - xs := sample.Sample_serially(dist1.Sampler, N_SAMPLES) - ys := sample.Sample_serially(dist2.Sampler, N_SAMPLES) + xs := sample.Serially(dist1.Sampler, N_SAMPLES) + ys := sample.Serially(dist2.Sampler, N_SAMPLES) zs := make([]float64, N_SAMPLES) for i := 0; i < N_SAMPLES; i++ { @@ -335,7 +251,7 @@ func operateDists(old_dist Dist, new_dist Dist, op string) (Dist, error) { case "-": return operateDistsAsSamples(old_dist, new_dist, "-") default: - return nil, printAndReturnErr("Can't combine distributions in this way") + return nil, PrintAndReturnErr("Can't combine distributions in this way") } } @@ -344,7 +260,7 @@ func parseMixture(words []string, vars map[string]Dist) (Dist, error) { // mx, mix, var weight var weight var weight ... // Check syntax if len(words)%2 != 0 { - return nil, printAndReturnErr("Not a mixture. \nMixture syntax: \nmx x 2.5 y 8 z 10\ni.e.: mx var weight var2 weight2 ... var_n weight_n") + return nil, PrintAndReturnErr("Not a mixture. \nMixture syntax: \nmx x 2.5 y 8 z 10\ni.e.: mx var weight var2 weight2 ... var_n weight_n") } var fs []func(int, sample.State) float64 @@ -354,29 +270,29 @@ func parseMixture(words []string, vars map[string]Dist) (Dist, error) { if i%2 == 0 { dist, exists := vars[word] if !exists { - return nil, printAndReturnErr("Expected mixture variable but didn't get a variable. \nMixture syntax: \nmx x 2.5 y 8 z 10\ni.e.: mx var weight var2 weight2 ... var_n weight_n") + return nil, PrintAndReturnErr("Expected mixture variable but didn't get a variable. \nMixture syntax: \nmx x 2.5 y 8 z 10\ni.e.: mx var weight var2 weight2 ... var_n weight_n") } f := dist.Sampler fs = append(fs, f) } else { - weight, err := pretty.ParseFloat(word) + weight, err := ParseFloat(word) if err != nil { - return nil, printAndReturnErr("Expected mixture weight but didn't get a float. \nMixture syntax: \nmx x 2.5 y 8 z 10\ni.e.: mx var weight var2 weight2 ... var_n weight_n") + return nil, PrintAndReturnErr("Expected mixture weight but didn't get a float. \nMixture syntax: \nmx x 2.5 y 8 z 10\ni.e.: mx var weight var2 weight2 ... var_n weight_n") } weights = append(weights, weight) } } // Sample from mixture - xs, err := sample.Sample_mixture_serially_from_samplers(fs, weights, N_SAMPLES) + xs, err := sample.Mixture_serially_from_samplers(fs, weights, N_SAMPLES) if err != nil { - return nil, printAndReturnErr(err.Error()) + return nil, PrintAndReturnErr(err.Error()) } return FilledSamples{xs: xs}, nil } /* Parser and repl */ func parseWordsErr(err_msg string) (string, Dist, error) { - return "", nil, printAndReturnErr(err_msg) + return "", nil, PrintAndReturnErr(err_msg) } func parseWordsIntoOpAndDist(words []string, vars map[string]Dist) (string, Dist, error) { @@ -396,7 +312,7 @@ func parseWordsIntoOpAndDist(words []string, vars map[string]Dist) (string, Dist return parseWordsErr("Operator must have operand; can't operate on nothing") case 1: var_word, var_word_exists := vars[words[0]] - single_float, err1 := pretty.ParseFloat(words[0]) // abstract this away to search for K/M/B/T/etc. + single_float, err1 := ParseFloat(words[0]) // abstract this away to search for K/M/B/T/etc. switch { case var_word_exists: dist = var_word @@ -406,8 +322,8 @@ func parseWordsIntoOpAndDist(words []string, vars map[string]Dist) (string, Dist return parseWordsErr("Trying to operate on a scalar, but scalar is neither a float nor an assigned variable") } case 2: - new_low, err1 := pretty.ParseFloat(words[0]) - new_high, err2 := pretty.ParseFloat(words[1]) + new_low, err1 := ParseFloat(words[0]) + new_high, err2 := ParseFloat(words[1]) switch { case err1 != nil || err2 != nil: return parseWordsErr("Trying to operate by a distribution, but distribution is not specified as two floats") @@ -422,8 +338,8 @@ func parseWordsIntoOpAndDist(words []string, vars map[string]Dist) (string, Dist case 3: switch { case words[0] == "beta" || words[0] == "b": - a, err1 := pretty.ParseFloat(words[1]) - b, err2 := pretty.ParseFloat(words[2]) + a, err1 := ParseFloat(words[1]) + b, err2 := ParseFloat(words[2]) if err1 != nil || err2 != nil { return parseWordsErr("Trying to specify a beta distribution? Try beta 1 2") } @@ -485,7 +401,7 @@ replForLoop: stack.old_dist = INIT_DIST fmt.Println() case words[0] == "stats" || words[0] == "s": - prettyPrintStats(stack.old_dist) + PrettyPrintStats(stack.old_dist) /* Variable assignment */ case words[0] == "=:" && len(words) == 2: stack.vars[words[1]] = stack.old_dist @@ -493,7 +409,7 @@ replForLoop: case words[0] == "=." && len(words) == 2: stack.vars[words[1]] = stack.old_dist fmt.Printf("%s ", words[1]) - prettyPrintDist(stack.old_dist) + PrettyPrintDist(stack.old_dist) stack.old_dist = INIT_DIST default: op, new_dist, err := parseWordsIntoOpAndDist(words, stack.vars) @@ -505,7 +421,7 @@ replForLoop: stack.old_dist = combined_dist } } - prettyPrintDist(stack.old_dist) + PrettyPrintDist(stack.old_dist) } } diff --git a/pretty/pretty.go b/main/pretty.go similarity index 51% rename from pretty/pretty.go rename to main/pretty.go index 3e6eb79..d86e41a 100644 --- a/pretty/pretty.go +++ b/main/pretty.go @@ -1,9 +1,11 @@ -package pretty +package main import ( "errors" "fmt" + "git.nunosempere.com/NunoSempere/fermi/sample" "math" + "sort" "strconv" ) @@ -87,3 +89,85 @@ func ParseFloat(word string) (float64, error) { } } + +/* Printers */ +func PrettyPrintDist(dist Dist) { + switch v := dist.(type) { + case Lognormal: + fmt.Printf("=> ") + PrettyPrint2Floats(v.low, v.high) + fmt.Println() + case Beta: + fmt.Printf("=> beta ") + PrettyPrint2Floats(v.a, v.b) + fmt.Println() + case Scalar: + fmt.Printf("=> scalar ") + w := float64(v) + PrettyPrintFloat(w) + fmt.Println() + case FilledSamples: + n := len(v.xs) + sorted_xs := make([]float64, n) + copy(sorted_xs, v.xs) + sort.Slice(sorted_xs, func(i, j int) bool { + return sorted_xs[i] < sorted_xs[j] + }) + + low := sorted_xs[int(math.Round(float64(n)*0.05))] + high := sorted_xs[int(math.Round(float64(n)*0.95))] + fmt.Printf("=> ") + PrettyPrint2Floats(low, high) + + fmt.Printf(" (") + PrettyPrintInt(N_SAMPLES) + fmt.Printf(" samples)") + fmt.Println() + default: + fmt.Printf("%v\n", v) + } +} + +func PrettyPrintStats(dist Dist) { + xs := sample.Serially(dist.Sampler, N_SAMPLES) + n := len(xs) + + mean := 0.0 + for i := 0; i < n; i++ { + mean += xs[i] + } + mean /= float64(n) + fmt.Printf("Mean: %f\n", mean) + + stdev := 0.0 + for i := 0; i < n; i++ { + stdev += math.Pow(xs[i]-mean, 2) + } + stdev = math.Sqrt(stdev / float64(n)) + fmt.Printf("Stdev: %f\n", stdev) + + sorted_xs := make([]float64, n) + copy(sorted_xs, xs) + sort.Slice(sorted_xs, func(i, j int) bool { + return sorted_xs[i] < sorted_xs[j] + }) + print_ci := func(ci float64, prefix string) { + x := sorted_xs[int(math.Round(float64(n)*ci))] + fmt.Printf("%s%f\n", prefix, x) + } + print_ci(0.01, "ci 1%: ") + print_ci(0.05, "ci 5%: ") + print_ci(0.10, "ci 10%: ") + print_ci(0.25, "ci 25%: ") + print_ci(0.50, "ci 50%: ") + print_ci(0.75, "ci 75%: ") + print_ci(0.90, "ci 90%: ") + print_ci(0.95, "ci 95%: ") + print_ci(0.99, "ci 99%: ") +} + +func PrintAndReturnErr(err_msg string) error { + fmt.Println(err_msg) + fmt.Println("Type \"help\" (without quotes) to see a pseudogrammar and examples") + return errors.New(err_msg) +} diff --git a/makefile b/makefile index fc60b55..b138a13 100644 --- a/makefile +++ b/makefile @@ -1,5 +1,5 @@ build: - go build fermi.go + go build main/fermi.go main/pretty.go run: go run fermi.go diff --git a/pretty.go b/pretty.go new file mode 100644 index 0000000..ef075bb --- /dev/null +++ b/pretty.go @@ -0,0 +1,173 @@ +package main + +import ( + "errors" + "fmt" + "git.nunosempere.com/NunoSempere/fermi/sample" + "math" + "sort" + "strconv" +) + +func PrettyPrintInt(n int) { + switch { + case math.Abs(float64(n)) >= 1_000_000_000_000: + fmt.Printf("%.2fT", float64(n)/1_000_000_000_000.0) + case math.Abs(float64(n)) >= 1_000_000_000: + fmt.Printf("%.2fB", float64(n)/1_000_000_000.0) + case math.Abs(float64(n)) >= 1_000_000: + fmt.Printf("%.2fM", float64(n)/1_000_000.0) + case math.Abs(float64(n)) >= 1_000: + fmt.Printf("%.2fK", float64(n)/1_000.0) + default: + fmt.Printf("%d", n) + } +} + +func PrettyPrintFloat(f float64) { + switch { + case math.Abs(f) >= 1_000_000_000_000: + fmt.Printf("%.2fT", f/1_000_000_000_000) + case math.Abs(f) >= 1_000_000_000: + fmt.Printf("%.2fB", f/1_000_000_000) + case math.Abs(f) >= 1_000_000: + fmt.Printf("%.2fM", f/1_000_000) + case math.Abs(f) >= 1_000: + fmt.Printf("%.2fK", f/1_000) + + case math.Abs(f) <= 0.0001: + fmt.Printf("%.6f", f) + case math.Abs(f) <= 0.001: + fmt.Printf("%.5f", f) + case math.Abs(f) <= 0.01: + fmt.Printf("%.4f", f) + case math.Abs(f) <= 0.1: + fmt.Printf("%.3f", f) + default: + fmt.Printf("%.2f", f) + } + +} +func PrettyPrint2Floats(low float64, high float64) { + PrettyPrintFloat(low) + fmt.Printf(" ") + PrettyPrintFloat(high) +} + +func multiplyOrPassThroughError(a float64, b float64, err error) (float64, error) { + if err != nil { + return b, err + } else { + return a * b, nil + } +} + +func ParseFloat(word string) (float64, error) { + // l = len(word) // assuming no UTF stuff + switch len(word) { + case 0: + return 0, errors.New("String to be parsed into float must not be the empty string") + case 1: + return strconv.ParseFloat(word, 64) + } + + n := len(word) - 1 + f, err := strconv.ParseFloat(word[:n], 64) + switch word[n] { + case '%': + return multiplyOrPassThroughError(0.01, f, err) + case 'K': + return multiplyOrPassThroughError(1_000, f, err) + case 'M': + return multiplyOrPassThroughError(1_000_000, f, err) + case 'B': + return multiplyOrPassThroughError(1_000_000_000, f, err) + case 'T': + return multiplyOrPassThroughError(1_000_000_000_000, f, err) + default: + return strconv.ParseFloat(word, 64) + } + +} + +/* Printers */ +func PrettyPrintDist(dist Dist) { + switch v := dist.(type) { + case Lognormal: + fmt.Printf("=> ") + PrettyPrint2Floats(v.low, v.high) + fmt.Println() + case Beta: + fmt.Printf("=> beta ") + PrettyPrint2Floats(v.a, v.b) + fmt.Println() + case Scalar: + fmt.Printf("=> scalar ") + w := float64(v) + PrettyPrintFloat(w) + fmt.Println() + case FilledSamples: + n := len(v.xs) + sorted_xs := make([]float64, n) + copy(sorted_xs, v.xs) + sort.Slice(sorted_xs, func(i, j int) bool { + return sorted_xs[i] < sorted_xs[j] + }) + + low := sorted_xs[int(math.Round(float64(n)*0.05))] + high := sorted_xs[int(math.Round(float64(n)*0.95))] + fmt.Printf("=> ") + PrettyPrint2Floats(low, high) + + fmt.Printf(" (") + PrettyPrintInt(N_SAMPLES) + fmt.Printf(" samples)") + fmt.Println() + default: + fmt.Printf("%v\n", v) + } +} + +func PrettyPrintStats(dist Dist) { + xs := sample.Sample_serially(dist.Sampler, N_SAMPLES) + n := len(xs) + + mean := 0.0 + for i := 0; i < n; i++ { + mean += xs[i] + } + mean /= float64(n) + fmt.Printf("Mean: %f\n", mean) + + stdev := 0.0 + for i := 0; i < n; i++ { + stdev += math.Pow(xs[i]-mean, 2) + } + stdev = math.Sqrt(stdev / float64(n)) + fmt.Printf("Stdev: %f\n", stdev) + + sorted_xs := make([]float64, n) + copy(sorted_xs, xs) + sort.Slice(sorted_xs, func(i, j int) bool { + return sorted_xs[i] < sorted_xs[j] + }) + print_ci := func(ci float64, prefix string) { + x := sorted_xs[int(math.Round(float64(n)*ci))] + fmt.Printf("%s%f\n", prefix, x) + } + print_ci(0.01, "ci 1%: ") + print_ci(0.05, "ci 5%: ") + print_ci(0.10, "ci 10%: ") + print_ci(0.25, "ci 25%: ") + print_ci(0.50, "ci 50%: ") + print_ci(0.75, "ci 75%: ") + print_ci(0.90, "ci 90%: ") + print_ci(0.95, "ci 95%: ") + print_ci(0.99, "ci 99%: ") +} + +func PrintAndReturnErr(err_msg string) error { + fmt.Println(err_msg) + fmt.Println("Type \"help\" (without quotes) to see a pseudogrammar and examples") + return errors.New(err_msg) +} diff --git a/sample/sample.go b/sample/sample.go index 33364e5..505d4c2 100644 --- a/sample/sample.go +++ b/sample/sample.go @@ -17,49 +17,49 @@ type func64i = func(int, State) float64 var global_state = rand.New(rand.NewPCG(uint64(1), uint64(2))) -func Sample_int(n int, r State) int { +func Int(n int, r State) int { return r.IntN(n) } -func Sample_unit_uniform(r State) float64 { +func Unit_uniform(r State) float64 { return r.Float64() } -func Sample_unit_normal(r State) float64 { +func Unit_normal(r State) float64 { return r.NormFloat64() } -func Sample_uniform(start float64, end float64, r State) float64 { - return Sample_unit_uniform(r)*(end-start) + start +func Uniform(start float64, end float64, r State) float64 { + return Unit_uniform(r)*(end-start) + start } -func Sample_normal(mean float64, sigma float64, r State) float64 { - return mean + Sample_unit_normal(r)*sigma +func Normal(mean float64, sigma float64, r State) float64 { + return mean + Unit_normal(r)*sigma } -func Sample_lognormal(logmean float64, logstd float64, r State) float64 { - return (math.Exp(Sample_normal(logmean, logstd, r))) +func Lognormal(logmean float64, logstd float64, r State) float64 { + return (math.Exp(Normal(logmean, logstd, r))) } -func Sample_normal_from_90_ci(low float64, high float64, r State) float64 { +func Normal_from_90_ci(low float64, high float64, r State) float64 { var normal90 float64 = 1.6448536269514727 var mean float64 = (high + low) / 2.0 var std float64 = (high - low) / (2.0 * normal90) - return Sample_normal(mean, std, r) + return Normal(mean, std, r) } -func Sample_to(low float64, high float64, r State) float64 { +func To(low float64, high float64, r State) float64 { // Given a (positive) 90% confidence interval, // returns a sample from a lognorma with a matching 90% c.i. // Key idea: If we want a lognormal with 90% confidence interval [a, b] // we need but get a normal with 90% confidence interval [log(a), log(b)]. - // Then see code for Sample_normal_from_90_ci + // Then see code for Normal_from_90_ci var loglow float64 = math.Log(low) var loghigh float64 = math.Log(high) - return math.Exp(Sample_normal_from_90_ci(loglow, loghigh, r)) + return math.Exp(Normal_from_90_ci(loglow, loghigh, r)) } -func Sample_gamma(alpha float64, r State) float64 { +func Gamma(alpha float64, r State) float64 { // a simple method for generating gamma variables, marsaglia and wan tsang, 2001 // https://dl.acm.org/doi/pdf/10.1145/358407.358414 @@ -80,7 +80,7 @@ func Sample_gamma(alpha float64, r State) float64 { InnerLoop: for { - x = Sample_unit_normal(r) + x = Unit_normal(r) v = 1.0 + c*x if v > 0.0 { break InnerLoop @@ -88,7 +88,7 @@ func Sample_gamma(alpha float64, r State) float64 { } v = v * v * v - u = Sample_unit_uniform(r) + u = Unit_uniform(r) if u < 1.0-0.0331*(x*x*x*x) { // Condition 1 // the 0.0331 doesn't inspire much confidence @@ -105,17 +105,17 @@ func Sample_gamma(alpha float64, r State) float64 { } } else { - return Sample_gamma(1.0+alpha, r) * math.Pow(Sample_unit_uniform(r), 1.0/alpha) + return Gamma(1.0+alpha, r) * math.Pow(Unit_uniform(r), 1.0/alpha) } } -func Sample_beta(a float64, b float64, r State) float64 { - gamma_a := Sample_gamma(a, r) - gamma_b := Sample_gamma(b, r) +func Beta(a float64, b float64, r State) float64 { + gamma_a := Gamma(a, r) + gamma_b := Gamma(b, r) return gamma_a / (gamma_a + gamma_b) } -func Sample_mixture_once(fs []func64, weights []float64, r State) float64 { +func Mixture_once(fs []func64, weights []float64, r State) float64 { // fmt.Println("weights initially: ", weights) var sum_weights float64 = 0 @@ -149,7 +149,7 @@ func Sample_mixture_once(fs []func64, weights []float64, r State) float64 { } -func Sample_serially(f func64i, n_samples int) []float64 { +func Serially(f func64i, n_samples int) []float64 { xs := make([]float64, n_samples) // var global_state = rand.New(rand.NewPCG(uint64(1), uint64(2))) for i := 0; i < n_samples; i++ { @@ -158,7 +158,7 @@ func Sample_serially(f func64i, n_samples int) []float64 { return xs } -func Sample_mixture_serially_from_samples(fs [][]float64, weights []float64, n_samples int) ([]float64, error) { +func Mixture_serially_from_samples(fs [][]float64, weights []float64, n_samples int) ([]float64, error) { // Checks if len(weights) != len(fs) { @@ -206,7 +206,7 @@ func Sample_mixture_serially_from_samples(fs [][]float64, weights []float64, n_s return xs, nil } -func Sample_mixture_serially_from_samplers(fs []func64i, weights []float64, n_samples int) ([]float64, error) { +func Mixture_serially_from_samplers(fs []func64i, weights []float64, n_samples int) ([]float64, error) { // Checks if len(weights) != len(fs) { @@ -247,7 +247,7 @@ func Sample_mixture_serially_from_samplers(fs []func64i, weights []float64, n_sa return xs, nil } -func Sample_parallel(f func64, n_samples int) []float64 { +func Parallel(f func64, n_samples int) []float64 { var num_threads = 16 var xs = make([]float64, n_samples) var wg sync.WaitGroup @@ -283,9 +283,9 @@ func main() { Sample_many := func(r State) float64 { return Sample_to(2, 10, r) } fs := [4](func64){Sample_0, Sample_1, Sample_few, Sample_many} - model := func(r State) float64 { return Sample_mixture(fs[0:], ws[0:], r) } + model := func(r State) float64 { return Mixture(fs[0:], ws[0:], r) } n_samples := 1_000_000 - xs := Sample_parallel(model, n_samples) + xs := Parallel(model, n_samples) var avg float64 = 0 for _, x := range xs { avg += x @@ -298,7 +298,7 @@ func main() { var r = rand.New(rand.NewPCG(uint64(1), uint64(2))) var avg float64 = 0 for i := 0; i < n_samples; i++ { - avg += Sample_mixture(fs[0:], ws[0:], r) + avg += Mixture(fs[0:], ws[0:], r) } avg = avg / float64(n_samples) fmt.Printf("Average: %v\n", avg)