Compare commits

..

No commits in common. "84bdfa004f946fe0aa2246a2b54ab18e274c5a5b" and "a99934387cde5a317fd8d3f0db1aa9a773143a5f" have entirely different histories.

4 changed files with 10 additions and 39 deletions

View File

@ -4,7 +4,7 @@ This project is a minimalist, calculator-style DSL for fermi estimation. It can
## Motivation
Sometimes, [Squiggle](https://github.com/quantified-uncertainty/squiggle), [simple squiggle](https://git.nunosempere.com/quantified.uncertainty/simple-squiggle) or [squiggle.c](https://git.nunosempere.com/personal/squiggle.c) are still too complicated and un-unix-like. In particular, their startup cost is not instant.
Sometimes, [Squiggle](https://github.com/quantified-uncertainty/squiggle), [simple squiggle](https://git.nunosempere.com/quantified.uncertainty/simple-squiggle) or [squiggle.c](https://git.nunosempere.com/personal/squiggle.c) are still too complicated and un-unix-like.
## Installation
@ -62,7 +62,6 @@ $ fermi
beta: beta alpha beta
Variable assignment: =: variable_name
Variable assignment and clear stack: =. variable_name
Suffixes: %, K, M, B, T
Special commands:
Comment: # this is a comment
Summary stats: stats
@ -95,7 +94,7 @@ Command flags:
-echo
Specifies whether inputs should be echoed back. Useful if reading from a file
. -f string
Specifies a file with a model to run. Sets the echo command to true by default.
Specifies a file with a model to run
-n int
Specifies the number of samples to draw when using samples (default 100000)
-h Shows help message
@ -192,20 +191,15 @@ Done:
- [x] Figure out how to make models executable, by adding a #!/bin/bash-style command at the top?
- [x] Make -n flag work
- [x] Add flag to repeat input lines (useful when reading from files)
- [x] Add percentages
To (possibly) do:
- [ ] Fix lognormal multiplication and division by 0 or < 0
- [ ] Consider adding an understanding of percentages
- [ ] With the -f command line option, the program doesn't read from stdin after finishing reading the file
- [ ] Add functions. Now easier to do with an explicit representation of the stakc
- [ ] Think about how to draw a histogram from samples
- [ ] Dump samples to file
- [ ] Represent samples/statistics in some other way
- [ ] Perhaps use qsort rather than full sorting
- [ ] Program into a small device, like a calculator?
- [ ] Units?
Discarded:

BIN
fermi Executable file

Binary file not shown.

View File

@ -254,16 +254,6 @@ func multiplyBetaDists(beta1 Beta, beta2 Beta) Beta {
return Beta{a: beta1.a + beta2.a, b: beta1.b + beta2.b}
}
func multiplyLogDistAndScalar(l Lognormal, s Scalar) (Dist, error) {
if s == 0.0 {
return Scalar(0.0), nil
} else if s < 0.0 {
return operateDistsAsSamples(s, l, "+")
} else {
return multiplyLogDists(l, Lognormal{low: float64(s), high: float64(s)}), nil
}
}
func multiplyDists(old_dist Dist, new_dist Dist) (Dist, error) {
switch o := old_dist.(type) {
@ -273,20 +263,17 @@ func multiplyDists(old_dist Dist, new_dist Dist) (Dist, error) {
case Lognormal:
return multiplyLogDists(o, n), nil
case Scalar:
return multiplyLogDistAndScalar(o, n)
return multiplyLogDists(o, Lognormal{low: float64(n), high: float64(n)}), nil
}
}
case Scalar:
{
switch o {
case 1.0:
if o == 1 {
return new_dist, nil
case 0.0:
return Scalar(0.0), nil
}
switch n := new_dist.(type) {
case Lognormal:
return multiplyLogDistAndScalar(n, o)
return multiplyLogDists(Lognormal{low: float64(o), high: float64(o)}, n), nil
case Scalar:
return Scalar(float64(o) * float64(n)), nil
}
@ -317,14 +304,14 @@ func divideDists(old_dist Dist, new_dist Dist) (Dist, error) {
fmt.Println("Error: Can't divide by 0.0")
return nil, errors.New("Error: division by zero scalar")
}
return multiplyLogDistAndScalar(o, Scalar(1.0/n))
return multiplyLogDists(o, Lognormal{low: 1.0 / float64(n), high: 1.0 / float64(n)}), nil
}
}
case Scalar:
{
switch n := new_dist.(type) {
case Lognormal:
return multiplyLogDistAndScalar(Lognormal{low: 1.0 / n.high, high: 1.0 / n.low}, o)
return multiplyLogDists(Lognormal{low: float64(o), high: float64(o)}, Lognormal{low: 1.0 / n.high, high: 1.0 / n.low}), nil
case Scalar:
if n == 0.0 {
fmt.Println("Error: Can't divide by 0.0")
@ -387,15 +374,8 @@ func parseWordsIntoOpAndDist(words []string, vars map[string]Dist) (string, Dist
case 2:
new_low, err1 := pretty.ParseFloat(words[0])
new_high, err2 := pretty.ParseFloat(words[1])
switch {
case err1 != nil || err2 != nil:
if err1 != nil || err2 != nil {
return parseWordsErr("Trying to operate by a distribution, but distribution is not specified as two floats")
case new_low <= 0.0 || new_high <= 0.0:
return parseWordsErr("Trying to parse two floats as a lognormal, but the two floats must be greater than 0")
case new_low == new_high:
return parseWordsErr("Trying to parse two floats as a lognormal, but the two floats must be different. Try a single scalar instead?")
case new_low > new_high:
return parseWordsErr("Trying to parse two floats as a lognormal, but the first number is larger than the second number")
}
dist = Lognormal{low: new_low, high: new_high}
case 3:
@ -424,7 +404,7 @@ replForLoop:
for {
new_line, _ := reader.ReadString('\n')
if *echo_flag {
fmt.Print(new_line)
fmt.Printf(new_line)
}
new_line_before_comments, _, _ := strings.Cut(new_line, "#")
new_line_trimmed := strings.TrimSpace(new_line_before_comments)
@ -479,7 +459,7 @@ replForLoop:
func main() {
num_samples_flag := flag.Int("n", N_SAMPLES, "Specifies the number of samples to draw when using samples")
filename := flag.String("f", "", "Specifies a file with a model to run. Sets the echo flag to true")
filename := flag.String("f", "", "Specifies a file with a model to run")
echo_flag := flag.Bool("echo", false, "Specifies whether inputs should be echoed back. Useful if reading from a file.")
help_flag := flag.Bool("h", false, "Shows help message")
flag.Parse()
@ -492,7 +472,6 @@ func main() {
if *filename != "" {
file, err := os.Open(*filename)
if err == nil {
*echo_flag = true
reader = bufio.NewReader(file)
} else {
fmt.Printf("Error opening filename; reading from stdin instead\n")

View File

@ -72,8 +72,6 @@ func ParseFloat(word string) (float64, error) {
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':